]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
cd399697abdca39d456ed43a18e698338a782dd5
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> ;
34 Variables are defined using:
39 /* Primitives provided by the program:
41 Two stacks are provided, a string stack and an integer stack.
43 Internal state variables:
44 internal_wanted - indicates whether `-i' was passed
45 internal_mode - user-settable
49 ! - pop top of integer stack for address, pop next for value; store
50 @ - treat value on integer stack as the address of an integer; push
51 that integer on the integer stack after popping the "address"
52 hello - print "hello\n" to stdout
53 stdout - put stdout marker on TOS
54 stderr - put stderr marker on TOS
55 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
58 copy_past_newline - append input, up to and including newline into TOS
62 remchar - delete last character from TOS
64 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
65 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
66 and @item to each "o" line; append @end itemize
67 courierize - put @example around . and | lines, translate {* *} { }
70 outputdots - strip out lines without leading dots
71 maybecatstr - do catstr if internal_mode == internal_wanted, discard
73 catstrif - do catstr if top of integer stack is nonzero
74 translatecomments - turn {* and *} into comment delimiters
75 kill_bogus_lines - get rid of extra newlines
77 print_stack_level - print current stack depth to stderr
78 strip_trailing_newlines - go ahead, guess...
79 [quoted string] - push string onto string stack
80 [word starting with digit] - push atol(str) onto integer stack
82 internalmode - the internalmode variable (evaluates to address)
84 A command must be all upper-case, and alone on a line.
98 /* Here is a string type ... */
100 typedef struct buffer
103 unsigned long write_idx
;
107 /* Compiled programs consist of arrays of these. */
112 struct dict_struct
*e
;
117 typedef struct dict_struct
120 struct dict_struct
*next
;
127 intptr_t *internal_mode
;
131 string_type stack
[STACK
];
134 unsigned int idx
= 0; /* Pos in input buffer */
135 string_type
*ptr
; /* and the buffer */
137 intptr_t istack
[STACK
];
138 intptr_t *isp
= &istack
[0];
147 fprintf (stderr
, "%s\n", msg
);
152 xmalloc (size_t size
)
158 newmem
= malloc (size
);
160 die ("out of memory");
166 xrealloc (void *oldmem
, size_t size
)
173 newmem
= malloc (size
);
175 newmem
= realloc (oldmem
, size
);
177 die ("out of memory");
183 xstrdup (const char *s
)
185 size_t len
= strlen (s
) + 1;
186 char *ret
= xmalloc (len
);
187 return memcpy (ret
, s
, len
);
191 init_string_with_size (string_type
*buffer
, unsigned int size
)
193 buffer
->write_idx
= 0;
195 buffer
->ptr
= xmalloc (size
);
199 init_string (string_type
*buffer
)
201 init_string_with_size (buffer
, DEF_SIZE
);
205 find (string_type
*str
, char *what
)
210 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
212 if (*p
== str
->ptr
[i
])
221 write_buffer (string_type
*buffer
, FILE *f
)
223 if (buffer
->write_idx
!= 0
224 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
225 die ("cannot write output");
229 delete_string (string_type
*buffer
)
236 addr (string_type
*buffer
, unsigned int idx
)
238 return buffer
->ptr
+ idx
;
242 at (string_type
*buffer
, unsigned int pos
)
244 if (pos
>= buffer
->write_idx
)
246 return buffer
->ptr
[pos
];
250 catchar (string_type
*buffer
, int ch
)
252 if (buffer
->write_idx
== buffer
->size
)
255 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
258 buffer
->ptr
[buffer
->write_idx
++] = ch
;
262 overwrite_string (string_type
*dst
, string_type
*src
)
265 dst
->size
= src
->size
;
266 dst
->write_idx
= src
->write_idx
;
271 catbuf (string_type
*buffer
, char *buf
, unsigned int len
)
273 if (buffer
->write_idx
+ len
>= buffer
->size
)
275 while (buffer
->write_idx
+ len
>= buffer
->size
)
277 buffer
->ptr
= xrealloc (buffer
->ptr
, buffer
->size
);
279 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
280 buffer
->write_idx
+= len
;
284 cattext (string_type
*buffer
, char *string
)
286 catbuf (buffer
, string
, (unsigned int) strlen (string
));
290 catstr (string_type
*dst
, string_type
*src
)
292 catbuf (dst
, src
->ptr
, src
->write_idx
);
296 skip_white_and_stars (string_type
*src
, unsigned int idx
)
299 while ((c
= at (src
, idx
)),
300 isspace ((unsigned char) c
)
302 /* Don't skip past end-of-comment or star as first
303 character on its line. */
304 && at (src
, idx
+1) != '/'
305 && at (src
, idx
-1) != '\n'))
311 skip_past_newline_1 (string_type
*ptr
, unsigned int idx
)
314 && at (ptr
, idx
) != '\n')
316 if (at (ptr
, idx
) == '\n')
325 die ("underflow in string stack");
326 if (tos
>= stack
+ STACK
)
327 die ("overflow in string stack");
334 die ("underflow in integer stack");
335 if (isp
>= istack
+ STACK
)
336 die ("overflow in integer stack");
340 exec (dict_type
*word
)
351 dict_type
*e
= pc
[1].e
;
365 strip_trailing_newlines (void)
367 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
368 || at (tos
, tos
->write_idx
- 1) == '\n')
369 && tos
->write_idx
> 0)
384 /* This is a wrapper for push_number just so we can correctly free the
385 variable at the end. */
399 cattext (tos
, pc
->s
);
403 /* This function removes everything not inside comments starting on
404 the first char of the line from the string, also when copying
405 comments, removes blank space and leading *'s.
406 Blank lines are turned into one blank line. */
409 remove_noncomments (string_type
*src
, string_type
*dst
)
411 unsigned int idx
= 0;
413 while (at (src
, idx
))
415 /* Now see if we have a comment at the start of the line. */
416 if (at (src
, idx
) == '\n'
417 && at (src
, idx
+ 1) == '/'
418 && at (src
, idx
+ 2) == '*')
422 idx
= skip_white_and_stars (src
, idx
);
424 /* Remove leading dot */
425 if (at (src
, idx
) == '.')
428 /* Copy to the end of the line, or till the end of the
430 while (at (src
, idx
))
432 if (at (src
, idx
) == '\n')
434 /* end of line, echo and scrape of leading blanks */
435 if (at (src
, idx
+ 1) == '\n')
439 idx
= skip_white_and_stars (src
, idx
);
441 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
444 cattext (dst
, "\nENDDD\n");
449 catchar (dst
, at (src
, idx
));
460 print_stack_level (void)
462 fprintf (stderr
, "current string stack depth = %ld, ",
463 (long) (tos
- stack
));
464 fprintf (stderr
, "current integer stack depth = %ld\n",
465 (long) (isp
- istack
));
470 and *} into comments */
473 translatecomments (void)
475 unsigned int idx
= 0;
479 while (at (tos
, idx
))
481 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
483 cattext (&out
, "/*");
486 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
488 cattext (&out
, "*/");
493 catchar (&out
, at (tos
, idx
));
498 overwrite_string (tos
, &out
);
503 /* Mod tos so that only lines with leading dots remain */
507 unsigned int idx
= 0;
511 while (at (tos
, idx
))
513 /* Every iteration begins at the start of a line. */
514 if (at (tos
, idx
) == '.')
520 while ((c
= at (tos
, idx
)) && c
!= '\n')
522 if (c
== '{' && at (tos
, idx
+ 1) == '*')
524 cattext (&out
, "/*");
527 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
529 cattext (&out
, "*/");
540 catchar (&out
, '\n');
544 idx
= skip_past_newline_1 (tos
, idx
);
548 overwrite_string (tos
, &out
);
552 /* Find lines starting with . and | and put example around them on tos */
557 unsigned int idx
= 0;
562 while (at (tos
, idx
))
564 if (at (tos
, idx
) == '\n'
565 && (at (tos
, idx
+1 ) == '.'
566 || at (tos
, idx
+ 1) == '|'))
568 cattext (&out
, "\n@example\n");
573 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
577 /* We are inside {} parameters of some command;
578 Just pass through until matching brace. */
579 if (at (tos
, idx
) == '{')
581 else if (at (tos
, idx
) == '}')
584 else if (command
!= 0)
586 if (at (tos
, idx
) == '{')
588 else if (!islower ((unsigned char) at (tos
, idx
)))
591 else if (at (tos
, idx
) == '@'
592 && islower ((unsigned char) at (tos
, idx
+ 1)))
596 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
598 cattext (&out
, "/*");
602 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
604 cattext (&out
, "*/");
608 else if (at (tos
, idx
) == '{'
609 || at (tos
, idx
) == '}')
614 catchar (&out
, at (tos
, idx
));
617 catchar (&out
, '\n');
619 while (at (tos
, idx
) == '\n'
620 && ((at (tos
, idx
+ 1) == '.')
621 || (at (tos
, idx
+ 1) == '|')))
623 cattext (&out
, "@end example");
627 catchar (&out
, at (tos
, idx
));
632 overwrite_string (tos
, &out
);
636 /* Finds any lines starting with "o ", if there are any, then turns
637 on @itemize @bullet, and @items each of them. Then ends with @end
638 itemize, inplace at TOS*/
643 unsigned int idx
= 0;
648 while (at (tos
, idx
))
650 if (at (tos
, idx
) == '@'
651 && at (tos
, idx
+ 1) == '*')
656 else if (at (tos
, idx
) == '\n'
657 && at (tos
, idx
+ 1) == 'o'
658 && isspace ((unsigned char) at (tos
, idx
+ 2)))
662 cattext (&out
, "\n@itemize @bullet\n");
666 cattext (&out
, "\n@item\n");
671 catchar (&out
, at (tos
, idx
));
672 if (on
&& at (tos
, idx
) == '\n'
673 && at (tos
, idx
+ 1) == '\n'
674 && at (tos
, idx
+ 2) != 'o')
676 cattext (&out
, "@end itemize");
685 cattext (&out
, "@end itemize\n");
693 /* Turn <<foo>> into @code{foo} in place at TOS*/
696 do_fancy_stuff (void)
698 unsigned int idx
= 0;
701 while (at (tos
, idx
))
703 if (at (tos
, idx
) == '<'
704 && at (tos
, idx
+ 1) == '<'
705 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
707 /* This qualifies as a << startup. */
709 cattext (&out
, "@code{");
711 && at (tos
, idx
) != '>' )
713 catchar (&out
, at (tos
, idx
));
722 catchar (&out
, at (tos
, idx
));
732 /* A command is all upper case,and alone on a line. */
735 iscommand (string_type
*ptr
, unsigned int idx
)
737 unsigned int len
= 0;
738 while (at (ptr
, idx
))
740 if (isupper ((unsigned char) at (ptr
, idx
))
741 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
746 else if (at (ptr
, idx
) == '\n')
759 copy_past_newline (string_type
*ptr
, unsigned int idx
, string_type
*dst
)
763 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
765 if (at (ptr
, idx
) == '\t')
767 /* Expand tabs. Neither makeinfo nor TeX can cope well with
771 while (++column
& 7);
775 catchar (dst
, at (ptr
, idx
));
781 catchar (dst
, at (ptr
, idx
));
788 icopy_past_newline (void)
793 idx
= copy_past_newline (ptr
, idx
, tos
);
798 Take the string at the top of the stack, do some prettying. */
801 kill_bogus_lines (void)
811 /* Drop leading nl. */
812 while (at (tos
, idx
) == '\n')
818 /* If the first char is a '.' prepend a newline so that it is
819 recognized properly later. */
820 if (at (tos
, idx
) == '.')
821 catchar (&out
, '\n');
823 /* Find the last char. */
824 while (at (tos
, idx
))
829 /* Find the last non white before the nl. */
832 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
836 /* Copy buffer upto last char, but blank lines before and after
842 if (at (tos
, c
) == '\n'
843 && at (tos
, c
+ 1) == '\n'
844 && at (tos
, c
+ 2) == '.')
846 /* Ignore two newlines before a dot. */
849 else if (at (tos
, c
) == '.' && sl
)
851 /* remember that this line started with a dot. */
854 else if (at (tos
, c
) == '\n'
855 && at (tos
, c
+ 1) == '\n'
859 /* Ignore two newlines when last line was dot. */
862 catchar (&out
, at (tos
, c
));
863 if (at (tos
, c
) == '\n')
880 catchar (&out
, '\n');
895 while (at (tos
, idx
))
897 switch (at (tos
, idx
))
900 cattext (&out
, "\n");
902 if (tab
&& at (tos
, idx
))
924 catchar (&out
, at (tos
, idx
));
939 get_stuff_in_command (void)
945 while (at (ptr
, idx
))
947 if (iscommand (ptr
, idx
))
949 idx
= copy_past_newline (ptr
, idx
, tos
);
971 catstr (tos
, tos
- 1);
980 delete_string (tos
+ 1);
997 catstr (tos
, tos
+ 1);
998 delete_string (tos
+ 1);
1003 skip_past_newline (void)
1005 idx
= skip_past_newline_1 (ptr
, idx
);
1012 if (internal_wanted
== *internal_mode
)
1014 catstr (tos
- 1, tos
);
1016 delete_string (tos
);
1029 catstr (tos
- 1, tos
);
1030 delete_string (tos
);
1037 nextword (char *string
, char **word
)
1046 while (isspace ((unsigned char) *string
) || *string
== '-')
1050 while (*string
&& *string
!= '\n')
1065 word_start
= string
;
1072 if (*string
== '\\')
1078 while (*string
!= '"');
1082 while (!isspace ((unsigned char) *string
))
1090 *word
= xmalloc (length
+ 1);
1095 for (idx
= 0; idx
< length
; idx
++)
1097 if (src
[idx
] == '\\')
1098 switch (src
[idx
+ 1])
1106 *dst
++ = src
[idx
+ 1];
1125 lookup_word (char *word
)
1127 dict_type
*ptr
= root
;
1130 if (strcmp (ptr
->word
, word
) == 0)
1135 fprintf (stderr
, "Can't find %s\n", word
);
1142 dict_type
*ptr
= root
;
1152 for (i
= 0; i
< ptr
->code_end
- 1; i
++)
1153 if (ptr
->code
[i
].f
== push_text
1154 && ptr
->code
[i
+ 1].s
)
1156 free (ptr
->code
[i
+ 1].s
- 1);
1159 else if (ptr
->code
[i
].f
== push_variable
)
1161 free ((void *) ptr
->code
[i
+ 1].l
);
1177 while (at (ptr
, idx
))
1179 /* It's worth looking through the command list. */
1180 if (iscommand (ptr
, idx
))
1185 (void) nextword (addr (ptr
, idx
), &next
);
1187 word
= lookup_word (next
);
1196 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1197 idx
= skip_past_newline_1 (ptr
, idx
);
1202 idx
= skip_past_newline_1 (ptr
, idx
);
1207 newentry (char *word
)
1209 dict_type
*new_d
= xmalloc (sizeof (*new_d
));
1213 new_d
->code
= xmalloc (sizeof (*new_d
->code
));
1214 new_d
->code_length
= 1;
1215 new_d
->code_end
= 0;
1220 add_to_definition (dict_type
*entry
, pcu word
)
1222 if (entry
->code_end
== entry
->code_length
)
1224 entry
->code_length
+= 2;
1225 entry
->code
= xrealloc (entry
->code
,
1226 entry
->code_length
* sizeof (*entry
->code
));
1228 entry
->code
[entry
->code_end
] = word
;
1230 return entry
->code_end
++;
1234 add_intrinsic (char *name
, void (*func
) (void))
1236 dict_type
*new_d
= newentry (xstrdup (name
));
1238 add_to_definition (new_d
, p
);
1240 add_to_definition (new_d
, p
);
1244 add_variable (char *name
, intptr_t *loc
)
1246 dict_type
*new_d
= newentry (name
);
1247 pcu p
= { push_variable
};
1248 add_to_definition (new_d
, p
);
1249 p
.l
= (intptr_t) loc
;
1250 add_to_definition (new_d
, p
);
1252 add_to_definition (new_d
, p
);
1256 add_intrinsic_variable (const char *name
, intptr_t *loc
)
1258 add_variable (xstrdup (name
), loc
);
1262 compile (char *string
)
1264 /* Add words to the dictionary. */
1267 string
= nextword (string
, &word
);
1268 while (string
&& *string
&& word
[0])
1275 /* Compile a word and add to dictionary. */
1277 string
= nextword (string
, &word
);
1280 ptr
= newentry (word
);
1281 string
= nextword (string
, &word
);
1289 while (word
[0] != ';')
1294 /* got a string, embed magic push string
1297 add_to_definition (ptr
, p
);
1299 add_to_definition (ptr
, p
);
1311 /* Got a number, embedd the magic push number
1314 add_to_definition (ptr
, p
);
1316 add_to_definition (ptr
, p
);
1321 add_to_definition (ptr
, p
);
1322 p
.e
= lookup_word (word
);
1323 add_to_definition (ptr
, p
);
1327 string
= nextword (string
, &word
);
1330 add_to_definition (ptr
, p
);
1332 string
= nextword (string
, &word
);
1334 else if (strcmp (word
, "variable") == 0)
1337 string
= nextword (string
, &word
);
1340 intptr_t *loc
= xmalloc (sizeof (intptr_t));
1342 add_variable (word
, loc
);
1343 string
= nextword (string
, &word
);
1347 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1356 *(intptr_t *) ((isp
[0])) = isp
[-1];
1365 isp
[0] = *(intptr_t *) (isp
[0]);
1398 write_buffer (tos
, stdout
);
1400 write_buffer (tos
, stderr
);
1402 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1411 read_in (string_type
*str
, FILE *file
)
1417 r
= fread (buff
, 1, sizeof (buff
), file
);
1418 catbuf (str
, buff
, r
);
1423 catbuf (str
, buff
, 1);
1429 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1433 /* There is no reliable way to declare exit. Sometimes it returns
1434 int, and sometimes it returns void. Sometimes it changes between
1435 OS releases. Trying to get it declared correctly in the hosts file
1436 is a pointless waste of time. */
1445 main (int ac
, char *av
[])
1451 init_string (&buffer
);
1452 init_string (&pptr
);
1453 init_string (stack
+ 0);
1457 add_intrinsic ("push_text", push_text
);
1458 add_intrinsic ("!", bang
);
1459 add_intrinsic ("@", atsign
);
1460 add_intrinsic ("hello", hello
);
1461 add_intrinsic ("stdout", stdout_
);
1462 add_intrinsic ("stderr", stderr_
);
1463 add_intrinsic ("print", print
);
1464 add_intrinsic ("skip_past_newline", skip_past_newline
);
1465 add_intrinsic ("catstr", icatstr
);
1466 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1467 add_intrinsic ("dup", other_dup
);
1468 add_intrinsic ("drop", drop
);
1469 add_intrinsic ("idrop", idrop
);
1470 add_intrinsic ("remchar", remchar
);
1471 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1472 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1473 add_intrinsic ("bulletize", bulletize
);
1474 add_intrinsic ("courierize", courierize
);
1475 /* If the following line gives an error, exit() is not declared in the
1476 ../hosts/foo.h file for this host. Fix it there, not here! */
1477 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1478 add_intrinsic ("exit", chew_exit
);
1479 add_intrinsic ("swap", swap
);
1480 add_intrinsic ("outputdots", outputdots
);
1481 add_intrinsic ("maybecatstr", maybecatstr
);
1482 add_intrinsic ("catstrif", catstrif
);
1483 add_intrinsic ("translatecomments", translatecomments
);
1484 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1485 add_intrinsic ("indent", indent
);
1486 add_intrinsic ("print_stack_level", print_stack_level
);
1487 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1489 internal_mode
= xmalloc (sizeof (intptr_t));
1491 add_intrinsic_variable ("internalmode", internal_mode
);
1493 /* Put a nl at the start. */
1494 catchar (&buffer
, '\n');
1496 read_in (&buffer
, stdin
);
1497 remove_noncomments (&buffer
, ptr
);
1498 for (i
= 1; i
< (unsigned int) ac
; i
++)
1500 if (av
[i
][0] == '-')
1502 if (av
[i
][1] == 'f')
1508 f
= fopen (av
[i
+ 1], "r");
1511 fprintf (stderr
, "Can't open the input file %s\n",
1521 else if (av
[i
][1] == 'i')
1523 internal_wanted
= 1;
1525 else if (av
[i
][1] == 'w')
1533 write_buffer (stack
+ 0, stdout
);
1535 delete_string (&pptr
);
1536 delete_string (&buffer
);
1539 fprintf (stderr
, "finishing with current stack level %ld\n",
1540 (long) (tos
- stack
));