]>
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 maybecatstr - do catstr if internal_mode == internal_wanted, discard
70 translatecomments - turn {* and *} into comment delimiters
71 kill_bogus_lines - get rid of extra newlines
73 internalmode - pop from integer stack, set `internalmode' to that value
74 print_stack_level - print current stack depth to stderr
75 strip_trailing_newlines - go ahead, guess...
76 [quoted string] - push string onto string stack
77 [word starting with digit] - push atol(str) onto integer stack
79 A command must be all upper-case, and alone on a line.
92 /* Here is a string type ... */
97 unsigned long write_idx
;
101 /* Compiled programs consist of arrays of these. */
106 struct dict_struct
*e
;
111 typedef struct dict_struct
114 struct dict_struct
*next
;
125 string_type stack
[STACK
];
128 unsigned int idx
= 0; /* Pos in input buffer */
129 string_type
*ptr
; /* and the buffer */
132 long *isp
= &istack
[0];
141 fprintf (stderr
, "%s\n", msg
);
146 xmalloc (size_t size
)
152 newmem
= malloc (size
);
154 die ("out of memory");
160 xrealloc (void *oldmem
, size_t size
)
167 newmem
= malloc (size
);
169 newmem
= realloc (oldmem
, size
);
171 die ("out of memory");
177 xstrdup (const char *s
)
179 size_t len
= strlen (s
) + 1;
180 char *ret
= xmalloc (len
);
181 return memcpy (ret
, s
, len
);
185 init_string_with_size (string_type
*buffer
, unsigned int size
)
187 buffer
->write_idx
= 0;
189 buffer
->ptr
= xmalloc (size
);
193 init_string (string_type
*buffer
)
195 init_string_with_size (buffer
, DEF_SIZE
);
199 find (string_type
*str
, char *what
)
204 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
206 if (*p
== str
->ptr
[i
])
215 write_buffer (string_type
*buffer
, FILE *f
)
217 if (buffer
->write_idx
!= 0
218 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
219 die ("cannot write output");
223 delete_string (string_type
*buffer
)
230 addr (string_type
*buffer
, unsigned int idx
)
232 return buffer
->ptr
+ idx
;
236 at (string_type
*buffer
, unsigned int pos
)
238 if (pos
>= buffer
->write_idx
)
240 return buffer
->ptr
[pos
];
244 catchar (string_type
*buffer
, int ch
)
246 if (buffer
->write_idx
== buffer
->size
)
249 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
252 buffer
->ptr
[buffer
->write_idx
++] = ch
;
256 overwrite_string (string_type
*dst
, string_type
*src
)
259 dst
->size
= src
->size
;
260 dst
->write_idx
= src
->write_idx
;
265 catbuf (string_type
*buffer
, char *buf
, unsigned int len
)
267 if (buffer
->write_idx
+ len
>= buffer
->size
)
269 while (buffer
->write_idx
+ len
>= buffer
->size
)
271 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
273 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
274 buffer
->write_idx
+= len
;
278 cattext (string_type
*buffer
, char *string
)
280 catbuf (buffer
, string
, (unsigned int) strlen (string
));
284 catstr (string_type
*dst
, string_type
*src
)
286 catbuf (dst
, src
->ptr
, src
->write_idx
);
290 skip_white_and_stars (string_type
*src
, unsigned int idx
)
293 while ((c
= at (src
, idx
)),
294 isspace ((unsigned char) c
)
296 /* Don't skip past end-of-comment or star as first
297 character on its line. */
298 && at (src
, idx
+1) != '/'
299 && at (src
, idx
-1) != '\n'))
305 skip_past_newline_1 (string_type
*ptr
, unsigned int idx
)
308 && at (ptr
, idx
) != '\n')
310 if (at (ptr
, idx
) == '\n')
319 die ("underflow in string stack");
320 if (tos
>= stack
+ STACK
)
321 die ("overflow in string stack");
328 die ("underflow in integer stack");
329 if (isp
>= istack
+ STACK
)
330 die ("overflow in integer stack");
334 exec (dict_type
*word
)
345 dict_type
*e
= pc
[1].e
;
359 strip_trailing_newlines (void)
361 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
362 || at (tos
, tos
->write_idx
- 1) == '\n')
363 && tos
->write_idx
> 0)
385 cattext (tos
, pc
->s
);
389 /* This function removes everything not inside comments starting on
390 the first char of the line from the string, also when copying
391 comments, removes blank space and leading *'s.
392 Blank lines are turned into one blank line. */
395 remove_noncomments (string_type
*src
, string_type
*dst
)
397 unsigned int idx
= 0;
399 while (at (src
, idx
))
401 /* Now see if we have a comment at the start of the line. */
402 if (at (src
, idx
) == '\n'
403 && at (src
, idx
+ 1) == '/'
404 && at (src
, idx
+ 2) == '*')
408 idx
= skip_white_and_stars (src
, idx
);
410 /* Remove leading dot */
411 if (at (src
, idx
) == '.')
414 /* Copy to the end of the line, or till the end of the
416 while (at (src
, idx
))
418 if (at (src
, idx
) == '\n')
420 /* end of line, echo and scrape of leading blanks */
421 if (at (src
, idx
+ 1) == '\n')
425 idx
= skip_white_and_stars (src
, idx
);
427 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
430 cattext (dst
, "\nENDDD\n");
435 catchar (dst
, at (src
, idx
));
446 print_stack_level (void)
448 fprintf (stderr
, "current string stack depth = %ld, ",
449 (long) (tos
- stack
));
450 fprintf (stderr
, "current integer stack depth = %ld\n",
451 (long) (isp
- istack
));
456 and *} into comments */
459 translatecomments (void)
461 unsigned int idx
= 0;
465 while (at (tos
, idx
))
467 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
469 cattext (&out
, "/*");
472 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
474 cattext (&out
, "*/");
479 catchar (&out
, at (tos
, idx
));
484 overwrite_string (tos
, &out
);
489 /* Mod tos so that only lines with leading dots remain */
493 unsigned int idx
= 0;
497 while (at (tos
, idx
))
499 /* Every iteration begins at the start of a line. */
500 if (at (tos
, idx
) == '.')
506 while ((c
= at (tos
, idx
)) && c
!= '\n')
508 if (c
== '{' && at (tos
, idx
+ 1) == '*')
510 cattext (&out
, "/*");
513 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
515 cattext (&out
, "*/");
526 catchar (&out
, '\n');
530 idx
= skip_past_newline_1 (tos
, idx
);
534 overwrite_string (tos
, &out
);
538 /* Find lines starting with . and | and put example around them on tos */
543 unsigned int idx
= 0;
548 while (at (tos
, idx
))
550 if (at (tos
, idx
) == '\n'
551 && (at (tos
, idx
+1 ) == '.'
552 || at (tos
, idx
+ 1) == '|'))
554 cattext (&out
, "\n@example\n");
559 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
563 /* We are inside {} parameters of some command;
564 Just pass through until matching brace. */
565 if (at (tos
, idx
) == '{')
567 else if (at (tos
, idx
) == '}')
570 else if (command
!= 0)
572 if (at (tos
, idx
) == '{')
574 else if (!islower ((unsigned char) at (tos
, idx
)))
577 else if (at (tos
, idx
) == '@'
578 && islower ((unsigned char) at (tos
, idx
+ 1)))
582 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
584 cattext (&out
, "/*");
588 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
590 cattext (&out
, "*/");
594 else if (at (tos
, idx
) == '{'
595 || at (tos
, idx
) == '}')
600 catchar (&out
, at (tos
, idx
));
603 catchar (&out
, '\n');
605 while (at (tos
, idx
) == '\n'
606 && ((at (tos
, idx
+ 1) == '.')
607 || (at (tos
, idx
+ 1) == '|')))
609 cattext (&out
, "@end example");
613 catchar (&out
, at (tos
, idx
));
618 overwrite_string (tos
, &out
);
622 /* Finds any lines starting with "o ", if there are any, then turns
623 on @itemize @bullet, and @items each of them. Then ends with @end
624 itemize, inplace at TOS*/
629 unsigned int idx
= 0;
634 while (at (tos
, idx
))
636 if (at (tos
, idx
) == '@'
637 && at (tos
, idx
+ 1) == '*')
642 else if (at (tos
, idx
) == '\n'
643 && at (tos
, idx
+ 1) == 'o'
644 && isspace ((unsigned char) at (tos
, idx
+ 2)))
648 cattext (&out
, "\n@itemize @bullet\n");
652 cattext (&out
, "\n@item\n");
657 catchar (&out
, at (tos
, idx
));
658 if (on
&& at (tos
, idx
) == '\n'
659 && at (tos
, idx
+ 1) == '\n'
660 && at (tos
, idx
+ 2) != 'o')
662 cattext (&out
, "@end itemize");
671 cattext (&out
, "@end itemize\n");
679 /* Turn <<foo>> into @code{foo} in place at TOS*/
682 do_fancy_stuff (void)
684 unsigned int idx
= 0;
687 while (at (tos
, idx
))
689 if (at (tos
, idx
) == '<'
690 && at (tos
, idx
+ 1) == '<'
691 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
693 /* This qualifies as a << startup. */
695 cattext (&out
, "@code{");
697 && at (tos
, idx
) != '>' )
699 catchar (&out
, at (tos
, idx
));
708 catchar (&out
, at (tos
, idx
));
718 /* A command is all upper case,and alone on a line. */
721 iscommand (string_type
*ptr
, unsigned int idx
)
723 unsigned int len
= 0;
724 while (at (ptr
, idx
))
726 if (isupper ((unsigned char) at (ptr
, idx
))
727 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
732 else if (at (ptr
, idx
) == '\n')
745 copy_past_newline (string_type
*ptr
, unsigned int idx
, string_type
*dst
)
749 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
751 if (at (ptr
, idx
) == '\t')
753 /* Expand tabs. Neither makeinfo nor TeX can cope well with
757 while (++column
& 7);
761 catchar (dst
, at (ptr
, idx
));
767 catchar (dst
, at (ptr
, idx
));
774 icopy_past_newline (void)
779 idx
= copy_past_newline (ptr
, idx
, tos
);
784 Take the string at the top of the stack, do some prettying. */
787 kill_bogus_lines (void)
797 /* Drop leading nl. */
798 while (at (tos
, idx
) == '\n')
804 /* If the first char is a '.' prepend a newline so that it is
805 recognized properly later. */
806 if (at (tos
, idx
) == '.')
807 catchar (&out
, '\n');
809 /* Find the last char. */
810 while (at (tos
, idx
))
815 /* Find the last non white before the nl. */
818 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
822 /* Copy buffer upto last char, but blank lines before and after
828 if (at (tos
, c
) == '\n'
829 && at (tos
, c
+ 1) == '\n'
830 && at (tos
, c
+ 2) == '.')
832 /* Ignore two newlines before a dot. */
835 else if (at (tos
, c
) == '.' && sl
)
837 /* remember that this line started with a dot. */
840 else if (at (tos
, c
) == '\n'
841 && at (tos
, c
+ 1) == '\n'
845 /* Ignore two newlines when last line was dot. */
848 catchar (&out
, at (tos
, c
));
849 if (at (tos
, c
) == '\n')
866 catchar (&out
, '\n');
881 while (at (tos
, idx
))
883 switch (at (tos
, idx
))
886 cattext (&out
, "\n");
888 if (tab
&& at (tos
, idx
))
910 catchar (&out
, at (tos
, idx
));
925 get_stuff_in_command (void)
931 while (at (ptr
, idx
))
933 if (iscommand (ptr
, idx
))
935 idx
= copy_past_newline (ptr
, idx
, tos
);
957 catstr (tos
, tos
- 1);
966 delete_string (tos
+ 1);
983 catstr (tos
, tos
+ 1);
984 delete_string (tos
+ 1);
989 skip_past_newline (void)
991 idx
= skip_past_newline_1 (ptr
, idx
);
998 internal_mode
= *(isp
);
1007 if (internal_wanted
== internal_mode
)
1009 catstr (tos
- 1, tos
);
1011 delete_string (tos
);
1018 nextword (char *string
, char **word
)
1027 while (isspace ((unsigned char) *string
) || *string
== '-')
1031 while (*string
&& *string
!= '\n')
1046 word_start
= string
;
1053 if (*string
== '\\')
1059 while (*string
!= '"');
1063 while (!isspace ((unsigned char) *string
))
1071 *word
= xmalloc (length
+ 1);
1076 for (idx
= 0; idx
< length
; idx
++)
1078 if (src
[idx
] == '\\')
1079 switch (src
[idx
+ 1])
1087 *dst
++ = src
[idx
+ 1];
1106 lookup_word (char *word
)
1108 dict_type
*ptr
= root
;
1111 if (strcmp (ptr
->word
, word
) == 0)
1116 fprintf (stderr
, "Can't find %s\n", word
);
1123 dict_type
*ptr
= root
;
1133 for (i
= 0; i
< ptr
->code_end
- 1; i
++)
1134 if (ptr
->code
[i
].f
== push_text
1135 && ptr
->code
[i
+ 1].s
)
1137 free (ptr
->code
[i
+ 1].s
- 1);
1153 while (at (ptr
, idx
))
1155 /* It's worth looking through the command list. */
1156 if (iscommand (ptr
, idx
))
1161 (void) nextword (addr (ptr
, idx
), &next
);
1163 word
= lookup_word (next
);
1172 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1173 idx
= skip_past_newline_1 (ptr
, idx
);
1178 idx
= skip_past_newline_1 (ptr
, idx
);
1183 newentry (char *word
)
1185 dict_type
*new_d
= xmalloc (sizeof (*new_d
));
1189 new_d
->code
= xmalloc (sizeof (*new_d
->code
));
1190 new_d
->code_length
= 1;
1191 new_d
->code_end
= 0;
1196 add_to_definition (dict_type
*entry
, pcu word
)
1198 if (entry
->code_end
== entry
->code_length
)
1200 entry
->code_length
+= 2;
1201 entry
->code
= xrealloc (entry
->code
,
1202 entry
->code_length
* sizeof (*entry
->code
));
1204 entry
->code
[entry
->code_end
] = word
;
1206 return entry
->code_end
++;
1210 add_intrinsic (char *name
, void (*func
) (void))
1212 dict_type
*new_d
= newentry (xstrdup (name
));
1214 add_to_definition (new_d
, p
);
1216 add_to_definition (new_d
, p
);
1220 compile (char *string
)
1222 /* Add words to the dictionary. */
1225 string
= nextword (string
, &word
);
1226 while (string
&& *string
&& word
[0])
1233 /* Compile a word and add to dictionary. */
1235 string
= nextword (string
, &word
);
1238 ptr
= newentry (word
);
1239 string
= nextword (string
, &word
);
1247 while (word
[0] != ';')
1252 /* got a string, embed magic push string
1255 add_to_definition (ptr
, p
);
1257 add_to_definition (ptr
, p
);
1269 /* Got a number, embedd the magic push number
1272 add_to_definition (ptr
, p
);
1274 add_to_definition (ptr
, p
);
1279 add_to_definition (ptr
, p
);
1280 p
.e
= lookup_word (word
);
1281 add_to_definition (ptr
, p
);
1285 string
= nextword (string
, &word
);
1288 add_to_definition (ptr
, p
);
1290 string
= nextword (string
, &word
);
1294 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1303 *(long *) ((isp
[0])) = isp
[-1];
1312 isp
[0] = *(long *) (isp
[0]);
1345 write_buffer (tos
, stdout
);
1347 write_buffer (tos
, stderr
);
1349 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1358 read_in (string_type
*str
, FILE *file
)
1364 r
= fread (buff
, 1, sizeof (buff
), file
);
1365 catbuf (str
, buff
, r
);
1370 catbuf (str
, buff
, 1);
1376 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1380 /* There is no reliable way to declare exit. Sometimes it returns
1381 int, and sometimes it returns void. Sometimes it changes between
1382 OS releases. Trying to get it declared correctly in the hosts file
1383 is a pointless waste of time. */
1392 main (int ac
, char *av
[])
1398 init_string (&buffer
);
1399 init_string (&pptr
);
1400 init_string (stack
+ 0);
1404 add_intrinsic ("push_text", push_text
);
1405 add_intrinsic ("!", bang
);
1406 add_intrinsic ("@", atsign
);
1407 add_intrinsic ("hello", hello
);
1408 add_intrinsic ("stdout", stdout_
);
1409 add_intrinsic ("stderr", stderr_
);
1410 add_intrinsic ("print", print
);
1411 add_intrinsic ("skip_past_newline", skip_past_newline
);
1412 add_intrinsic ("catstr", icatstr
);
1413 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1414 add_intrinsic ("dup", other_dup
);
1415 add_intrinsic ("drop", drop
);
1416 add_intrinsic ("idrop", idrop
);
1417 add_intrinsic ("remchar", remchar
);
1418 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1419 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1420 add_intrinsic ("bulletize", bulletize
);
1421 add_intrinsic ("courierize", courierize
);
1422 /* If the following line gives an error, exit() is not declared in the
1423 ../hosts/foo.h file for this host. Fix it there, not here! */
1424 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1425 add_intrinsic ("exit", chew_exit
);
1426 add_intrinsic ("swap", swap
);
1427 add_intrinsic ("outputdots", outputdots
);
1428 add_intrinsic ("maybecatstr", maybecatstr
);
1429 add_intrinsic ("translatecomments", translatecomments
);
1430 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1431 add_intrinsic ("indent", indent
);
1432 add_intrinsic ("internalmode", internalmode
);
1433 add_intrinsic ("print_stack_level", print_stack_level
);
1434 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1436 /* Put a nl at the start. */
1437 catchar (&buffer
, '\n');
1439 read_in (&buffer
, stdin
);
1440 remove_noncomments (&buffer
, ptr
);
1441 for (i
= 1; i
< (unsigned int) ac
; i
++)
1443 if (av
[i
][0] == '-')
1445 if (av
[i
][1] == 'f')
1451 f
= fopen (av
[i
+ 1], "r");
1454 fprintf (stderr
, "Can't open the input file %s\n",
1464 else if (av
[i
][1] == 'i')
1466 internal_wanted
= 1;
1468 else if (av
[i
][1] == 'w')
1476 write_buffer (stack
+ 0, stdout
);
1478 delete_string (&pptr
);
1479 delete_string (&buffer
);
1482 fprintf (stderr
, "finishing with current stack level %ld\n",
1483 (long) (tos
- stack
));