/* glom.c: builds an argument list out of words, variables, etc. */
static List
*backq(Node
*, Node
*);
static List
*bqinput(List
*, int);
static List
*count(List
*);
static List
*mkcmdarg(Node
*);
extern List
*word(char *w
, char *m
) {
Append list s2 to list s1 by copying s1 and making the new copy
extern List
*append(List
*s1
, List
*s2
) {
for (r
= top
= nnew(List
); 1; r
= r
->n
= nnew(List
)) {
if ((s1
= s1
->n
) == NULL
)
extern List
*concat(List
*s1
, List
*s2
) {
if ((n1
= listnel(s1
)) != (n2
= listnel(s2
)) && n1
!= 1 && n2
!= 1)
rc_error("bad concatenation");
for (r
= top
= nnew(List
); 1; r
= r
->n
= nnew(List
)) {
size_t x
= strlen(s1
->w
);
size_t y
= strlen(s2
->w
);
if (s1
->m
== NULL
&& s2
->m
== NULL
) {
memcpy(&r
->m
[x
], s2
->m
, y
);
if (s1
== NULL
|| s2
== NULL
|| (n1
== 1 && n2
== 1))
extern List
*varsub(List
*var
, List
*subs
) {
for (top
= r
= NULL
; subs
!= NULL
; subs
= subs
->n
) {
rc_error("bad subscript");
sub
= sub
->n
; /* loop until sub == var(i) */
extern List
*flatten(List
*s
) {
if (s
== NULL
|| s
->n
== NULL
)
f
= r
->w
= nalloc(listlen(s
) + 1);
r
->m
= NULL
; /* flattened lists come from variables, so no meta */
static List
*count(List
*l
) {
s
->w
= nprint("%d", listnel(l
));
extern void assign(List
*s1
, List
*s2
, bool stack
) {
rc_error("null variable name");
rc_error("multi-word variable name");
rc_error("zero-length variable name");
rc_error("numeric variable name");
if (strchr(s1
->w
, '=') != NULL
)
rc_error("'=' in variable name");
if (*s1
->w
== '*' && s1
->w
[1] == '\0')
val
= append(varlookup("0"), s2
); /* preserve $0 when * is assigned explicitly */
if (s2
!= NULL
|| stack
) {
prettyprint_var(2, s1
->w
, val
);
varassign(s1
->w
, val
, stack
);
alias(s1
->w
, varlookup(s1
->w
), stack
);
prettyprint_var(2, s1
->w
, NULL
);
The following two functions are by the courtesy of Paul Haahr,
who could not stand the incompetence of my own backquote implementation.
#define BUFSIZE ((size_t) 1000)
static List
*bqinput(List
*ifs
, int fd
) {
int n
, state
; /* a simple FSA is used to read in data */
clear(isifs
, sizeof isifs
);
for (isifs
['\0'] = TRUE
; ifs
!= NULL
; ifs
= ifs
->n
)
for (s
= ifs
->w
; *s
!= '\0'; s
++)
isifs
[*(unsigned char *)s
] = TRUE
;
remain
= bufsize
= BUFSIZE
;
r
->w
= end
= nalloc(bufsize
+ 1);
if (remain
== 0) { /* is the string bigger than the buffer? */
while (bufsize
< m
+ BUFSIZE
)
buf
= nalloc(bufsize
+ 1);
if ((n
= rc_read(fd
, end
, remain
)) <= 0) {
uerror("backquote read");
for (bufend
= &end
[n
]; end
< bufend
; end
++)
if (!isifs
[*(unsigned char *)end
]) {
if (isifs
[*(unsigned char *)end
]) {
if (state
== 1) { /* terminate last string */
if (prev
== NULL
) /* no input at all? */
prev
->n
= NULL
; /* else terminate list */
static List
*backq(Node
*ifs
, Node
*n
) {
if ((pid
= rc_fork()) == 0) {
bq
= bqinput(glom(ifs
), p
[0]);
rc_wait4(pid
, &sp
, TRUE
);
extern void qredir(Node
*n
) {
next
= redirq
= nnew(Rq
);
for (next
= redirq
; next
->n
!= NULL
; next
= next
->n
)
static List
*mkcmdarg(Node
*n
) {
Estack
*e
= nnew(Estack
);
if (mvfd(p
[n
->u
[0].i
== rFrom
], n
->u
[0].i
== rFrom
) < 0) /* stupid hack */
close(p
[n
->u
[0].i
!= rFrom
]);
name
= nprint("/dev/fd/%d", p
[n
->u
[0].i
!= rFrom
]);
efd
.fd
= p
[n
->u
[0].i
!= rFrom
];
close(p
[n
->u
[0].i
== rFrom
]);
extern List
*glom(Node
*n
) {
while (words
!= NULL
&& (words
->type
== nArgs
|| words
->type
== nLappend
)) {
if (words
->u
[1].p
!= NULL
&& words
->u
[1].p
->type
!= nWord
&& words
->u
[1].p
->type
!= nQword
)
head
= glom(words
->u
[1].p
);
v
= append(glom(words
), tail
); /* force left to right evaluation */
return append(v
, glom(n
->u
[1].p
));
return backq(n
->u
[0].p
, n
->u
[1].p
);
head
= glom(n
->u
[0].p
); /* force left-to-right evaluation */
return concat(head
, glom(n
->u
[1].p
));
return word(n
->u
[0].s
, n
->u
[1].s
);
The next four operations depend on the left-child of glom
to be a variable name. Therefore the variable is looked up
if ((v
= glom(n
->u
[0].p
)) == NULL
)
rc_error("null variable name");
rc_error("multi-word variable name");
rc_error("zero-length variable name");
v
= (*v
->w
== '*' && v
->w
[1] == '\0') ? varlookup(v
->w
)->n
: varlookup(v
->w
);
panic("unexpected node in glom");
return varsub(v
, glom(n
->u
[1].p
));