]>
git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
2 Copyright (C) 1990-2014 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.
99 /* Here is a string type ... */
101 typedef struct buffer
104 unsigned long write_idx
;
109 static void init_string_with_size (string_type
*, unsigned int);
110 static void init_string (string_type
*);
111 static int find (string_type
*, char *);
112 static void write_buffer (string_type
*, FILE *);
113 static void delete_string (string_type
*);
114 static char *addr (string_type
*, unsigned int);
115 static char at (string_type
*, unsigned int);
116 static void catchar (string_type
*, int);
117 static void overwrite_string (string_type
*, string_type
*);
118 static void catbuf (string_type
*, char *, unsigned int);
119 static void cattext (string_type
*, char *);
120 static void catstr (string_type
*, string_type
*);
121 static void die (char *);
125 init_string_with_size (buffer
, size
)
129 buffer
->write_idx
= 0;
131 buffer
->ptr
= (char *) malloc (size
);
138 init_string_with_size (buffer
, DEF_SIZE
);
149 for (i
= 0; i
< str
->write_idx
&& *p
; i
++)
151 if (*p
== str
->ptr
[i
])
160 write_buffer (buffer
, f
)
164 if (buffer
->write_idx
!= 0
165 && fwrite (buffer
->ptr
, buffer
->write_idx
, 1, f
) != 1)
166 die ("cannot write output");
170 delete_string (buffer
)
181 return buffer
->ptr
+ idx
;
189 if (pos
>= buffer
->write_idx
)
191 return buffer
->ptr
[pos
];
199 if (buffer
->write_idx
== buffer
->size
)
202 buffer
->ptr
= (char *) realloc (buffer
->ptr
, buffer
->size
);
205 buffer
->ptr
[buffer
->write_idx
++] = ch
;
209 overwrite_string (dst
, src
)
214 dst
->size
= src
->size
;
215 dst
->write_idx
= src
->write_idx
;
220 catbuf (buffer
, buf
, len
)
225 if (buffer
->write_idx
+ len
>= buffer
->size
)
227 while (buffer
->write_idx
+ len
>= buffer
->size
)
229 buffer
->ptr
= (char *) realloc (buffer
->ptr
, buffer
->size
);
231 memcpy (buffer
->ptr
+ buffer
->write_idx
, buf
, len
);
232 buffer
->write_idx
+= len
;
236 cattext (buffer
, string
)
240 catbuf (buffer
, string
, (unsigned int) strlen (string
));
248 catbuf (dst
, src
->ptr
, src
->write_idx
);
252 skip_white_and_stars (src
, idx
)
257 while ((c
= at (src
, idx
)),
258 isspace ((unsigned char) c
)
260 /* Don't skip past end-of-comment or star as first
261 character on its line. */
262 && at (src
, idx
+1) != '/'
263 && at (src
, idx
-1) != '\n'))
268 /***********************************************************************/
270 string_type stack
[STACK
];
273 unsigned int idx
= 0; /* Pos in input buffer */
274 string_type
*ptr
; /* and the buffer */
275 typedef void (*stinst_type
)();
277 stinst_type sstack
[STACK
];
278 stinst_type
*ssp
= &sstack
[0];
280 long *isp
= &istack
[0];
282 typedef int *word_type
;
287 struct dict_struct
*next
;
294 typedef struct dict_struct dict_type
;
300 fprintf (stderr
, "%s\n", msg
);
308 die ("underflow in string stack");
309 if (tos
>= stack
+ STACK
)
310 die ("overflow in string stack");
317 die ("underflow in integer stack");
318 if (isp
>= istack
+ STACK
)
319 die ("overflow in integer stack");
323 static void exec (dict_type
*);
324 static void call (void);
325 static void remchar (void), strip_trailing_newlines (void), push_number (void);
326 static void push_text (void);
327 static void remove_noncomments (string_type
*, string_type
*);
328 static void print_stack_level (void);
329 static void paramstuff (void), translatecomments (void);
330 static void outputdots (void), courierize (void), bulletize (void);
331 static void do_fancy_stuff (void);
332 static int iscommand (string_type
*, unsigned int);
333 static int copy_past_newline (string_type
*, unsigned int, string_type
*);
334 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
335 static void get_stuff_in_command (void), swap (void), other_dup (void);
336 static void drop (void), idrop (void);
337 static void icatstr (void), skip_past_newline (void), internalmode (void);
338 static void maybecatstr (void);
339 static char *nextword (char *, char **);
340 dict_type
*lookup_word (char *);
341 static void perform (void);
342 dict_type
*newentry (char *);
343 unsigned int add_to_definition (dict_type
*, stinst_type
);
344 void add_intrinsic (char *, void (*)());
345 void add_var (char *);
346 void compile (char *);
347 static void bang (void);
348 static void atsign (void);
349 static void hello (void);
350 static void stdout_ (void);
351 static void stderr_ (void);
352 static void print (void);
353 static void read_in (string_type
*, FILE *);
354 static void usage (void);
355 static void chew_exit (void);
370 stinst_type
*oldpc
= pc
;
372 e
= (dict_type
*) (pc
[1]);
386 strip_trailing_newlines ()
388 while ((isspace ((unsigned char) at (tos
, tos
->write_idx
- 1))
389 || at (tos
, tos
->write_idx
- 1) == '\n')
390 && tos
->write_idx
> 0)
412 cattext (tos
, *((char **) pc
));
416 /* This function removes everything not inside comments starting on
417 the first char of the line from the string, also when copying
418 comments, removes blank space and leading *'s.
419 Blank lines are turned into one blank line. */
422 remove_noncomments (src
, dst
)
426 unsigned int idx
= 0;
428 while (at (src
, idx
))
430 /* Now see if we have a comment at the start of the line. */
431 if (at (src
, idx
) == '\n'
432 && at (src
, idx
+ 1) == '/'
433 && at (src
, idx
+ 2) == '*')
437 idx
= skip_white_and_stars (src
, idx
);
439 /* Remove leading dot */
440 if (at (src
, idx
) == '.')
443 /* Copy to the end of the line, or till the end of the
445 while (at (src
, idx
))
447 if (at (src
, idx
) == '\n')
449 /* end of line, echo and scrape of leading blanks */
450 if (at (src
, idx
+ 1) == '\n')
454 idx
= skip_white_and_stars (src
, idx
);
456 else if (at (src
, idx
) == '*' && at (src
, idx
+ 1) == '/')
459 cattext (dst
, "\nENDDD\n");
464 catchar (dst
, at (src
, idx
));
477 fprintf (stderr
, "current string stack depth = %ld, ", tos
- stack
);
478 fprintf (stderr
, "current integer stack depth = %ld\n", isp
- istack
);
486 name PARAMS ((stuff));
502 /* Make sure that it's not already param'd or proto'd. */
504 || find (tos
, "PARAMS") || find (tos
, "PROTO") || !find (tos
, "("))
510 /* Find the open paren. */
511 for (openp
= 0; at (tos
, openp
) != '(' && at (tos
, openp
); openp
++)
515 /* Step back to the fname. */
517 while (fname
&& isspace ((unsigned char) at (tos
, fname
)))
520 && !isspace ((unsigned char) at (tos
,fname
))
521 && at (tos
,fname
) != '*')
526 /* Output type, omitting trailing whitespace character(s), if
528 for (len
= fname
; 0 < len
; len
--)
530 if (!isspace ((unsigned char) at (tos
, len
- 1)))
533 for (idx
= 0; idx
< len
; idx
++)
534 catchar (&out
, at (tos
, idx
));
536 cattext (&out
, "\n"); /* Insert a newline between type and fnname */
538 /* Output function name, omitting trailing whitespace
539 character(s), if any. */
540 for (len
= openp
; 0 < len
; len
--)
542 if (!isspace ((unsigned char) at (tos
, len
- 1)))
545 for (idx
= fname
; idx
< len
; idx
++)
546 catchar (&out
, at (tos
, idx
));
548 cattext (&out
, " PARAMS (");
550 for (idx
= openp
; at (tos
, idx
) && at (tos
, idx
) != ';'; idx
++)
551 catchar (&out
, at (tos
, idx
));
553 cattext (&out
, ");\n\n");
555 overwrite_string (tos
, &out
);
561 and *} into comments */
566 unsigned int idx
= 0;
570 while (at (tos
, idx
))
572 if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
574 cattext (&out
, "/*");
577 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
579 cattext (&out
, "*/");
584 catchar (&out
, at (tos
, idx
));
589 overwrite_string (tos
, &out
);
594 /* Mod tos so that only lines with leading dots remain */
598 unsigned int idx
= 0;
602 while (at (tos
, idx
))
604 if (at (tos
, idx
) == '\n' && at (tos
, idx
+ 1) == '.')
609 while ((c
= at (tos
, idx
)) && c
!= '\n')
611 if (c
== '{' && at (tos
, idx
+ 1) == '*')
613 cattext (&out
, "/*");
616 else if (c
== '*' && at (tos
, idx
+ 1) == '}')
618 cattext (&out
, "*/");
627 catchar (&out
, '\n');
635 overwrite_string (tos
, &out
);
639 /* Find lines starting with . and | and put example around them on tos */
644 unsigned int idx
= 0;
649 while (at (tos
, idx
))
651 if (at (tos
, idx
) == '\n'
652 && (at (tos
, idx
+1 ) == '.'
653 || at (tos
, idx
+ 1) == '|'))
655 cattext (&out
, "\n@example\n");
660 while (at (tos
, idx
) && at (tos
, idx
) != '\n')
664 /* We are inside {} parameters of some command;
665 Just pass through until matching brace. */
666 if (at (tos
, idx
) == '{')
668 else if (at (tos
, idx
) == '}')
671 else if (command
!= 0)
673 if (at (tos
, idx
) == '{')
675 else if (!islower ((unsigned char) at (tos
, idx
)))
678 else if (at (tos
, idx
) == '@'
679 && islower ((unsigned char) at (tos
, idx
+ 1)))
683 else if (at (tos
, idx
) == '{' && at (tos
, idx
+ 1) == '*')
685 cattext (&out
, "/*");
689 else if (at (tos
, idx
) == '*' && at (tos
, idx
+ 1) == '}')
691 cattext (&out
, "*/");
695 else if (at (tos
, idx
) == '{'
696 || at (tos
, idx
) == '}')
701 catchar (&out
, at (tos
, idx
));
704 catchar (&out
, '\n');
706 while (at (tos
, idx
) == '\n'
707 && ((at (tos
, idx
+ 1) == '.')
708 || (at (tos
, idx
+ 1) == '|')))
710 cattext (&out
, "@end example");
714 catchar (&out
, at (tos
, idx
));
719 overwrite_string (tos
, &out
);
723 /* Finds any lines starting with "o ", if there are any, then turns
724 on @itemize @bullet, and @items each of them. Then ends with @end
725 itemize, inplace at TOS*/
730 unsigned int idx
= 0;
735 while (at (tos
, idx
))
737 if (at (tos
, idx
) == '@'
738 && at (tos
, idx
+ 1) == '*')
743 else if (at (tos
, idx
) == '\n'
744 && at (tos
, idx
+ 1) == 'o'
745 && isspace ((unsigned char) at (tos
, idx
+ 2)))
749 cattext (&out
, "\n@itemize @bullet\n");
753 cattext (&out
, "\n@item\n");
758 catchar (&out
, at (tos
, idx
));
759 if (on
&& at (tos
, idx
) == '\n'
760 && at (tos
, idx
+ 1) == '\n'
761 && at (tos
, idx
+ 2) != 'o')
763 cattext (&out
, "@end itemize");
772 cattext (&out
, "@end itemize\n");
780 /* Turn <<foo>> into @code{foo} in place at TOS*/
785 unsigned int idx
= 0;
788 while (at (tos
, idx
))
790 if (at (tos
, idx
) == '<'
791 && at (tos
, idx
+ 1) == '<'
792 && !isspace ((unsigned char) at (tos
, idx
+ 2)))
794 /* This qualifies as a << startup. */
796 cattext (&out
, "@code{");
798 && at (tos
, idx
) != '>' )
800 catchar (&out
, at (tos
, idx
));
809 catchar (&out
, at (tos
, idx
));
819 /* A command is all upper case,and alone on a line. */
826 unsigned int len
= 0;
827 while (at (ptr
, idx
))
829 if (isupper ((unsigned char) at (ptr
, idx
))
830 || at (ptr
, idx
) == ' ' || at (ptr
, idx
) == '_')
835 else if (at (ptr
, idx
) == '\n')
848 copy_past_newline (ptr
, idx
, dst
)
855 while (at (ptr
, idx
) && at (ptr
, idx
) != '\n')
857 if (at (ptr
, idx
) == '\t')
859 /* Expand tabs. Neither makeinfo nor TeX can cope well with
863 while (++column
& 7);
867 catchar (dst
, at (ptr
, idx
));
873 catchar (dst
, at (ptr
, idx
));
880 icopy_past_newline ()
885 idx
= copy_past_newline (ptr
, idx
, tos
);
890 Take the string at the top of the stack, do some prettying. */
903 /* Drop leading nl. */
904 while (at (tos
, idx
) == '\n')
910 /* If the first char is a '.' prepend a newline so that it is
911 recognized properly later. */
912 if (at (tos
, idx
) == '.')
913 catchar (&out
, '\n');
915 /* Find the last char. */
916 while (at (tos
, idx
))
921 /* Find the last non white before the nl. */
924 while (idx
&& isspace ((unsigned char) at (tos
, idx
)))
928 /* Copy buffer upto last char, but blank lines before and after
934 if (at (tos
, c
) == '\n'
935 && at (tos
, c
+ 1) == '\n'
936 && at (tos
, c
+ 2) == '.')
938 /* Ignore two newlines before a dot. */
941 else if (at (tos
, c
) == '.' && sl
)
943 /* remember that this line started with a dot. */
946 else if (at (tos
, c
) == '\n'
947 && at (tos
, c
+ 1) == '\n'
951 /* Ignore two newlines when last line was dot. */
954 catchar (&out
, at (tos
, c
));
955 if (at (tos
, c
) == '\n')
972 catchar (&out
, '\n');
987 while (at (tos
, idx
))
989 switch (at (tos
, idx
))
992 cattext (&out
, "\n");
994 if (tab
&& at (tos
, idx
))
1003 cattext (&out
, " ");
1005 cattext (&out
, "(");
1010 cattext (&out
, ")");
1016 catchar (&out
, at (tos
, idx
));
1025 delete_string (tos
);
1031 get_stuff_in_command ()
1037 while (at (ptr
, idx
))
1039 if (iscommand (ptr
, idx
))
1041 idx
= copy_past_newline (ptr
, idx
, tos
);
1063 catstr (tos
, tos
- 1);
1088 catstr (tos
, tos
+ 1);
1089 delete_string (tos
+ 1);
1094 skip_past_newline ()
1096 while (at (ptr
, idx
)
1097 && at (ptr
, idx
) != '\n')
1106 internal_mode
= *(isp
);
1115 if (internal_wanted
== internal_mode
)
1117 catstr (tos
- 1, tos
);
1119 delete_string (tos
);
1126 nextword (string
, word
)
1137 while (isspace ((unsigned char) *string
) || *string
== '-')
1141 while (*string
&& *string
!= '\n')
1153 word_start
= string
;
1160 if (*string
== '\\')
1166 while (*string
!= '"');
1170 while (!isspace ((unsigned char) *string
))
1178 *word
= (char *) malloc (length
+ 1);
1183 for (idx
= 0; idx
< length
; idx
++)
1185 if (src
[idx
] == '\\')
1186 switch (src
[idx
+ 1])
1194 *dst
++ = src
[idx
+ 1];
1218 dict_type
*ptr
= root
;
1221 if (strcmp (ptr
->word
, word
) == 0)
1226 fprintf (stderr
, "Can't find %s\n", word
);
1235 while (at (ptr
, idx
))
1237 /* It's worth looking through the command list. */
1238 if (iscommand (ptr
, idx
))
1243 (void) nextword (addr (ptr
, idx
), &next
);
1245 word
= lookup_word (next
);
1254 fprintf (stderr
, "warning, %s is not recognised\n", next
);
1255 skip_past_newline ();
1260 skip_past_newline ();
1268 dict_type
*new_d
= (dict_type
*) malloc (sizeof (dict_type
));
1272 new_d
->code
= (stinst_type
*) malloc (sizeof (stinst_type
));
1273 new_d
->code_length
= 1;
1274 new_d
->code_end
= 0;
1279 add_to_definition (entry
, word
)
1283 if (entry
->code_end
== entry
->code_length
)
1285 entry
->code_length
+= 2;
1287 (stinst_type
*) realloc ((char *) (entry
->code
),
1288 entry
->code_length
* sizeof (word_type
));
1290 entry
->code
[entry
->code_end
] = word
;
1292 return entry
->code_end
++;
1296 add_intrinsic (name
, func
)
1300 dict_type
*new_d
= newentry (name
);
1301 add_to_definition (new_d
, func
);
1302 add_to_definition (new_d
, 0);
1309 dict_type
*new_d
= newentry (name
);
1310 add_to_definition (new_d
, push_number
);
1311 add_to_definition (new_d
, (stinst_type
) (&(new_d
->var
)));
1312 add_to_definition (new_d
, 0);
1319 /* Add words to the dictionary. */
1321 string
= nextword (string
, &word
);
1322 while (string
&& *string
&& word
[0])
1324 if (strcmp (word
, "var") == 0)
1326 string
= nextword (string
, &word
);
1329 string
= nextword (string
, &word
);
1331 else if (word
[0] == ':')
1334 /* Compile a word and add to dictionary. */
1335 string
= nextword (string
, &word
);
1337 ptr
= newentry (word
);
1338 string
= nextword (string
, &word
);
1339 while (word
[0] != ';')
1344 /* got a string, embed magic push string
1346 add_to_definition (ptr
, push_text
);
1347 add_to_definition (ptr
, (stinst_type
) (word
+ 1));
1359 /* Got a number, embedd the magic push number
1361 add_to_definition (ptr
, push_number
);
1362 add_to_definition (ptr
, (stinst_type
) atol (word
));
1365 add_to_definition (ptr
, call
);
1366 add_to_definition (ptr
, (stinst_type
) lookup_word (word
));
1369 string
= nextword (string
, &word
);
1371 add_to_definition (ptr
, 0);
1372 string
= nextword (string
, &word
);
1376 fprintf (stderr
, "syntax error at %s\n", string
- 1);
1384 *(long *) ((isp
[0])) = isp
[-1];
1393 isp
[0] = *(long *) (isp
[0]);
1426 write_buffer (tos
, stdout
);
1428 write_buffer (tos
, stderr
);
1430 fprintf (stderr
, "print: illegal print destination `%ld'\n", *isp
);
1447 r
= fread (buff
, 1, sizeof (buff
), file
);
1448 catbuf (str
, buff
, r
);
1453 catbuf (str
, buff
, 1);
1459 fprintf (stderr
, "usage: -[d|i|g] <file >file\n");
1463 /* There is no reliable way to declare exit. Sometimes it returns
1464 int, and sometimes it returns void. Sometimes it changes between
1465 OS releases. Trying to get it declared correctly in the hosts file
1466 is a pointless waste of time. */
1483 init_string (&buffer
);
1484 init_string (&pptr
);
1485 init_string (stack
+ 0);
1489 add_intrinsic ("push_text", push_text
);
1490 add_intrinsic ("!", bang
);
1491 add_intrinsic ("@", atsign
);
1492 add_intrinsic ("hello", hello
);
1493 add_intrinsic ("stdout", stdout_
);
1494 add_intrinsic ("stderr", stderr_
);
1495 add_intrinsic ("print", print
);
1496 add_intrinsic ("skip_past_newline", skip_past_newline
);
1497 add_intrinsic ("catstr", icatstr
);
1498 add_intrinsic ("copy_past_newline", icopy_past_newline
);
1499 add_intrinsic ("dup", other_dup
);
1500 add_intrinsic ("drop", drop
);
1501 add_intrinsic ("idrop", idrop
);
1502 add_intrinsic ("remchar", remchar
);
1503 add_intrinsic ("get_stuff_in_command", get_stuff_in_command
);
1504 add_intrinsic ("do_fancy_stuff", do_fancy_stuff
);
1505 add_intrinsic ("bulletize", bulletize
);
1506 add_intrinsic ("courierize", courierize
);
1507 /* If the following line gives an error, exit() is not declared in the
1508 ../hosts/foo.h file for this host. Fix it there, not here! */
1509 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1510 add_intrinsic ("exit", chew_exit
);
1511 add_intrinsic ("swap", swap
);
1512 add_intrinsic ("outputdots", outputdots
);
1513 add_intrinsic ("paramstuff", paramstuff
);
1514 add_intrinsic ("maybecatstr", maybecatstr
);
1515 add_intrinsic ("translatecomments", translatecomments
);
1516 add_intrinsic ("kill_bogus_lines", kill_bogus_lines
);
1517 add_intrinsic ("indent", indent
);
1518 add_intrinsic ("internalmode", internalmode
);
1519 add_intrinsic ("print_stack_level", print_stack_level
);
1520 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines
);
1522 /* Put a nl at the start. */
1523 catchar (&buffer
, '\n');
1525 read_in (&buffer
, stdin
);
1526 remove_noncomments (&buffer
, ptr
);
1527 for (i
= 1; i
< (unsigned int) ac
; i
++)
1529 if (av
[i
][0] == '-')
1531 if (av
[i
][1] == 'f')
1537 f
= fopen (av
[i
+ 1], "r");
1540 fprintf (stderr
, "Can't open the input file %s\n",
1549 else if (av
[i
][1] == 'i')
1551 internal_wanted
= 1;
1553 else if (av
[i
][1] == 'w')
1561 write_buffer (stack
+ 0, stdout
);
1564 fprintf (stderr
, "finishing with current stack level %ld\n",