version 1.23, 2000/11/24 14:29:55 |
version 1.24, 2001/05/03 13:41:05 |
|
|
|
/* $OpenPackages$ */ |
/* $OpenBSD$ */ |
/* $OpenBSD$ */ |
/* $NetBSD: for.c,v 1.4 1996/11/06 17:59:05 christos Exp $ */ |
/* $NetBSD: for.c,v 1.4 1996/11/06 17:59:05 christos Exp $ */ |
|
|
/* |
/* |
* Copyright (c) 1999 Marc Espie. |
* Copyright (c) 1999 Marc Espie. |
|
|
* Functions to handle loops in a makefile. |
* Functions to handle loops in a makefile. |
* |
* |
* Interface: |
* Interface: |
* For_Eval Evaluate the .for in the passed line |
* For_Eval Evaluate the .for in the passed line. |
* For_Accumulate Add lines to an accumulating loop |
* For_Accumulate Add lines to an accumulating loop |
* For_Run Run accumulated loop |
* For_Run Run accumulated loop |
* |
* |
*/ |
*/ |
|
|
|
|
/* |
/* |
* For statements are of the form: |
* For statements are of the form: |
* |
* |
* .for <variable> in <varlist> |
* .for <variable> [variable...] in <varlist> |
* ... |
* ... |
* .endfor |
* .endfor |
* |
* |
|
|
|
|
/* State of a for loop. */ |
/* State of a for loop. */ |
struct For_ { |
struct For_ { |
char *text; /* unexpanded text */ |
char *text; /* unexpanded text */ |
char *var; /* Index name */ |
LIST vars; /* list of variables */ |
LIST lst; /* List of items */ |
LstNode var; /* current var */ |
|
int nvars; /* total number of vars */ |
|
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 */ |
|
Boolean freeold; |
}; |
}; |
|
|
static void ForExec __P((void *, void *)); |
static void ForExec(void *, void *); |
static void build_words_list __P((Lst, const char *)); |
static unsigned long build_words_list(Lst, const char *); |
|
|
/* Cut a string into words, stuff that into list. */ |
/* Cut a string into words, stuff that into list. */ |
static void |
static unsigned long |
build_words_list(lst, s) |
build_words_list(lst, s) |
Lst lst; |
Lst lst; |
const char *s; |
const char *s; |
{ |
{ |
const char *end, *wrd; |
const char *end, *wrd; |
|
unsigned long n; |
|
|
|
n = 0; |
end = s; |
end = s; |
|
|
while ((wrd = iterate_words(&end)) != NULL) |
while ((wrd = iterate_words(&end)) != NULL) { |
Lst_AtFront(lst, escape_dup(wrd, end, "\"'")); |
Lst_AtFront(lst, escape_dup(wrd, end, "\"'")); |
|
n++; |
|
} |
|
return n; |
} |
} |
|
|
/* |
/* |
|
|
|
|
For * |
For * |
For_Eval(line) |
For_Eval(line) |
char *line; /* Line to parse */ |
const char *line; /* Line to parse */ |
{ |
{ |
char *ptr = line; |
const char *ptr = line; |
char *wrd; |
const char *wrd; |
char *sub; |
char *sub; |
char *endVar; |
const char *endVar; |
For *arg; |
For *arg; |
|
unsigned long n; |
|
|
for (ptr++; *ptr && isspace(*ptr); ptr++) |
|
continue; |
|
/* If we are not in a for loop quickly determine if the statement is |
/* If we are not in a for loop quickly determine if the statement is |
* a for. */ |
* a for. */ |
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || |
if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || |
|
|
|
|
/* We found a for loop, and now we are going to parse it. */ |
/* We found a for loop, and now we are going to parse it. */ |
|
|
/* Grab the variable. */ |
arg = emalloc(sizeof(*arg)); |
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++) |
arg->nvars = 0; |
continue; |
Lst_Init(&arg->vars); |
if (ptr - wrd == 0) { |
|
Parse_Error(PARSE_FATAL, "missing variable in for"); |
for (;;) { |
|
/* Grab the variables. */ |
|
for (wrd = ptr; *ptr && !isspace(*ptr); ptr++) |
|
continue; |
|
if (ptr - wrd == 0) { |
|
Parse_Error(PARSE_FATAL, "Syntax error in for"); |
|
return 0; |
|
} |
|
endVar = ptr++; |
|
while (*ptr && isspace(*ptr)) |
|
ptr++; |
|
/* finished variable list */ |
|
if (endVar - wrd == 2 && wrd[0] == 'i' && wrd[1] == 'n') |
|
break; |
|
Lst_AtEnd(&arg->vars, interval_dup(wrd, endVar)); |
|
arg->nvars++; |
|
} |
|
if (arg->nvars == 0) { |
|
Parse_Error(PARSE_FATAL, "Missing variable in for"); |
return 0; |
return 0; |
} |
} |
endVar = ptr++; |
|
|
|
while (*ptr && isspace(*ptr)) |
|
ptr++; |
|
|
|
/* Grab the `in'. */ |
|
if (ptr[0] != 'i' || ptr[1] != 'n' || |
|
!isspace(ptr[2])) { |
|
Parse_Error(PARSE_FATAL, "missing `in' in for"); |
|
printf("%s\n", ptr); |
|
return NULL; |
|
} |
|
ptr += 3; |
|
|
|
/* .for loop is go, collate what we need. */ |
|
arg = emalloc(sizeof(*arg)); |
|
arg->var = interval_dup(wrd, endVar); |
|
|
|
/* 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)) { |
(void)fprintf(stderr, "For: Iterator %s List %s\n", arg->var, sub); |
LstNode ln; |
|
(void)fprintf(stderr, "For: Iterator "); |
|
for (ln = Lst_First(&arg->vars); ln != NULL; ln = Lst_Adv(ln)) |
|
(void)fprintf(stderr, "%s ", (char *)Lst_Datum(ln)); |
|
(void)fprintf(stderr, "List %s\n", sub); |
|
} |
|
|
Lst_Init(&arg->lst); |
Lst_Init(&arg->lst); |
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) { |
|
Parse_Error(PARSE_FATAL, "Wrong number of items in for loop"); |
|
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; |
} |
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* For_Accumulate -- |
* For_Accumulate -- |
|
|
*/ |
*/ |
Boolean |
Boolean |
For_Accumulate(arg, line) |
For_Accumulate(arg, line) |
For *arg; |
For *arg; |
const char *line; /* Line to parse */ |
const char *line; /* Line to parse */ |
{ |
{ |
const char *ptr = line; |
const char *ptr = line; |
|
|
|
|
{ |
{ |
char *name = (char *)namep; |
char *name = (char *)namep; |
For *arg = (For *)argp; |
For *arg = (For *)argp; |
|
BUFFER buf; |
|
|
|
/* Parse_FromString pushes stuff back, so we need to go over vars in |
|
reverse. */ |
|
if (arg->var == NULL) { |
|
arg->var = Lst_Last(&arg->vars); |
|
arg->text = Buf_Retrieve(&arg->buf); |
|
arg->freeold = FALSE; |
|
} |
|
|
if (DEBUG(FOR)) |
if (DEBUG(FOR)) |
(void)fprintf(stderr, "--- %s = %s\n", arg->var, name); |
(void)fprintf(stderr, "--- %s = %s\n", (char *)Lst_Datum(arg->var), name); |
Parse_FromString(Var_SubstVar(arg->text, arg->var, name, |
Buf_Init(&buf, arg->guess); |
arg->guess), arg->lineno); |
Var_SubstVar(&buf, arg->text, Lst_Datum(arg->var), name); |
|
if (arg->freeold) |
|
free(arg->text); |
|
arg->text = Buf_Retrieve(&buf); |
|
arg->freeold = TRUE; |
|
arg->var = Lst_Rev(arg->var); |
|
if (arg->var == NULL) |
|
Parse_FromString(arg->text, arg->lineno); |
} |
} |
|
|
|
|
/*- |
/*- |
*----------------------------------------------------------------------- |
*----------------------------------------------------------------------- |
* For_Run -- |
* For_Run -- |
|
|
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; |
Lst_ForEach(&arg->lst, ForExec, arg); |
Lst_ForEach(&arg->lst, ForExec, arg); |
free(arg->var); |
Buf_Destroy(&arg->buf); |
free(arg->text); |
Lst_Destroy(&arg->vars, (SimpleProc)free); |
Lst_Destroy(&arg->lst, (SimpleProc)free); |
Lst_Destroy(&arg->lst, (SimpleProc)free); |
free(arg); |
free(arg); |
} |
} |