]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - bfd/doc/chew.c
2000-09-08 Kazu Hirata <kazu@hxi.com>
[thirdparty/binutils-gdb.git] / bfd / doc / chew.c
1 /* chew
2 Copyright (C) 1990, 91, 92, 93, 94, 95, 96, 1998, 2000
3 Free Software Foundation, Inc.
4 Contributed by steve chamberlain @cygnus
5
6 This file is part of BFD, the Binary File Descriptor library.
7
8 This program is free software; you can redistribute it and/or modify
9 it under the terms of the GNU General Public License as published by
10 the Free Software Foundation; either version 2 of the License, or
11 (at your option) any later version.
12
13 This program is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */
21
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
25
26 sac
27
28 Basically, this is a sort of string forth, maybe we should call it
29 struth?
30
31 You define new words thus:
32 : <newword> <oldwords> ;
33
34 */
35
36 /* Primitives provided by the program:
37
38 Two stacks are provided, a string stack and an integer stack.
39
40 Internal state variables:
41 internal_wanted - indicates whether `-i' was passed
42 internal_mode - user-settable
43
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
79
80 A command must be all upper-case, and alone on a line.
81
82 Foo. */
83
84 #include <ansidecl.h>
85 #include "sysdep.h"
86 #include <assert.h>
87 #include <stdio.h>
88 #include <ctype.h>
89
90 #define DEF_SIZE 5000
91 #define STACK 50
92
93 int internal_wanted;
94 int internal_mode;
95
96 int warning;
97
98 /* Here is a string type ... */
99
100 typedef struct buffer
101 {
102 char *ptr;
103 unsigned long write_idx;
104 unsigned long size;
105 } string_type;
106
107 #ifdef __STDC__
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 *);
120 #endif
121
122 static void
123 init_string_with_size (buffer, size)
124 string_type *buffer;
125 unsigned int size;
126 {
127 buffer->write_idx = 0;
128 buffer->size = size;
129 buffer->ptr = malloc (size);
130 }
131
132 static void
133 init_string (buffer)
134 string_type *buffer;
135 {
136 init_string_with_size (buffer, DEF_SIZE);
137 }
138
139 static int
140 find (str, what)
141 string_type *str;
142 char *what;
143 {
144 unsigned int i;
145 char *p;
146 p = what;
147 for (i = 0; i < str->write_idx && *p; i++)
148 {
149 if (*p == str->ptr[i])
150 p++;
151 else
152 p = what;
153 }
154 return (*p == 0);
155 }
156
157 static void
158 write_buffer (buffer, f)
159 string_type *buffer;
160 FILE *f;
161 {
162 fwrite (buffer->ptr, buffer->write_idx, 1, f);
163 }
164
165 static void
166 delete_string (buffer)
167 string_type *buffer;
168 {
169 free (buffer->ptr);
170 }
171
172 static char *
173 addr (buffer, idx)
174 string_type *buffer;
175 unsigned int idx;
176 {
177 return buffer->ptr + idx;
178 }
179
180 static char
181 at (buffer, pos)
182 string_type *buffer;
183 unsigned int pos;
184 {
185 if (pos >= buffer->write_idx)
186 return 0;
187 return buffer->ptr[pos];
188 }
189
190 static void
191 catchar (buffer, ch)
192 string_type *buffer;
193 int ch;
194 {
195 if (buffer->write_idx == buffer->size)
196 {
197 buffer->size *= 2;
198 buffer->ptr = realloc (buffer->ptr, buffer->size);
199 }
200
201 buffer->ptr[buffer->write_idx++] = ch;
202 }
203
204 static void
205 overwrite_string (dst, src)
206 string_type *dst;
207 string_type *src;
208 {
209 free (dst->ptr);
210 dst->size = src->size;
211 dst->write_idx = src->write_idx;
212 dst->ptr = src->ptr;
213 }
214
215 static void
216 catbuf (buffer, buf, len)
217 string_type *buffer;
218 char *buf;
219 unsigned int len;
220 {
221 if (buffer->write_idx + len >= buffer->size)
222 {
223 while (buffer->write_idx + len >= buffer->size)
224 buffer->size *= 2;
225 buffer->ptr = realloc (buffer->ptr, buffer->size);
226 }
227 memcpy (buffer->ptr + buffer->write_idx, buf, len);
228 buffer->write_idx += len;
229 }
230
231 static void
232 cattext (buffer, string)
233 string_type *buffer;
234 char *string;
235 {
236 catbuf (buffer, string, (unsigned int) strlen (string));
237 }
238
239 static void
240 catstr (dst, src)
241 string_type *dst;
242 string_type *src;
243 {
244 catbuf (dst, src->ptr, src->write_idx);
245 }
246
247 static unsigned int
248 skip_white_and_stars (src, idx)
249 string_type *src;
250 unsigned int idx;
251 {
252 char c;
253 while ((c = at (src, idx)),
254 isspace ((unsigned char) c)
255 || (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'))
260 idx++;
261 return idx;
262 }
263
264 /***********************************************************************/
265
266 string_type stack[STACK];
267 string_type *tos;
268
269 unsigned int idx = 0; /* Pos in input buffer */
270 string_type *ptr; /* and the buffer */
271 typedef void (*stinst_type)();
272 stinst_type *pc;
273 stinst_type sstack[STACK];
274 stinst_type *ssp = &sstack[0];
275 long istack[STACK];
276 long *isp = &istack[0];
277
278 typedef int *word_type;
279
280 struct dict_struct
281 {
282 char *word;
283 struct dict_struct *next;
284 stinst_type *code;
285 int code_length;
286 int code_end;
287 int var;
288 };
289
290 typedef struct dict_struct dict_type;
291
292 #define WORD(x) static void x()
293
294 static void
295 die (msg)
296 char *msg;
297 {
298 fprintf (stderr, "%s\n", msg);
299 exit (1);
300 }
301
302 static void
303 check_range ()
304 {
305 if (tos < stack)
306 die ("underflow in string stack");
307 if (tos >= stack + STACK)
308 die ("overflow in string stack");
309 }
310
311 static void
312 icheck_range ()
313 {
314 if (isp < istack)
315 die ("underflow in integer stack");
316 if (isp >= istack + STACK)
317 die ("overflow in integer stack");
318 }
319
320 #ifdef __STDC__
321 static void exec (dict_type *);
322 static void call (void);
323 static void remchar (void), strip_trailing_newlines (void), push_number (void);
324 static void push_text (void);
325 static void remove_noncomments (string_type *, string_type *);
326 static void print_stack_level (void);
327 static void paramstuff (void), translatecomments (void);
328 static void outputdots (void), courierize (void), bulletize (void);
329 static void do_fancy_stuff (void);
330 static int iscommand (string_type *, unsigned int);
331 static int copy_past_newline (string_type *, unsigned int, string_type *);
332 static void icopy_past_newline (void), kill_bogus_lines (void), indent (void);
333 static void get_stuff_in_command (void), swap (void), other_dup (void);
334 static void drop (void), idrop (void);
335 static void icatstr (void), skip_past_newline (void), internalmode (void);
336 static void maybecatstr (void);
337 static char *nextword (char *, char **);
338 dict_type *lookup_word (char *);
339 static void perform (void);
340 dict_type *newentry (char *);
341 unsigned int add_to_definition (dict_type *, stinst_type);
342 void add_intrinsic (char *, void (*)());
343 void add_var (char *);
344 void compile (char *);
345 static void bang (void);
346 static void atsign (void);
347 static void hello (void);
348 static void stdout_ (void);
349 static void stderr_ (void);
350 static void print (void);
351 static void read_in (string_type *, FILE *);
352 static void usage (void);
353 static void chew_exit (void);
354 #endif
355
356 static void
357 exec (word)
358 dict_type *word;
359 {
360 pc = word->code;
361 while (*pc)
362 (*pc) ();
363 }
364
365 WORD (call)
366 {
367 stinst_type *oldpc = pc;
368 dict_type *e;
369 e = (dict_type *) (pc[1]);
370 exec (e);
371 pc = oldpc + 2;
372 }
373
374 WORD (remchar)
375 {
376 if (tos->write_idx)
377 tos->write_idx--;
378 pc++;
379 }
380
381 static void
382 strip_trailing_newlines ()
383 {
384 while ((isspace ((unsigned char) at (tos, tos->write_idx - 1))
385 || at (tos, tos->write_idx - 1) == '\n')
386 && tos->write_idx > 0)
387 tos->write_idx--;
388 pc++;
389 }
390
391 WORD (push_number)
392 {
393 isp++;
394 icheck_range ();
395 pc++;
396 *isp = (long) (*pc);
397 pc++;
398 }
399
400 WORD (push_text)
401 {
402 tos++;
403 check_range ();
404 init_string (tos);
405 pc++;
406 cattext (tos, *((char **) pc));
407 pc++;
408 }
409
410 /* This function removes everything not inside comments starting on
411 the first char of the line from the string, also when copying
412 comments, removes blank space and leading *'s.
413 Blank lines are turned into one blank line. */
414
415 static void
416 remove_noncomments (src, dst)
417 string_type *src;
418 string_type *dst;
419 {
420 unsigned int idx = 0;
421
422 while (at (src, idx))
423 {
424 /* Now see if we have a comment at the start of the line. */
425 if (at (src, idx) == '\n'
426 && at (src, idx + 1) == '/'
427 && at (src, idx + 2) == '*')
428 {
429 idx += 3;
430
431 idx = skip_white_and_stars (src, idx);
432
433 /* Remove leading dot */
434 if (at (src, idx) == '.')
435 idx++;
436
437 /* Copy to the end of the line, or till the end of the
438 comment. */
439 while (at (src, idx))
440 {
441 if (at (src, idx) == '\n')
442 {
443 /* end of line, echo and scrape of leading blanks */
444 if (at (src, idx + 1) == '\n')
445 catchar (dst, '\n');
446 catchar (dst, '\n');
447 idx++;
448 idx = skip_white_and_stars (src, idx);
449 }
450 else if (at (src, idx) == '*' && at (src, idx + 1) == '/')
451 {
452 idx += 2;
453 cattext (dst, "\nENDDD\n");
454 break;
455 }
456 else
457 {
458 catchar (dst, at (src, idx));
459 idx++;
460 }
461 }
462 }
463 else
464 idx++;
465 }
466 }
467
468 static void
469 print_stack_level ()
470 {
471 fprintf (stderr, "current string stack depth = %d, ", tos - stack);
472 fprintf (stderr, "current integer stack depth = %d\n", isp - istack);
473 pc++;
474 }
475
476 /* turn:
477 foobar name(stuff);
478 into:
479 foobar
480 name PARAMS ((stuff));
481 and a blank line.
482 */
483
484 static void
485 paramstuff (void)
486 {
487 unsigned int openp;
488 unsigned int fname;
489 unsigned int idx;
490 string_type out;
491 init_string (&out);
492
493 /* Make sure that it's not already param'd or proto'd. */
494 if (find (tos, "PARAMS") || find (tos, "PROTO") || !find (tos, "("))
495 {
496 catstr (&out, tos);
497 }
498 else
499 {
500 /* Find the open paren. */
501 for (openp = 0; at (tos, openp) != '(' && at (tos, openp); openp++)
502 ;
503
504 fname = openp;
505 /* Step back to the fname. */
506 fname--;
507 while (fname && isspace ((unsigned char) at (tos, fname)))
508 fname--;
509 while (fname
510 && !isspace ((unsigned char) at (tos,fname))
511 && at (tos,fname) != '*')
512 fname--;
513
514 fname++;
515
516 for (idx = 0; idx < fname; idx++) /* Output type */
517 {
518 catchar (&out, at (tos, idx));
519 }
520
521 cattext (&out, "\n"); /* Insert a newline between type and fnname */
522
523 for (idx = fname; idx < openp; idx++) /* Output fnname */
524 {
525 catchar (&out, at (tos, idx));
526 }
527
528 cattext (&out, " PARAMS (");
529
530 while (at (tos, idx) && at (tos, idx) != ';')
531 {
532 catchar (&out, at (tos, idx));
533 idx++;
534 }
535 cattext (&out, ");\n\n");
536 }
537 overwrite_string (tos, &out);
538 pc++;
539
540 }
541
542 /* turn {*
543 and *} into comments */
544
545 WORD (translatecomments)
546 {
547 unsigned int idx = 0;
548 string_type out;
549 init_string (&out);
550
551 while (at (tos, idx))
552 {
553 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
554 {
555 cattext (&out, "/*");
556 idx += 2;
557 }
558 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
559 {
560 cattext (&out, "*/");
561 idx += 2;
562 }
563 else
564 {
565 catchar (&out, at (tos, idx));
566 idx++;
567 }
568 }
569
570 overwrite_string (tos, &out);
571
572 pc++;
573 }
574
575 #if 0
576
577 /* This is not currently used. */
578
579 /* turn everything not starting with a . into a comment */
580
581 WORD (manglecomments)
582 {
583 unsigned int idx = 0;
584 string_type out;
585 init_string (&out);
586
587 while (at (tos, idx))
588 {
589 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '*')
590 {
591 cattext (&out, " /*");
592 idx += 2;
593 }
594 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
595 {
596 cattext (&out, "*/");
597 idx += 2;
598 }
599 else
600 {
601 catchar (&out, at (tos, idx));
602 idx++;
603 }
604 }
605
606 overwrite_string (tos, &out);
607
608 pc++;
609 }
610
611 #endif
612
613 /* Mod tos so that only lines with leading dots remain */
614 static void
615 outputdots (void)
616 {
617 unsigned int idx = 0;
618 string_type out;
619 init_string (&out);
620
621 while (at (tos, idx))
622 {
623 if (at (tos, idx) == '\n' && at (tos, idx + 1) == '.')
624 {
625 char c;
626 idx += 2;
627
628 while ((c = at (tos, idx)) && c != '\n')
629 {
630 if (c == '{' && at (tos, idx + 1) == '*')
631 {
632 cattext (&out, "/*");
633 idx += 2;
634 }
635 else if (c == '*' && at (tos, idx + 1) == '}')
636 {
637 cattext (&out, "*/");
638 idx += 2;
639 }
640 else
641 {
642 catchar (&out, c);
643 idx++;
644 }
645 }
646 catchar (&out, '\n');
647 }
648 else
649 {
650 idx++;
651 }
652 }
653
654 overwrite_string (tos, &out);
655 pc++;
656 }
657
658 /* Find lines starting with . and | and put example around them on tos */
659 WORD (courierize)
660 {
661 string_type out;
662 unsigned int idx = 0;
663 int command = 0;
664
665 init_string (&out);
666
667 while (at (tos, idx))
668 {
669 if (at (tos, idx) == '\n'
670 && (at (tos, idx +1 ) == '.'
671 || at (tos, idx + 1) == '|'))
672 {
673 cattext (&out, "\n@example\n");
674 do
675 {
676 idx += 2;
677
678 while (at (tos, idx) && at (tos, idx) != '\n')
679 {
680 if (at (tos, idx) == '{' && at (tos, idx + 1) == '*')
681 {
682 cattext (&out, "/*");
683 idx += 2;
684 }
685 else if (at (tos, idx) == '*' && at (tos, idx + 1) == '}')
686 {
687 cattext (&out, "*/");
688 idx += 2;
689 }
690 else if (at (tos, idx) == '{' && !command)
691 {
692 cattext (&out, "@{");
693 idx++;
694 }
695 else if (at (tos, idx) == '}' && !command)
696 {
697 cattext (&out, "@}");
698 idx++;
699 }
700 else
701 {
702 if (at (tos, idx) == '@')
703 command = 1;
704 else if (isspace ((unsigned char) at (tos, idx))
705 || at (tos, idx) == '}')
706 command = 0;
707 catchar (&out, at (tos, idx));
708 idx++;
709 }
710
711 }
712 catchar (&out, '\n');
713 }
714 while (at (tos, idx) == '\n'
715 && ((at (tos, idx + 1) == '.')
716 || (at (tos, idx + 1) == '|')))
717 ;
718 cattext (&out, "@end example");
719 }
720 else
721 {
722 catchar (&out, at (tos, idx));
723 idx++;
724 }
725 }
726
727 overwrite_string (tos, &out);
728 pc++;
729 }
730
731 /* Finds any lines starting with "o ", if there are any, then turns
732 on @itemize @bullet, and @items each of them. Then ends with @end
733 itemize, inplace at TOS*/
734
735 WORD (bulletize)
736 {
737 unsigned int idx = 0;
738 int on = 0;
739 string_type out;
740 init_string (&out);
741
742 while (at (tos, idx))
743 {
744 if (at (tos, idx) == '@'
745 && at (tos, idx + 1) == '*')
746 {
747 cattext (&out, "*");
748 idx += 2;
749 }
750 else if (at (tos, idx) == '\n'
751 && at (tos, idx + 1) == 'o'
752 && isspace ((unsigned char) at (tos, idx + 2)))
753 {
754 if (!on)
755 {
756 cattext (&out, "\n@itemize @bullet\n");
757 on = 1;
758
759 }
760 cattext (&out, "\n@item\n");
761 idx += 3;
762 }
763 else
764 {
765 catchar (&out, at (tos, idx));
766 if (on && at (tos, idx) == '\n'
767 && at (tos, idx + 1) == '\n'
768 && at (tos, idx + 2) != 'o')
769 {
770 cattext (&out, "@end itemize");
771 on = 0;
772 }
773 idx++;
774
775 }
776 }
777 if (on)
778 {
779 cattext (&out, "@end itemize\n");
780 }
781
782 delete_string (tos);
783 *tos = out;
784 pc++;
785 }
786
787 /* Turn <<foo>> into @code{foo} in place at TOS*/
788
789 WORD (do_fancy_stuff)
790 {
791 unsigned int idx = 0;
792 string_type out;
793 init_string (&out);
794 while (at (tos, idx))
795 {
796 if (at (tos, idx) == '<'
797 && at (tos, idx + 1) == '<'
798 && !isspace ((unsigned char) at (tos, idx + 2)))
799 {
800 /* This qualifies as a << startup. */
801 idx += 2;
802 cattext (&out, "@code{");
803 while (at (tos, idx)
804 && at (tos, idx) != '>' )
805 {
806 catchar (&out, at (tos, idx));
807 idx++;
808
809 }
810 cattext (&out, "}");
811 idx += 2;
812 }
813 else
814 {
815 catchar (&out, at (tos, idx));
816 idx++;
817 }
818 }
819 delete_string (tos);
820 *tos = out;
821 pc++;
822
823 }
824
825 /* A command is all upper case,and alone on a line. */
826
827 static int
828 iscommand (ptr, idx)
829 string_type *ptr;
830 unsigned int idx;
831 {
832 unsigned int len = 0;
833 while (at (ptr, idx))
834 {
835 if (isupper ((unsigned char) at (ptr, idx))
836 || at (ptr, idx) == ' ' || at (ptr, idx) == '_')
837 {
838 len++;
839 idx++;
840 }
841 else if (at (ptr, idx) == '\n')
842 {
843 if (len > 3)
844 return 1;
845 return 0;
846 }
847 else
848 return 0;
849 }
850 return 0;
851 }
852
853 static int
854 copy_past_newline (ptr, idx, dst)
855 string_type *ptr;
856 unsigned int idx;
857 string_type *dst;
858 {
859 int column = 0;
860
861 while (at (ptr, idx) && at (ptr, idx) != '\n')
862 {
863 if (at (ptr, idx) == '\t')
864 {
865 /* Expand tabs. Neither makeinfo nor TeX can cope well with
866 them. */
867 do
868 catchar (dst, ' ');
869 while (++column & 7);
870 }
871 else
872 {
873 catchar (dst, at (ptr, idx));
874 column++;
875 }
876 idx++;
877
878 }
879 catchar (dst, at (ptr, idx));
880 idx++;
881 return idx;
882
883 }
884
885 WORD (icopy_past_newline)
886 {
887 tos++;
888 check_range ();
889 init_string (tos);
890 idx = copy_past_newline (ptr, idx, tos);
891 pc++;
892 }
893
894 /* indent
895 Take the string at the top of the stack, do some prettying. */
896
897 WORD (kill_bogus_lines)
898 {
899 int sl;
900
901 int idx = 0;
902 int c;
903 int dot = 0;
904
905 string_type out;
906 init_string (&out);
907 /* Drop leading nl. */
908 while (at (tos, idx) == '\n')
909 {
910 idx++;
911 }
912 c = idx;
913
914 /* If the first char is a '.' prepend a newline so that it is
915 recognized properly later. */
916 if (at (tos, idx) == '.')
917 catchar (&out, '\n');
918
919 /* Find the last char. */
920 while (at (tos, idx))
921 {
922 idx++;
923 }
924
925 /* Find the last non white before the nl. */
926 idx--;
927
928 while (idx && isspace ((unsigned char) at (tos, idx)))
929 idx--;
930 idx++;
931
932 /* Copy buffer upto last char, but blank lines before and after
933 dots don't count. */
934 sl = 1;
935
936 while (c < idx)
937 {
938 if (at (tos, c) == '\n'
939 && at (tos, c + 1) == '\n'
940 && at (tos, c + 2) == '.')
941 {
942 /* Ignore two newlines before a dot. */
943 c++;
944 }
945 else if (at (tos, c) == '.' && sl)
946 {
947 /* remember that this line started with a dot. */
948 dot = 2;
949 }
950 else if (at (tos, c) == '\n'
951 && at (tos, c + 1) == '\n'
952 && dot)
953 {
954 c++;
955 /* Ignore two newlines when last line was dot. */
956 }
957
958 catchar (&out, at (tos, c));
959 if (at (tos, c) == '\n')
960 {
961 sl = 1;
962
963 if (dot == 2)
964 dot = 1;
965 else
966 dot = 0;
967 }
968 else
969 sl = 0;
970
971 c++;
972
973 }
974
975 /* Append nl. */
976 catchar (&out, '\n');
977 pc++;
978 delete_string (tos);
979 *tos = out;
980
981 }
982
983 WORD (indent)
984 {
985 string_type out;
986 int tab = 0;
987 int idx = 0;
988 int ol = 0;
989 init_string (&out);
990 while (at (tos, idx))
991 {
992 switch (at (tos, idx))
993 {
994 case '\n':
995 cattext (&out, "\n");
996 idx++;
997 if (tab && at (tos, idx))
998 {
999 cattext (&out, " ");
1000 }
1001 ol = 0;
1002 break;
1003 case '(':
1004 tab++;
1005 if (ol == 0)
1006 cattext (&out, " ");
1007 idx++;
1008 cattext (&out, "(");
1009 ol = 1;
1010 break;
1011 case ')':
1012 tab--;
1013 cattext (&out, ")");
1014 idx++;
1015 ol = 1;
1016
1017 break;
1018 default:
1019 catchar (&out, at (tos, idx));
1020 ol = 1;
1021
1022 idx++;
1023 break;
1024 }
1025 }
1026
1027 pc++;
1028 delete_string (tos);
1029 *tos = out;
1030
1031 }
1032
1033 WORD (get_stuff_in_command)
1034 {
1035 tos++;
1036 check_range ();
1037 init_string (tos);
1038
1039 while (at (ptr, idx))
1040 {
1041 if (iscommand (ptr, idx))
1042 break;
1043 idx = copy_past_newline (ptr, idx, tos);
1044 }
1045 pc++;
1046 }
1047
1048 WORD (swap)
1049 {
1050 string_type t;
1051
1052 t = tos[0];
1053 tos[0] = tos[-1];
1054 tos[-1] = t;
1055 pc++;
1056 }
1057
1058 WORD (other_dup)
1059 {
1060 tos++;
1061 check_range ();
1062 init_string (tos);
1063 catstr (tos, tos - 1);
1064 pc++;
1065 }
1066
1067 WORD (drop)
1068 {
1069 tos--;
1070 check_range ();
1071 pc++;
1072 }
1073
1074 WORD (idrop)
1075 {
1076 isp--;
1077 icheck_range ();
1078 pc++;
1079 }
1080
1081 WORD (icatstr)
1082 {
1083 tos--;
1084 check_range ();
1085 catstr (tos, tos + 1);
1086 delete_string (tos + 1);
1087 pc++;
1088 }
1089
1090 WORD (skip_past_newline)
1091 {
1092 while (at (ptr, idx)
1093 && at (ptr, idx) != '\n')
1094 idx++;
1095 idx++;
1096 pc++;
1097 }
1098
1099 WORD (internalmode)
1100 {
1101 internal_mode = *(isp);
1102 isp--;
1103 icheck_range ();
1104 pc++;
1105 }
1106
1107 WORD (maybecatstr)
1108 {
1109 if (internal_wanted == internal_mode)
1110 {
1111 catstr (tos - 1, tos);
1112 }
1113 delete_string (tos);
1114 tos--;
1115 check_range ();
1116 pc++;
1117 }
1118
1119 char *
1120 nextword (string, word)
1121 char *string;
1122 char **word;
1123 {
1124 char *word_start;
1125 int idx;
1126 char *dst;
1127 char *src;
1128
1129 int length = 0;
1130
1131 while (isspace ((unsigned char) *string) || *string == '-')
1132 {
1133 if (*string == '-')
1134 {
1135 while (*string && *string != '\n')
1136 string++;
1137
1138 }
1139 else
1140 {
1141 string++;
1142 }
1143 }
1144 if (!*string)
1145 return 0;
1146
1147 word_start = string;
1148 if (*string == '"')
1149 {
1150 do
1151 {
1152 string++;
1153 length++;
1154 if (*string == '\\')
1155 {
1156 string += 2;
1157 length += 2;
1158 }
1159 }
1160 while (*string != '"');
1161 }
1162 else
1163 {
1164 while (!isspace ((unsigned char) *string))
1165 {
1166 string++;
1167 length++;
1168
1169 }
1170 }
1171
1172 *word = malloc (length + 1);
1173
1174 dst = *word;
1175 src = word_start;
1176
1177 for (idx = 0; idx < length; idx++)
1178 {
1179 if (src[idx] == '\\')
1180 switch (src[idx + 1])
1181 {
1182 case 'n':
1183 *dst++ = '\n';
1184 idx++;
1185 break;
1186 case '"':
1187 case '\\':
1188 *dst++ = src[idx + 1];
1189 idx++;
1190 break;
1191 default:
1192 *dst++ = '\\';
1193 break;
1194 }
1195 else
1196 *dst++ = src[idx];
1197 }
1198 *dst++ = 0;
1199
1200 if (*string)
1201 return string + 1;
1202 else
1203 return 0;
1204 }
1205
1206 dict_type *root;
1207
1208 dict_type *
1209 lookup_word (word)
1210 char *word;
1211 {
1212 dict_type *ptr = root;
1213 while (ptr)
1214 {
1215 if (strcmp (ptr->word, word) == 0)
1216 return ptr;
1217 ptr = ptr->next;
1218 }
1219 if (warning)
1220 fprintf (stderr, "Can't find %s\n", word);
1221 return 0;
1222 }
1223
1224 static void
1225 perform (void)
1226 {
1227 tos = stack;
1228
1229 while (at (ptr, idx))
1230 {
1231 /* It's worth looking through the command list. */
1232 if (iscommand (ptr, idx))
1233 {
1234 char *next;
1235 dict_type *word;
1236
1237 (void) nextword (addr (ptr, idx), &next);
1238
1239 word = lookup_word (next);
1240
1241 if (word)
1242 {
1243 exec (word);
1244 }
1245 else
1246 {
1247 if (warning)
1248 fprintf (stderr, "warning, %s is not recognised\n", next);
1249 skip_past_newline ();
1250 }
1251
1252 }
1253 else
1254 skip_past_newline ();
1255 }
1256 }
1257
1258 dict_type *
1259 newentry (word)
1260 char *word;
1261 {
1262 dict_type *new = (dict_type *) malloc (sizeof (dict_type));
1263 new->word = word;
1264 new->next = root;
1265 root = new;
1266 new->code = (stinst_type *) malloc (sizeof (stinst_type));
1267 new->code_length = 1;
1268 new->code_end = 0;
1269 return new;
1270 }
1271
1272 unsigned int
1273 add_to_definition (entry, word)
1274 dict_type *entry;
1275 stinst_type word;
1276 {
1277 if (entry->code_end == entry->code_length)
1278 {
1279 entry->code_length += 2;
1280 entry->code =
1281 (stinst_type *) realloc ((char *) (entry->code),
1282 entry->code_length * sizeof (word_type));
1283 }
1284 entry->code[entry->code_end] = word;
1285
1286 return entry->code_end++;
1287 }
1288
1289 void
1290 add_intrinsic (name, func)
1291 char *name;
1292 void (*func) ();
1293 {
1294 dict_type *new = newentry (name);
1295 add_to_definition (new, func);
1296 add_to_definition (new, 0);
1297 }
1298
1299 void
1300 add_var (name)
1301 char *name;
1302 {
1303 dict_type *new = newentry (name);
1304 add_to_definition (new, push_number);
1305 add_to_definition (new, (stinst_type) (&(new->var)));
1306 add_to_definition (new, 0);
1307 }
1308
1309 void
1310 compile (string)
1311 char *string;
1312 {
1313 /* Add words to the dictionary. */
1314 char *word;
1315 string = nextword (string, &word);
1316 while (string && *string && word[0])
1317 {
1318 if (strcmp (word, "var") == 0)
1319 {
1320 string = nextword (string, &word);
1321
1322 add_var (word);
1323 string = nextword (string, &word);
1324 }
1325 else if (word[0] == ':')
1326 {
1327 dict_type *ptr;
1328 /* Compile a word and add to dictionary. */
1329 string = nextword (string, &word);
1330
1331 ptr = newentry (word);
1332 string = nextword (string, &word);
1333 while (word[0] != ';')
1334 {
1335 switch (word[0])
1336 {
1337 case '"':
1338 /* got a string, embed magic push string
1339 function */
1340 add_to_definition (ptr, push_text);
1341 add_to_definition (ptr, (stinst_type) (word + 1));
1342 break;
1343 case '0':
1344 case '1':
1345 case '2':
1346 case '3':
1347 case '4':
1348 case '5':
1349 case '6':
1350 case '7':
1351 case '8':
1352 case '9':
1353 /* Got a number, embedd the magic push number
1354 function */
1355 add_to_definition (ptr, push_number);
1356 add_to_definition (ptr, (stinst_type) atol (word));
1357 break;
1358 default:
1359 add_to_definition (ptr, call);
1360 add_to_definition (ptr, (stinst_type) lookup_word (word));
1361 }
1362
1363 string = nextword (string, &word);
1364 }
1365 add_to_definition (ptr, 0);
1366 string = nextword (string, &word);
1367 }
1368 else
1369 {
1370 fprintf (stderr, "syntax error at %s\n", string - 1);
1371 }
1372 }
1373 }
1374
1375 static void
1376 bang (void)
1377 {
1378 *(long *) ((isp[0])) = isp[-1];
1379 isp -= 2;
1380 icheck_range ();
1381 pc++;
1382 }
1383
1384 WORD (atsign)
1385 {
1386 isp[0] = *(long *) (isp[0]);
1387 pc++;
1388 }
1389
1390 WORD (hello)
1391 {
1392 printf ("hello\n");
1393 pc++;
1394 }
1395
1396 WORD (stdout_)
1397 {
1398 isp++;
1399 icheck_range ();
1400 *isp = 1;
1401 pc++;
1402 }
1403
1404 WORD (stderr_)
1405 {
1406 isp++;
1407 icheck_range ();
1408 *isp = 2;
1409 pc++;
1410 }
1411
1412 WORD (print)
1413 {
1414 if (*isp == 1)
1415 write_buffer (tos, stdout);
1416 else if (*isp == 2)
1417 write_buffer (tos, stderr);
1418 else
1419 fprintf (stderr, "print: illegal print destination `%ld'\n", *isp);
1420 isp--;
1421 tos--;
1422 icheck_range ();
1423 check_range ();
1424 pc++;
1425 }
1426
1427 static void
1428 read_in (str, file)
1429 string_type *str;
1430 FILE *file;
1431 {
1432 char buff[10000];
1433 unsigned int r;
1434 do
1435 {
1436 r = fread (buff, 1, sizeof (buff), file);
1437 catbuf (str, buff, r);
1438 }
1439 while (r);
1440 buff[0] = 0;
1441
1442 catbuf (str, buff, 1);
1443 }
1444
1445 static void
1446 usage (void)
1447 {
1448 fprintf (stderr, "usage: -[d|i|g] <file >file\n");
1449 exit (33);
1450 }
1451
1452 /* There is no reliable way to declare exit. Sometimes it returns
1453 int, and sometimes it returns void. Sometimes it changes between
1454 OS releases. Trying to get it declared correctly in the hosts file
1455 is a pointless waste of time. */
1456
1457 static void
1458 chew_exit ()
1459 {
1460 exit (0);
1461 }
1462
1463 int
1464 main (ac, av)
1465 int ac;
1466 char *av[];
1467 {
1468 unsigned int i;
1469 string_type buffer;
1470 string_type pptr;
1471
1472 init_string (&buffer);
1473 init_string (&pptr);
1474 init_string (stack + 0);
1475 tos = stack + 1;
1476 ptr = &pptr;
1477
1478 add_intrinsic ("push_text", push_text);
1479 add_intrinsic ("!", bang);
1480 add_intrinsic ("@", atsign);
1481 add_intrinsic ("hello", hello);
1482 add_intrinsic ("stdout", stdout_);
1483 add_intrinsic ("stderr", stderr_);
1484 add_intrinsic ("print", print);
1485 add_intrinsic ("skip_past_newline", skip_past_newline);
1486 add_intrinsic ("catstr", icatstr);
1487 add_intrinsic ("copy_past_newline", icopy_past_newline);
1488 add_intrinsic ("dup", other_dup);
1489 add_intrinsic ("drop", drop);
1490 add_intrinsic ("idrop", idrop);
1491 add_intrinsic ("remchar", remchar);
1492 add_intrinsic ("get_stuff_in_command", get_stuff_in_command);
1493 add_intrinsic ("do_fancy_stuff", do_fancy_stuff);
1494 add_intrinsic ("bulletize", bulletize);
1495 add_intrinsic ("courierize", courierize);
1496 /* If the following line gives an error, exit() is not declared in the
1497 ../hosts/foo.h file for this host. Fix it there, not here! */
1498 /* No, don't fix it anywhere; see comment on chew_exit--Ian Taylor. */
1499 add_intrinsic ("exit", chew_exit);
1500 add_intrinsic ("swap", swap);
1501 add_intrinsic ("outputdots", outputdots);
1502 add_intrinsic ("paramstuff", paramstuff);
1503 add_intrinsic ("maybecatstr", maybecatstr);
1504 add_intrinsic ("translatecomments", translatecomments);
1505 add_intrinsic ("kill_bogus_lines", kill_bogus_lines);
1506 add_intrinsic ("indent", indent);
1507 add_intrinsic ("internalmode", internalmode);
1508 add_intrinsic ("print_stack_level", print_stack_level);
1509 add_intrinsic ("strip_trailing_newlines", strip_trailing_newlines);
1510
1511 /* Put a nl at the start. */
1512 catchar (&buffer, '\n');
1513
1514 read_in (&buffer, stdin);
1515 remove_noncomments (&buffer, ptr);
1516 for (i = 1; i < (unsigned int) ac; i++)
1517 {
1518 if (av[i][0] == '-')
1519 {
1520 if (av[i][1] == 'f')
1521 {
1522 string_type b;
1523 FILE *f;
1524 init_string (&b);
1525
1526 f = fopen (av[i + 1], "r");
1527 if (!f)
1528 {
1529 fprintf (stderr, "Can't open the input file %s\n",
1530 av[i + 1]);
1531 return 33;
1532 }
1533
1534 read_in (&b, f);
1535 compile (b.ptr);
1536 perform ();
1537 }
1538 else if (av[i][1] == 'i')
1539 {
1540 internal_wanted = 1;
1541 }
1542 else if (av[i][1] == 'w')
1543 {
1544 warning = 1;
1545 }
1546 else
1547 usage ();
1548 }
1549 }
1550 write_buffer (stack + 0, stdout);
1551 if (tos != stack)
1552 {
1553 fprintf (stderr, "finishing with current stack level %d\n",
1554 tos - stack);
1555 return 1;
1556 }
1557 return 0;
1558 }