* Lexical and argument processing routines
* lex - driver for lexical analysis
* word - reads next word into line and pointer thereto via args
* getc - gets a character from the logical input stream
* readc - reads a character from the 'input device'
* setargs - sets up the parameter variables initially
* rewind - backs up the shell arguments to their original values
* setnargs - resets nargs variable after changes to arg list
* shift - manipulates the shell parameters
* lex is the driver routine for the lexical input of the shell.
* Basic strategy is to read a logical line into linebuf
* with successive words pointed to by successive elements of args.
* Termination condition is a newline.
* Returns a pointer to a linked list of the words.
register struct shvar2
*hp
;
register struct shvar2
*wdp
;
wdp
->next
= calloc(1, sizeof *wdp
);
} while (wdp
->value
[0] != '\n');
register struct shvar
*vp
;
register struct shvar
*fp
;
/* static */ char peekc
, peekx
;
* word breaks the input character stream into words.
* Blanks and tabs in the input are ignored, the characters
* are considered to be separators.
* Characters may be escaped here by surrounding them with
* 's or "s. This causes the QUOTE (high order) bit of the
* corresponding character to be set so the character will
* fail subsequent comparisons. The quoting is eventually
* stripped off. More quoting by QUOTE is also done in readc.
* Note importantly that quoted character strings do not undergo
* parameter substitution!
* Return value is a pointer to a structure containing the word.
* Loop to get something solid
while ((c
= echo(readc())) != c1
) {
seterr("Unmatched ' or \"");
* We have discovered something solid (not a separator).
* We want to gather in as many characters
* as possible but don't want to grab a separator.
* If we find another quotation in this word we go back to
if (any(c
, " '\"\t;&<>()|^\n")) {
seterr("Too many characters");
/* static */ struct shvar2 paramhd
, *paramp
, *dolnxt
;
* setargs sets up the initial argument linked list.
* paramp is a working pointer to the front of the list (actually
* one before the front), paramhd the actual origin which contains
* dolnxt is used in expanding $*.
* dolc is maintained by setnargs who also maintains the nargs variable
* dolp is the pointer into the expanding string in getc
register struct shvar2
*vp
, *lvp
;
vp
= calloc(1, sizeof *vp
);
* rewind the shell arguments
* set up nargs variable after a parameter list change
register struct shvar2
*vp
;
for (vp
= paramp
; vp
!= 0; vp
= vp
->next
)
set(n_args
, putn(dolc
- 1));
* shift the shell arguments
register struct shvar2
*vp
;
n
= *v
== 0 ? 1 : getn(*v
++);
for (vp
= paramp
; vp
&& n
;)
bferr(": Count too large");
/* static */ char dol2bra
;
* getc gets a character from the logical input stream.
* It handles parameter expansion via $[0-9], all parameters
* via $*, shell variables via $[A-Za-z], and the process number via $$.
* Also handled is the trimming of the sufficies from expanded
* names via the . notation. For example if $1 is "foo.p" then
* The variable dol2bra's value has the following meaning:
* 2 echo characters to : or }, if : discard chars to }
* -1 discard characters to }
* -2 discard characters to : or }, if : echo to }
* This handles the constructs
* ${name?str1:str2} name set -> str1 ; t -> str2
* ${name:default} name set -> $name ; t -> default
* ${name?string} name set -> strings ; t -> ""
if (c
&& (c
!= '.' || !doldot
|| any('.', dolp
)))
if (dolnxt
&& (dolnxt
= dolnxt
->next
)) {
if (c
== '{' || letter(c
)) {
register struct shvar
*vp
;
for (c
= readc(); letter(c
); c
= readc())
if (np
< &name
[sizeof name
- 1]) {
seterr("Variable syntax");
seterr("Undefined variable");
* read a character from the input device.
* this may be an argument e.g. for sh -c.
* also for sh -t stop after one line.
else if ((c
= *arginp
++) == '\0') {
else if (read(0, &cc
, 1) != 1) {
} else if ((c
= cc
) == '\n' && onelflg
)
register struct shvar
*tp
;
if (!digit(r
) || (r
=- '0') > dolc
)
for (tp
= paramp
; r
> 0; tp
= tp
->next
)
register struct shvar
*tp
;
return (tp
? tp
->value
: "");