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 3 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,
22 MA 02110-1301, USA. */
24 /* Yet another way of extracting documentation from source.
25 No, I haven't finished it yet, but I hope you people like it better
30 Basically, this is a sort of string forth, maybe we should call it
33 You define new words thus:
34 : <newword> <oldwords> ;
38 /* Primitives provided by the program:
40 Two stacks are provided, a string stack and an integer stack.
42 Internal state variables:
43 internal_wanted - indicates whether `-i' was passed
44 internal_mode - user-settable
48 ! - pop top of integer stack for address, pop next for value; store
49 @ - treat value on integer stack as the address of an integer; push
50 that integer on the integer stack after popping the "address"
51 hello - print "hello\n" to stdout
52 stdout - put stdout marker on TOS
53 stderr - put stderr marker on TOS
54 print - print TOS-1 on TOS (eg: "hello\n" stdout print)
57 copy_past_newline - append input, up to and including newline into TOS
61 remchar - delete last character from TOS
63 do_fancy_stuff - translate <<foo>> to @code{foo} in TOS
64 bulletize - if "o" lines found, prepend @itemize @bullet to TOS
65 and @item to each "o" line; append @end itemize
66 courierize - put @example around . and | lines, translate {* *} { }
69 outputdots - strip out lines without leading dots
70 paramstuff - convert full declaration into "PARAMS" form if not already
71 maybecatstr - do catstr if internal_mode == internal_wanted, discard
73 translatecomments - turn {* and *} into comment delimiters
74 kill_bogus_lines - get rid of extra newlines
76 internalmode - pop from integer stack, set `internalmode' to that value
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 A command must be all upper-case, and alone on a line.
101 /* Here is a string type ... */
103 typedef struct buffer
106 unsigned long write_idx
;
111 static void init_string_with_size (string_type
*, unsigned int);
112 static void init_string (string_type
*);
113 static int find (string_type
*, char *);
114 static void write_buffer (string_type
*, FILE *);
115 static void delete_string (string_type
*);
116 static char *addr (string_type
*, unsigned int);
117 static char at (string_type
*, unsigned int);
118 static void catchar (string_type
*, int);
119 static void overwrite_string (string_type
*, string_type
*);
120 static void catbuf (string_type
*, char *, unsigned int);
121 static void cattext (string_type
*, char *);
122 static void catstr (string_type
*, string_type
*);
123 static void die (char *);
127 init_string_with_size (buffer
, size
)
131 buffer
->write_idx
= 0;
133 buffer
->ptr
= malloc (size
);
140 init_string_with_size (buffer
, DEF_SIZE
);
151 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
153 if (*p
== str
->ptr
[i
])
162 write_buffer (buffer
, f
)
166 if (buffer
->write_idx
!= 0
167 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
168 die ("cannot write output");
172 delete_string (buffer
)
183 return buffer
->ptr
+ idx
;
191 if (pos
>= buffer
->write_idx
)
193 return buffer
->ptr
[pos
];
201 if (buffer
->write_idx
== buffer
->size
)
204 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
207 buffer
->ptr
[buffer
->write_idx
++] = ch
;
211 overwrite_string (dst
, src
)
216 dst
->size
= src
->size
;
217 dst
->write_idx
= src
->write_idx
;
222 catbuf (buffer
, buf
, len
)
227 if (buffer
->write_idx
+ len
>= buffer
->size
)
229 while (buffer
->write_idx
+ len
>= buffer
->size
)
231 buffer
->ptr
= realloc (buffer
->ptr
, buffer
->size
);
233 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
234 buffer
->write_idx
+= len
;
238 cattext (buffer
, string
)
242 catbuf (buffer
, string
, (unsigned int) strlen (string
));
250 catbuf (dst
, src
->ptr
, src
->write_idx
);
254 skip_white_and_stars (src
, idx
)
259 while ((c
= at (src
, idx
)),
260 isspace ((unsigned char) c
)
262 /* Don't skip past end-of-comment or star as first
263 character on its line. */
264 && at (src
, idx
+1) != '/'
265 && at (src
, idx
-1) != '\n'))
270 /***********************************************************************/
272 string_type stack
[STACK
];
275 unsigned int idx
= 0; /* Pos in input buffer */
276 string_type
*ptr
; /* and the buffer */
277 typedef void (*stinst_type
)();
279 stinst_type sstack
[STACK
];
280 stinst_type
*ssp
= &sstack
[0];
282 long *isp
= &istack
[0];
284 typedef int *word_type
;
289 struct dict_struct
*next
;
296 typedef struct dict_struct dict_type
;
302 fprintf (stderr
, "%s\n", msg
);
310 die ("underflow in string stack");
311 if (tos
>= stack
+ STACK
)
312 die ("overflow in string stack");
319 die ("underflow in integer stack");
320 if (isp
>= istack
+ STACK
)
321 die ("overflow in integer stack");
325 static void exec (dict_type
*);
326 static void call (void);
327 static void remchar (void), strip_trailing_newlines (void), push_number (void);
328 static void push_text (void);
329 static void remove_noncomments (string_type
*, string_type
*);
330 static void print_stack_level (void);
331 static void paramstuff (void), translatecomments (void);
332 static void outputdots (void), courierize (void), bulletize (void);
333 static void do_fancy_stuff (void);
334 static int iscommand (string_type
*, unsigned int);
335 static int copy_past_newline (string_type
*, unsigned int, string_type
*);
336 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
337 static void get_stuff_in_command (void), swap (void), other_dup (void);
338 static void drop (void), idrop (void);
339 static void icatstr (void), skip_past_newline (void), internalmode (void);
340 static void maybecatstr (void);
341 static char *nextword (char *, char **);
342 dict_type
*lookup_word (char *);
343 static void perform (void);
344 dict_type
*newentry (char *);
345 unsigned int add_to_definition (dict_type
*, stinst_type
);
346 void add_intrinsic (char *, void (*)());
347 void add_var (char *);
348 void compile (char *);
349 static void bang (void);
350 static void atsign (void);
351 static void hello (void);
352 static void stdout_ (void);
353 static void stderr_ (void);
354 static void print (void);
355 static void read_in (string_type
*, FILE *);
356 static void usage (void);
357 static void chew_exit (void);
372 stinst_type
*oldpc
= pc
;
374 e
= (dict_type
*) (pc
[1]);
388 strip_trailing_newlines ()
390 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
391 || at (tos
, tos
->write_idx
- 1) == '\n')
392 && tos
->write_idx
> 0)
414 cattext (tos
, *((char **) pc
));
418 /* This function removes everything not inside comments starting on
419 the first char of the line from the string, also when copying
420 comments, removes blank space and leading *'s.
421 Blank lines are turned into one blank line. */
424 remove_noncomments (src
, dst
)
428 unsigned int idx
= 0;
430 while (at (src
, idx
))
432 /* Now see if we have a comment at the start of the line. */
433 if (at (src
, idx
) == '\n'
434 && at (src
, idx
+ 1) == '/'
435 && at (src
, idx
+ 2) == '*')
439 idx
= skip_white_and_stars (src
, idx
);
441 /* Remove leading dot */
442 if (at (src
, idx
) == '.')
445 /* Copy to the end of the line, or till the end of the
447 while (at (src
, idx
))
449 if (at (src
, idx
) == '\n')
451 /* end of line, echo and scrape of leading blanks */
452 if (at (src
, idx
+ 1) == '\n')
456 idx
= skip_white_and_stars (src
, idx
);
458 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
461 cattext (dst
, "\nENDDD\n");
466 catchar (dst
, at (src
, idx
));
479 fprintf (stderr
, "current string stack depth = %d, ", tos
- stack
);
480 fprintf (stderr
, "current integer stack depth = %d\n", isp
- istack
);
488 name PARAMS ((stuff));
504 /* Make sure that it's not already param'd or proto'd. */
506 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
512 /* Find the open paren. */
513 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
517 /* Step back to the fname. */
519 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
522 && !isspace ((unsigned char) at (tos
,fname
))
523 && at (tos
,fname
) != '*')
528 /* Output type, omitting trailing whitespace character(s), if
530 for (len
= fname
; 0 < len
; len
--)
532 if (!isspace ((unsigned char) at (tos
, len
- 1)))
535 for (idx
= 0; idx
< len
; idx
++)
536 catchar (&out
, at (tos
, idx
));
538 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
540 /* Output function name, omitting trailing whitespace
541 character(s), if any. */
542 for (len
= openp
; 0 < len
; len
--)
544 if (!isspace ((unsigned char) at (tos
, len
- 1)))
547 for (idx
= fname
; idx
< len
; idx
++)
548 catchar (&out
, at (tos
, idx
));
550 cattext (&out
, " PARAMS (");
552 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
553 catchar (&out
, at (tos
, idx
));
555 cattext (&out
, ");\n\n");
557 overwrite_string (tos
, &out
);
563 and *} into comments */
568 unsigned int idx
= 0;
572 while (at (tos
, idx
))
574 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
576 cattext (&out
, "/*");
579 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
581 cattext (&out
, "*/");
586 catchar (&out
, at (tos
, idx
));
591 overwrite_string (tos
, &out
);
596 /* Mod tos so that only lines with leading dots remain */
600 unsigned int idx
= 0;
604 while (at (tos
, idx
))
606 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '.')
611 while ((c
= at (tos
, idx
)) && c
!= '\n')
613 if (c
== '{' && at (tos
, idx
+ 1) == '*')
615 cattext (&out
, "/*");
618 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
620 cattext (&out
, "*/");
629 catchar (&out
, '\n');
637 overwrite_string (tos
, &out
);
641 /* Find lines starting with . and | and put example around them on tos */
646 unsigned int idx
= 0;
651 while (at (tos
, idx
))
653 if (at (tos
, idx
) == '\n'
654 && (at (tos
, idx
+1 ) == '.'
655 || at (tos
, idx
+ 1) == '|'))
657 cattext (&out
, "\n@example\n");
662 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
666 /* We are inside {} parameters of some command;
667 Just pass through until matching brace. */
668 if (at (tos
, idx
) == '{')
670 else if (at (tos
, idx
) == '}')
673 else if (command
!= 0)
675 if (at (tos
, idx
) == '{')
677 else if (!islower ((unsigned char) at (tos
, idx
)))
680 else if (at (tos
, idx
) == '@'
681 && islower ((unsigned char) at (tos
, idx
+ 1)))
685 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
687 cattext (&out
, "/*");
691 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
693 cattext (&out
, "*/");
697 else if (at (tos
, idx
) == '{'
698 || at (tos
, idx
) == '}')
703 catchar (&out
, at (tos
, idx
));
706 catchar (&out
, '\n');
708 while (at (tos
, idx
) == '\n'
709 && ((at (tos
, idx
+ 1) == '.')
710 || (at (tos
, idx
+ 1) == '|')))
712 cattext (&out
, "@end example");
716 catchar (&out
, at (tos
, idx
));
721 overwrite_string (tos
, &out
);
725 /* Finds any lines starting with "o ", if there are any, then turns
726 on @itemize @bullet, and @items each of them. Then ends with @end
727 itemize, inplace at TOS*/
732 unsigned int idx
= 0;
737 while (at (tos
, idx
))
739 if (at (tos
, idx
) == '@'
740 && at (tos
, idx
+ 1) == '*')
745 else if (at (tos
, idx
) == '\n'
746 && at (tos
, idx
+ 1) == 'o'
747 && isspace ((unsigned char) at (tos
, idx
+ 2)))
751 cattext (&out
, "\n@itemize @bullet\n");
755 cattext (&out
, "\n@item\n");
760 catchar (&out
, at (tos
, idx
));
761 if (on
&& at (tos
, idx
) == '\n'
762 && at (tos
, idx
+ 1) == '\n'
763 && at (tos
, idx
+ 2) != 'o')
765 cattext (&out
, "@end itemize");
774 cattext (&out
, "@end itemize\n");
782 /* Turn <<foo>> into @code{foo} in place at TOS*/
787 unsigned int idx
= 0;
790 while (at (tos
, idx
))
792 if (at (tos
, idx
) == '<'
793 && at (tos
, idx
+ 1) == '<'
794 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
796 /* This qualifies as a << startup. */
798 cattext (&out
, "@code{");
800 && at (tos
, idx
) != '>' )
802 catchar (&out
, at (tos
, idx
));
811 catchar (&out
, at (tos
, idx
));
821 /* A command is all upper case,and alone on a line. */
828 unsigned int len
= 0;
829 while (at (ptr
, idx
))
831 if (isupper ((unsigned char) at (ptr
, idx
))
832 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
837 else if (at (ptr
, idx
) == '\n')
850 copy_past_newline (ptr
, idx
, dst
)
857 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
859 if (at (ptr
, idx
) == '\t')
861 /* Expand tabs. Neither makeinfo nor TeX can cope well with
865 while (++column
& 7);
869 catchar (dst
, at (ptr
, idx
));
875 catchar (dst
, at (ptr
, idx
));
882 icopy_past_newline ()
887 idx
= copy_past_newline (ptr
, idx
, tos
);
892 Take the string at the top of the stack, do some prettying. */
905 /* Drop leading nl. */
906 while (at (tos
, idx
) == '\n')
912 /* If the first char is a '.' prepend a newline so that it is
913 recognized properly later. */
914 if (at (tos
, idx
) == '.')
915 catchar (&out
, '\n');
917 /* Find the last char. */
918 while (at (tos
, idx
))
923 /* Find the last non white before the nl. */
926 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
930 /* Copy buffer upto last char, but blank lines before and after
936 if (at (tos
, c
) == '\n'
937 && at (tos
, c
+ 1) == '\n'
938 && at (tos
, c
+ 2) == '.')
940 /* Ignore two newlines before a dot. */
943 else if (at (tos
, c
) == '.' && sl
)
945 /* remember that this line started with a dot. */
948 else if (at (tos
, c
) == '\n'
949 && at (tos
, c
+ 1) == '\n'
953 /* Ignore two newlines when last line was dot. */
956 catchar (&out
, at (tos
, c
));
957 if (at (tos
, c
) == '\n')
974 catchar (&out
, '\n');
989 while (at (tos
, idx
))
991 switch (at (tos
, idx
))
994 cattext (&out
, "\n");
996 if (tab
&& at (tos
, idx
))
1005 cattext (&out
, " ");
1007 cattext (&out
, "(");
1012 cattext (&out
, ")");
1018 catchar (&out
, at (tos
, idx
));
1027 delete_string (tos
);
1033 get_stuff_in_command ()
1039 while (at (ptr
, idx
))
1041 if (iscommand (ptr
, idx
))
1043 idx
= copy_past_newline (ptr
, idx
, tos
);
1065 catstr (tos
, tos
- 1);
1090 catstr (tos
, tos
+ 1);
1091 delete_string (tos
+ 1);
1096 skip_past_newline ()
1098 while (at (ptr
, idx
)
1099 && at (ptr
, idx
) != '\n')
1108 internal_mode
= *(isp
);
1117 if (internal_wanted
== internal_mode
)
1119 catstr (tos
- 1, tos
);
1121 delete_string (tos
);
1128 nextword (string
, word
)
1139 while (isspace ((unsigned char) *string
) || *string
== '-')
1143 while (*string
&& *string
!= '\n')
1155 word_start
= string
;
1162 if (*string
== '\\')
1168 while (*string
!= '"');
1172 while (!isspace ((unsigned char) *string
))
1180 *word
= malloc (length
+ 1);
1185 for (idx
= 0; idx
< length
; idx
++)
1187 if (src
[idx
] == '\\')
1188 switch (src
[idx
+ 1])
1196 *dst
++ = src
[idx
+ 1];
1220 dict_type
*ptr
= root
;
1223 if (strcmp (ptr
->word
, word
) == 0)
1228 fprintf (stderr
, "Can't find %s\n", word
);
1237 while (at (ptr
, idx
))
1239 /* It's worth looking through the command list. */
1240 if (iscommand (ptr
, idx
))
1245 (void) nextword (addr (ptr
, idx
), &next
);
1247 word
= lookup_word (next
);
1256 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1257 skip_past_newline ();
1262 skip_past_newline ();
1270 dict_type
*new = (dict_type
*) malloc (sizeof (dict_type
));
1274 new->code
= (stinst_type
*) malloc (sizeof (stinst_type
));
1275 new->code_length
= 1;
1281 add_to_definition (entry
, word
)
1285 if (entry
->code_end
== entry
->code_length
)
1287 entry
->code_length
+= 2;
1289 (stinst_type
*) realloc ((char *) (entry
->code
),
1290 entry
->code_length
* sizeof (word_type
));
1292 entry
->code
[entry
->code_end
] = word
;
1294 return entry
->code_end
++;
1298 add_intrinsic (name
, func
)
1302 dict_type
*new = newentry (name
);
1303 add_to_definition (new, func
);
1304 add_to_definition (new, 0);
1311 dict_type
*new = newentry (name
);
1312 add_to_definition (new, push_number
);
1313 add_to_definition (new, (stinst_type
) (&(new->var
)));
1314 add_to_definition (new, 0);
1321 /* Add words to the dictionary. */
1323 string
= nextword (string
, &word
);
1324 while (string
&& *string
&& word
[0])
1326 if (strcmp (word
, "var") == 0)
1328 string
= nextword (string
, &word
);
1331 string
= nextword (string
, &word
);
1333 else if (word
[0] == ':')
1336 /* Compile a word and add to dictionary. */
1337 string
= nextword (string
, &word
);
1339 ptr
= newentry (word
);
1340 string
= nextword (string
, &word
);
1341 while (word
[0] != ';')
1346 /* got a string, embed magic push string
1348 add_to_definition (ptr
, push_text
);
1349 add_to_definition (ptr
, (stinst_type
) (word
+ 1));
1361 /* Got a number, embedd the magic push number
1363 add_to_definition (ptr
, push_number
);
1364 add_to_definition (ptr
, (stinst_type
) atol (word
));
1367 add_to_definition (ptr
, call
);
1368 add_to_definition (ptr
, (stinst_type
) lookup_word (word
));
1371 string
= nextword (string
, &word
);
1373 add_to_definition (ptr
, 0);
1374 string
= nextword (string
, &word
);
1378 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1386 *(long *) ((isp
[0])) = isp
[-1];
1395 isp
[0] = *(long *) (isp
[0]);
1428 write_buffer (tos
, stdout
);
1430 write_buffer (tos
, stderr
);
1432 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1449 r
= fread (buff
, 1, sizeof (buff
), file
);
1450 catbuf (str
, buff
, r
);
1455 catbuf (str
, buff
, 1);
1461 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1465 /* There is no reliable way to declare exit. Sometimes it returns
1466 int, and sometimes it returns void. Sometimes it changes between
1467 OS releases. Trying to get it declared correctly in the hosts file
1468 is a pointless waste of time. */
1485 init_string (&buffer
);
1486 init_string (&pptr
);
1487 init_string (stack
+ 0);
1491 add_intrinsic ("push_text", push_text
);
1492 add_intrinsic ("!", bang
);
1493 add_intrinsic ("@", atsign
);
1494 add_intrinsic ("hello", hello
);
1495 add_intrinsic ("stdout", stdout_
);
1496 add_intrinsic ("stderr", stderr_
);
1497 add_intrinsic ("print", print
);
1498 add_intrinsic ("skip_past_newline", skip_past_newline
);
1499 add_intrinsic ("catstr", icatstr
);
1500 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1501 add_intrinsic ("dup", other_dup
);
1502 add_intrinsic ("drop", drop
);
1503 add_intrinsic ("idrop", idrop
);
1504 add_intrinsic ("remchar", remchar
);
1505 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1506 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1507 add_intrinsic ("bulletize", bulletize
);
1508 add_intrinsic ("courierize", courierize
);
1509 /* If the following line gives an error, exit() is not declared in the
1510 ../hosts/foo.h file for this host. Fix it there, not here! */
1511 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1512 add_intrinsic ("exit", chew_exit
);
1513 add_intrinsic ("swap", swap
);
1514 add_intrinsic ("outputdots", outputdots
);
1515 add_intrinsic ("paramstuff", paramstuff
);
1516 add_intrinsic ("maybecatstr", maybecatstr
);
1517 add_intrinsic ("translatecomments", translatecomments
);
1518 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1519 add_intrinsic ("indent", indent
);
1520 add_intrinsic ("internalmode", internalmode
);
1521 add_intrinsic ("print_stack_level", print_stack_level
);
1522 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1524 /* Put a nl at the start. */
1525 catchar (&buffer
, '\n');
1527 read_in (&buffer
, stdin
);
1528 remove_noncomments (&buffer
, ptr
);
1529 for (i
= 1; i
< (unsigned int) ac
; i
++)
1531 if (av
[i
][0] == '-')
1533 if (av
[i
][1] == 'f')
1539 f
= fopen (av
[i
+ 1], "r");
1542 fprintf (stderr
, "Can't open the input file %s\n",
1551 else if (av
[i
][1] == 'i')
1553 internal_wanted
= 1;
1555 else if (av
[i
][1] == 'w')
1563 write_buffer (stack
+ 0, stdout
);
1566 fprintf (stderr
, "finishing with current stack level %d\n",