Bug Summary

File:src/gnu/usr.bin/binutils-2.17/bfd/doc/chew.c
Warning:line 1285, column 18
Result of 'realloc' is converted to a pointer of type 'stinst_type', which is incompatible with sizeof operand type 'word_type'

Annotated Source Code

Press '?' to see keyboard shortcuts

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