]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
2 Copyright (C) 1990-2023 Free Software Foundation, Inc.
3 Contributed by steve chamberlain @cygnus
5 This file is part of BFD, the Binary File Descriptor library.
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 3 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston,
20 MA 02110-1301, USA. */
22 /* Yet another way of extracting documentation from source.
23 No, I haven't finished it yet, but I hope you people like it better
28 Basically, this is a sort of string forth, maybe we should call it
31 You define new words thus:
32 : <newword> <oldwords> ;
36 /* Primitives provided by the program:
38 Two stacks are provided, a string stack and an integer stack.
40 Internal state variables:
41 internal_wanted - indicates whether `-i' was passed
42 internal_mode - user-settable
46 ! - pop top of integer stack for address, pop next for value; store
47 @ - treat value on integer stack as the address of an integer; push
48 that integer on the integer stack after popping the "address"
49 hello - print "hello\n" to stdout
50 stdout - put stdout marker on TOS
51 stderr - put stderr marker on TOS
52 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
55 copy_past_newline - append input, up to and including newline into TOS
59 remchar - delete last character from TOS
61 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
62 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
63 and @item to each "o" line; append @end itemize
64 courierize - put @example around . and | lines, translate {* *} { }
67 outputdots - strip out lines without leading dots
68 paramstuff - convert full declaration into "PARAMS" form if not already
69 maybecatstr - do catstr if internal_mode == internal_wanted, discard
71 translatecomments - turn {* and *} into comment delimiters
72 kill_bogus_lines - get rid of extra newlines
74 internalmode - pop from integer stack, set `internalmode' to that value
75 print_stack_level - print current stack depth to stderr
76 strip_trailing_newlines - go ahead, guess...
77 [quoted string] - push string onto string stack
78 [word starting with digit] - push atol(str) onto integer stack
80 A command must be all upper-case, and alone on a line.
93 /* Here is a string type ... */
98 unsigned long write_idx
;
102 /* Compiled programs consist of arrays of these. */
107 struct dict_struct
*e
;
112 typedef struct dict_struct
115 struct dict_struct
*next
;
126 string_type stack
[STACK
];
129 unsigned int idx
= 0; /* Pos in input buffer */
130 string_type
*ptr
; /* and the buffer */
133 long *isp
= &istack
[0];
142 fprintf (stderr
, "%s\n", msg
);
147 xmalloc (size_t size
)
153 newmem
= malloc (size
);
155 die ("out of memory");
161 xrealloc (void *oldmem
, size_t size
)
168 newmem
= malloc (size
);
170 newmem
= realloc (oldmem
, size
);
172 die ("out of memory");
178 xstrdup (const char *s
)
180 size_t len
= strlen (s
) + 1;
181 char *ret
= xmalloc (len
);
182 return memcpy (ret
, s
, len
);
186 init_string_with_size (string_type
*buffer
, unsigned int size
)
188 buffer
->write_idx
= 0;
190 buffer
->ptr
= xmalloc (size
);
194 init_string (string_type
*buffer
)
196 init_string_with_size (buffer
, DEF_SIZE
);
200 find (string_type
*str
, char *what
)
205 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
207 if (*p
== str
->ptr
[i
])
216 write_buffer (string_type
*buffer
, FILE *f
)
218 if (buffer
->write_idx
!= 0
219 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
220 die ("cannot write output");
224 delete_string (string_type
*buffer
)
231 addr (string_type
*buffer
, unsigned int idx
)
233 return buffer
->ptr
+ idx
;
237 at (string_type
*buffer
, unsigned int pos
)
239 if (pos
>= buffer
->write_idx
)
241 return buffer
->ptr
[pos
];
245 catchar (string_type
*buffer
, int ch
)
247 if (buffer
->write_idx
== buffer
->size
)
250 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
253 buffer
->ptr
[buffer
->write_idx
++] = ch
;
257 overwrite_string (string_type
*dst
, string_type
*src
)
260 dst
->size
= src
->size
;
261 dst
->write_idx
= src
->write_idx
;
266 catbuf (string_type
*buffer
, char *buf
, unsigned int len
)
268 if (buffer
->write_idx
+ len
>= buffer
->size
)
270 while (buffer
->write_idx
+ len
>= buffer
->size
)
272 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
274 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
275 buffer
->write_idx
+= len
;
279 cattext (string_type
*buffer
, char *string
)
281 catbuf (buffer
, string
, (unsigned int) strlen (string
));
285 catstr (string_type
*dst
, string_type
*src
)
287 catbuf (dst
, src
->ptr
, src
->write_idx
);
291 skip_white_and_stars (string_type
*src
, unsigned int idx
)
294 while ((c
= at (src
, idx
)),
295 isspace ((unsigned char) c
)
297 /* Don't skip past end-of-comment or star as first
298 character on its line. */
299 && at (src
, idx
+1) != '/'
300 && at (src
, idx
-1) != '\n'))
306 skip_past_newline_1 (string_type
*ptr
, unsigned int idx
)
309 && at (ptr
, idx
) != '\n')
311 if (at (ptr
, idx
) == '\n')
320 die ("underflow in string stack");
321 if (tos
>= stack
+ STACK
)
322 die ("overflow in string stack");
329 die ("underflow in integer stack");
330 if (isp
>= istack
+ STACK
)
331 die ("overflow in integer stack");
335 exec (dict_type
*word
)
346 dict_type
*e
= pc
[1].e
;
360 strip_trailing_newlines (void)
362 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
363 || at (tos
, tos
->write_idx
- 1) == '\n')
364 && tos
->write_idx
> 0)
386 cattext (tos
, pc
->s
);
390 /* This function removes everything not inside comments starting on
391 the first char of the line from the string, also when copying
392 comments, removes blank space and leading *'s.
393 Blank lines are turned into one blank line. */
396 remove_noncomments (string_type
*src
, string_type
*dst
)
398 unsigned int idx
= 0;
400 while (at (src
, idx
))
402 /* Now see if we have a comment at the start of the line. */
403 if (at (src
, idx
) == '\n'
404 && at (src
, idx
+ 1) == '/'
405 && at (src
, idx
+ 2) == '*')
409 idx
= skip_white_and_stars (src
, idx
);
411 /* Remove leading dot */
412 if (at (src
, idx
) == '.')
415 /* Copy to the end of the line, or till the end of the
417 while (at (src
, idx
))
419 if (at (src
, idx
) == '\n')
421 /* end of line, echo and scrape of leading blanks */
422 if (at (src
, idx
+ 1) == '\n')
426 idx
= skip_white_and_stars (src
, idx
);
428 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
431 cattext (dst
, "\nENDDD\n");
436 catchar (dst
, at (src
, idx
));
447 print_stack_level (void)
449 fprintf (stderr
, "current string stack depth = %ld, ",
450 (long) (tos
- stack
));
451 fprintf (stderr
, "current integer stack depth = %ld\n",
452 (long) (isp
- istack
));
460 name PARAMS ((stuff));
476 /* Make sure that it's not already param'd or proto'd. */
478 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
484 /* Find the open paren. */
485 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
489 /* Step back to the fname. */
491 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
494 && !isspace ((unsigned char) at (tos
,fname
))
495 && at (tos
,fname
) != '*')
500 /* Output type, omitting trailing whitespace character(s), if
502 for (len
= fname
; 0 < len
; len
--)
504 if (!isspace ((unsigned char) at (tos
, len
- 1)))
507 for (idx
= 0; idx
< len
; idx
++)
508 catchar (&out
, at (tos
, idx
));
510 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
512 /* Output function name, omitting trailing whitespace
513 character(s), if any. */
514 for (len
= openp
; 0 < len
; len
--)
516 if (!isspace ((unsigned char) at (tos
, len
- 1)))
519 for (idx
= fname
; idx
< len
; idx
++)
520 catchar (&out
, at (tos
, idx
));
522 cattext (&out
, " PARAMS (");
524 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
525 catchar (&out
, at (tos
, idx
));
527 cattext (&out
, ");\n\n");
529 overwrite_string (tos
, &out
);
535 and *} into comments */
538 translatecomments (void)
540 unsigned int idx
= 0;
544 while (at (tos
, idx
))
546 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
548 cattext (&out
, "/*");
551 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
553 cattext (&out
, "*/");
558 catchar (&out
, at (tos
, idx
));
563 overwrite_string (tos
, &out
);
568 /* Mod tos so that only lines with leading dots remain */
572 unsigned int idx
= 0;
576 while (at (tos
, idx
))
578 /* Every iteration begins at the start of a line. */
579 if (at (tos
, idx
) == '.')
585 while ((c
= at (tos
, idx
)) && c
!= '\n')
587 if (c
== '{' && at (tos
, idx
+ 1) == '*')
589 cattext (&out
, "/*");
592 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
594 cattext (&out
, "*/");
605 catchar (&out
, '\n');
609 idx
= skip_past_newline_1 (tos
, idx
);
613 overwrite_string (tos
, &out
);
617 /* Find lines starting with . and | and put example around them on tos */
622 unsigned int idx
= 0;
627 while (at (tos
, idx
))
629 if (at (tos
, idx
) == '\n'
630 && (at (tos
, idx
+1 ) == '.'
631 || at (tos
, idx
+ 1) == '|'))
633 cattext (&out
, "\n@example\n");
638 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
642 /* We are inside {} parameters of some command;
643 Just pass through until matching brace. */
644 if (at (tos
, idx
) == '{')
646 else if (at (tos
, idx
) == '}')
649 else if (command
!= 0)
651 if (at (tos
, idx
) == '{')
653 else if (!islower ((unsigned char) at (tos
, idx
)))
656 else if (at (tos
, idx
) == '@'
657 && islower ((unsigned char) at (tos
, idx
+ 1)))
661 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
663 cattext (&out
, "/*");
667 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
669 cattext (&out
, "*/");
673 else if (at (tos
, idx
) == '{'
674 || at (tos
, idx
) == '}')
679 catchar (&out
, at (tos
, idx
));
682 catchar (&out
, '\n');
684 while (at (tos
, idx
) == '\n'
685 && ((at (tos
, idx
+ 1) == '.')
686 || (at (tos
, idx
+ 1) == '|')))
688 cattext (&out
, "@end example");
692 catchar (&out
, at (tos
, idx
));
697 overwrite_string (tos
, &out
);
701 /* Finds any lines starting with "o ", if there are any, then turns
702 on @itemize @bullet, and @items each of them. Then ends with @end
703 itemize, inplace at TOS*/
708 unsigned int idx
= 0;
713 while (at (tos
, idx
))
715 if (at (tos
, idx
) == '@'
716 && at (tos
, idx
+ 1) == '*')
721 else if (at (tos
, idx
) == '\n'
722 && at (tos
, idx
+ 1) == 'o'
723 && isspace ((unsigned char) at (tos
, idx
+ 2)))
727 cattext (&out
, "\n@itemize @bullet\n");
731 cattext (&out
, "\n@item\n");
736 catchar (&out
, at (tos
, idx
));
737 if (on
&& at (tos
, idx
) == '\n'
738 && at (tos
, idx
+ 1) == '\n'
739 && at (tos
, idx
+ 2) != 'o')
741 cattext (&out
, "@end itemize");
750 cattext (&out
, "@end itemize\n");
758 /* Turn <<foo>> into @code{foo} in place at TOS*/
761 do_fancy_stuff (void)
763 unsigned int idx
= 0;
766 while (at (tos
, idx
))
768 if (at (tos
, idx
) == '<'
769 && at (tos
, idx
+ 1) == '<'
770 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
772 /* This qualifies as a << startup. */
774 cattext (&out
, "@code{");
776 && at (tos
, idx
) != '>' )
778 catchar (&out
, at (tos
, idx
));
787 catchar (&out
, at (tos
, idx
));
797 /* A command is all upper case,and alone on a line. */
800 iscommand (string_type
*ptr
, unsigned int idx
)
802 unsigned int len
= 0;
803 while (at (ptr
, idx
))
805 if (isupper ((unsigned char) at (ptr
, idx
))
806 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
811 else if (at (ptr
, idx
) == '\n')
824 copy_past_newline (string_type
*ptr
, unsigned int idx
, string_type
*dst
)
828 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
830 if (at (ptr
, idx
) == '\t')
832 /* Expand tabs. Neither makeinfo nor TeX can cope well with
836 while (++column
& 7);
840 catchar (dst
, at (ptr
, idx
));
846 catchar (dst
, at (ptr
, idx
));
853 icopy_past_newline (void)
858 idx
= copy_past_newline (ptr
, idx
, tos
);
863 Take the string at the top of the stack, do some prettying. */
866 kill_bogus_lines (void)
876 /* Drop leading nl. */
877 while (at (tos
, idx
) == '\n')
883 /* If the first char is a '.' prepend a newline so that it is
884 recognized properly later. */
885 if (at (tos
, idx
) == '.')
886 catchar (&out
, '\n');
888 /* Find the last char. */
889 while (at (tos
, idx
))
894 /* Find the last non white before the nl. */
897 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
901 /* Copy buffer upto last char, but blank lines before and after
907 if (at (tos
, c
) == '\n'
908 && at (tos
, c
+ 1) == '\n'
909 && at (tos
, c
+ 2) == '.')
911 /* Ignore two newlines before a dot. */
914 else if (at (tos
, c
) == '.' && sl
)
916 /* remember that this line started with a dot. */
919 else if (at (tos
, c
) == '\n'
920 && at (tos
, c
+ 1) == '\n'
924 /* Ignore two newlines when last line was dot. */
927 catchar (&out
, at (tos
, c
));
928 if (at (tos
, c
) == '\n')
945 catchar (&out
, '\n');
960 while (at (tos
, idx
))
962 switch (at (tos
, idx
))
965 cattext (&out
, "\n");
967 if (tab
&& at (tos
, idx
))
989 catchar (&out
, at (tos
, idx
));
1004 get_stuff_in_command (void)
1010 while (at (ptr
, idx
))
1012 if (iscommand (ptr
, idx
))
1014 idx
= copy_past_newline (ptr
, idx
, tos
);
1036 catstr (tos
, tos
- 1);
1045 delete_string (tos
+ 1);
1062 catstr (tos
, tos
+ 1);
1063 delete_string (tos
+ 1);
1068 skip_past_newline (void)
1070 idx
= skip_past_newline_1 (ptr
, idx
);
1077 internal_mode
= *(isp
);
1086 if (internal_wanted
== internal_mode
)
1088 catstr (tos
- 1, tos
);
1090 delete_string (tos
);
1097 nextword (char *string
, char **word
)
1106 while (isspace ((unsigned char) *string
) || *string
== '-')
1110 while (*string
&& *string
!= '\n')
1125 word_start
= string
;
1132 if (*string
== '\\')
1138 while (*string
!= '"');
1142 while (!isspace ((unsigned char) *string
))
1150 *word
= xmalloc (length
+ 1);
1155 for (idx
= 0; idx
< length
; idx
++)
1157 if (src
[idx
] == '\\')
1158 switch (src
[idx
+ 1])
1166 *dst
++ = src
[idx
+ 1];
1185 lookup_word (char *word
)
1187 dict_type
*ptr
= root
;
1190 if (strcmp (ptr
->word
, word
) == 0)
1195 fprintf (stderr
, "Can't find %s\n", word
);
1202 dict_type
*ptr
= root
;
1212 for (i
= 0; i
< ptr
->code_end
- 1; i
++)
1213 if (ptr
->code
[i
].f
== push_text
1214 && ptr
->code
[i
+ 1].s
)
1216 free (ptr
->code
[i
+ 1].s
- 1);
1232 while (at (ptr
, idx
))
1234 /* It's worth looking through the command list. */
1235 if (iscommand (ptr
, idx
))
1240 (void) nextword (addr (ptr
, idx
), &next
);
1242 word
= lookup_word (next
);
1251 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1252 idx
= skip_past_newline_1 (ptr
, idx
);
1257 idx
= skip_past_newline_1 (ptr
, idx
);
1262 newentry (char *word
)
1264 dict_type
*new_d
= xmalloc (sizeof (*new_d
));
1268 new_d
->code
= xmalloc (sizeof (*new_d
->code
));
1269 new_d
->code_length
= 1;
1270 new_d
->code_end
= 0;
1275 add_to_definition (dict_type
*entry
, pcu word
)
1277 if (entry
->code_end
== entry
->code_length
)
1279 entry
->code_length
+= 2;
1280 entry
->code
= xrealloc (entry
->code
,
1281 entry
->code_length
* sizeof (*entry
->code
));
1283 entry
->code
[entry
->code_end
] = word
;
1285 return entry
->code_end
++;
1289 add_intrinsic (char *name
, void (*func
) (void))
1291 dict_type
*new_d
= newentry (xstrdup (name
));
1293 add_to_definition (new_d
, p
);
1295 add_to_definition (new_d
, p
);
1299 compile (char *string
)
1301 /* Add words to the dictionary. */
1304 string
= nextword (string
, &word
);
1305 while (string
&& *string
&& word
[0])
1312 /* Compile a word and add to dictionary. */
1314 string
= nextword (string
, &word
);
1317 ptr
= newentry (word
);
1318 string
= nextword (string
, &word
);
1326 while (word
[0] != ';')
1331 /* got a string, embed magic push string
1334 add_to_definition (ptr
, p
);
1336 add_to_definition (ptr
, p
);
1348 /* Got a number, embedd the magic push number
1351 add_to_definition (ptr
, p
);
1353 add_to_definition (ptr
, p
);
1358 add_to_definition (ptr
, p
);
1359 p
.e
= lookup_word (word
);
1360 add_to_definition (ptr
, p
);
1364 string
= nextword (string
, &word
);
1367 add_to_definition (ptr
, p
);
1369 string
= nextword (string
, &word
);
1373 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1382 *(long *) ((isp
[0])) = isp
[-1];
1391 isp
[0] = *(long *) (isp
[0]);
1424 write_buffer (tos
, stdout
);
1426 write_buffer (tos
, stderr
);
1428 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1437 read_in (string_type
*str
, FILE *file
)
1443 r
= fread (buff
, 1, sizeof (buff
), file
);
1444 catbuf (str
, buff
, r
);
1449 catbuf (str
, buff
, 1);
1455 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1459 /* There is no reliable way to declare exit. Sometimes it returns
1460 int, and sometimes it returns void. Sometimes it changes between
1461 OS releases. Trying to get it declared correctly in the hosts file
1462 is a pointless waste of time. */
1471 main (int ac
, char *av
[])
1477 init_string (&buffer
);
1478 init_string (&pptr
);
1479 init_string (stack
+ 0);
1483 add_intrinsic ("push_text", push_text
);
1484 add_intrinsic ("!", bang
);
1485 add_intrinsic ("@", atsign
);
1486 add_intrinsic ("hello", hello
);
1487 add_intrinsic ("stdout", stdout_
);
1488 add_intrinsic ("stderr", stderr_
);
1489 add_intrinsic ("print", print
);
1490 add_intrinsic ("skip_past_newline", skip_past_newline
);
1491 add_intrinsic ("catstr", icatstr
);
1492 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1493 add_intrinsic ("dup", other_dup
);
1494 add_intrinsic ("drop", drop
);
1495 add_intrinsic ("idrop", idrop
);
1496 add_intrinsic ("remchar", remchar
);
1497 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1498 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1499 add_intrinsic ("bulletize", bulletize
);
1500 add_intrinsic ("courierize", courierize
);
1501 /* If the following line gives an error, exit() is not declared in the
1502 ../hosts/foo.h file for this host. Fix it there, not here! */
1503 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1504 add_intrinsic ("exit", chew_exit
);
1505 add_intrinsic ("swap", swap
);
1506 add_intrinsic ("outputdots", outputdots
);
1507 add_intrinsic ("paramstuff", paramstuff
);
1508 add_intrinsic ("maybecatstr", maybecatstr
);
1509 add_intrinsic ("translatecomments", translatecomments
);
1510 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1511 add_intrinsic ("indent", indent
);
1512 add_intrinsic ("internalmode", internalmode
);
1513 add_intrinsic ("print_stack_level", print_stack_level
);
1514 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1516 /* Put a nl at the start. */
1517 catchar (&buffer
, '\n');
1519 read_in (&buffer
, stdin
);
1520 remove_noncomments (&buffer
, ptr
);
1521 for (i
= 1; i
< (unsigned int) ac
; i
++)
1523 if (av
[i
][0] == '-')
1525 if (av
[i
][1] == 'f')
1531 f
= fopen (av
[i
+ 1], "r");
1534 fprintf (stderr
, "Can't open the input file %s\n",
1544 else if (av
[i
][1] == 'i')
1546 internal_wanted
= 1;
1548 else if (av
[i
][1] == 'w')
1556 write_buffer (stack
+ 0, stdout
);
1558 delete_string (&pptr
);
1559 delete_string (&buffer
);
1562 fprintf (stderr
, "finishing with current stack level %ld\n",
1563 (long) (tos
- stack
));