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