OSDN Git Service

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