]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
2 Copyright 1990, 1991, 1992, 1993, 1994, 1995, 1996, 1998, 2000, 2001,
4 Free Software Foundation, Inc.
5 Contributed by steve chamberlain @cygnus
7 This file is part of BFD, the Binary File Descriptor library.
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA. */
23 /* Yet another way of extracting documentation from source.
24 No, I haven't finished it yet, but I hope you people like it better
29 Basically, this is a sort of string forth, maybe we should call it
32 You define new words thus:
33 : <newword> <oldwords> ;
37 /* Primitives provided by the program:
39 Two stacks are provided, a string stack and an integer stack.
41 Internal state variables:
42 internal_wanted - indicates whether `-i' was passed
43 internal_mode - user-settable
47 ! - pop top of integer stack for address, pop next for value; store
48 @ - treat value on integer stack as the address of an integer; push
49 that integer on the integer stack after popping the "address"
50 hello - print "hello\n" to stdout
51 stdout - put stdout marker on TOS
52 stderr - put stderr marker on TOS
53 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
56 copy_past_newline - append input, up to and including newline into TOS
60 remchar - delete last character from TOS
62 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
63 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
64 and @item to each "o" line; append @end itemize
65 courierize - put @example around . and | lines, translate {* *} { }
68 outputdots - strip out lines without leading dots
69 paramstuff - convert full declaration into "PARAMS" form if not already
70 maybecatstr - do catstr if internal_mode == internal_wanted, discard
72 translatecomments - turn {* and *} into comment delimiters
73 kill_bogus_lines - get rid of extra newlines
75 internalmode - pop from integer stack, set `internalmode' to that value
76 print_stack_level - print current stack depth to stderr
77 strip_trailing_newlines - go ahead, guess...
78 [quoted string] - push string onto string stack
79 [word starting with digit] - push atol(str) onto integer stack
81 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
;
108 static void init_string_with_size (string_type
*, unsigned int);
109 static void init_string (string_type
*);
110 static int find (string_type
*, char *);
111 static void write_buffer (string_type
*, FILE *);
112 static void delete_string (string_type
*);
113 static char *addr (string_type
*, unsigned int);
114 static char at (string_type
*, unsigned int);
115 static void catchar (string_type
*, int);
116 static void overwrite_string (string_type
*, string_type
*);
117 static void catbuf (string_type
*, char *, unsigned int);
118 static void cattext (string_type
*, char *);
119 static void catstr (string_type
*, string_type
*);
123 init_string_with_size (buffer
, size
)
127 buffer
->write_idx
= 0;
129 buffer
->ptr
= malloc (size
);
136 init_string_with_size (buffer
, DEF_SIZE
);
147 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
149 if (*p
== str
->ptr
[i
])
158 write_buffer (buffer
, f
)
162 fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
);
166 delete_string (buffer
)
177 return buffer
->ptr
+ idx
;
185 if (pos
>= buffer
->write_idx
)
187 return buffer
->ptr
[pos
];
195 if (buffer
->write_idx
== buffer
->size
)
198 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
201 buffer
->ptr
[buffer
->write_idx
++] = ch
;
205 overwrite_string (dst
, src
)
210 dst
->size
= src
->size
;
211 dst
->write_idx
= src
->write_idx
;
216 catbuf (buffer
, buf
, len
)
221 if (buffer
->write_idx
+ len
>= buffer
->size
)
223 while (buffer
->write_idx
+ len
>= buffer
->size
)
225 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
227 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
228 buffer
->write_idx
+= len
;
232 cattext (buffer
, string
)
236 catbuf (buffer
, string
, (unsigned int) strlen (string
));
244 catbuf (dst
, src
->ptr
, src
->write_idx
);
248 skip_white_and_stars (src
, idx
)
253 while ((c
= at (src
, idx
)),
254 isspace ((unsigned char) c
)
256 /* Don't skip past end-of-comment or star as first
257 character on its line. */
258 && at (src
, idx
+1) != '/'
259 && at (src
, idx
-1) != '\n'))
264 /***********************************************************************/
266 string_type stack
[STACK
];
269 unsigned int idx
= 0; /* Pos in input buffer */
270 string_type
*ptr
; /* and the buffer */
271 typedef void (*stinst_type
)();
273 stinst_type sstack
[STACK
];
274 stinst_type
*ssp
= &sstack
[0];
276 long *isp
= &istack
[0];
278 typedef int *word_type
;
283 struct dict_struct
*next
;
290 typedef struct dict_struct dict_type
;
296 fprintf (stderr
, "%s\n", msg
);
304 die ("underflow in string stack");
305 if (tos
>= stack
+ STACK
)
306 die ("overflow in string stack");
313 die ("underflow in integer stack");
314 if (isp
>= istack
+ STACK
)
315 die ("overflow in integer stack");
319 static void exec (dict_type
*);
320 static void call (void);
321 static void remchar (void), strip_trailing_newlines (void), push_number (void);
322 static void push_text (void);
323 static void remove_noncomments (string_type
*, string_type
*);
324 static void print_stack_level (void);
325 static void paramstuff (void), translatecomments (void);
326 static void outputdots (void), courierize (void), bulletize (void);
327 static void do_fancy_stuff (void);
328 static int iscommand (string_type
*, unsigned int);
329 static int copy_past_newline (string_type
*, unsigned int, string_type
*);
330 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
331 static void get_stuff_in_command (void), swap (void), other_dup (void);
332 static void drop (void), idrop (void);
333 static void icatstr (void), skip_past_newline (void), internalmode (void);
334 static void maybecatstr (void);
335 static char *nextword (char *, char **);
336 dict_type
*lookup_word (char *);
337 static void perform (void);
338 dict_type
*newentry (char *);
339 unsigned int add_to_definition (dict_type
*, stinst_type
);
340 void add_intrinsic (char *, void (*)());
341 void add_var (char *);
342 void compile (char *);
343 static void bang (void);
344 static void atsign (void);
345 static void hello (void);
346 static void stdout_ (void);
347 static void stderr_ (void);
348 static void print (void);
349 static void read_in (string_type
*, FILE *);
350 static void usage (void);
351 static void chew_exit (void);
366 stinst_type
*oldpc
= pc
;
368 e
= (dict_type
*) (pc
[1]);
382 strip_trailing_newlines ()
384 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
385 || at (tos
, tos
->write_idx
- 1) == '\n')
386 && tos
->write_idx
> 0)
408 cattext (tos
, *((char **) pc
));
412 /* This function removes everything not inside comments starting on
413 the first char of the line from the string, also when copying
414 comments, removes blank space and leading *'s.
415 Blank lines are turned into one blank line. */
418 remove_noncomments (src
, dst
)
422 unsigned int idx
= 0;
424 while (at (src
, idx
))
426 /* Now see if we have a comment at the start of the line. */
427 if (at (src
, idx
) == '\n'
428 && at (src
, idx
+ 1) == '/'
429 && at (src
, idx
+ 2) == '*')
433 idx
= skip_white_and_stars (src
, idx
);
435 /* Remove leading dot */
436 if (at (src
, idx
) == '.')
439 /* Copy to the end of the line, or till the end of the
441 while (at (src
, idx
))
443 if (at (src
, idx
) == '\n')
445 /* end of line, echo and scrape of leading blanks */
446 if (at (src
, idx
+ 1) == '\n')
450 idx
= skip_white_and_stars (src
, idx
);
452 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
455 cattext (dst
, "\nENDDD\n");
460 catchar (dst
, at (src
, idx
));
473 fprintf (stderr
, "current string stack depth = %d, ", tos
- stack
);
474 fprintf (stderr
, "current integer stack depth = %d\n", isp
- istack
);
482 name PARAMS ((stuff));
498 /* Make sure that it's not already param'd or proto'd. */
500 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
506 /* Find the open paren. */
507 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
511 /* Step back to the fname. */
513 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
516 && !isspace ((unsigned char) at (tos
,fname
))
517 && at (tos
,fname
) != '*')
522 /* Output type, omitting trailing whitespace character(s), if
524 for (len
= fname
; 0 < len
; len
--)
526 if (!isspace ((unsigned char) at (tos
, len
- 1)))
529 for (idx
= 0; idx
< len
; idx
++)
530 catchar (&out
, at (tos
, idx
));
532 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
534 /* Output function name, omitting trailing whitespace
535 character(s), if any. */
536 for (len
= openp
; 0 < len
; len
--)
538 if (!isspace ((unsigned char) at (tos
, len
- 1)))
541 for (idx
= fname
; idx
< len
; idx
++)
542 catchar (&out
, at (tos
, idx
));
544 cattext (&out
, " PARAMS (");
546 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
547 catchar (&out
, at (tos
, idx
));
549 cattext (&out
, ");\n\n");
551 overwrite_string (tos
, &out
);
557 and *} into comments */
562 unsigned int idx
= 0;
566 while (at (tos
, idx
))
568 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
570 cattext (&out
, "/*");
573 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
575 cattext (&out
, "*/");
580 catchar (&out
, at (tos
, idx
));
585 overwrite_string (tos
, &out
);
590 /* Mod tos so that only lines with leading dots remain */
594 unsigned int idx
= 0;
598 while (at (tos
, idx
))
600 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '.')
605 while ((c
= at (tos
, idx
)) && c
!= '\n')
607 if (c
== '{' && at (tos
, idx
+ 1) == '*')
609 cattext (&out
, "/*");
612 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
614 cattext (&out
, "*/");
623 catchar (&out
, '\n');
631 overwrite_string (tos
, &out
);
635 /* Find lines starting with . and | and put example around them on tos */
640 unsigned int idx
= 0;
645 while (at (tos
, idx
))
647 if (at (tos
, idx
) == '\n'
648 && (at (tos
, idx
+1 ) == '.'
649 || at (tos
, idx
+ 1) == '|'))
651 cattext (&out
, "\n@example\n");
656 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
660 /* We are inside {} parameters of some command;
661 Just pass through until matching brace. */
662 if (at (tos
, idx
) == '{')
664 else if (at (tos
, idx
) == '}')
667 else if (command
!= 0)
669 if (at (tos
, idx
) == '{')
671 else if (!islower ((unsigned char) at (tos
, idx
)))
674 else if (at (tos
, idx
) == '@'
675 && islower ((unsigned char) at (tos
, idx
+ 1)))
679 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
681 cattext (&out
, "/*");
685 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
687 cattext (&out
, "*/");
691 else if (at (tos
, idx
) == '{'
692 || at (tos
, idx
) == '}')
697 catchar (&out
, at (tos
, idx
));
700 catchar (&out
, '\n');
702 while (at (tos
, idx
) == '\n'
703 && ((at (tos
, idx
+ 1) == '.')
704 || (at (tos
, idx
+ 1) == '|')))
706 cattext (&out
, "@end example");
710 catchar (&out
, at (tos
, idx
));
715 overwrite_string (tos
, &out
);
719 /* Finds any lines starting with "o ", if there are any, then turns
720 on @itemize @bullet, and @items each of them. Then ends with @end
721 itemize, inplace at TOS*/
726 unsigned int idx
= 0;
731 while (at (tos
, idx
))
733 if (at (tos
, idx
) == '@'
734 && at (tos
, idx
+ 1) == '*')
739 else if (at (tos
, idx
) == '\n'
740 && at (tos
, idx
+ 1) == 'o'
741 && isspace ((unsigned char) at (tos
, idx
+ 2)))
745 cattext (&out
, "\n@itemize @bullet\n");
749 cattext (&out
, "\n@item\n");
754 catchar (&out
, at (tos
, idx
));
755 if (on
&& at (tos
, idx
) == '\n'
756 && at (tos
, idx
+ 1) == '\n'
757 && at (tos
, idx
+ 2) != 'o')
759 cattext (&out
, "@end itemize");
768 cattext (&out
, "@end itemize\n");
776 /* Turn <<foo>> into @code{foo} in place at TOS*/
781 unsigned int idx
= 0;
784 while (at (tos
, idx
))
786 if (at (tos
, idx
) == '<'
787 && at (tos
, idx
+ 1) == '<'
788 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
790 /* This qualifies as a << startup. */
792 cattext (&out
, "@code{");
794 && at (tos
, idx
) != '>' )
796 catchar (&out
, at (tos
, idx
));
805 catchar (&out
, at (tos
, idx
));
815 /* A command is all upper case,and alone on a line. */
822 unsigned int len
= 0;
823 while (at (ptr
, idx
))
825 if (isupper ((unsigned char) at (ptr
, idx
))
826 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
831 else if (at (ptr
, idx
) == '\n')
844 copy_past_newline (ptr
, idx
, dst
)
851 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
853 if (at (ptr
, idx
) == '\t')
855 /* Expand tabs. Neither makeinfo nor TeX can cope well with
859 while (++column
& 7);
863 catchar (dst
, at (ptr
, idx
));
869 catchar (dst
, at (ptr
, idx
));
876 icopy_past_newline ()
881 idx
= copy_past_newline (ptr
, idx
, tos
);
886 Take the string at the top of the stack, do some prettying. */
899 /* Drop leading nl. */
900 while (at (tos
, idx
) == '\n')
906 /* If the first char is a '.' prepend a newline so that it is
907 recognized properly later. */
908 if (at (tos
, idx
) == '.')
909 catchar (&out
, '\n');
911 /* Find the last char. */
912 while (at (tos
, idx
))
917 /* Find the last non white before the nl. */
920 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
924 /* Copy buffer upto last char, but blank lines before and after
930 if (at (tos
, c
) == '\n'
931 && at (tos
, c
+ 1) == '\n'
932 && at (tos
, c
+ 2) == '.')
934 /* Ignore two newlines before a dot. */
937 else if (at (tos
, c
) == '.' && sl
)
939 /* remember that this line started with a dot. */
942 else if (at (tos
, c
) == '\n'
943 && at (tos
, c
+ 1) == '\n'
947 /* Ignore two newlines when last line was dot. */
950 catchar (&out
, at (tos
, c
));
951 if (at (tos
, c
) == '\n')
968 catchar (&out
, '\n');
983 while (at (tos
, idx
))
985 switch (at (tos
, idx
))
988 cattext (&out
, "\n");
990 if (tab
&& at (tos
, idx
))
1001 cattext (&out
, "(");
1006 cattext (&out
, ")");
1012 catchar (&out
, at (tos
, idx
));
1021 delete_string (tos
);
1027 get_stuff_in_command ()
1033 while (at (ptr
, idx
))
1035 if (iscommand (ptr
, idx
))
1037 idx
= copy_past_newline (ptr
, idx
, tos
);
1059 catstr (tos
, tos
- 1);
1084 catstr (tos
, tos
+ 1);
1085 delete_string (tos
+ 1);
1090 skip_past_newline ()
1092 while (at (ptr
, idx
)
1093 && at (ptr
, idx
) != '\n')
1102 internal_mode
= *(isp
);
1111 if (internal_wanted
== internal_mode
)
1113 catstr (tos
- 1, tos
);
1115 delete_string (tos
);
1122 nextword (string
, word
)
1133 while (isspace ((unsigned char) *string
) || *string
== '-')
1137 while (*string
&& *string
!= '\n')
1149 word_start
= string
;
1156 if (*string
== '\\')
1162 while (*string
!= '"');
1166 while (!isspace ((unsigned char) *string
))
1174 *word
= malloc (length
+ 1);
1179 for (idx
= 0; idx
< length
; idx
++)
1181 if (src
[idx
] == '\\')
1182 switch (src
[idx
+ 1])
1190 *dst
++ = src
[idx
+ 1];
1214 dict_type
*ptr
= root
;
1217 if (strcmp (ptr
->word
, word
) == 0)
1222 fprintf (stderr
, "Can't find %s\n", word
);
1231 while (at (ptr
, idx
))
1233 /* It's worth looking through the command list. */
1234 if (iscommand (ptr
, idx
))
1239 (void) nextword (addr (ptr
, idx
), &next
);
1241 word
= lookup_word (next
);
1250 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1251 skip_past_newline ();
1256 skip_past_newline ();
1264 dict_type
*new = (dict_type
*) malloc (sizeof (dict_type
));
1268 new->code
= (stinst_type
*) malloc (sizeof (stinst_type
));
1269 new->code_length
= 1;
1275 add_to_definition (entry
, word
)
1279 if (entry
->code_end
== entry
->code_length
)
1281 entry
->code_length
+= 2;
1283 (stinst_type
*) realloc ((char *) (entry
->code
),
1284 entry
->code_length
* sizeof (word_type
));
1286 entry
->code
[entry
->code_end
] = word
;
1288 return entry
->code_end
++;
1292 add_intrinsic (name
, func
)
1296 dict_type
*new = newentry (name
);
1297 add_to_definition (new, func
);
1298 add_to_definition (new, 0);
1305 dict_type
*new = newentry (name
);
1306 add_to_definition (new, push_number
);
1307 add_to_definition (new, (stinst_type
) (&(new->var
)));
1308 add_to_definition (new, 0);
1315 /* Add words to the dictionary. */
1317 string
= nextword (string
, &word
);
1318 while (string
&& *string
&& word
[0])
1320 if (strcmp (word
, "var") == 0)
1322 string
= nextword (string
, &word
);
1325 string
= nextword (string
, &word
);
1327 else if (word
[0] == ':')
1330 /* Compile a word and add to dictionary. */
1331 string
= nextword (string
, &word
);
1333 ptr
= newentry (word
);
1334 string
= nextword (string
, &word
);
1335 while (word
[0] != ';')
1340 /* got a string, embed magic push string
1342 add_to_definition (ptr
, push_text
);
1343 add_to_definition (ptr
, (stinst_type
) (word
+ 1));
1355 /* Got a number, embedd the magic push number
1357 add_to_definition (ptr
, push_number
);
1358 add_to_definition (ptr
, (stinst_type
) atol (word
));
1361 add_to_definition (ptr
, call
);
1362 add_to_definition (ptr
, (stinst_type
) lookup_word (word
));
1365 string
= nextword (string
, &word
);
1367 add_to_definition (ptr
, 0);
1368 string
= nextword (string
, &word
);
1372 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1380 *(long *) ((isp
[0])) = isp
[-1];
1389 isp
[0] = *(long *) (isp
[0]);
1422 write_buffer (tos
, stdout
);
1424 write_buffer (tos
, stderr
);
1426 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
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. */
1479 init_string (&buffer
);
1480 init_string (&pptr
);
1481 init_string (stack
+ 0);
1485 add_intrinsic ("push_text", push_text
);
1486 add_intrinsic ("!", bang
);
1487 add_intrinsic ("@", atsign
);
1488 add_intrinsic ("hello", hello
);
1489 add_intrinsic ("stdout", stdout_
);
1490 add_intrinsic ("stderr", stderr_
);
1491 add_intrinsic ("print", print
);
1492 add_intrinsic ("skip_past_newline", skip_past_newline
);
1493 add_intrinsic ("catstr", icatstr
);
1494 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1495 add_intrinsic ("dup", other_dup
);
1496 add_intrinsic ("drop", drop
);
1497 add_intrinsic ("idrop", idrop
);
1498 add_intrinsic ("remchar", remchar
);
1499 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1500 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1501 add_intrinsic ("bulletize", bulletize
);
1502 add_intrinsic ("courierize", courierize
);
1503 /* If the following line gives an error, exit() is not declared in the
1504 ../hosts/foo.h file for this host. Fix it there, not here! */
1505 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1506 add_intrinsic ("exit", chew_exit
);
1507 add_intrinsic ("swap", swap
);
1508 add_intrinsic ("outputdots", outputdots
);
1509 add_intrinsic ("paramstuff", paramstuff
);
1510 add_intrinsic ("maybecatstr", maybecatstr
);
1511 add_intrinsic ("translatecomments", translatecomments
);
1512 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1513 add_intrinsic ("indent", indent
);
1514 add_intrinsic ("internalmode", internalmode
);
1515 add_intrinsic ("print_stack_level", print_stack_level
);
1516 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1518 /* Put a nl at the start. */
1519 catchar (&buffer
, '\n');
1521 read_in (&buffer
, stdin
);
1522 remove_noncomments (&buffer
, ptr
);
1523 for (i
= 1; i
< (unsigned int) ac
; i
++)
1525 if (av
[i
][0] == '-')
1527 if (av
[i
][1] == 'f')
1533 f
= fopen (av
[i
+ 1], "r");
1536 fprintf (stderr
, "Can't open the input file %s\n",
1545 else if (av
[i
][1] == 'i')
1547 internal_wanted
= 1;
1549 else if (av
[i
][1] == 'w')
1557 write_buffer (stack
+ 0, stdout
);
1560 fprintf (stderr
, "finishing with current stack level %d\n",