version 1.35, 2007/07/24 18:58:48 |
version 1.36, 2007/07/24 23:29:49 |
|
|
|
|
/* State of a for loop. */ |
/* State of a for loop. */ |
struct For_ { |
struct For_ { |
char *text; /* Unexpanded text */ |
char *text; /* Unexpanded text */ |
LIST vars; /* List of variables */ |
LIST vars; /* List of variables */ |
LstNode var; /* Current var */ |
LstNode var; /* Current var */ |
int nvars; /* Total number of vars */ |
int nvars; /* Total number of vars */ |
LIST lst; /* List of items */ |
LIST lst; /* List of items */ |
size_t guess; /* Estimated expansion size */ |
size_t guess; /* Estimated expansion size */ |
BUFFER buf; /* Accumulating text */ |
BUFFER buf; /* Accumulating text */ |
unsigned long lineno; /* Line number at start of loop */ |
unsigned long lineno; /* Line number at start of loop */ |
unsigned long level; /* Nesting level */ |
unsigned long level; /* Nesting level */ |
bool freeold; |
bool freeold; |
}; |
}; |
|
|
/* ForExec(value, handle); |
/* ForExec(value, handle); |
|
|
static unsigned long |
static unsigned long |
build_words_list(Lst lst, const char *s) |
build_words_list(Lst lst, const char *s) |
{ |
{ |
const char *end, *wrd; |
const char *end, *wrd; |
unsigned long n; |
unsigned long n; |
|
|
n = 0; |
n = 0; |
end = s; |
end = s; |
|
|
while ((wrd = iterate_words(&end)) != NULL) { |
while ((wrd = iterate_words(&end)) != NULL) { |
Lst_AtFront(lst, escape_dupi(wrd, end, "\"'")); |
Lst_AtFront(lst, escape_dupi(wrd, end, "\"'")); |
n++; |
n++; |
} |
} |
return n; |
return n; |
} |
} |
|
|
For * |
For * |
For_Eval(const char *line) |
For_Eval(const char *line) |
{ |
{ |
const char *ptr = line; |
const char *ptr = line; |
const char *wrd; |
const char *wrd; |
char *sub; |
char *sub; |
const char *endVar; |
const char *endVar; |
For *arg; |
For *arg; |
unsigned long n; |
unsigned long n; |
|
|
while (isspace(*ptr)) |
while (isspace(*ptr)) |
ptr++; |
ptr++; |
|
|
/* Parse loop. */ |
/* Parse loop. */ |
|
|
arg = emalloc(sizeof(*arg)); |
arg = emalloc(sizeof(*arg)); |
arg->nvars = 0; |
arg->nvars = 0; |
Lst_Init(&arg->vars); |
Lst_Init(&arg->vars); |
|
|
for (;;) { |
for (;;) { |
/* Grab the variables. */ |
/* Grab the variables. */ |
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++) |
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++) |
continue; |
continue; |
if (ptr - wrd == 0) { |
if (ptr - wrd == 0) { |
Parse_Error(PARSE_FATAL, "Syntax error in for"); |
Parse_Error(PARSE_FATAL, "Syntax error in for"); |
return 0; |
return 0; |
|
} |
|
endVar = ptr++; |
|
while (isspace(*ptr)) |
|
ptr++; |
|
/* End of variable list ? */ |
|
if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n') |
|
break; |
|
Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar)); |
|
arg->nvars++; |
} |
} |
endVar = ptr++; |
if (arg->nvars == 0) { |
while (isspace(*ptr)) |
Parse_Error(PARSE_FATAL, "Missing variable in for"); |
ptr++; |
return 0; |
/* End of variable list ? */ |
} |
if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n') |
|
break; |
|
Lst_AtEnd(&arg->vars, Var_NewLoopVar(wrd, endVar)); |
|
arg->nvars++; |
|
} |
|
if (arg->nvars == 0) { |
|
Parse_Error(PARSE_FATAL, "Missing variable in for"); |
|
return 0; |
|
} |
|
|
|
/* Make a list with the remaining words. */ |
/* Make a list with the remaining words. */ |
sub = Var_Subst(ptr, NULL, false); |
sub = Var_Subst(ptr, NULL, false); |
if (DEBUG(FOR)) { |
if (DEBUG(FOR)) { |
LstNode ln; |
LstNode ln; |
(void)fprintf(stderr, "For: Iterator "); |
(void)fprintf(stderr, "For: Iterator "); |
for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln)) |
for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln)) |
(void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln)); |
(void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln)); |
(void)fprintf(stderr, "List %s\n", sub); |
(void)fprintf(stderr, "List %s\n", sub); |
} |
} |
|
|
Lst_Init(&arg->lst); |
Lst_Init(&arg->lst); |
n = build_words_list(&arg->lst, sub); |
n = build_words_list(&arg->lst, sub); |
free(sub); |
free(sub); |
if (arg->nvars != 1 && n % arg->nvars != 0) { |
if (arg->nvars != 1 && n % arg->nvars != 0) { |
Parse_Error(PARSE_FATAL, "Wrong number of items in for loop"); |
Parse_Error(PARSE_FATAL, "Wrong number of items in for loop"); |
return 0; |
return 0; |
} |
} |
arg->lineno = Parse_Getlineno(); |
arg->lineno = Parse_Getlineno(); |
arg->level = 1; |
arg->level = 1; |
Buf_Init(&arg->buf, 0); |
Buf_Init(&arg->buf, 0); |
|
|
return arg; |
return arg; |
} |
} |
|
|
|
|
bool |
bool |
For_Accumulate(For *arg, const char *line) |
For_Accumulate(For *arg, const char *line) |
{ |
{ |
const char *ptr = line; |
const char *ptr = line; |
|
|
assert(arg->level > 0); |
assert(arg->level > 0); |
|
|
if (*ptr == '.') { |
if (*ptr == '.') { |
|
|
for (ptr++; isspace(*ptr); ptr++) |
for (ptr++; isspace(*ptr); ptr++) |
continue; |
continue; |
|
|
if (strncmp(ptr, "endfor", 6) == 0 && |
if (strncmp(ptr, "endfor", 6) == 0 && |
(isspace(ptr[6]) || !ptr[6])) { |
(isspace(ptr[6]) || !ptr[6])) { |
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void)fprintf(stderr, "For: end for %lu\n", arg->level); |
(void)fprintf(stderr, "For: end for %lu\n", |
/* If matching endfor, don't add line to buffer. */ |
arg->level); |
if (--arg->level == 0) |
/* If matching endfor, don't add line to buffer. */ |
return false; |
if (--arg->level == 0) |
|
return false; |
|
} |
|
else if (strncmp(ptr, "for", 3) == 0 && |
|
isspace(ptr[3])) { |
|
arg->level++; |
|
if (DEBUG(FOR)) |
|
(void)fprintf(stderr, "For: new loop %lu\n", |
|
arg->level); |
|
} |
} |
} |
else if (strncmp(ptr, "for", 3) == 0 && |
Buf_AddString(&arg->buf, line); |
isspace(ptr[3])) { |
Buf_AddChar(&arg->buf, '\n'); |
arg->level++; |
return true; |
if (DEBUG(FOR)) |
|
(void)fprintf(stderr, "For: new loop %lu\n", arg->level); |
|
} |
|
} |
|
Buf_AddString(&arg->buf, line); |
|
Buf_AddChar(&arg->buf, '\n'); |
|
return true; |
|
} |
} |
|
|
|
|
|
|
static void |
static void |
ForExec(void *valuep, void *argp) |
ForExec(void *valuep, void *argp) |
{ |
{ |
char *value = (char *)valuep; |
char *value = (char *)valuep; |
For *arg = (For *)argp; |
For *arg = (For *)argp; |
BUFFER buf; |
BUFFER buf; |
|
|
/* Parse_FromString pushes stuff back, so we need to go over vars in |
/* Parse_FromString pushes stuff back, so we need to go over vars in |
reverse. */ |
reverse. */ |
if (arg->var == NULL) { |
if (arg->var == NULL) { |
arg->var = Lst_Last(&arg->vars); |
arg->var = Lst_Last(&arg->vars); |
arg->text = Buf_Retrieve(&arg->buf); |
arg->text = Buf_Retrieve(&arg->buf); |
arg->freeold = false; |
arg->freeold = false; |
} |
} |
|
|
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void)fprintf(stderr, "--- %s = %s\n", (char *)Lst_Datum(arg->var), |
(void)fprintf(stderr, "--- %s = %s\n", |
value); |
(char *)Lst_Datum(arg->var), value); |
Buf_Init(&buf, arg->guess); |
Buf_Init(&buf, arg->guess); |
Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value); |
Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), value); |
if (arg->freeold) |
if (arg->freeold) |
free(arg->text); |
free(arg->text); |
arg->text = Buf_Retrieve(&buf); |
arg->text = Buf_Retrieve(&buf); |
arg->freeold = true; |
arg->freeold = true; |
arg->var = Lst_Rev(arg->var); |
arg->var = Lst_Rev(arg->var); |
if (arg->var == NULL) |
if (arg->var == NULL) |
Parse_FromString(arg->text, arg->lineno); |
Parse_FromString(arg->text, arg->lineno); |
} |
} |
|
|
|
|
void |
void |
For_Run(For *arg) |
For_Run(For *arg) |
{ |
{ |
arg->text = Buf_Retrieve(&arg->buf); |
arg->text = Buf_Retrieve(&arg->buf); |
arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION; |
arg->guess = Buf_Size(&arg->buf) + GUESS_EXPANSION; |
|
|
arg->var = NULL; |
arg->var = NULL; |
Lst_ForEach(&arg->lst, ForExec, arg); |
Lst_ForEach(&arg->lst, ForExec, arg); |
Buf_Destroy(&arg->buf); |
Buf_Destroy(&arg->buf); |
Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar); |
Lst_Destroy(&arg->vars, (SimpleProc)Var_DeleteLoopVar); |
Lst_Destroy(&arg->lst, (SimpleProc)free); |
Lst_Destroy(&arg->lst, (SimpleProc)free); |
free(arg); |
free(arg); |
} |
} |