Reorganise bfd/doc/chew.c a little
[binutils-gdb/blckswan.git] / bfd / doc / chew.c
blob2f987821bd99f39dd873fe72f9981507e1cbfcca
1 /* chew
2 Copyright (C) 1990-2022 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
24 than the old way
26 sac
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
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
44 Commands:
45 push_text
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)
53 skip_past_newline
54 catstr - fn icatstr
55 copy_past_newline - append input, up to and including newline into TOS
56 dup - fn other_dup
57 drop - discard TOS
58 idrop - ditto
59 remchar - delete last character from TOS
60 get_stuff_in_command
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 {* *} { }
65 exit - fn chew_exit
66 swap
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
70 value in any case
71 translatecomments - turn {* and *} into comment delimiters
72 kill_bogus_lines - get rid of extra newlines
73 indent
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.
82 Foo. */
84 #include "ansidecl.h"
85 #include <assert.h>
86 #include <stdio.h>
87 #include <ctype.h>
88 #include <stdlib.h>
89 #include <string.h>
91 #define DEF_SIZE 5000
92 #define STACK 50
94 /* Here is a string type ... */
96 typedef struct buffer
98 char *ptr;
99 unsigned long write_idx;
100 unsigned long size;
101 } string_type;
103 typedef void (*stinst_type)();
105 typedef struct dict_struct
107 char *word;
108 struct dict_struct *next;
109 stinst_type *code;
110 int code_length;
111 int code_end;
112 } dict_type;
114 int internal_wanted;
115 int internal_mode;
117 int warning;
119 string_type stack[STACK];
120 string_type *tos;
122 unsigned int idx = 0; /* Pos in input buffer */
123 string_type *ptr; /* and the buffer */
125 long istack[STACK];
126 long *isp = &istack[0];
128 dict_type *root;
130 stinst_type *pc;
132 #ifdef __STDC__
133 static void init_string_with_size (string_type *, unsigned int);
134 static void init_string (string_type *);
135 static int find (string_type *, char *);
136 static void write_buffer (string_type *, FILE *);
137 static void delete_string (string_type *);
138 static char *addr (string_type *, unsigned int);
139 static char at (string_type *, unsigned int);
140 static void catchar (string_type *, int);
141 static void overwrite_string (string_type *, string_type *);
142 static void catbuf (string_type *, char *, unsigned int);
143 static void cattext (string_type *, char *);
144 static void catstr (string_type *, string_type *);
145 static void die (char *);
146 #endif
148 static void
149 die (msg)
150 char *msg;
152 fprintf (stderr, "%s\n", msg);
153 exit (1);
156 static void
157 init_string_with_size (buffer, size)
158 string_type *buffer;
159 unsigned int size;
161 buffer->write_idx = 0;
162 buffer->size = size;
163 buffer->ptr = (char *) malloc (size);
166 static void
167 init_string (buffer)
168 string_type *buffer;
170 init_string_with_size (buffer, DEF_SIZE);
173 static int
174 find (str, what)
175 string_type *str;
176 char *what;
178 unsigned int i;
179 char *p;
180 p = what;
181 for (i = 0; i < str->write_idx && *p; i++)
183 if (*p == str->ptr[i])
184 p++;
185 else
186 p = what;
188 return (*p == 0);
191 static void
192 write_buffer (buffer, f)
193 string_type *buffer;
194 FILE *f;
196 if (buffer->write_idx != 0
197 && fwrite (buffer->ptr, buffer->write_idx, 1, f) != 1)
198 die ("cannot write output");
201 static void
202 delete_string (buffer)
203 string_type *buffer;
205 free (buffer->ptr);
206 buffer->ptr = NULL;
209 static char *
210 addr (buffer, idx)
211 string_type *buffer;
212 unsigned int idx;
214 return buffer->ptr + idx;
217 static char
218 at (buffer, pos)
219 string_type *buffer;
220 unsigned int pos;
222 if (pos >= buffer->write_idx)
223 return 0;
224 return buffer->ptr[pos];
227 static void
228 catchar (buffer, ch)
229 string_type *buffer;
230 int ch;
232 if (buffer->write_idx == buffer->size)
234 buffer->size *= 2;
235 buffer->ptr = (char *) realloc (buffer->ptr, buffer->size);
238 buffer->ptr[buffer->write_idx++] = ch;
241 static void
242 overwrite_string (dst, src)
243 string_type *dst;
244 string_type *src;
246 free (dst->ptr);
247 dst->size = src->size;
248 dst->write_idx = src->write_idx;
249 dst->ptr = src->ptr;
252 static void
253 catbuf (buffer, buf, len)
254 string_type *buffer;
255 char *buf;
256 unsigned int len;
258 if (buffer->write_idx + len >= buffer->size)
260 while (buffer->write_idx + len >= buffer->size)
261 buffer->size *= 2;
262 buffer->ptr = (char *) realloc (buffer->ptr, buffer->size);
264 memcpy (buffer->ptr + buffer->write_idx, buf, len);
265 buffer->write_idx += len;
268 static void
269 cattext (buffer, string)
270 string_type *buffer;
271 char *string;
273 catbuf (buffer, string, (unsigned int) strlen (string));
276 static void
277 catstr (dst, src)
278 string_type *dst;
279 string_type *src;
281 catbuf (dst, src->ptr, src->write_idx);
284 static unsigned int
285 skip_white_and_stars (src, idx)
286 string_type *src;
287 unsigned int idx;
289 char c;
290 while ((c = at (src, idx)),
291 isspace ((unsigned char) c)
292 || (c == '*'
293 /* Don't skip past end-of-comment or star as first
294 character on its line. */
295 && at (src, idx +1) != '/'
296 && at (src, idx -1) != '\n'))
297 idx++;
298 return idx;
301 static unsigned int
302 skip_past_newline_1 (ptr, idx)
303 string_type *ptr;
304 unsigned int idx;
306 while (at (ptr, idx)
307 && at (ptr, idx) != '\n')
308 idx++;
309 if (at (ptr, idx) == '\n')
310 return idx + 1;
311 return idx;
314 static void
315 check_range ()
317 if (tos < stack)
318 die ("underflow in string stack");
319 if (tos >= stack + STACK)
320 die ("overflow in string stack");
323 static void
324 icheck_range ()
326 if (isp < istack)
327 die ("underflow in integer stack");
328 if (isp >= istack + STACK)
329 die ("overflow in integer stack");
332 #ifdef __STDC__
333 static void exec (dict_type *);
334 static void call (void);
335 static void remchar (void), strip_trailing_newlines (void), push_number (void);
336 static void push_text (void);
337 static void remove_noncomments (string_type *, string_type *);
338 static void print_stack_level (void);
339 static void paramstuff (void), translatecomments (void);
340 static void outputdots (void), courierize (void), bulletize (void);
341 static void do_fancy_stuff (void);
342 static int iscommand (string_type *, unsigned int);
343 static int copy_past_newline (string_type *, unsigned int, string_type *);
344 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
345 static void get_stuff_in_command (void), swap (void), other_dup (void);
346 static void drop (void), idrop (void);
347 static void icatstr (void), skip_past_newline (void), internalmode (void);
348 static void maybecatstr (void);
349 static char *nextword (char *, char **);
350 dict_type *lookup_word (char *);
351 static void perform (void);
352 dict_type *newentry (char *);
353 unsigned int add_to_definition (dict_type *, stinst_type);
354 void add_intrinsic (char *, void (*)());
355 void compile (char *);
356 static void bang (void);
357 static void atsign (void);
358 static void hello (void);
359 static void stdout_ (void);
360 static void stderr_ (void);
361 static void print (void);
362 static void read_in (string_type *, FILE *);
363 static void usage (void);
364 static void chew_exit (void);
365 #endif
367 static void
368 exec (word)
369 dict_type *word;
371 pc = word->code;
372 while (*pc)
373 (*pc) ();
376 static void
377 call ()
379 stinst_type *oldpc = pc;
380 dict_type *e;
381 e = (dict_type *) (pc[1]);
382 exec (e);
383 pc = oldpc + 2;
386 static void
387 remchar ()
389 if (tos->write_idx)
390 tos->write_idx--;
391 pc++;
394 static void
395 strip_trailing_newlines ()
397 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
398 || at (tos, tos->write_idx - 1) == '\n')
399 && tos->write_idx > 0)
400 tos->write_idx--;
401 pc++;
404 static void
405 push_number ()
407 isp++;
408 icheck_range ();
409 pc++;
410 *isp = (long) (*pc);
411 pc++;
414 static void
415 push_text ()
417 tos++;
418 check_range ();
419 init_string (tos);
420 pc++;
421 cattext (tos, *((char **) pc));
422 pc++;
425 /* This function removes everything not inside comments starting on
426 the first char of the line from the string, also when copying
427 comments, removes blank space and leading *'s.
428 Blank lines are turned into one blank line. */
430 static void
431 remove_noncomments (src, dst)
432 string_type *src;
433 string_type *dst;
435 unsigned int idx = 0;
437 while (at (src, idx))
439 /* Now see if we have a comment at the start of the line. */
440 if (at (src, idx) == '\n'
441 && at (src, idx + 1) == '/'
442 && at (src, idx + 2) == '*')
444 idx += 3;
446 idx = skip_white_and_stars (src, idx);
448 /* Remove leading dot */
449 if (at (src, idx) == '.')
450 idx++;
452 /* Copy to the end of the line, or till the end of the
453 comment. */
454 while (at (src, idx))
456 if (at (src, idx) == '\n')
458 /* end of line, echo and scrape of leading blanks */
459 if (at (src, idx + 1) == '\n')
460 catchar (dst, '\n');
461 catchar (dst, '\n');
462 idx++;
463 idx = skip_white_and_stars (src, idx);
465 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
467 idx += 2;
468 cattext (dst, "\nENDDD\n");
469 break;
471 else
473 catchar (dst, at (src, idx));
474 idx++;
478 else
479 idx++;
483 static void
484 print_stack_level ()
486 fprintf (stderr, "current string stack depth = %ld, ",
487 (long) (tos - stack));
488 fprintf (stderr, "current integer stack depth = %ld\n",
489 (long) (isp - istack));
490 pc++;
493 /* turn:
494 foobar name(stuff);
495 into:
496 foobar
497 name PARAMS ((stuff));
498 and a blank line.
501 static void
502 paramstuff ()
504 unsigned int openp;
505 unsigned int fname;
506 unsigned int idx;
507 unsigned int len;
508 string_type out;
509 init_string (&out);
511 #define NO_PARAMS 1
513 /* Make sure that it's not already param'd or proto'd. */
514 if (NO_PARAMS
515 || find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
517 catstr (&out, tos);
519 else
521 /* Find the open paren. */
522 for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
525 fname = openp;
526 /* Step back to the fname. */
527 fname--;
528 while (fname && isspace ((unsigned char) at (tos, fname)))
529 fname--;
530 while (fname
531 && !isspace ((unsigned char) at (tos,fname))
532 && at (tos,fname) != '*')
533 fname--;
535 fname++;
537 /* Output type, omitting trailing whitespace character(s), if
538 any. */
539 for (len = fname; 0 < len; len--)
541 if (!isspace ((unsigned char) at (tos, len - 1)))
542 break;
544 for (idx = 0; idx < len; idx++)
545 catchar (&out, at (tos, idx));
547 cattext (&out, "\n"); /* Insert a newline between type and fnname */
549 /* Output function name, omitting trailing whitespace
550 character(s), if any. */
551 for (len = openp; 0 < len; len--)
553 if (!isspace ((unsigned char) at (tos, len - 1)))
554 break;
556 for (idx = fname; idx < len; idx++)
557 catchar (&out, at (tos, idx));
559 cattext (&out, " PARAMS (");
561 for (idx = openp; at (tos, idx) && at (tos, idx) != ';'; idx++)
562 catchar (&out, at (tos, idx));
564 cattext (&out, ");\n\n");
566 overwrite_string (tos, &out);
567 pc++;
571 /* turn {*
572 and *} into comments */
574 static void
575 translatecomments ()
577 unsigned int idx = 0;
578 string_type out;
579 init_string (&out);
581 while (at (tos, idx))
583 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
585 cattext (&out, "/*");
586 idx += 2;
588 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
590 cattext (&out, "*/");
591 idx += 2;
593 else
595 catchar (&out, at (tos, idx));
596 idx++;
600 overwrite_string (tos, &out);
602 pc++;
605 /* Mod tos so that only lines with leading dots remain */
606 static void
607 outputdots ()
609 unsigned int idx = 0;
610 string_type out;
611 init_string (&out);
613 while (at (tos, idx))
615 /* Every iteration begins at the start of a line. */
616 if (at (tos, idx) == '.')
618 char c;
620 idx++;
622 while ((c = at (tos, idx)) && c != '\n')
624 if (c == '{' && at (tos, idx + 1) == '*')
626 cattext (&out, "/*");
627 idx += 2;
629 else if (c == '*' && at (tos, idx + 1) == '}')
631 cattext (&out, "*/");
632 idx += 2;
634 else
636 catchar (&out, c);
637 idx++;
640 if (c == '\n')
641 idx++;
642 catchar (&out, '\n');
644 else
646 idx = skip_past_newline_1 (tos, idx);
650 overwrite_string (tos, &out);
651 pc++;
654 /* Find lines starting with . and | and put example around them on tos */
655 static void
656 courierize ()
658 string_type out;
659 unsigned int idx = 0;
660 int command = 0;
662 init_string (&out);
664 while (at (tos, idx))
666 if (at (tos, idx) == '\n'
667 && (at (tos, idx +1 ) == '.'
668 || at (tos, idx + 1) == '|'))
670 cattext (&out, "\n@example\n");
673 idx += 2;
675 while (at (tos, idx) && at (tos, idx) != '\n')
677 if (command > 1)
679 /* We are inside {} parameters of some command;
680 Just pass through until matching brace. */
681 if (at (tos, idx) == '{')
682 ++command;
683 else if (at (tos, idx) == '}')
684 --command;
686 else if (command != 0)
688 if (at (tos, idx) == '{')
689 ++command;
690 else if (!islower ((unsigned char) at (tos, idx)))
691 --command;
693 else if (at (tos, idx) == '@'
694 && islower ((unsigned char) at (tos, idx + 1)))
696 ++command;
698 else if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
700 cattext (&out, "/*");
701 idx += 2;
702 continue;
704 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
706 cattext (&out, "*/");
707 idx += 2;
708 continue;
710 else if (at (tos, idx) == '{'
711 || at (tos, idx) == '}')
713 catchar (&out, '@');
716 catchar (&out, at (tos, idx));
717 idx++;
719 catchar (&out, '\n');
721 while (at (tos, idx) == '\n'
722 && ((at (tos, idx + 1) == '.')
723 || (at (tos, idx + 1) == '|')))
725 cattext (&out, "@end example");
727 else
729 catchar (&out, at (tos, idx));
730 idx++;
734 overwrite_string (tos, &out);
735 pc++;
738 /* Finds any lines starting with "o ", if there are any, then turns
739 on @itemize @bullet, and @items each of them. Then ends with @end
740 itemize, inplace at TOS*/
742 static void
743 bulletize ()
745 unsigned int idx = 0;
746 int on = 0;
747 string_type out;
748 init_string (&out);
750 while (at (tos, idx))
752 if (at (tos, idx) == '@'
753 && at (tos, idx + 1) == '*')
755 cattext (&out, "*");
756 idx += 2;
758 else if (at (tos, idx) == '\n'
759 && at (tos, idx + 1) == 'o'
760 && isspace ((unsigned char) at (tos, idx + 2)))
762 if (!on)
764 cattext (&out, "\n@itemize @bullet\n");
765 on = 1;
768 cattext (&out, "\n@item\n");
769 idx += 3;
771 else
773 catchar (&out, at (tos, idx));
774 if (on && at (tos, idx) == '\n'
775 && at (tos, idx + 1) == '\n'
776 && at (tos, idx + 2) != 'o')
778 cattext (&out, "@end itemize");
779 on = 0;
781 idx++;
785 if (on)
787 cattext (&out, "@end itemize\n");
790 delete_string (tos);
791 *tos = out;
792 pc++;
795 /* Turn <<foo>> into @code{foo} in place at TOS*/
797 static void
798 do_fancy_stuff ()
800 unsigned int idx = 0;
801 string_type out;
802 init_string (&out);
803 while (at (tos, idx))
805 if (at (tos, idx) == '<'
806 && at (tos, idx + 1) == '<'
807 && !isspace ((unsigned char) at (tos, idx + 2)))
809 /* This qualifies as a << startup. */
810 idx += 2;
811 cattext (&out, "@code{");
812 while (at (tos, idx)
813 && at (tos, idx) != '>' )
815 catchar (&out, at (tos, idx));
816 idx++;
819 cattext (&out, "}");
820 idx += 2;
822 else
824 catchar (&out, at (tos, idx));
825 idx++;
828 delete_string (tos);
829 *tos = out;
830 pc++;
834 /* A command is all upper case,and alone on a line. */
836 static int
837 iscommand (ptr, idx)
838 string_type *ptr;
839 unsigned int idx;
841 unsigned int len = 0;
842 while (at (ptr, idx))
844 if (isupper ((unsigned char) at (ptr, idx))
845 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
847 len++;
848 idx++;
850 else if (at (ptr, idx) == '\n')
852 if (len > 3)
853 return 1;
854 return 0;
856 else
857 return 0;
859 return 0;
862 static int
863 copy_past_newline (ptr, idx, dst)
864 string_type *ptr;
865 unsigned int idx;
866 string_type *dst;
868 int column = 0;
870 while (at (ptr, idx) && at (ptr, idx) != '\n')
872 if (at (ptr, idx) == '\t')
874 /* Expand tabs. Neither makeinfo nor TeX can cope well with
875 them. */
877 catchar (dst, ' ');
878 while (++column & 7);
880 else
882 catchar (dst, at (ptr, idx));
883 column++;
885 idx++;
888 catchar (dst, at (ptr, idx));
889 idx++;
890 return idx;
894 static void
895 icopy_past_newline ()
897 tos++;
898 check_range ();
899 init_string (tos);
900 idx = copy_past_newline (ptr, idx, tos);
901 pc++;
904 /* indent
905 Take the string at the top of the stack, do some prettying. */
907 static void
908 kill_bogus_lines ()
910 int sl;
912 int idx = 0;
913 int c;
914 int dot = 0;
916 string_type out;
917 init_string (&out);
918 /* Drop leading nl. */
919 while (at (tos, idx) == '\n')
921 idx++;
923 c = idx;
925 /* If the first char is a '.' prepend a newline so that it is
926 recognized properly later. */
927 if (at (tos, idx) == '.')
928 catchar (&out, '\n');
930 /* Find the last char. */
931 while (at (tos, idx))
933 idx++;
936 /* Find the last non white before the nl. */
937 idx--;
939 while (idx && isspace ((unsigned char) at (tos, idx)))
940 idx--;
941 idx++;
943 /* Copy buffer upto last char, but blank lines before and after
944 dots don't count. */
945 sl = 1;
947 while (c < idx)
949 if (at (tos, c) == '\n'
950 && at (tos, c + 1) == '\n'
951 && at (tos, c + 2) == '.')
953 /* Ignore two newlines before a dot. */
954 c++;
956 else if (at (tos, c) == '.' && sl)
958 /* remember that this line started with a dot. */
959 dot = 2;
961 else if (at (tos, c) == '\n'
962 && at (tos, c + 1) == '\n'
963 && dot)
965 c++;
966 /* Ignore two newlines when last line was dot. */
969 catchar (&out, at (tos, c));
970 if (at (tos, c) == '\n')
972 sl = 1;
974 if (dot == 2)
975 dot = 1;
976 else
977 dot = 0;
979 else
980 sl = 0;
982 c++;
986 /* Append nl. */
987 catchar (&out, '\n');
988 pc++;
989 delete_string (tos);
990 *tos = out;
994 static void
995 indent ()
997 string_type out;
998 int tab = 0;
999 int idx = 0;
1000 int ol = 0;
1001 init_string (&out);
1002 while (at (tos, idx))
1004 switch (at (tos, idx))
1006 case '\n':
1007 cattext (&out, "\n");
1008 idx++;
1009 if (tab && at (tos, idx))
1011 cattext (&out, " ");
1013 ol = 0;
1014 break;
1015 case '(':
1016 tab++;
1017 if (ol == 0)
1018 cattext (&out, " ");
1019 idx++;
1020 cattext (&out, "(");
1021 ol = 1;
1022 break;
1023 case ')':
1024 tab--;
1025 cattext (&out, ")");
1026 idx++;
1027 ol = 1;
1029 break;
1030 default:
1031 catchar (&out, at (tos, idx));
1032 ol = 1;
1034 idx++;
1035 break;
1039 pc++;
1040 delete_string (tos);
1041 *tos = out;
1045 static void
1046 get_stuff_in_command ()
1048 tos++;
1049 check_range ();
1050 init_string (tos);
1052 while (at (ptr, idx))
1054 if (iscommand (ptr, idx))
1055 break;
1056 idx = copy_past_newline (ptr, idx, tos);
1058 pc++;
1061 static void
1062 swap ()
1064 string_type t;
1066 t = tos[0];
1067 tos[0] = tos[-1];
1068 tos[-1] = t;
1069 pc++;
1072 static void
1073 other_dup ()
1075 tos++;
1076 check_range ();
1077 init_string (tos);
1078 catstr (tos, tos - 1);
1079 pc++;
1082 static void
1083 drop ()
1085 tos--;
1086 check_range ();
1087 delete_string (tos + 1);
1088 pc++;
1091 static void
1092 idrop ()
1094 isp--;
1095 icheck_range ();
1096 pc++;
1099 static void
1100 icatstr ()
1102 tos--;
1103 check_range ();
1104 catstr (tos, tos + 1);
1105 delete_string (tos + 1);
1106 pc++;
1109 static void
1110 skip_past_newline ()
1112 idx = skip_past_newline_1 (ptr, idx);
1113 pc++;
1116 static void
1117 internalmode ()
1119 internal_mode = *(isp);
1120 isp--;
1121 icheck_range ();
1122 pc++;
1125 static void
1126 maybecatstr ()
1128 if (internal_wanted == internal_mode)
1130 catstr (tos - 1, tos);
1132 delete_string (tos);
1133 tos--;
1134 check_range ();
1135 pc++;
1138 char *
1139 nextword (string, word)
1140 char *string;
1141 char **word;
1143 char *word_start;
1144 int idx;
1145 char *dst;
1146 char *src;
1148 int length = 0;
1150 while (isspace ((unsigned char) *string) || *string == '-')
1152 if (*string == '-')
1154 while (*string && *string != '\n')
1155 string++;
1158 else
1160 string++;
1163 if (!*string)
1165 *word = NULL;
1166 return NULL;
1169 word_start = string;
1170 if (*string == '"')
1174 string++;
1175 length++;
1176 if (*string == '\\')
1178 string += 2;
1179 length += 2;
1182 while (*string != '"');
1184 else
1186 while (!isspace ((unsigned char) *string))
1188 string++;
1189 length++;
1194 *word = (char *) malloc (length + 1);
1196 dst = *word;
1197 src = word_start;
1199 for (idx = 0; idx < length; idx++)
1201 if (src[idx] == '\\')
1202 switch (src[idx + 1])
1204 case 'n':
1205 *dst++ = '\n';
1206 idx++;
1207 break;
1208 case '"':
1209 case '\\':
1210 *dst++ = src[idx + 1];
1211 idx++;
1212 break;
1213 default:
1214 *dst++ = '\\';
1215 break;
1217 else
1218 *dst++ = src[idx];
1220 *dst++ = 0;
1222 if (*string)
1223 return string + 1;
1224 else
1225 return NULL;
1228 dict_type *
1229 lookup_word (word)
1230 char *word;
1232 dict_type *ptr = root;
1233 while (ptr)
1235 if (strcmp (ptr->word, word) == 0)
1236 return ptr;
1237 ptr = ptr->next;
1239 if (warning)
1240 fprintf (stderr, "Can't find %s\n", word);
1241 return NULL;
1244 static void
1245 free_words (void)
1247 dict_type *ptr = root;
1249 while (ptr)
1251 dict_type *next;
1253 free (ptr->word);
1254 if (ptr->code)
1256 int i;
1257 for (i = 0; i < ptr->code_end - 1; i ++)
1258 if (ptr->code[i] == push_text
1259 && ptr->code[i + 1])
1261 free ((char *) ptr->code[i + 1] - 1);
1262 ++ i;
1264 free (ptr->code);
1266 next = ptr->next;
1267 free (ptr);
1268 ptr = next;
1272 static void
1273 perform (void)
1275 tos = stack;
1277 while (at (ptr, idx))
1279 /* It's worth looking through the command list. */
1280 if (iscommand (ptr, idx))
1282 char *next;
1283 dict_type *word;
1285 (void) nextword (addr (ptr, idx), &next);
1287 word = lookup_word (next);
1289 if (word)
1291 exec (word);
1293 else
1295 if (warning)
1296 fprintf (stderr, "warning, %s is not recognised\n", next);
1297 idx = skip_past_newline_1 (ptr, idx);
1299 free (next);
1301 else
1302 idx = skip_past_newline_1 (ptr, idx);
1306 dict_type *
1307 newentry (word)
1308 char *word;
1310 dict_type *new_d = (dict_type *) malloc (sizeof (dict_type));
1311 new_d->word = word;
1312 new_d->next = root;
1313 root = new_d;
1314 new_d->code = (stinst_type *) malloc (sizeof (stinst_type));
1315 new_d->code_length = 1;
1316 new_d->code_end = 0;
1317 return new_d;
1320 unsigned int
1321 add_to_definition (entry, word)
1322 dict_type *entry;
1323 stinst_type word;
1325 if (entry->code_end == entry->code_length)
1327 entry->code_length += 2;
1328 entry->code =
1329 (stinst_type *) realloc ((char *) (entry->code),
1330 entry->code_length * sizeof (stinst_type));
1332 entry->code[entry->code_end] = word;
1334 return entry->code_end++;
1337 void
1338 add_intrinsic (name, func)
1339 char *name;
1340 void (*func) ();
1342 dict_type *new_d = newentry (strdup (name));
1343 add_to_definition (new_d, func);
1344 add_to_definition (new_d, 0);
1347 void
1348 compile (string)
1349 char *string;
1351 /* Add words to the dictionary. */
1352 char *word;
1354 string = nextword (string, &word);
1355 while (string && *string && word[0])
1357 if (word[0] == ':')
1359 dict_type *ptr;
1361 /* Compile a word and add to dictionary. */
1362 free (word);
1363 string = nextword (string, &word);
1364 if (!string)
1365 continue;
1366 ptr = newentry (word);
1367 string = nextword (string, &word);
1368 if (!string)
1370 free (ptr->code);
1371 free (ptr);
1372 continue;
1375 while (word[0] != ';')
1377 switch (word[0])
1379 case '"':
1380 /* got a string, embed magic push string
1381 function */
1382 add_to_definition (ptr, push_text);
1383 add_to_definition (ptr, (stinst_type) (word + 1));
1384 break;
1385 case '0':
1386 case '1':
1387 case '2':
1388 case '3':
1389 case '4':
1390 case '5':
1391 case '6':
1392 case '7':
1393 case '8':
1394 case '9':
1395 /* Got a number, embedd the magic push number
1396 function */
1397 add_to_definition (ptr, push_number);
1398 add_to_definition (ptr, (stinst_type) atol (word));
1399 free (word);
1400 break;
1401 default:
1402 add_to_definition (ptr, call);
1403 add_to_definition (ptr, (stinst_type) lookup_word (word));
1404 free (word);
1407 string = nextword (string, &word);
1409 add_to_definition (ptr, 0);
1410 free (word);
1411 string = nextword (string, &word);
1413 else
1415 fprintf (stderr, "syntax error at %s\n", string - 1);
1418 free (word);
1421 static void
1422 bang ()
1424 *(long *) ((isp[0])) = isp[-1];
1425 isp -= 2;
1426 icheck_range ();
1427 pc++;
1430 static void
1431 atsign ()
1433 isp[0] = *(long *) (isp[0]);
1434 pc++;
1437 static void
1438 hello ()
1440 printf ("hello\n");
1441 pc++;
1444 static void
1445 stdout_ ()
1447 isp++;
1448 icheck_range ();
1449 *isp = 1;
1450 pc++;
1453 static void
1454 stderr_ ()
1456 isp++;
1457 icheck_range ();
1458 *isp = 2;
1459 pc++;
1462 static void
1463 print ()
1465 if (*isp == 1)
1466 write_buffer (tos, stdout);
1467 else if (*isp == 2)
1468 write_buffer (tos, stderr);
1469 else
1470 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1471 isp--;
1472 tos--;
1473 icheck_range ();
1474 check_range ();
1475 pc++;
1478 static void
1479 read_in (str, file)
1480 string_type *str;
1481 FILE *file;
1483 char buff[10000];
1484 unsigned int r;
1487 r = fread (buff, 1, sizeof (buff), file);
1488 catbuf (str, buff, r);
1490 while (r);
1491 buff[0] = 0;
1493 catbuf (str, buff, 1);
1496 static void
1497 usage ()
1499 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1500 exit (33);
1503 /* There is no reliable way to declare exit. Sometimes it returns
1504 int, and sometimes it returns void. Sometimes it changes between
1505 OS releases. Trying to get it declared correctly in the hosts file
1506 is a pointless waste of time. */
1508 static void
1509 chew_exit ()
1511 exit (0);
1515 main (ac, av)
1516 int ac;
1517 char *av[];
1519 unsigned int i;
1520 string_type buffer;
1521 string_type pptr;
1523 init_string (&buffer);
1524 init_string (&pptr);
1525 init_string (stack + 0);
1526 tos = stack + 1;
1527 ptr = &pptr;
1529 add_intrinsic ("push_text", push_text);
1530 add_intrinsic ("!", bang);
1531 add_intrinsic ("@", atsign);
1532 add_intrinsic ("hello", hello);
1533 add_intrinsic ("stdout", stdout_);
1534 add_intrinsic ("stderr", stderr_);
1535 add_intrinsic ("print", print);
1536 add_intrinsic ("skip_past_newline", skip_past_newline);
1537 add_intrinsic ("catstr", icatstr);
1538 add_intrinsic ("copy_past_newline", icopy_past_newline);
1539 add_intrinsic ("dup", other_dup);
1540 add_intrinsic ("drop", drop);
1541 add_intrinsic ("idrop", idrop);
1542 add_intrinsic ("remchar", remchar);
1543 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1544 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1545 add_intrinsic ("bulletize", bulletize);
1546 add_intrinsic ("courierize", courierize);
1547 /* If the following line gives an error, exit() is not declared in the
1548 ../hosts/foo.h file for this host. Fix it there, not here! */
1549 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1550 add_intrinsic ("exit", chew_exit);
1551 add_intrinsic ("swap", swap);
1552 add_intrinsic ("outputdots", outputdots);
1553 add_intrinsic ("paramstuff", paramstuff);
1554 add_intrinsic ("maybecatstr", maybecatstr);
1555 add_intrinsic ("translatecomments", translatecomments);
1556 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1557 add_intrinsic ("indent", indent);
1558 add_intrinsic ("internalmode", internalmode);
1559 add_intrinsic ("print_stack_level", print_stack_level);
1560 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1562 /* Put a nl at the start. */
1563 catchar (&buffer, '\n');
1565 read_in (&buffer, stdin);
1566 remove_noncomments (&buffer, ptr);
1567 for (i = 1; i < (unsigned int) ac; i++)
1569 if (av[i][0] == '-')
1571 if (av[i][1] == 'f')
1573 string_type b;
1574 FILE *f;
1575 init_string (&b);
1577 f = fopen (av[i + 1], "r");
1578 if (!f)
1580 fprintf (stderr, "Can't open the input file %s\n",
1581 av[i + 1]);
1582 return 33;
1585 read_in (&b, f);
1586 compile (b.ptr);
1587 perform ();
1588 delete_string (&b);
1590 else if (av[i][1] == 'i')
1592 internal_wanted = 1;
1594 else if (av[i][1] == 'w')
1596 warning = 1;
1598 else
1599 usage ();
1602 write_buffer (stack + 0, stdout);
1603 free_words ();
1604 delete_string (&pptr);
1605 delete_string (&buffer);
1606 if (tos != stack)
1608 fprintf (stderr, "finishing with current stack level %ld\n",
1609 (long) (tos - stack));
1610 return 1;
1612 return 0;