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