1 /***************************************************************************
2 JSPICE3 adaptation of Spice3e2 - Copyright (c) Stephen R. Whiteley 1992
3 Copyright 1990 Regents of the University of California.  All rights reserved.
4 Authors: 1985 Wayne A. Christopher
5          1992 Stephen R. Whiteley
6 ****************************************************************************/
7 
8 /*
9  * Initial lexer.
10  */
11 
12 /***************************************************************************
13 To implement command completion under DOS, one must define TIOCSTI in
14 os_msdos.h, and add routines mygetc() and ioctl() which do the right
15 things, i.e., allow stuffing characters into the input buffer.  In DOS,
16 ^A and ^Z call the abort routine in interactive mode. ^D signals command
17 match printing and can be first on a line unlike in UNIX.  Beware that
18 some compilers supply an ioctl() routine which won't work here, if this
19 is the case, you may have to define ioctl to something else in os_msdos.h.
20 ****************************************************************************/
21 
22 #include "spice.h"
23 #include "cpdefs.h"
24 #include <errno.h>
25 
26 #include <sys/types.h>
27 
28 #ifdef HAVE_SGTTY_H
29 #include <sgtty.h>
30 #else
31 #ifdef HAVE_TERMIO_H
32 #include <termio.h>
33 #else
34 #ifdef HAVE_TERMIOS_H
35 #include <termios.h>
36 #endif
37 #endif
38 #endif
39 
40 #include "ftegraph.h"
41 
42 #ifdef __STDC__
43 static void prompt(void);
44 #else
45 static void prompt();
46 #endif
47 
48 FILE *cp_inp_cur = NULL;
49 int cp_event = 1;
50 bool cp_interactive = true;
51 bool cp_bqflag = false;
52 char *cp_promptstring = NULL;
53 char *cp_altprompt = NULL;
54 char cp_hash = '#';
55 
56 static int numeofs = 0;
57 
58 #define ESCAPE  '\033'
59 
60 /* Return a list of words, with backslash quoting and '' quoting done.
61  * Strings en(void) closed in "" or `` are made single words and returned,
62  * but with the "" or `` still present. For the \ and '' cases, the
63  * 8th bit is turned on (as in csh) to prevent them from being recogized,
64  * and stripped off once all processing is done. We also have to deal with
65  * command, filename, and keyword completion here.
66  * If string is non-NULL, then use it instead of the fp. Escape and EOF
67  * have no business being in the string.
68  */
69 
70 #define newword cw->wl_word = copy(buf); \
71         cw->wl_next = alloc(struct wordlist); \
72         cw->wl_next->wl_prev = cw; \
73         cw = cw->wl_next; \
74         bzero(buf, BSIZE_SP); \
75         i = 0;
76 
77 
78 wordlist *
cp_lexer(string)79 cp_lexer(string)
80 
81 char *string;
82 {
83     int c;
84     int i, j;
85     wordlist *wlist = NULL, *cw = NULL;
86     char buf[BSIZE_SP], linebuf[BSIZE_SP], d;
87 
88     if (cp_inp_cur == NULL)
89         cp_inp_cur = cp_in;
90 
91     if (!string && cp_interactive) {
92         cp_ccon(true);
93         prompt();
94     }
95 nloop:
96     i = 0;
97     j = 0;
98     bzero(linebuf, BSIZE_SP);
99     bzero(buf, BSIZE_SP);
100     wlist = cw = alloc(struct wordlist);
101     cw->wl_next = cw->wl_prev = NULL;
102     for (;;) {
103         if (string) {
104             c = *string++;
105             if (c == '\0')
106                 c = '\n';
107             if (c == ESCAPE)
108                 c = '[';
109         }
110         else
111             c = DevGetchar(cp_inp_cur);
112 gotchar:
113         if ((c != EOF) && (c != ESCAPE) && (c != 4)) /* SRW - 4 added */
114             linebuf[j++] = c;
115         if (c != EOF && c != 4) /* SRW - ditto */
116             numeofs = 0;
117         if (i == BSIZE_SP - 1) {
118             fprintf(cp_err, "Warning: word too long.\n");
119             c = ' ';
120         }
121         if (j == BSIZE_SP - 1) {
122             fprintf(cp_err, "Warning: line too long.\n");
123             if (cp_bqflag)
124                 c = EOF;
125             else
126                 c = '\n';
127         }
128         if (c != EOF)
129             c = strip(c);   /* Don't need to do this really. */
130 
131         /* "backslash" quoting */
132         if (c == '\\' && DIR_TERM != '\\' || c == '\026' /* ^V */ ) {
133             c = quote(string ? *string++ : DevGetchar(cp_inp_cur));
134             linebuf[j++] = strip(c);
135         }
136 
137         if ((c == '\n') && cp_bqflag)
138             c = ' ';
139         if ((c == EOF || c == 4) && cp_bqflag) /* SRW - 4 added */
140             c = '\n';
141         if ((c == cp_hash) && !cp_interactive && (j == 1)) {
142             if (string)
143                 return (NULL);
144             while (((c = DevGetchar(cp_inp_cur)) != '\n') &&
145                     (c != EOF));
146             goto nloop;
147         }
148         switch (c) {
149 
150     case ' ':
151     case '\t':
152             if (i > 0) {
153                 newword;
154             }
155             break;
156 
157     case '\n':
158             if (i) {
159                 buf[i] = '\0';
160                 cw->wl_word = copy(buf);
161             }
162             else if (cw->wl_prev) {
163                 cw->wl_prev->wl_next = NULL;
164                 tfree(cw);
165             }
166             else {
167                 cw->wl_word = NULL;
168             }
169             goto done;
170 
171     case '\'':
172             while (((c = (string ? *string++ :
173                     DevGetchar(cp_inp_cur))) != '\'')
174                     && (i < BSIZE_SP - 1)) {
175                 if ((c == '\n') || (c == EOF) || (c == ESCAPE))
176                     goto gotchar;
177                 else {
178                     buf[i++] = quote(c);
179                     linebuf[j++] = c;
180                 }
181             }
182             linebuf[j++] = '\'';
183             break;
184 
185     case '"':
186     case '`':
187             d = c;
188             buf[i++] = d;
189             while (((c = (string ? *string++ : DevGetchar(cp_inp_cur)))
190                     != d) && (i < BSIZE_SP - 2)) {
191                 if ((c == '\n') || (c == EOF) || (c == ESCAPE))
192                     goto gotchar;
193                 else if (c == '\\') {
194                     linebuf[j++] = c;
195                     c = (string ? *string++ :
196                             DevGetchar(cp_inp_cur));
197                     buf[i++] = quote(c);
198                     linebuf[j++] = c;
199                 }
200                 else {
201                     buf[i++] = c;
202                     linebuf[j++] = c;
203                 }
204             }
205             buf[i++] = d;
206             linebuf[j++] = d;
207             break;
208 
209     case EOF:
210     case 4: /* ^D */
211 
212             if (cp_interactive && !cp_nocc &&
213                     (string == NULL)) {
214 #ifdef notdef
215 /* ^D logout */
216                 if (j == 0) {
217                     if (cp_ignoreeof && (numeofs++
218                             < 23)) {
219                         fputs(
220                     "Use \"quit\" to quit.\n",
221                             stdout);
222                     }
223                     else {
224                         fputs("quit\n", stdout);
225                         cp_doquit();
226                     }
227                     goto done;
228                 }
229 #endif
230                 cp_ccom(wlist, buf, false);
231                 wl_free(wlist);
232                 (void) fputc('\r', cp_out);
233                 prompt();
234                 for (j = 0; linebuf[j]; j++)
235 #ifdef TIOCSTI
236                     /* SRW - below was cp_out, a bug */
237                     (void) ioctl(fileno(cp_in), TIOCSTI,
238                             linebuf + j);
239 #else
240                 fputc(linebuf[j], cp_out);    /* But you can't edit */
241 #endif
242                 goto nloop;
243             }
244             else {   /* EOF during a source */
245 
246                 if (cp_interactive) {
247                     fputs("quit\n", stdout);
248                     cp_doquit();
249                     goto done;
250                 }
251                 else
252                     return (NULL);
253             }
254     case ESCAPE:
255             if (cp_interactive && !cp_nocc) {
256 
257                 fputs("\b\b  \b\b\r", cp_out);
258                 prompt();
259                 for (j = 0; linebuf[j]; j++)
260 #ifdef TIOCSTI
261                 /* SRW - below was cp_out, a bug */
262                 (void) ioctl(fileno(cp_in), TIOCSTI,
263                         linebuf + j);
264 #else
265                 fputc(linebuf[j], cp_out);    /* But you can't edit */
266 #endif
267                 cp_ccom(wlist, buf, true);
268                 wl_free(wlist);
269                 goto nloop;
270             } /* Else fall through */
271 
272     default:
273             /* We have to remember the special cases $<, $&, $#&, $?& */
274             if ((cp_chars[c] & CPC_BRL) && (i > 0)) {
275                 switch (c) {
276 
277                     case '<':
278                         if (buf[i-1] == '$')
279                             break;
280                         { newword; }
281                         break;
282 
283                     case '&':
284                         if (buf[i-1] == '$')
285                             break;
286                         if (i > 1 && (buf[i-1] == '#' || buf[i-1] == '?') &&
287                                 buf[i-2] == '$')
288                             break;
289                         { newword; }
290                         break;
291 
292                     default:
293                         { newword; }
294                 }
295             }
296 
297             buf[i++] = c;
298 
299             /* have to also catch <=, >=, and <> */
300 
301             if (cp_chars[c] & CPC_BRR) {
302                 switch (c) {
303 
304                     case '<':
305                         if (i > 1 && buf[i-2] == '$')
306                             break;
307 
308                     case '>':
309                         d = c;
310                         if (string) {
311                             c = *string++;
312                             if (c == '\0')
313                                 c = '\n';
314                             if (c == ESCAPE)
315                                 c = '[';
316                         }
317                         else
318                             c = DevGetchar(cp_inp_cur);
319 
320                         if (c == '=' || (d == '<' && c == '>')) {
321                             buf[i++] = c;
322                             linebuf[j++] = c;
323                             { newword; }
324                             break;
325                         }
326                         { newword; }
327                         goto gotchar;
328 
329                     case '&':
330                         if (i > 1 && buf[i-2] == '$')
331                             break;
332                         if (i > 2 && (buf[i-2] == '#' || buf[i-2] == '?') &&
333                                 buf[i-3] == '$')
334                             break;
335                         { newword; }
336                         break;
337 
338                     default:
339                         { newword; }
340                 }
341             }
342         }
343     }
344 done:
345     return (wlist);
346 }
347 
348 
349 static void
prompt()350 prompt()
351 {
352     char *s;
353 
354     if (cp_interactive == false)
355         return;
356     if (cp_promptstring == NULL)
357         s = "-> ";
358     else
359         s = cp_promptstring;
360     if (cp_altprompt)
361         s = cp_altprompt;
362 
363     while (*s) {
364         switch (strip(*s)) {
365             case '!':
366                 fprintf(cp_out, "%d", cp_event);
367                 break;
368             case '\\':
369                 if (*(s + 1))
370                     (void) putc(strip(*++s), cp_out);
371 
372             /* SRW  -p prints cwd */
373             case '-':
374                 if (*(s+1) == 'p') {
375                     char *c, *getcwd();
376                     (void) fprintf(cp_out,"%s",c = getcwd(NULL,128));
377                     tfree(c);
378                     s++;
379                     break;
380                 }
381             default:
382                 (void) putc(strip(*s), cp_out);
383         }
384         s++;
385     }
386     (void) fflush(cp_out);
387     return;
388 }
389