1 |
|
|
/* $OpenBSD: lex.c,v 1.25 2017/08/30 07:54:54 anton Exp $ */ |
2 |
|
|
/* $NetBSD: lex.c,v 1.9 1995/09/27 00:38:46 jtc Exp $ */ |
3 |
|
|
|
4 |
|
|
/*- |
5 |
|
|
* Copyright (c) 1980, 1991, 1993 |
6 |
|
|
* The Regents of the University of California. All rights reserved. |
7 |
|
|
* |
8 |
|
|
* Redistribution and use in source and binary forms, with or without |
9 |
|
|
* modification, are permitted provided that the following conditions |
10 |
|
|
* are met: |
11 |
|
|
* 1. Redistributions of source code must retain the above copyright |
12 |
|
|
* notice, this list of conditions and the following disclaimer. |
13 |
|
|
* 2. Redistributions in binary form must reproduce the above copyright |
14 |
|
|
* notice, this list of conditions and the following disclaimer in the |
15 |
|
|
* documentation and/or other materials provided with the distribution. |
16 |
|
|
* 3. Neither the name of the University nor the names of its contributors |
17 |
|
|
* may be used to endorse or promote products derived from this software |
18 |
|
|
* without specific prior written permission. |
19 |
|
|
* |
20 |
|
|
* THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
21 |
|
|
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
22 |
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
23 |
|
|
* ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
24 |
|
|
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
25 |
|
|
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
26 |
|
|
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
27 |
|
|
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
28 |
|
|
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
29 |
|
|
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
30 |
|
|
* SUCH DAMAGE. |
31 |
|
|
*/ |
32 |
|
|
|
33 |
|
|
#include <sys/types.h> |
34 |
|
|
#include <termios.h> |
35 |
|
|
#include <errno.h> |
36 |
|
|
#include <fcntl.h> |
37 |
|
|
#include <stdlib.h> |
38 |
|
|
#include <string.h> |
39 |
|
|
#include <unistd.h> |
40 |
|
|
#include <stdarg.h> |
41 |
|
|
|
42 |
|
|
#include "csh.h" |
43 |
|
|
#include "extern.h" |
44 |
|
|
|
45 |
|
|
/* |
46 |
|
|
* These lexical routines read input and form lists of words. |
47 |
|
|
* There is some involved processing here, because of the complications |
48 |
|
|
* of input buffering, and especially because of history substitution. |
49 |
|
|
*/ |
50 |
|
|
|
51 |
|
|
static Char *word(void); |
52 |
|
|
static int getC1(int); |
53 |
|
|
static void getdol(void); |
54 |
|
|
static void getexcl(int); |
55 |
|
|
static struct Hist |
56 |
|
|
*findev(Char *, bool); |
57 |
|
|
static void setexclp(Char *); |
58 |
|
|
static int bgetc(void); |
59 |
|
|
static void bfree(void); |
60 |
|
|
static struct wordent |
61 |
|
|
*gethent(int); |
62 |
|
|
static int matchs(Char *, Char *); |
63 |
|
|
static int getsel(int *, int *, int); |
64 |
|
|
static struct wordent |
65 |
|
|
*getsub(struct wordent *); |
66 |
|
|
static Char *subword(Char *, int, bool *); |
67 |
|
|
static struct wordent |
68 |
|
|
*dosub(int, struct wordent *, bool); |
69 |
|
|
|
70 |
|
|
/* |
71 |
|
|
* Peekc is a peek character for getC, peekread for readc. |
72 |
|
|
* There is a subtlety here in many places... history routines |
73 |
|
|
* will read ahead and then insert stuff into the input stream. |
74 |
|
|
* If they push back a character then they must push it behind |
75 |
|
|
* the text substituted by the history substitution. On the other |
76 |
|
|
* hand in several places we need 2 peek characters. To make this |
77 |
|
|
* all work, the history routines read with getC, and make use both |
78 |
|
|
* of ungetC and unreadc. The key observation is that the state |
79 |
|
|
* of getC at the call of a history reference is such that calls |
80 |
|
|
* to getC from the history routines will always yield calls of |
81 |
|
|
* readc, unless this peeking is involved. That is to say that during |
82 |
|
|
* getexcl the variables lap, exclp, and exclnxt are all zero. |
83 |
|
|
* |
84 |
|
|
* Getdol invokes history substitution, hence the extra peek, peekd, |
85 |
|
|
* which it can ungetD to be before history substitutions. |
86 |
|
|
*/ |
87 |
|
|
static Char peekc = 0, peekd = 0; |
88 |
|
|
static Char peekread = 0; |
89 |
|
|
|
90 |
|
|
/* (Tail of) current word from ! subst */ |
91 |
|
|
static Char *exclp = NULL; |
92 |
|
|
|
93 |
|
|
/* The rest of the ! subst words */ |
94 |
|
|
static struct wordent *exclnxt = NULL; |
95 |
|
|
|
96 |
|
|
/* Count of remaining words in ! subst */ |
97 |
|
|
static int exclc = 0; |
98 |
|
|
|
99 |
|
|
/* "Globp" for alias resubstitution */ |
100 |
|
|
Char *alvecp = NULL; |
101 |
|
|
int aret = F_SEEK; |
102 |
|
|
|
103 |
|
|
/* |
104 |
|
|
* Labuf implements a general buffer for lookahead during lexical operations. |
105 |
|
|
* Text which is to be placed in the input stream can be stuck here. |
106 |
|
|
* We stick parsed ahead $ constructs during initial input, |
107 |
|
|
* process id's from `$$', and modified variable values (from qualifiers |
108 |
|
|
* during expansion in sh.dol.c) here. |
109 |
|
|
*/ |
110 |
|
|
static Char labuf[BUFSIZ]; |
111 |
|
|
|
112 |
|
|
/* |
113 |
|
|
* Lex returns to its caller not only a wordlist (as a "var" parameter) |
114 |
|
|
* but also whether a history substitution occurred. This is used in |
115 |
|
|
* the main (process) routine to determine whether to echo, and also |
116 |
|
|
* when called by the alias routine to determine whether to keep the |
117 |
|
|
* argument list. |
118 |
|
|
*/ |
119 |
|
|
static bool hadhist = 0; |
120 |
|
|
|
121 |
|
|
/* |
122 |
|
|
* Avoid alias expansion recursion via \!# |
123 |
|
|
*/ |
124 |
|
|
int hleft; |
125 |
|
|
|
126 |
|
|
static Char getCtmp; |
127 |
|
|
|
128 |
|
|
#define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f)) |
129 |
|
|
#define ungetC(c) peekc = c |
130 |
|
|
#define ungetD(c) peekd = c |
131 |
|
|
|
132 |
|
|
int |
133 |
|
|
lex(struct wordent *hp) |
134 |
|
|
{ |
135 |
|
|
struct wordent *wdp; |
136 |
|
|
int c; |
137 |
|
|
|
138 |
|
|
btell(&lineloc); |
139 |
|
|
hp->next = hp->prev = hp; |
140 |
|
|
hp->word = STRNULL; |
141 |
|
|
hadhist = 0; |
142 |
|
|
do |
143 |
|
|
c = readc(0); |
144 |
|
|
while (c == ' ' || c == '\t'); |
145 |
|
|
if (c == HISTSUB && intty) |
146 |
|
|
/* ^lef^rit from tty is short !:s^lef^rit */ |
147 |
|
|
getexcl(c); |
148 |
|
|
else |
149 |
|
|
unreadc(c); |
150 |
|
|
wdp = hp; |
151 |
|
|
/* |
152 |
|
|
* The following loop is written so that the links needed by freelex will |
153 |
|
|
* be ready and rarin to go even if it is interrupted. |
154 |
|
|
*/ |
155 |
|
|
do { |
156 |
|
|
struct wordent *new; |
157 |
|
|
|
158 |
|
|
new = xmalloc((size_t) sizeof(*wdp)); |
159 |
|
|
new->word = 0; |
160 |
|
|
new->prev = wdp; |
161 |
|
|
new->next = hp; |
162 |
|
|
wdp->next = new; |
163 |
|
|
wdp = new; |
164 |
|
|
wdp->word = word(); |
165 |
|
|
} while (wdp->word[0] != '\n'); |
166 |
|
|
hp->prev = wdp; |
167 |
|
|
return (hadhist); |
168 |
|
|
} |
169 |
|
|
|
170 |
|
|
void |
171 |
|
|
prlex(FILE *fp, struct wordent *sp0) |
172 |
|
|
{ |
173 |
|
|
struct wordent *sp = sp0->next; |
174 |
|
|
|
175 |
|
|
for (;;) { |
176 |
|
|
(void) fprintf(fp, "%s", vis_str(sp->word)); |
177 |
|
|
sp = sp->next; |
178 |
|
|
if (sp == sp0) |
179 |
|
|
break; |
180 |
|
|
if (sp->word[0] != '\n') |
181 |
|
|
(void) fputc(' ', fp); |
182 |
|
|
} |
183 |
|
|
} |
184 |
|
|
|
185 |
|
|
void |
186 |
|
|
copylex(struct wordent *hp, struct wordent *fp) |
187 |
|
|
{ |
188 |
|
|
struct wordent *wdp; |
189 |
|
|
|
190 |
|
|
wdp = hp; |
191 |
|
|
fp = fp->next; |
192 |
|
|
do { |
193 |
|
|
struct wordent *new; |
194 |
|
|
|
195 |
|
|
new = xmalloc((size_t) sizeof(*wdp)); |
196 |
|
|
new->prev = wdp; |
197 |
|
|
new->next = hp; |
198 |
|
|
wdp->next = new; |
199 |
|
|
wdp = new; |
200 |
|
|
wdp->word = Strsave(fp->word); |
201 |
|
|
fp = fp->next; |
202 |
|
|
} while (wdp->word[0] != '\n'); |
203 |
|
|
hp->prev = wdp; |
204 |
|
|
} |
205 |
|
|
|
206 |
|
|
void |
207 |
|
|
freelex(struct wordent *vp) |
208 |
|
|
{ |
209 |
|
|
struct wordent *fp; |
210 |
|
|
|
211 |
|
|
while (vp->next != vp) { |
212 |
|
|
fp = vp->next; |
213 |
|
|
vp->next = fp->next; |
214 |
|
|
free(fp->word); |
215 |
|
|
free(fp); |
216 |
|
|
} |
217 |
|
|
vp->prev = vp; |
218 |
|
|
} |
219 |
|
|
|
220 |
|
|
static Char * |
221 |
|
|
word(void) |
222 |
|
|
{ |
223 |
|
|
Char c, c1; |
224 |
|
|
Char *wp; |
225 |
|
|
Char wbuf[BUFSIZ]; |
226 |
|
|
bool dolflg; |
227 |
|
|
int i; |
228 |
|
|
|
229 |
|
|
wp = wbuf; |
230 |
|
|
i = BUFSIZ - 4; |
231 |
|
|
loop: |
232 |
|
|
while ((c = getC(DOALL)) == ' ' || c == '\t') |
233 |
|
|
continue; |
234 |
|
|
if (cmap(c, _META | _ESC)) |
235 |
|
|
switch (c) { |
236 |
|
|
case '&': |
237 |
|
|
case '|': |
238 |
|
|
case '<': |
239 |
|
|
case '>': |
240 |
|
|
*wp++ = c; |
241 |
|
|
c1 = getC(DOALL); |
242 |
|
|
if (c1 == c) |
243 |
|
|
*wp++ = c1; |
244 |
|
|
else |
245 |
|
|
ungetC(c1); |
246 |
|
|
goto ret; |
247 |
|
|
|
248 |
|
|
case '#': |
249 |
|
|
if (intty) |
250 |
|
|
break; |
251 |
|
|
c = 0; |
252 |
|
|
do { |
253 |
|
|
c1 = c; |
254 |
|
|
c = getC(0); |
255 |
|
|
} while (c != '\n'); |
256 |
|
|
if (c1 == '\\') |
257 |
|
|
goto loop; |
258 |
|
|
/* fall into ... */ |
259 |
|
|
|
260 |
|
|
case ';': |
261 |
|
|
case '(': |
262 |
|
|
case ')': |
263 |
|
|
case '\n': |
264 |
|
|
*wp++ = c; |
265 |
|
|
goto ret; |
266 |
|
|
|
267 |
|
|
case '\\': |
268 |
|
|
c = getC(0); |
269 |
|
|
if (c == '\n') { |
270 |
|
|
if (onelflg == 1) |
271 |
|
|
onelflg = 2; |
272 |
|
|
goto loop; |
273 |
|
|
} |
274 |
|
|
if (c != HIST) |
275 |
|
|
*wp++ = '\\', --i; |
276 |
|
|
c |= QUOTE; |
277 |
|
|
} |
278 |
|
|
c1 = 0; |
279 |
|
|
dolflg = DOALL; |
280 |
|
|
for (;;) { |
281 |
|
|
if (c1) { |
282 |
|
|
if (c == c1) { |
283 |
|
|
c1 = 0; |
284 |
|
|
dolflg = DOALL; |
285 |
|
|
} |
286 |
|
|
else if (c == '\\') { |
287 |
|
|
c = getC(0); |
288 |
|
|
if (c == HIST) |
289 |
|
|
c |= QUOTE; |
290 |
|
|
else { |
291 |
|
|
if (c == '\n') |
292 |
|
|
/* |
293 |
|
|
* if (c1 == '`') c = ' '; else |
294 |
|
|
*/ |
295 |
|
|
c |= QUOTE; |
296 |
|
|
ungetC(c); |
297 |
|
|
c = '\\'; |
298 |
|
|
} |
299 |
|
|
} |
300 |
|
|
else if (c == '\n') { |
301 |
|
|
seterror(ERR_UNMATCHED, c1); |
302 |
|
|
ungetC(c); |
303 |
|
|
break; |
304 |
|
|
} |
305 |
|
|
} |
306 |
|
|
else if (cmap(c, _META | _QF | _QB | _ESC)) { |
307 |
|
|
if (c == '\\') { |
308 |
|
|
c = getC(0); |
309 |
|
|
if (c == '\n') { |
310 |
|
|
if (onelflg == 1) |
311 |
|
|
onelflg = 2; |
312 |
|
|
break; |
313 |
|
|
} |
314 |
|
|
if (c != HIST) |
315 |
|
|
*wp++ = '\\', --i; |
316 |
|
|
c |= QUOTE; |
317 |
|
|
} |
318 |
|
|
else if (cmap(c, _QF | _QB)) { /* '"` */ |
319 |
|
|
c1 = c; |
320 |
|
|
dolflg = c == '"' ? DOALL : DOEXCL; |
321 |
|
|
} |
322 |
|
|
else if (c != '#' || !intty) { |
323 |
|
|
ungetC(c); |
324 |
|
|
break; |
325 |
|
|
} |
326 |
|
|
} |
327 |
|
|
if (--i > 0) { |
328 |
|
|
*wp++ = c; |
329 |
|
|
c = getC(dolflg); |
330 |
|
|
} |
331 |
|
|
else { |
332 |
|
|
seterror(ERR_WTOOLONG); |
333 |
|
|
wp = &wbuf[1]; |
334 |
|
|
break; |
335 |
|
|
} |
336 |
|
|
} |
337 |
|
|
ret: |
338 |
|
|
*wp = 0; |
339 |
|
|
return (Strsave(wbuf)); |
340 |
|
|
} |
341 |
|
|
|
342 |
|
|
static int |
343 |
|
|
getC1(int flag) |
344 |
|
|
{ |
345 |
|
|
Char c; |
346 |
|
|
|
347 |
|
|
while (1) { |
348 |
|
|
if ((c = peekc) != '\0') { |
349 |
|
|
peekc = 0; |
350 |
|
|
return (c); |
351 |
|
|
} |
352 |
|
|
if (lap) { |
353 |
|
|
if ((c = *lap++) == 0) |
354 |
|
|
lap = 0; |
355 |
|
|
else { |
356 |
|
|
if (cmap(c, _META | _QF | _QB)) |
357 |
|
|
c |= QUOTE; |
358 |
|
|
return (c); |
359 |
|
|
} |
360 |
|
|
} |
361 |
|
|
if ((c = peekd) != '\0') { |
362 |
|
|
peekd = 0; |
363 |
|
|
return (c); |
364 |
|
|
} |
365 |
|
|
if (exclp) { |
366 |
|
|
if ((c = *exclp++) != '\0') |
367 |
|
|
return (c); |
368 |
|
|
if (exclnxt && --exclc >= 0) { |
369 |
|
|
exclnxt = exclnxt->next; |
370 |
|
|
setexclp(exclnxt->word); |
371 |
|
|
return (' '); |
372 |
|
|
} |
373 |
|
|
exclp = 0; |
374 |
|
|
exclnxt = 0; |
375 |
|
|
} |
376 |
|
|
if (exclnxt) { |
377 |
|
|
exclnxt = exclnxt->next; |
378 |
|
|
if (--exclc < 0) |
379 |
|
|
exclnxt = 0; |
380 |
|
|
else |
381 |
|
|
setexclp(exclnxt->word); |
382 |
|
|
continue; |
383 |
|
|
} |
384 |
|
|
c = readc(0); |
385 |
|
|
if (c == '$' && (flag & DODOL)) { |
386 |
|
|
getdol(); |
387 |
|
|
continue; |
388 |
|
|
} |
389 |
|
|
if (c == HIST && (flag & DOEXCL)) { |
390 |
|
|
getexcl(0); |
391 |
|
|
continue; |
392 |
|
|
} |
393 |
|
|
break; |
394 |
|
|
} |
395 |
|
|
return (c); |
396 |
|
|
} |
397 |
|
|
|
398 |
|
|
static void |
399 |
|
|
getdol(void) |
400 |
|
|
{ |
401 |
|
|
Char *np, *ep; |
402 |
|
|
Char name[4 * MAXVARLEN + 1]; |
403 |
|
|
int c; |
404 |
|
|
int sc; |
405 |
|
|
bool special = 0, toolong; |
406 |
|
|
|
407 |
|
|
np = name, *np++ = '$'; |
408 |
|
|
c = sc = getC(DOEXCL); |
409 |
|
|
if (any("\t \n", c)) { |
410 |
|
|
ungetD(c); |
411 |
|
|
ungetC('$' | QUOTE); |
412 |
|
|
return; |
413 |
|
|
} |
414 |
|
|
if (c == '{') |
415 |
|
|
*np++ = c, c = getC(DOEXCL); |
416 |
|
|
if (c == '#' || c == '?') |
417 |
|
|
special++, *np++ = c, c = getC(DOEXCL); |
418 |
|
|
*np++ = c; |
419 |
|
|
switch (c) { |
420 |
|
|
|
421 |
|
|
case '<': |
422 |
|
|
case '$': |
423 |
|
|
case '!': |
424 |
|
|
if (special) |
425 |
|
|
seterror(ERR_SPDOLLT); |
426 |
|
|
*np = 0; |
427 |
|
|
addla(name); |
428 |
|
|
return; |
429 |
|
|
|
430 |
|
|
case '\n': |
431 |
|
|
ungetD(c); |
432 |
|
|
np--; |
433 |
|
|
seterror(ERR_NEWLINE); |
434 |
|
|
*np = 0; |
435 |
|
|
addla(name); |
436 |
|
|
return; |
437 |
|
|
|
438 |
|
|
case '*': |
439 |
|
|
if (special) |
440 |
|
|
seterror(ERR_SPSTAR); |
441 |
|
|
*np = 0; |
442 |
|
|
addla(name); |
443 |
|
|
return; |
444 |
|
|
|
445 |
|
|
default: |
446 |
|
|
toolong = 0; |
447 |
|
|
if (Isdigit(c)) { |
448 |
|
|
/* we know that np < &name[4] */ |
449 |
|
|
ep = &np[MAXVARLEN]; |
450 |
|
|
while ((c = getC(DOEXCL)) != '\0'){ |
451 |
|
|
if (!Isdigit(c)) |
452 |
|
|
break; |
453 |
|
|
if (np < ep) |
454 |
|
|
*np++ = c; |
455 |
|
|
else |
456 |
|
|
toolong = 1; |
457 |
|
|
} |
458 |
|
|
} |
459 |
|
|
else if (letter(c)) { |
460 |
|
|
/* we know that np < &name[4] */ |
461 |
|
|
ep = &np[MAXVARLEN]; |
462 |
|
|
toolong = 0; |
463 |
|
|
while ((c = getC(DOEXCL)) != '\0') { |
464 |
|
|
/* Bugfix for ${v123x} from Chris Torek, DAS DEC-90. */ |
465 |
|
|
if (!letter(c) && !Isdigit(c)) |
466 |
|
|
break; |
467 |
|
|
if (np < ep) |
468 |
|
|
*np++ = c; |
469 |
|
|
else |
470 |
|
|
toolong = 1; |
471 |
|
|
} |
472 |
|
|
} |
473 |
|
|
else { |
474 |
|
|
*np = 0; |
475 |
|
|
seterror(ERR_VARILL); |
476 |
|
|
addla(name); |
477 |
|
|
return; |
478 |
|
|
} |
479 |
|
|
if (toolong) { |
480 |
|
|
seterror(ERR_VARTOOLONG); |
481 |
|
|
*np = 0; |
482 |
|
|
addla(name); |
483 |
|
|
return; |
484 |
|
|
} |
485 |
|
|
break; |
486 |
|
|
} |
487 |
|
|
if (c == '[') { |
488 |
|
|
*np++ = c; |
489 |
|
|
/* |
490 |
|
|
* Name up to here is a max of MAXVARLEN + 8. |
491 |
|
|
*/ |
492 |
|
|
ep = &np[2 * MAXVARLEN + 8]; |
493 |
|
|
do { |
494 |
|
|
/* |
495 |
|
|
* Michael Greim: Allow $ expansion to take place in selector |
496 |
|
|
* expressions. (limits the number of characters returned) |
497 |
|
|
*/ |
498 |
|
|
c = getC(DOEXCL | DODOL); |
499 |
|
|
if (c == '\n') { |
500 |
|
|
ungetD(c); |
501 |
|
|
np--; |
502 |
|
|
seterror(ERR_NLINDEX); |
503 |
|
|
*np = 0; |
504 |
|
|
addla(name); |
505 |
|
|
return; |
506 |
|
|
} |
507 |
|
|
if (np < ep) |
508 |
|
|
*np++ = c; |
509 |
|
|
} while (c != ']'); |
510 |
|
|
*np = '\0'; |
511 |
|
|
if (np >= ep) { |
512 |
|
|
seterror(ERR_SELOVFL); |
513 |
|
|
addla(name); |
514 |
|
|
return; |
515 |
|
|
} |
516 |
|
|
c = getC(DOEXCL); |
517 |
|
|
} |
518 |
|
|
/* |
519 |
|
|
* Name up to here is a max of 2 * MAXVARLEN + 8. |
520 |
|
|
*/ |
521 |
|
|
if (c == ':') { |
522 |
|
|
/* |
523 |
|
|
* if the :g modifier is followed by a newline, then error right away! |
524 |
|
|
* -strike |
525 |
|
|
*/ |
526 |
|
|
|
527 |
|
|
int gmodflag = 0, amodflag = 0; |
528 |
|
|
|
529 |
|
|
do { |
530 |
|
|
*np++ = c, c = getC(DOEXCL); |
531 |
|
|
if (c == 'g' || c == 'a') { |
532 |
|
|
if (c == 'g') |
533 |
|
|
gmodflag++; |
534 |
|
|
else |
535 |
|
|
amodflag++; |
536 |
|
|
*np++ = c; c = getC(DOEXCL); |
537 |
|
|
} |
538 |
|
|
if ((c == 'g' && !gmodflag) || (c == 'a' && !amodflag)) { |
539 |
|
|
if (c == 'g') |
540 |
|
|
gmodflag++; |
541 |
|
|
else |
542 |
|
|
amodflag++; |
543 |
|
|
*np++ = c; c = getC(DOEXCL); |
544 |
|
|
} |
545 |
|
|
*np++ = c; |
546 |
|
|
/* scan s// [eichin:19910926.0512EST] */ |
547 |
|
|
if (c == 's') { |
548 |
|
|
int delimcnt = 2; |
549 |
|
|
int delim = getC(0); |
550 |
|
|
*np++ = delim; |
551 |
|
|
|
552 |
|
|
if (!delim || letter(delim) |
553 |
|
|
|| Isdigit(delim) || any(" \t\n", delim)) { |
554 |
|
|
seterror(ERR_BADSUBST); |
555 |
|
|
break; |
556 |
|
|
} |
557 |
|
|
while ((c = getC(0)) != (-1)) { |
558 |
|
|
*np++ = c; |
559 |
|
|
if(c == delim) delimcnt--; |
560 |
|
|
if(!delimcnt) break; |
561 |
|
|
} |
562 |
|
|
if(delimcnt) { |
563 |
|
|
seterror(ERR_BADSUBST); |
564 |
|
|
break; |
565 |
|
|
} |
566 |
|
|
c = 's'; |
567 |
|
|
} |
568 |
|
|
if (!any("htrqxes", c)) { |
569 |
|
|
if ((amodflag || gmodflag) && c == '\n') |
570 |
|
|
stderror(ERR_VARSYN); /* strike */ |
571 |
|
|
seterror(ERR_VARMOD, c); |
572 |
|
|
*np = 0; |
573 |
|
|
addla(name); |
574 |
|
|
return; |
575 |
|
|
} |
576 |
|
|
} |
577 |
|
|
while ((c = getC(DOEXCL)) == ':'); |
578 |
|
|
ungetD(c); |
579 |
|
|
} |
580 |
|
|
else |
581 |
|
|
ungetD(c); |
582 |
|
|
if (sc == '{') { |
583 |
|
|
c = getC(DOEXCL); |
584 |
|
|
if (c != '}') { |
585 |
|
|
ungetD(c); |
586 |
|
|
seterror(ERR_MISSING, '}'); |
587 |
|
|
*np = 0; |
588 |
|
|
addla(name); |
589 |
|
|
return; |
590 |
|
|
} |
591 |
|
|
*np++ = c; |
592 |
|
|
} |
593 |
|
|
*np = 0; |
594 |
|
|
addla(name); |
595 |
|
|
return; |
596 |
|
|
} |
597 |
|
|
|
598 |
|
|
void |
599 |
|
|
addla(Char *cp) |
600 |
|
|
{ |
601 |
|
|
Char buf[BUFSIZ]; |
602 |
|
|
|
603 |
|
|
if (Strlen(cp) + (lap ? Strlen(lap) : 0) >= |
604 |
|
|
(sizeof(labuf) - 4) / sizeof(Char)) { |
605 |
|
|
seterror(ERR_EXPOVFL); |
606 |
|
|
return; |
607 |
|
|
} |
608 |
|
|
if (lap) |
609 |
|
|
(void) Strlcpy(buf, lap, sizeof buf/sizeof(Char)); |
610 |
|
|
(void) Strlcpy(labuf, cp, sizeof labuf/sizeof(Char)); |
611 |
|
|
if (lap) |
612 |
|
|
(void) Strlcat(labuf, buf, sizeof labuf/sizeof(Char)); |
613 |
|
|
lap = labuf; |
614 |
|
|
} |
615 |
|
|
|
616 |
|
|
static Char lhsb[32]; |
617 |
|
|
static Char slhs[32]; |
618 |
|
|
static Char rhsb[64]; |
619 |
|
|
static int quesarg; |
620 |
|
|
|
621 |
|
|
static void |
622 |
|
|
getexcl(int sc) |
623 |
|
|
{ |
624 |
|
|
struct wordent *hp, *ip; |
625 |
|
|
int left, right, dol; |
626 |
|
|
int c; |
627 |
|
|
|
628 |
|
|
if (sc == 0) { |
629 |
|
|
sc = getC(0); |
630 |
|
|
if (sc != '{') { |
631 |
|
|
ungetC(sc); |
632 |
|
|
sc = 0; |
633 |
|
|
} |
634 |
|
|
} |
635 |
|
|
quesarg = -1; |
636 |
|
|
lastev = eventno; |
637 |
|
|
hp = gethent(sc); |
638 |
|
|
if (hp == 0) |
639 |
|
|
return; |
640 |
|
|
hadhist = 1; |
641 |
|
|
dol = 0; |
642 |
|
|
if (hp == alhistp) |
643 |
|
|
for (ip = hp->next->next; ip != alhistt; ip = ip->next) |
644 |
|
|
dol++; |
645 |
|
|
else |
646 |
|
|
for (ip = hp->next->next; ip != hp->prev; ip = ip->next) |
647 |
|
|
dol++; |
648 |
|
|
left = 0, right = dol; |
649 |
|
|
if (sc == HISTSUB) { |
650 |
|
|
ungetC('s'), unreadc(HISTSUB), c = ':'; |
651 |
|
|
goto subst; |
652 |
|
|
} |
653 |
|
|
c = getC(0); |
654 |
|
|
if (!any(":^$*-%", c)) |
655 |
|
|
goto subst; |
656 |
|
|
left = right = -1; |
657 |
|
|
if (c == ':') { |
658 |
|
|
c = getC(0); |
659 |
|
|
unreadc(c); |
660 |
|
|
if (letter(c) || c == '&') { |
661 |
|
|
c = ':'; |
662 |
|
|
left = 0, right = dol; |
663 |
|
|
goto subst; |
664 |
|
|
} |
665 |
|
|
} |
666 |
|
|
else |
667 |
|
|
ungetC(c); |
668 |
|
|
if (!getsel(&left, &right, dol)) |
669 |
|
|
return; |
670 |
|
|
c = getC(0); |
671 |
|
|
if (c == '*') |
672 |
|
|
ungetC(c), c = '-'; |
673 |
|
|
if (c == '-') { |
674 |
|
|
if (!getsel(&left, &right, dol)) |
675 |
|
|
return; |
676 |
|
|
c = getC(0); |
677 |
|
|
} |
678 |
|
|
subst: |
679 |
|
|
exclc = right - left + 1; |
680 |
|
|
while (--left >= 0) |
681 |
|
|
hp = hp->next; |
682 |
|
|
if (sc == HISTSUB || c == ':') { |
683 |
|
|
do { |
684 |
|
|
hp = getsub(hp); |
685 |
|
|
c = getC(0); |
686 |
|
|
} while (c == ':'); |
687 |
|
|
} |
688 |
|
|
unreadc(c); |
689 |
|
|
if (sc == '{') { |
690 |
|
|
c = getC(0); |
691 |
|
|
if (c != '}') |
692 |
|
|
seterror(ERR_BADBANG); |
693 |
|
|
} |
694 |
|
|
exclnxt = hp; |
695 |
|
|
} |
696 |
|
|
|
697 |
|
|
static struct wordent * |
698 |
|
|
getsub(struct wordent *en) |
699 |
|
|
{ |
700 |
|
|
Char *cp; |
701 |
|
|
int delim; |
702 |
|
|
int c; |
703 |
|
|
int sc; |
704 |
|
|
bool global; |
705 |
|
|
Char orhsb[sizeof(rhsb) / sizeof(Char)]; |
706 |
|
|
|
707 |
|
|
do { |
708 |
|
|
exclnxt = 0; |
709 |
|
|
global = 0; |
710 |
|
|
sc = c = getC(0); |
711 |
|
|
if (c == 'g' || c == 'a') { |
712 |
|
|
global |= (c == 'g') ? 1 : 2; |
713 |
|
|
sc = c = getC(0); |
714 |
|
|
} |
715 |
|
|
if (((c =='g') && !(global & 1)) || ((c == 'a') && !(global & 2))) { |
716 |
|
|
global |= (c == 'g') ? 1 : 2; |
717 |
|
|
sc = c = getC(0); |
718 |
|
|
} |
719 |
|
|
|
720 |
|
|
switch (c) { |
721 |
|
|
case 'p': |
722 |
|
|
justpr++; |
723 |
|
|
return (en); |
724 |
|
|
|
725 |
|
|
case 'x': |
726 |
|
|
case 'q': |
727 |
|
|
global |= 1; |
728 |
|
|
|
729 |
|
|
/* fall into ... */ |
730 |
|
|
|
731 |
|
|
case 'h': |
732 |
|
|
case 'r': |
733 |
|
|
case 't': |
734 |
|
|
case 'e': |
735 |
|
|
break; |
736 |
|
|
|
737 |
|
|
case '&': |
738 |
|
|
if (slhs[0] == 0) { |
739 |
|
|
seterror(ERR_NOSUBST); |
740 |
|
|
return (en); |
741 |
|
|
} |
742 |
|
|
(void) Strlcpy(lhsb, slhs, sizeof(lhsb)/sizeof(Char)); |
743 |
|
|
break; |
744 |
|
|
|
745 |
|
|
case 's': |
746 |
|
|
delim = getC(0); |
747 |
|
|
if (letter(delim) || Isdigit(delim) || any(" \t\n", delim)) { |
748 |
|
|
unreadc(delim); |
749 |
|
|
lhsb[0] = 0; |
750 |
|
|
seterror(ERR_BADSUBST); |
751 |
|
|
return (en); |
752 |
|
|
} |
753 |
|
|
cp = lhsb; |
754 |
|
|
for (;;) { |
755 |
|
|
c = getC(0); |
756 |
|
|
if (c == '\n') { |
757 |
|
|
unreadc(c); |
758 |
|
|
break; |
759 |
|
|
} |
760 |
|
|
if (c == delim) |
761 |
|
|
break; |
762 |
|
|
if (cp > &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) { |
763 |
|
|
lhsb[0] = 0; |
764 |
|
|
seterror(ERR_BADSUBST); |
765 |
|
|
return (en); |
766 |
|
|
} |
767 |
|
|
if (c == '\\') { |
768 |
|
|
c = getC(0); |
769 |
|
|
if (c != delim && c != '\\') |
770 |
|
|
*cp++ = '\\'; |
771 |
|
|
} |
772 |
|
|
*cp++ = c; |
773 |
|
|
} |
774 |
|
|
if (cp != lhsb) |
775 |
|
|
*cp++ = 0; |
776 |
|
|
else if (lhsb[0] == 0) { |
777 |
|
|
seterror(ERR_LHS); |
778 |
|
|
return (en); |
779 |
|
|
} |
780 |
|
|
cp = rhsb; |
781 |
|
|
(void) Strlcpy(orhsb, cp, sizeof(orhsb)/sizeof(Char)); |
782 |
|
|
for (;;) { |
783 |
|
|
c = getC(0); |
784 |
|
|
if (c == '\n') { |
785 |
|
|
unreadc(c); |
786 |
|
|
break; |
787 |
|
|
} |
788 |
|
|
if (c == delim) |
789 |
|
|
break; |
790 |
|
|
if (cp > &rhsb[sizeof(rhsb) / sizeof(Char) - 2]) { |
791 |
|
|
seterror(ERR_RHSLONG); |
792 |
|
|
return (en); |
793 |
|
|
} |
794 |
|
|
if (c == '\\') { |
795 |
|
|
c = getC(0); |
796 |
|
|
if (c != delim /* && c != '~' */ ) |
797 |
|
|
*cp++ = '\\'; |
798 |
|
|
} |
799 |
|
|
*cp++ = c; |
800 |
|
|
} |
801 |
|
|
*cp++ = 0; |
802 |
|
|
break; |
803 |
|
|
|
804 |
|
|
default: |
805 |
|
|
if (c == '\n') |
806 |
|
|
unreadc(c); |
807 |
|
|
seterror(ERR_BADBANGMOD, c); |
808 |
|
|
return (en); |
809 |
|
|
} |
810 |
|
|
(void) Strlcpy(slhs, lhsb, sizeof(slhs)/sizeof(Char)); |
811 |
|
|
if (exclc) |
812 |
|
|
en = dosub(sc, en, global); |
813 |
|
|
} |
814 |
|
|
while ((c = getC(0)) == ':'); |
815 |
|
|
unreadc(c); |
816 |
|
|
return (en); |
817 |
|
|
} |
818 |
|
|
|
819 |
|
|
static struct wordent * |
820 |
|
|
dosub(int sc, struct wordent *en, bool global) |
821 |
|
|
{ |
822 |
|
|
struct wordent lexi; |
823 |
|
|
bool didsub = 0, didone = 0; |
824 |
|
|
struct wordent *hp = &lexi; |
825 |
|
|
struct wordent *wdp; |
826 |
|
|
int i = exclc; |
827 |
|
|
|
828 |
|
|
wdp = hp; |
829 |
|
|
while (--i >= 0) { |
830 |
|
|
struct wordent *new = xcalloc(1, sizeof *wdp); |
831 |
|
|
|
832 |
|
|
new->word = 0; |
833 |
|
|
new->prev = wdp; |
834 |
|
|
new->next = hp; |
835 |
|
|
wdp->next = new; |
836 |
|
|
wdp = new; |
837 |
|
|
en = en->next; |
838 |
|
|
if (en->word) { |
839 |
|
|
Char *tword, *otword; |
840 |
|
|
|
841 |
|
|
if ((global & 1) || didsub == 0) { |
842 |
|
|
tword = subword(en->word, sc, &didone); |
843 |
|
|
if (didone) |
844 |
|
|
didsub = 1; |
845 |
|
|
if (global & 2) { |
846 |
|
|
while (didone && tword != STRNULL) { |
847 |
|
|
otword = tword; |
848 |
|
|
tword = subword(otword, sc, &didone); |
849 |
|
|
if (Strcmp(tword, otword) == 0) { |
850 |
|
|
free(otword); |
851 |
|
|
break; |
852 |
|
|
} |
853 |
|
|
else |
854 |
|
|
free(otword); |
855 |
|
|
} |
856 |
|
|
} |
857 |
|
|
} |
858 |
|
|
else |
859 |
|
|
tword = Strsave(en->word); |
860 |
|
|
wdp->word = tword; |
861 |
|
|
} |
862 |
|
|
} |
863 |
|
|
if (didsub == 0) |
864 |
|
|
seterror(ERR_MODFAIL); |
865 |
|
|
hp->prev = wdp; |
866 |
|
|
return (&enthist(-1000, &lexi, 0)->Hlex); |
867 |
|
|
} |
868 |
|
|
|
869 |
|
|
static Char * |
870 |
|
|
subword(Char *cp, int type, bool *adid) |
871 |
|
|
{ |
872 |
|
|
Char wbuf[BUFSIZ]; |
873 |
|
|
Char *wp, *mp, *np; |
874 |
|
|
int i; |
875 |
|
|
|
876 |
|
|
*adid = 0; |
877 |
|
|
switch (type) { |
878 |
|
|
|
879 |
|
|
case 'r': |
880 |
|
|
case 'e': |
881 |
|
|
case 'h': |
882 |
|
|
case 't': |
883 |
|
|
case 'q': |
884 |
|
|
case 'x': |
885 |
|
|
wp = domod(cp, type); |
886 |
|
|
if (wp == 0) |
887 |
|
|
return (Strsave(cp)); |
888 |
|
|
*adid = 1; |
889 |
|
|
return (wp); |
890 |
|
|
|
891 |
|
|
default: |
892 |
|
|
wp = wbuf; |
893 |
|
|
i = BUFSIZ - 4; |
894 |
|
|
for (mp = cp; *mp; mp++) |
895 |
|
|
if (matchs(mp, lhsb)) { |
896 |
|
|
for (np = cp; np < mp;) |
897 |
|
|
*wp++ = *np++, --i; |
898 |
|
|
for (np = rhsb; *np; np++) |
899 |
|
|
switch (*np) { |
900 |
|
|
|
901 |
|
|
case '\\': |
902 |
|
|
if (np[1] == '&') |
903 |
|
|
np++; |
904 |
|
|
/* fall into ... */ |
905 |
|
|
|
906 |
|
|
default: |
907 |
|
|
if (--i < 0) { |
908 |
|
|
seterror(ERR_SUBOVFL); |
909 |
|
|
return (STRNULL); |
910 |
|
|
} |
911 |
|
|
*wp++ = *np; |
912 |
|
|
continue; |
913 |
|
|
|
914 |
|
|
case '&': |
915 |
|
|
i -= Strlen(lhsb); |
916 |
|
|
if (i < 0) { |
917 |
|
|
seterror(ERR_SUBOVFL); |
918 |
|
|
return (STRNULL); |
919 |
|
|
} |
920 |
|
|
*wp = 0; |
921 |
|
|
(void)Strlcat(wp, lhsb, |
922 |
|
|
sizeof(wbuf)/sizeof(Char) - (wp - wbuf)); |
923 |
|
|
wp = Strend(wp); |
924 |
|
|
continue; |
925 |
|
|
} |
926 |
|
|
mp += Strlen(lhsb); |
927 |
|
|
i -= Strlen(mp); |
928 |
|
|
if (i < 0) { |
929 |
|
|
seterror(ERR_SUBOVFL); |
930 |
|
|
return (STRNULL); |
931 |
|
|
} |
932 |
|
|
*wp = 0; |
933 |
|
|
(void)Strlcat(wp, mp, |
934 |
|
|
sizeof(wbuf)/sizeof(Char) - (wp - wbuf)); |
935 |
|
|
*adid = 1; |
936 |
|
|
return (Strsave(wbuf)); |
937 |
|
|
} |
938 |
|
|
return (Strsave(cp)); |
939 |
|
|
} |
940 |
|
|
} |
941 |
|
|
|
942 |
|
|
Char * |
943 |
|
|
domod(Char *cp, int type) |
944 |
|
|
{ |
945 |
|
|
Char *wp, *xp; |
946 |
|
|
int c; |
947 |
|
|
|
948 |
|
|
switch (type) { |
949 |
|
|
|
950 |
|
|
case 'x': |
951 |
|
|
case 'q': |
952 |
|
|
wp = Strsave(cp); |
953 |
|
|
for (xp = wp; (c = *xp) != '\0'; xp++) |
954 |
|
|
if ((c != ' ' && c != '\t') || type == 'q') |
955 |
|
|
*xp |= QUOTE; |
956 |
|
|
return (wp); |
957 |
|
|
|
958 |
|
|
case 'h': |
959 |
|
|
case 't': |
960 |
|
|
if (!any(short2str(cp), '/')) |
961 |
|
|
return (type == 't' ? Strsave(cp) : 0); |
962 |
|
|
wp = Strend(cp); |
963 |
|
|
while (*--wp != '/') |
964 |
|
|
continue; |
965 |
|
|
if (type == 'h') |
966 |
|
|
xp = Strsave(cp), xp[wp - cp] = 0; |
967 |
|
|
else |
968 |
|
|
xp = Strsave(wp + 1); |
969 |
|
|
return (xp); |
970 |
|
|
|
971 |
|
|
case 'e': |
972 |
|
|
case 'r': |
973 |
|
|
wp = Strend(cp); |
974 |
|
|
for (wp--; wp >= cp && *wp != '/'; wp--) |
975 |
|
|
if (*wp == '.') { |
976 |
|
|
if (type == 'e') |
977 |
|
|
xp = Strsave(wp + 1); |
978 |
|
|
else |
979 |
|
|
xp = Strsave(cp), xp[wp - cp] = 0; |
980 |
|
|
return (xp); |
981 |
|
|
} |
982 |
|
|
return (Strsave(type == 'e' ? STRNULL : cp)); |
983 |
|
|
default: |
984 |
|
|
break; |
985 |
|
|
} |
986 |
|
|
return (0); |
987 |
|
|
} |
988 |
|
|
|
989 |
|
|
static int |
990 |
|
|
matchs(Char *str, Char *pat) |
991 |
|
|
{ |
992 |
|
|
while (*str && *pat && *str == *pat) |
993 |
|
|
str++, pat++; |
994 |
|
|
return (*pat == 0); |
995 |
|
|
} |
996 |
|
|
|
997 |
|
|
static int |
998 |
|
|
getsel(int *al, int *ar, int dol) |
999 |
|
|
{ |
1000 |
|
|
int c = getC(0); |
1001 |
|
|
int i; |
1002 |
|
|
bool first = *al < 0; |
1003 |
|
|
|
1004 |
|
|
switch (c) { |
1005 |
|
|
|
1006 |
|
|
case '%': |
1007 |
|
|
if (quesarg == -1) { |
1008 |
|
|
seterror(ERR_BADBANGARG); |
1009 |
|
|
return (0); |
1010 |
|
|
} |
1011 |
|
|
if (*al < 0) |
1012 |
|
|
*al = quesarg; |
1013 |
|
|
*ar = quesarg; |
1014 |
|
|
break; |
1015 |
|
|
|
1016 |
|
|
case '-': |
1017 |
|
|
if (*al < 0) { |
1018 |
|
|
*al = 0; |
1019 |
|
|
*ar = dol - 1; |
1020 |
|
|
unreadc(c); |
1021 |
|
|
} |
1022 |
|
|
return (1); |
1023 |
|
|
|
1024 |
|
|
case '^': |
1025 |
|
|
if (*al < 0) |
1026 |
|
|
*al = 1; |
1027 |
|
|
*ar = 1; |
1028 |
|
|
break; |
1029 |
|
|
|
1030 |
|
|
case '$': |
1031 |
|
|
if (*al < 0) |
1032 |
|
|
*al = dol; |
1033 |
|
|
*ar = dol; |
1034 |
|
|
break; |
1035 |
|
|
|
1036 |
|
|
case '*': |
1037 |
|
|
if (*al < 0) |
1038 |
|
|
*al = 1; |
1039 |
|
|
*ar = dol; |
1040 |
|
|
if (*ar < *al) { |
1041 |
|
|
*ar = 0; |
1042 |
|
|
*al = 1; |
1043 |
|
|
return (1); |
1044 |
|
|
} |
1045 |
|
|
break; |
1046 |
|
|
|
1047 |
|
|
default: |
1048 |
|
|
if (Isdigit(c)) { |
1049 |
|
|
i = 0; |
1050 |
|
|
while (Isdigit(c)) { |
1051 |
|
|
i = i * 10 + c - '0'; |
1052 |
|
|
c = getC(0); |
1053 |
|
|
} |
1054 |
|
|
if (i < 0) |
1055 |
|
|
i = dol + 1; |
1056 |
|
|
if (*al < 0) |
1057 |
|
|
*al = i; |
1058 |
|
|
*ar = i; |
1059 |
|
|
} |
1060 |
|
|
else if (*al < 0) |
1061 |
|
|
*al = 0, *ar = dol; |
1062 |
|
|
else |
1063 |
|
|
*ar = dol - 1; |
1064 |
|
|
unreadc(c); |
1065 |
|
|
break; |
1066 |
|
|
} |
1067 |
|
|
if (first) { |
1068 |
|
|
c = getC(0); |
1069 |
|
|
unreadc(c); |
1070 |
|
|
if (any("-$*", c)) |
1071 |
|
|
return (1); |
1072 |
|
|
} |
1073 |
|
|
if (*al > *ar || *ar > dol) { |
1074 |
|
|
seterror(ERR_BADBANGARG); |
1075 |
|
|
return (0); |
1076 |
|
|
} |
1077 |
|
|
return (1); |
1078 |
|
|
|
1079 |
|
|
} |
1080 |
|
|
|
1081 |
|
|
static struct wordent * |
1082 |
|
|
gethent(int sc) |
1083 |
|
|
{ |
1084 |
|
|
struct Hist *hp; |
1085 |
|
|
Char *np; |
1086 |
|
|
int c; |
1087 |
|
|
int event; |
1088 |
|
|
bool back = 0; |
1089 |
|
|
|
1090 |
|
|
c = sc == HISTSUB ? HIST : getC(0); |
1091 |
|
|
if (c == HIST) { |
1092 |
|
|
if (alhistp) |
1093 |
|
|
return (alhistp); |
1094 |
|
|
event = eventno; |
1095 |
|
|
} |
1096 |
|
|
else |
1097 |
|
|
switch (c) { |
1098 |
|
|
|
1099 |
|
|
case ':': |
1100 |
|
|
case '^': |
1101 |
|
|
case '$': |
1102 |
|
|
case '*': |
1103 |
|
|
case '%': |
1104 |
|
|
ungetC(c); |
1105 |
|
|
if (lastev == eventno && alhistp) |
1106 |
|
|
return (alhistp); |
1107 |
|
|
event = lastev; |
1108 |
|
|
break; |
1109 |
|
|
|
1110 |
|
|
case '#': /* !# is command being typed in (mrh) */ |
1111 |
|
|
if (--hleft == 0) { |
1112 |
|
|
seterror(ERR_HISTLOOP); |
1113 |
|
|
return (0); |
1114 |
|
|
} |
1115 |
|
|
else |
1116 |
|
|
return (¶ml); |
1117 |
|
|
/* NOTREACHED */ |
1118 |
|
|
|
1119 |
|
|
case '-': |
1120 |
|
|
back = 1; |
1121 |
|
|
c = getC(0); |
1122 |
|
|
/* FALLSTHROUGH */ |
1123 |
|
|
|
1124 |
|
|
default: |
1125 |
|
|
if (any("(=~", c)) { |
1126 |
|
|
unreadc(c); |
1127 |
|
|
ungetC(HIST); |
1128 |
|
|
return (0); |
1129 |
|
|
} |
1130 |
|
|
np = lhsb; |
1131 |
|
|
event = 0; |
1132 |
|
|
while (!cmap(c, _ESC | _META | _QF | _QB) && !any("${}:", c)) { |
1133 |
|
|
if (event != -1 && Isdigit(c)) |
1134 |
|
|
event = event * 10 + c - '0'; |
1135 |
|
|
else |
1136 |
|
|
event = -1; |
1137 |
|
|
if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) |
1138 |
|
|
*np++ = c; |
1139 |
|
|
c = getC(0); |
1140 |
|
|
} |
1141 |
|
|
unreadc(c); |
1142 |
|
|
if (np == lhsb) { |
1143 |
|
|
ungetC(HIST); |
1144 |
|
|
return (0); |
1145 |
|
|
} |
1146 |
|
|
*np++ = 0; |
1147 |
|
|
if (event != -1) { |
1148 |
|
|
/* |
1149 |
|
|
* History had only digits |
1150 |
|
|
*/ |
1151 |
|
|
if (back) |
1152 |
|
|
event = eventno + (alhistp == 0) - (event ? event : 0); |
1153 |
|
|
break; |
1154 |
|
|
} |
1155 |
|
|
hp = findev(lhsb, 0); |
1156 |
|
|
if (hp) |
1157 |
|
|
lastev = hp->Hnum; |
1158 |
|
|
return (&hp->Hlex); |
1159 |
|
|
|
1160 |
|
|
case '?': |
1161 |
|
|
np = lhsb; |
1162 |
|
|
for (;;) { |
1163 |
|
|
c = getC(0); |
1164 |
|
|
if (c == '\n') { |
1165 |
|
|
unreadc(c); |
1166 |
|
|
break; |
1167 |
|
|
} |
1168 |
|
|
if (c == '?') |
1169 |
|
|
break; |
1170 |
|
|
if (np < &lhsb[sizeof(lhsb) / sizeof(Char) - 2]) |
1171 |
|
|
*np++ = c; |
1172 |
|
|
} |
1173 |
|
|
if (np == lhsb) { |
1174 |
|
|
if (lhsb[0] == 0) { |
1175 |
|
|
seterror(ERR_NOSEARCH); |
1176 |
|
|
return (0); |
1177 |
|
|
} |
1178 |
|
|
} |
1179 |
|
|
else |
1180 |
|
|
*np++ = 0; |
1181 |
|
|
hp = findev(lhsb, 1); |
1182 |
|
|
if (hp) |
1183 |
|
|
lastev = hp->Hnum; |
1184 |
|
|
return (&hp->Hlex); |
1185 |
|
|
} |
1186 |
|
|
|
1187 |
|
|
for (hp = Histlist.Hnext; hp; hp = hp->Hnext) |
1188 |
|
|
if (hp->Hnum == event) { |
1189 |
|
|
hp->Href = eventno; |
1190 |
|
|
lastev = hp->Hnum; |
1191 |
|
|
return (&hp->Hlex); |
1192 |
|
|
} |
1193 |
|
|
np = putn(event); |
1194 |
|
|
seterror(ERR_NOEVENT, vis_str(np)); |
1195 |
|
|
return (0); |
1196 |
|
|
} |
1197 |
|
|
|
1198 |
|
|
static struct Hist * |
1199 |
|
|
findev(Char *cp, bool anyarg) |
1200 |
|
|
{ |
1201 |
|
|
struct Hist *hp; |
1202 |
|
|
|
1203 |
|
|
for (hp = Histlist.Hnext; hp; hp = hp->Hnext) { |
1204 |
|
|
Char *dp; |
1205 |
|
|
Char *p, *q; |
1206 |
|
|
struct wordent *lp = hp->Hlex.next; |
1207 |
|
|
int argno = 0; |
1208 |
|
|
|
1209 |
|
|
/* |
1210 |
|
|
* The entries added by alias substitution don't have a newline but do |
1211 |
|
|
* have a negative event number. Savehist() trims off these entries, |
1212 |
|
|
* but it happens before alias expansion, too early to delete those |
1213 |
|
|
* from the previous command. |
1214 |
|
|
*/ |
1215 |
|
|
if (hp->Hnum < 0) |
1216 |
|
|
continue; |
1217 |
|
|
if (lp->word[0] == '\n') |
1218 |
|
|
continue; |
1219 |
|
|
if (!anyarg) { |
1220 |
|
|
p = cp; |
1221 |
|
|
q = lp->word; |
1222 |
|
|
do |
1223 |
|
|
if (!*p) |
1224 |
|
|
return (hp); |
1225 |
|
|
while (*p++ == *q++); |
1226 |
|
|
continue; |
1227 |
|
|
} |
1228 |
|
|
do { |
1229 |
|
|
for (dp = lp->word; *dp; dp++) { |
1230 |
|
|
p = cp; |
1231 |
|
|
q = dp; |
1232 |
|
|
do |
1233 |
|
|
if (!*p) { |
1234 |
|
|
quesarg = argno; |
1235 |
|
|
return (hp); |
1236 |
|
|
} |
1237 |
|
|
while (*p++ == *q++); |
1238 |
|
|
} |
1239 |
|
|
lp = lp->next; |
1240 |
|
|
argno++; |
1241 |
|
|
} while (lp->word[0] != '\n'); |
1242 |
|
|
} |
1243 |
|
|
seterror(ERR_NOEVENT, vis_str(cp)); |
1244 |
|
|
return (0); |
1245 |
|
|
} |
1246 |
|
|
|
1247 |
|
|
|
1248 |
|
|
static void |
1249 |
|
|
setexclp(Char *cp) |
1250 |
|
|
{ |
1251 |
|
|
if (cp && cp[0] == '\n') |
1252 |
|
|
return; |
1253 |
|
|
exclp = cp; |
1254 |
|
|
} |
1255 |
|
|
|
1256 |
|
|
void |
1257 |
|
|
unreadc(int c) |
1258 |
|
|
{ |
1259 |
|
|
peekread = c; |
1260 |
|
|
} |
1261 |
|
|
|
1262 |
|
|
int |
1263 |
|
|
readc(bool wanteof) |
1264 |
|
|
{ |
1265 |
|
|
int c; |
1266 |
|
|
static int sincereal; |
1267 |
|
|
|
1268 |
|
|
aret = F_SEEK; |
1269 |
|
|
if ((c = peekread) != '\0') { |
1270 |
|
|
peekread = 0; |
1271 |
|
|
return (c); |
1272 |
|
|
} |
1273 |
|
|
top: |
1274 |
|
|
aret = F_SEEK; |
1275 |
|
|
if (alvecp) { |
1276 |
|
|
aret = A_SEEK; |
1277 |
|
|
if ((c = *alvecp++) != '\0') |
1278 |
|
|
return (c); |
1279 |
|
|
if (alvec && *alvec) { |
1280 |
|
|
alvecp = *alvec++; |
1281 |
|
|
return (' '); |
1282 |
|
|
} |
1283 |
|
|
else { |
1284 |
|
|
aret = F_SEEK; |
1285 |
|
|
alvecp = NULL; |
1286 |
|
|
return('\n'); |
1287 |
|
|
} |
1288 |
|
|
} |
1289 |
|
|
if (alvec) { |
1290 |
|
|
if ((alvecp = *alvec) != '\0') { |
1291 |
|
|
alvec++; |
1292 |
|
|
goto top; |
1293 |
|
|
} |
1294 |
|
|
/* Infinite source! */ |
1295 |
|
|
return ('\n'); |
1296 |
|
|
} |
1297 |
|
|
if (evalp) { |
1298 |
|
|
aret = E_SEEK; |
1299 |
|
|
if ((c = *evalp++) != '\0') |
1300 |
|
|
return (c); |
1301 |
|
|
if (evalvec && *evalvec) { |
1302 |
|
|
evalp = *evalvec++; |
1303 |
|
|
return (' '); |
1304 |
|
|
} |
1305 |
|
|
aret = F_SEEK; |
1306 |
|
|
evalp = 0; |
1307 |
|
|
} |
1308 |
|
|
if (evalvec) { |
1309 |
|
|
if (evalvec == (Char **) 1) { |
1310 |
|
|
doneinp = 1; |
1311 |
|
|
reset(); |
1312 |
|
|
} |
1313 |
|
|
if ((evalp = *evalvec) != '\0') { |
1314 |
|
|
evalvec++; |
1315 |
|
|
goto top; |
1316 |
|
|
} |
1317 |
|
|
evalvec = (Char **) 1; |
1318 |
|
|
return ('\n'); |
1319 |
|
|
} |
1320 |
|
|
do { |
1321 |
|
|
if (arginp == (Char *) 1 || onelflg == 1) { |
1322 |
|
|
if (wanteof) |
1323 |
|
|
return (-1); |
1324 |
|
|
exitstat(); |
1325 |
|
|
} |
1326 |
|
|
if (arginp) { |
1327 |
|
|
if ((c = *arginp++) == 0) { |
1328 |
|
|
arginp = (Char *) 1; |
1329 |
|
|
return ('\n'); |
1330 |
|
|
} |
1331 |
|
|
return (c); |
1332 |
|
|
} |
1333 |
|
|
reread: |
1334 |
|
|
c = bgetc(); |
1335 |
|
|
if (c < 0) { |
1336 |
|
|
struct termios tty; |
1337 |
|
|
if (wanteof) |
1338 |
|
|
return (-1); |
1339 |
|
|
/* was isatty but raw with ignoreeof yields problems */ |
1340 |
|
|
if (isatty(SHIN) && tcgetattr(SHIN, &tty) == 0 && (tty.c_lflag & ICANON)) |
1341 |
|
|
{ |
1342 |
|
|
pid_t ctpgrp; |
1343 |
|
|
|
1344 |
|
|
if (++sincereal > 25) |
1345 |
|
|
goto oops; |
1346 |
|
|
if (tpgrp != -1 && |
1347 |
|
|
(ctpgrp = tcgetpgrp(FSHTTY)) != -1 && |
1348 |
|
|
tpgrp != ctpgrp) { |
1349 |
|
|
(void) tcsetpgrp(FSHTTY, tpgrp); |
1350 |
|
|
(void) kill(-ctpgrp, SIGHUP); |
1351 |
|
|
(void) fprintf(csherr, "Reset tty pgrp from %d to %d\n", |
1352 |
|
|
ctpgrp, tpgrp); |
1353 |
|
|
goto reread; |
1354 |
|
|
} |
1355 |
|
|
if (adrof(STRignoreeof)) { |
1356 |
|
|
if (loginsh) |
1357 |
|
|
(void) fprintf(csherr,"\nUse \"logout\" to logout.\n"); |
1358 |
|
|
else |
1359 |
|
|
(void) fprintf(csherr,"\nUse \"exit\" to leave csh.\n"); |
1360 |
|
|
reset(); |
1361 |
|
|
} |
1362 |
|
|
if (chkstop == 0) |
1363 |
|
|
panystop(1); |
1364 |
|
|
} |
1365 |
|
|
oops: |
1366 |
|
|
doneinp = 1; |
1367 |
|
|
reset(); |
1368 |
|
|
} |
1369 |
|
|
sincereal = 0; |
1370 |
|
|
if (c == '\n' && onelflg) |
1371 |
|
|
onelflg--; |
1372 |
|
|
} while (c == 0); |
1373 |
|
|
return (c); |
1374 |
|
|
} |
1375 |
|
|
|
1376 |
|
|
static int |
1377 |
|
|
bgetc(void) |
1378 |
|
|
{ |
1379 |
|
|
int buf, off, c; |
1380 |
|
|
|
1381 |
|
|
int numleft = 0, roomleft; |
1382 |
|
|
Char ttyline[BUFSIZ]; |
1383 |
|
|
char tbuf[BUFSIZ + 1]; |
1384 |
|
|
|
1385 |
|
|
if (cantell) { |
1386 |
|
|
if (fseekp < fbobp || fseekp > feobp) { |
1387 |
|
|
fbobp = feobp = fseekp; |
1388 |
|
|
(void) lseek(SHIN, fseekp, SEEK_SET); |
1389 |
|
|
} |
1390 |
|
|
if (fseekp == feobp) { |
1391 |
|
|
int i; |
1392 |
|
|
|
1393 |
|
|
fbobp = feobp; |
1394 |
|
|
do |
1395 |
|
|
c = read(SHIN, tbuf, BUFSIZ); |
1396 |
|
|
while (c < 0 && errno == EINTR); |
1397 |
|
|
if (c <= 0) |
1398 |
|
|
return (-1); |
1399 |
|
|
for (i = 0; i < c; i++) |
1400 |
|
|
fbuf[0][i] = (unsigned char) tbuf[i]; |
1401 |
|
|
feobp += c; |
1402 |
|
|
} |
1403 |
|
|
c = fbuf[0][fseekp - fbobp]; |
1404 |
|
|
fseekp++; |
1405 |
|
|
return (c); |
1406 |
|
|
} |
1407 |
|
|
|
1408 |
|
|
again: |
1409 |
|
|
buf = (int) fseekp / BUFSIZ; |
1410 |
|
|
if (buf >= fblocks) { |
1411 |
|
|
Char **nfbuf = xcalloc((size_t) (fblocks + 2), |
1412 |
|
|
sizeof(Char **)); |
1413 |
|
|
|
1414 |
|
|
if (fbuf) { |
1415 |
|
|
(void) blkcpy(nfbuf, fbuf); |
1416 |
|
|
free(fbuf); |
1417 |
|
|
} |
1418 |
|
|
fbuf = nfbuf; |
1419 |
|
|
fbuf[fblocks] = xcalloc(BUFSIZ, sizeof(Char)); |
1420 |
|
|
fblocks++; |
1421 |
|
|
if (!intty) |
1422 |
|
|
goto again; |
1423 |
|
|
} |
1424 |
|
|
if (fseekp >= feobp) { |
1425 |
|
|
buf = (int) feobp / BUFSIZ; |
1426 |
|
|
off = (int) feobp % BUFSIZ; |
1427 |
|
|
roomleft = BUFSIZ - off; |
1428 |
|
|
|
1429 |
|
|
for (;;) { |
1430 |
|
|
if (filec && intty) { |
1431 |
|
|
c = numleft ? numleft : tenex(ttyline, BUFSIZ); |
1432 |
|
|
if (c > roomleft) { |
1433 |
|
|
/* start with fresh buffer */ |
1434 |
|
|
feobp = fseekp = fblocks * BUFSIZ; |
1435 |
|
|
numleft = c; |
1436 |
|
|
goto again; |
1437 |
|
|
} |
1438 |
|
|
if (c > 0) |
1439 |
|
|
memcpy(fbuf[buf] + off, ttyline, c * sizeof(Char)); |
1440 |
|
|
numleft = 0; |
1441 |
|
|
} |
1442 |
|
|
else { |
1443 |
|
|
c = read(SHIN, tbuf, roomleft); |
1444 |
|
|
if (c > 0) { |
1445 |
|
|
int i; |
1446 |
|
|
Char *ptr = fbuf[buf] + off; |
1447 |
|
|
|
1448 |
|
|
for (i = 0; i < c; i++) |
1449 |
|
|
ptr[i] = (unsigned char) tbuf[i]; |
1450 |
|
|
} |
1451 |
|
|
} |
1452 |
|
|
if (c >= 0) |
1453 |
|
|
break; |
1454 |
|
|
if (errno == EWOULDBLOCK) { |
1455 |
|
|
int flags; |
1456 |
|
|
|
1457 |
|
|
flags = fcntl(SHIN, F_GETFL); |
1458 |
|
|
(void) fcntl(SHIN, F_SETFL, (flags & ~O_NONBLOCK)); |
1459 |
|
|
} |
1460 |
|
|
else if (errno != EINTR) |
1461 |
|
|
break; |
1462 |
|
|
} |
1463 |
|
|
if (c <= 0) |
1464 |
|
|
return (-1); |
1465 |
|
|
feobp += c; |
1466 |
|
|
if (filec && !intty) |
1467 |
|
|
goto again; |
1468 |
|
|
} |
1469 |
|
|
c = fbuf[buf][(int) fseekp % BUFSIZ]; |
1470 |
|
|
fseekp++; |
1471 |
|
|
return (c); |
1472 |
|
|
} |
1473 |
|
|
|
1474 |
|
|
static void |
1475 |
|
|
bfree(void) |
1476 |
|
|
{ |
1477 |
|
|
int sb, i; |
1478 |
|
|
|
1479 |
|
|
if (cantell) |
1480 |
|
|
return; |
1481 |
|
|
if (whyles) |
1482 |
|
|
return; |
1483 |
|
|
sb = (int) (fseekp - 1) / BUFSIZ; |
1484 |
|
|
if (sb > 0) { |
1485 |
|
|
for (i = 0; i < sb; i++) |
1486 |
|
|
free(fbuf[i]); |
1487 |
|
|
(void) blkcpy(fbuf, &fbuf[sb]); |
1488 |
|
|
fseekp -= BUFSIZ * sb; |
1489 |
|
|
feobp -= BUFSIZ * sb; |
1490 |
|
|
fblocks -= sb; |
1491 |
|
|
} |
1492 |
|
|
} |
1493 |
|
|
|
1494 |
|
|
void |
1495 |
|
|
bseek(struct Ain *l) |
1496 |
|
|
{ |
1497 |
|
|
switch (aret = l->type) { |
1498 |
|
|
case E_SEEK: |
1499 |
|
|
evalvec = l->a_seek; |
1500 |
|
|
evalp = l->c_seek; |
1501 |
|
|
return; |
1502 |
|
|
case A_SEEK: |
1503 |
|
|
alvec = l->a_seek; |
1504 |
|
|
alvecp = l->c_seek; |
1505 |
|
|
return; |
1506 |
|
|
case F_SEEK: |
1507 |
|
|
fseekp = l->f_seek; |
1508 |
|
|
return; |
1509 |
|
|
default: |
1510 |
|
|
(void) fprintf(csherr, "Bad seek type %d\n", aret); |
1511 |
|
|
abort(); |
1512 |
|
|
} |
1513 |
|
|
} |
1514 |
|
|
|
1515 |
|
|
void |
1516 |
|
|
btell(struct Ain *l) |
1517 |
|
|
{ |
1518 |
|
|
switch (l->type = aret) { |
1519 |
|
|
case E_SEEK: |
1520 |
|
|
l->a_seek = evalvec; |
1521 |
|
|
l->c_seek = evalp; |
1522 |
|
|
return; |
1523 |
|
|
case A_SEEK: |
1524 |
|
|
l->a_seek = alvec; |
1525 |
|
|
l->c_seek = alvecp; |
1526 |
|
|
return; |
1527 |
|
|
case F_SEEK: |
1528 |
|
|
l->f_seek = fseekp; |
1529 |
|
|
l->a_seek = NULL; |
1530 |
|
|
return; |
1531 |
|
|
default: |
1532 |
|
|
(void) fprintf(csherr, "Bad seek type %d\n", aret); |
1533 |
|
|
abort(); |
1534 |
|
|
} |
1535 |
|
|
} |
1536 |
|
|
|
1537 |
|
|
void |
1538 |
|
|
btoeof(void) |
1539 |
|
|
{ |
1540 |
|
|
(void) lseek(SHIN, (off_t) 0, SEEK_END); |
1541 |
|
|
aret = F_SEEK; |
1542 |
|
|
fseekp = feobp; |
1543 |
|
|
alvec = NULL; |
1544 |
|
|
alvecp = NULL; |
1545 |
|
|
evalvec = NULL; |
1546 |
|
|
evalp = NULL; |
1547 |
|
|
wfree(); |
1548 |
|
|
bfree(); |
1549 |
|
|
} |
1550 |
|
|
|
1551 |
|
|
void |
1552 |
|
|
settell(void) |
1553 |
|
|
{ |
1554 |
|
|
cantell = 0; |
1555 |
|
|
if (arginp || onelflg || intty) |
1556 |
|
|
return; |
1557 |
|
|
if (lseek(SHIN, (off_t) 0, SEEK_CUR) < 0 || errno == ESPIPE) |
1558 |
|
|
return; |
1559 |
|
|
fbuf = xcalloc(2, sizeof(Char **)); |
1560 |
|
|
fblocks = 1; |
1561 |
|
|
fbuf[0] = xcalloc(BUFSIZ, sizeof(Char)); |
1562 |
|
|
fseekp = fbobp = feobp = lseek(SHIN, (off_t) 0, SEEK_CUR); |
1563 |
|
|
cantell = 1; |
1564 |
|
|
} |