2 * Copyright 2006 Sun Microsystems, Inc. All rights reserved.
3 * Use is subject to license terms.
6 /* Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T */
7 /* All Rights Reserved */
10 * Copyright (c) 1980 Regents of the University of California.
11 * All rights reserved. The Berkeley Software License Agreement
12 * specifies the terms and conditions for redistribution.
15 #pragma ident "%Z%%M% %I% %E% SMI"
17 #include <unistd.h> /* for lseek prototype */
19 #include "sh.tconst.h"
20 #include <sys/filio.h>
21 #include <sys/ttold.h>
28 * These lexical routines read input and form lists of words.
29 * There is some involved processing here, because of the complications
30 * of input buffering, and especially because of history substitution.
35 tchar
*subword(tchar
*, int, bool *);
40 void setexclp(tchar
*);
43 struct wordent
*dosub(int, struct wordent
*, bool);
44 struct Hist
*findev(tchar
*, bool);
45 struct wordent
*gethent(int);
46 struct wordent
*getsub(struct wordent
*);
49 * Peekc is a peek characer for getC, peekread for readc.
50 * There is a subtlety here in many places... history routines
51 * will read ahead and then insert stuff into the input stream.
52 * If they push back a character then they must push it behind
53 * the text substituted by the history substitution. On the other
54 * hand in several places we need 2 peek characters. To make this
55 * all work, the history routines read with getC, and make use both
56 * of ungetC and unreadc. The key observation is that the state
57 * of getC at the call of a history reference is such that calls
58 * to getC from the history routines will always yield calls of
59 * readc, unless this peeking is involved. That is to say that during
60 * getexcl the variables lap, exclp, and exclnxt are all zero.
62 * Getdol invokes history substitution, hence the extra peek, peekd,
63 * which it can ungetD to be before history substitutions.
68 tchar
*exclp
; /* (Tail of) current word from ! subst */
69 struct wordent
*exclnxt
; /* The rest of the ! subst words */
70 int exclc
; /* Count of remainig words in ! subst */
71 tchar
*alvecp
; /* "Globp" for alias resubstitution */
74 * Lex returns to its caller not only a wordlist (as a "var" parameter)
75 * but also whether a history substitution occurred. This is used in
76 * the main (process) routine to determine whether to echo, and also
77 * when called by the alias routine to determine whether to keep the
83 #define getC(f) ((getCtmp = peekc) ? (peekc = 0, getCtmp) : getC1(f))
84 #define ungetC(c) peekc = c
85 #define ungetD(c) peekd = c
88 lex(struct wordent
*hp
)
94 tprintf("TRACE- lex()\n");
97 hp
->next
= hp
->prev
= hp
;
98 hp
->word
= S_
/* "" */;
99 alvecp
= 0, hadhist
= 0;
103 /* make sure history is enabled */
104 if (HIST
&& c
== HISTSUB
&& intty
)
105 /* ^lef^rit from tty is short !:s^lef^rit */
111 * The following loop is written so that the links needed
112 * by freelex will be ready and rarin to go even if it is
116 struct wordent
*new = (struct wordent
*)xalloc(sizeof *wdp
);
124 } while (wdp
->word
[0] != '\n');
126 tprintf("Exiting lex()\n");
133 prlex(struct wordent
*sp0
)
135 struct wordent
*sp
= sp0
->next
;
138 tprintf("TRACE- prlex()\n");
141 printf("%t", sp
->word
);
145 if (sp
->word
[0] != '\n')
151 copylex(struct wordent
*hp
, struct wordent
*fp
)
156 tprintf("TRACE- copylex()\n");
161 struct wordent
*new = (struct wordent
*)xalloc(sizeof *wdp
);
167 wdp
->word
= savestr(fp
->word
);
169 } while (wdp
->word
[0] != '\n');
174 freelex(struct wordent
*vp
)
179 tprintf("TRACE- freelex()\n");
181 while (vp
->next
!= vp
) {
200 tprintf("TRACE- word()\n");
205 while (issp(c
= getC(DOALL
)))
207 if (cmap(c
, _META
|_ESC
)||isauxsp(c
))
258 } else if (c
== '\\') {
273 } else if (c
== '\n') {
274 seterrc(gettext("Unmatched "), c1
);
278 } else if (cmap(c
, _META
|_Q
|_Q1
|_ESC
)||isauxsp(c
)) {
289 } else if (cmap(c
, _Q
|_Q1
)) { /* '"` */
291 dolflg
= c
== '"' ? DOALL
: DOEXCL
;
292 } else if (c
!= '#' || !intty
) {
301 seterr("Word too long");
309 tprintf("word() returning:%t\n", wbuf
);
311 return (savestr(wbuf
));
325 if ((c
= *lap
++) == 0)
329 * don't quote things if there was an error (err!=0)
330 * the input is original, not from a substitution and
331 * therefore should not be quoted
333 if (!err
&& cmap(c
, _META
|_Q
|_Q1
)||isauxsp(c
))
345 if (exclnxt
&& --exclc
>= 0) {
346 exclnxt
= exclnxt
->next
;
347 setexclp(exclnxt
->word
);
354 exclnxt
= exclnxt
->next
;
358 setexclp(exclnxt
->word
);
362 if (c
== '$' && (flag
& DODOL
)) {
366 if (c
== HIST
&& (flag
& DOEXCL
)) {
377 tchar name
[MAX_VREF_LEN
];
383 tprintf("TRACE- getdol()\n");
385 np
= name
, *np
++ = '$';
386 c
= sc
= getC(DOEXCL
);
393 *np
++ = c
, c
= getC(DOEXCL
);
394 if (c
== '#' || c
== '?')
395 special
++, *np
++ = c
, c
= getC(DOEXCL
);
414 /* make sure the variable names are MAX_VAR_LEN chars or less */
415 while (digit(c
= getC(DOEXCL
)) && (np
- p
) < MAX_VAR_LEN
) {
418 } else if (letter(c
)) {
419 while ((letter(c
= getC(DOEXCL
)) || digit(c
)) &&
420 (np
- p
) < MAX_VAR_LEN
) {
427 if ((np
- p
) > MAX_VAR_LEN
)
429 seterr("Variable name too long");
442 /* need to leave space for possible modifiers */
443 if (np
>= &name
[MAX_VREF_LEN
- 8])
445 seterr("Variable reference too long");
453 *np
++ = c
, c
= getC(DOEXCL
);
455 *np
++ = c
, c
= getC(DOEXCL
);
457 if (!any(c
, S_htrqxe
))
475 seterr("Variable syntax");
486 tprintf("TRACE- addla()\n");
490 buf
= xalloc((len
+1) * sizeof (tchar
));
491 (void) strcpy_(buf
, lap
);
495 /* len+5 is allow 4 additional charecters just to be safe */
496 labuf
= xrealloc(labuf
, (len
+5) * sizeof (tchar
));
497 (void) strcpy_(labuf
, cp
);
499 (void) strcat_(labuf
, buf
);
513 struct wordent
*hp
, *ip
;
514 int left
, right
, dol
;
518 tprintf("TRACE- getexcl()\n");
535 for (ip
= hp
->next
->next
; ip
!= alhistt
; ip
= ip
->next
)
538 for (ip
= hp
->next
->next
; ip
!= hp
->prev
; ip
= ip
->next
)
540 left
= 0, right
= dol
;
542 ungetC('s'), unreadc(HISTSUB
), c
= ':';
546 /* if (!any(c, ":^$*-%")) */ /* change needed for char -> tchar */
547 if (! (c
== ':' || c
== '^' || c
== '$' || c
== '*' ||
548 c
== '-' || c
== '%'))
554 if (letter(c
) || c
== '&') {
556 left
= 0, right
= dol
;
561 if (!getsel(&left
, &right
, dol
))
567 if (!getsel(&left
, &right
, dol
))
572 exclc
= right
- left
+ 1;
575 if (sc
== HISTSUB
|| c
== ':') {
585 seterr("Bad ! form");
591 getsub(struct wordent
*en
)
598 tchar orhsb
[(sizeof rhsb
)/(sizeof rhsb
[0])];
601 tprintf("TRACE- getsub()\n");
606 global
++, c
= getC(0);
626 seterr("No prev sub");
629 (void) strcpy_(lhsb
, slhs
);
641 if (alnum(delim
) || isspnl(delim
)) {
645 seterr("Bad substitute");
657 if (cp
> &lhsb
[(sizeof lhsb
)/(sizeof lhsb
[0]) - 2])
661 if (c
!= delim
&& c
!= '\\')
668 else if (lhsb
[0] == 0) {
670 seterr("No prev lhs");
674 (void) strcpy_(orhsb
, cp
);
685 if (&cp
[strlen_(orhsb
)]
686 > &rhsb
[(sizeof rhsb
)/(sizeof rhsb
[0]) - 2])
688 (void) strcpy_(cp
, orhsb
);
693 if (cp
> &rhsb
[(sizeof rhsb
)/(sizeof rhsb
[0]) - 2]) {
695 seterr("Rhs too long");
700 if (c
!= delim
/* && c != '~' */)
711 seterrc(gettext("Bad ! modifier: "), c
);
714 (void) strcpy_(slhs
, lhsb
);
716 en
= dosub(sc
, en
, global
);
722 dosub(int sc
, struct wordent
*en
, bool global
)
726 struct wordent
*hp
= &lex
;
731 tprintf("TRACE- dosub()\n");
735 struct wordent
*new = (struct wordent
*)xcalloc(1, sizeof *wdp
);
742 wdp
->word
= global
|| didsub
== 0 ?
743 subword(en
->word
, sc
, &didsub
) : savestr(en
->word
);
746 seterr("Modifier failed");
748 return (&enthist(-1000, &lex
, 0)->Hlex
);
752 subword(tchar
*cp
, int type
, bool *adid
)
759 tprintf("TRACE- subword()\n");
769 wp
= domod(cp
, type
);
771 return (savestr(cp
));
778 for (mp
= cp
; *mp
; mp
++)
779 if (matchs(mp
, lhsb
)) {
780 for (np
= cp
; np
< mp
; )
782 for (np
= rhsb
; *np
; np
++) switch (*np
) {
800 (void) strcat_(wp
, lhsb
);
808 seterr("Subst buf ovflo");
809 return (S_
/* "" */);
812 (void) strcat_(wp
, mp
);
814 return (savestr(wbuf
));
816 return (savestr(cp
));
821 domod(tchar
*cp
, int type
)
827 tprintf("TRACE- domod()\n");
834 for (xp
= wp
; c
= *xp
; xp
++)
835 if (!issp(c
) || type
== 'q')
842 return (type
== 't' ? savestr(cp
) : 0);
847 xp
= savestr(cp
), xp
[wp
- cp
] = 0;
849 xp
= savestr(wp
+ 1);
855 for (wp
--; wp
>= cp
&& *wp
!= '/'; wp
--)
858 xp
= savestr(wp
+ 1);
860 xp
= savestr(cp
), xp
[wp
- cp
] = 0;
863 return (savestr(type
== 'e' ? S_
/* "" */ : cp
));
869 matchs(tchar
*str
, tchar
*pat
)
873 tprintf("TRACE- matchs()\n");
875 while (*str
&& *pat
&& *str
== *pat
)
881 getsel(int *al
, int *ar
, int dol
)
885 bool first
= *al
< 0;
888 tprintf("TRACE- getsel()\n");
935 i
= i
* 10 + c
- '0';
954 /* if (any(c, "-$*")) */ /* char -> tchar */
955 if (c
== '-' || c
== '$' || c
== '*')
958 if (*al
> *ar
|| *ar
> dol
) {
960 seterr("Bad ! arg selector");
977 tprintf("TRACE- gethent()\n");
979 c
= sc
== HISTSUB
? HIST
: getC(0);
994 if (lastev
== eventno
&& alhistp
)
1004 case '#': /* !# is command being typed in (mrh) */
1008 /* if (any(c, "(=~")) { */
1009 if (c
== '(' || c
== '=' || c
== '~') {
1017 /* while (!any(c, ": \t\\\n}")) { */
1018 while (! (c
== ':' || c
== '\\' || isspnl(c
) || c
== '}')) {
1019 if (np
< &lhsb
[(sizeof lhsb
)/(sizeof lhsb
[0]) - 2])
1029 hp
= findev(lhsb
, 0);
1044 if (np
< &lhsb
[(sizeof lhsb
)/(sizeof lhsb
[0]) - 2])
1049 seterr("No prev search");
1054 hp
= findev(lhsb
, 1);
1062 event
= event
* 10 + c
- '0';
1066 event
= eventno
+ (alhistp
== 0) - (event
? event
: 0);
1071 for (hp
= Histlist
.Hnext
; hp
; hp
= hp
->Hnext
)
1072 if (hp
->Hnum
== event
) {
1083 findev(tchar
*cp
, bool anyarg
)
1088 tprintf("TRACE- findev()\n");
1090 for (hp
= Histlist
.Hnext
; hp
; hp
= hp
->Hnext
) {
1093 struct wordent
*lp
= hp
->Hlex
.next
;
1096 if (lp
->word
[0] == '\n')
1104 while (*p
++ == *q
++);
1108 for (dp
= lp
->word
; *dp
; dp
++) {
1116 while (*p
++ == *q
++);
1120 } while (lp
->word
[0] != '\n');
1131 tprintf("TRACE- noev()\n");
1133 seterr2(cp
, ": Event not found");
1141 tprintf("TRACE- setexclp()\n");
1143 if (cp
&& cp
[0] == '\n')
1159 static int sincereal
;
1175 if (alvecp
= *alvec
) {
1179 /* Infinite source! */
1192 if (evalvec
== (tchar
**)1) {
1196 if (evalp
= *evalvec
) {
1200 evalvec
= (tchar
**)1;
1204 if (arginp
== (tchar
*) 1 || onelflg
== 1) {
1210 if ((c
= *arginp
++) == 0) {
1211 arginp
= (tchar
*) 1;
1223 /* was isatty but raw with ignoreeof yields problems */
1224 if (ioctl(SHIN
, TIOCGETP
, (char *)&tty
) == 0 &&
1225 (tty
.sg_flags
& RAW
) == 0) {
1226 /* was 'short' for FILEC */
1229 if (++sincereal
> 25)
1232 ioctl(FSHTTY
, TIOCGPGRP
, (char *)&ctpgrp
) == 0 &&
1234 (void) ioctl(FSHTTY
, TIOCSPGRP
,
1236 (void) killpg(ctpgrp
, SIGHUP
);
1237 printf("Reset tty pgrp from %d to %d\n", ctpgrp
, tpgrp
);
1240 if (adrof(S_ignoreeof
/* "ignoreeof" */)) {
1242 printf("\nUse \"logout\" to logout.\n");
1244 printf("\nUse \"exit\" to leave csh.\n");
1256 if (c
== '\n' && onelflg
)
1266 (tchar
**)xcalloc((unsigned)(fblocks
+ 2), sizeof (tchar
**));
1269 (void) blkcpy(nfbuf
, fbuf
);
1270 xfree((char *)fbuf
);
1273 fbuf
[fblocks
] = (tchar
*)xcalloc(BUFSIZ
+ MB_LEN_MAX
,
1283 tchar ttyline
[BUFSIZ
+ MB_LEN_MAX
]; /* read_() can return extra bytes */
1289 if (fseekp
< fbobp
|| fseekp
> feobp
) {
1290 fbobp
= feobp
= fseekp
;
1291 (void) lseek(SHIN
, fseekp
, 0);
1293 if (fseekp
== feobp
) {
1296 c
= read_(SHIN
, fbuf
[0], BUFSIZ
);
1297 while (c
< 0 && errno
== EINTR
);
1302 c
= fbuf
[0][fseekp
- fbobp
];
1308 buf
= (int)fseekp
/ BUFSIZ
;
1309 if (buf
>= fblocks
) {
1313 if (fseekp
>= feobp
) {
1314 buf
= (int)feobp
/ BUFSIZ
;
1315 off
= (int)feobp
% BUFSIZ
;
1318 c
= read_(SHIN
, fbuf
[buf
] + off
, BUFSIZ
- off
);
1320 roomleft
= BUFSIZ
- off
;
1322 if (filec
&& intty
) {
1323 c
= tenex(ttyline
, BUFSIZ
);
1326 copy(fbuf
[buf
] + off
, ttyline
,
1327 roomleft
* sizeof (tchar
));
1328 copy(fbuf
[buf
+ 1], ttyline
+ roomleft
,
1329 (c
- roomleft
) * sizeof (tchar
));
1331 copy(fbuf
[buf
] + off
, ttyline
,
1332 c
* sizeof (tchar
));
1335 c
= read_(SHIN
, fbuf
[buf
] + off
, roomleft
);
1339 fbuf
[buf
] + off
+ roomleft
,
1340 (c
- roomleft
) * sizeof (tchar
));
1346 if (errno
== EWOULDBLOCK
) {
1349 (void) ioctl(SHIN
, FIONBIO
, (char *)&off
);
1350 } else if (errno
!= EINTR
)
1359 if (filec
&& !intty
)
1363 c
= fbuf
[buf
][(int)fseekp
% BUFSIZ
];
1379 sb
= (int)(fseekp
- 1) / BUFSIZ
;
1381 for (i
= 0; i
< sb
; i
++)
1383 (void) blkcpy(fbuf
, &fbuf
[sb
]);
1384 fseekp
-= BUFSIZ
* sb
;
1385 feobp
-= BUFSIZ
* sb
;
1401 for (wp
= whyles
; wp
->w_next
; wp
= wp
->w_next
)
1403 if (wp
->w_start
> l
)
1410 /* any similarity to bell telephone is purely accidental */
1424 (void) lseek(SHIN
, (off_t
)0, 2);
1436 if (arginp
|| onelflg
|| intty
)
1438 if (lseek(SHIN
, (off_t
)0, 1) < 0 || errno
== ESPIPE
)
1440 fbuf
= (tchar
**)xcalloc(2, sizeof (tchar
**));
1442 fbuf
[0] = (tchar
*)xcalloc(BUFSIZ
+ MB_LEN_MAX
, sizeof (tchar
));
1443 fseekp
= fbobp
= feobp
= lseek(SHIN
, (off_t
)0, 1);