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