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