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