]> CyberLeo.Net >> Repos - FreeBSD/releng/8.1.git/blob - usr.bin/make/for.c
Copy stable/8 to releng/8.1 in preparation for 8.1-RC1.
[FreeBSD/releng/8.1.git] / usr.bin / make / for.c
1 /*-
2  * Copyright (c) 1993
3  *      The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Christos Zoulas.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  * @(#)for.c    8.1 (Berkeley) 6/6/93
33  */
34
35 #include <sys/cdefs.h>
36 __FBSDID("$FreeBSD$");
37
38 /*-
39  * for.c --
40  *      Functions to handle loops in a makefile.
41  *
42  * Interface:
43  *      For_Eval        Evaluate the loop in the passed line.
44  *      For_Run         Run accumulated loop
45  *
46  */
47
48 #include <ctype.h>
49 #include <stdlib.h>
50 #include <string.h>
51
52 #include "buf.h"
53 #include "dir.h"
54 #include "for.h"
55 #include "globals.h"
56 #include "lst.h"
57 #include "make.h"
58 #include "parse.h"
59 #include "str.h"
60 #include "util.h"
61 #include "var.h"
62
63 /*
64  * For statements are of the form:
65  *
66  * .for <variable> in <varlist>
67  * ...
68  * .endfor
69  *
70  * The trick is to look for the matching end inside for for loop
71  * To do that, we count the current nesting level of the for loops.
72  * and the .endfor statements, accumulating all the statements between
73  * the initial .for loop and the matching .endfor;
74  * then we evaluate the for loop for each variable in the varlist.
75  */
76
77 static int      forLevel = 0;   /* Nesting level */
78 static char     *forVar;        /* Iteration variable */
79 static Buffer   *forBuf;        /* Commands in loop */
80 static Lst      forLst;         /* List of items */
81
82 /**
83  * For_For
84  *      Evaluate the for loop in the passed line. The line
85  *      looks like this:
86  *          .for <variable> in <varlist>
87  *      The line pointer points just behind the for.
88  *
89  * Results:
90  *      TRUE: Syntax ok.
91  *      FALSE: Syntax error.
92  */
93 Boolean
94 For_For(char *line)
95 {
96         char    *ptr;
97         char    *wrd;
98         char    *sub;
99         Buffer  *buf;
100         size_t  varlen;
101         int     i;
102         ArgArray words;
103
104         ptr = line;
105
106         /*
107          * Skip space between for and the variable.
108          */
109         for (ptr++; *ptr && isspace((u_char)*ptr); ptr++)
110                 ;
111
112         /*
113          * Grab the variable
114          */
115         for (wrd = ptr; *ptr && !isspace((u_char)*ptr); ptr++)
116                 ;
117
118         buf = Buf_Init(0);
119         Buf_AppendRange(buf, wrd, ptr);
120         forVar = Buf_GetAll(buf, &varlen);
121
122         if (varlen == 0) {
123                 Buf_Destroy(buf, TRUE);
124                 Parse_Error(PARSE_FATAL, "missing variable in for");
125                 return (FALSE);
126         }
127         Buf_Destroy(buf, FALSE);
128
129         /*
130          * Skip to 'in'.
131          */
132         while (*ptr && isspace((u_char)*ptr))
133                 ptr++;
134
135         /*
136          * Grab the `in'
137          */
138         if (ptr[0] != 'i' || ptr[1] != 'n' || !isspace((u_char)ptr[2])) {
139                 free(forVar);
140                 Parse_Error(PARSE_FATAL, "missing `in' in for");
141                 fprintf(stderr, "%s\n", ptr);
142                 return (FALSE);
143         }
144         ptr += 3;
145
146         /*
147          * Skip to values
148          */
149         while (*ptr && isspace((u_char)*ptr))
150                 ptr++;
151
152         /*
153          * Make a list with the remaining words
154          */
155         sub = Buf_Peel(Var_Subst(ptr, VAR_CMD, FALSE));
156         brk_string(&words, sub, FALSE);
157         Lst_Init(&forLst);
158         for (i = 1; i < words.argc; i++) {
159                 if (words.argv[i][0] != '\0')
160                         Lst_AtFront(&forLst, estrdup(words.argv[i]));
161         }
162         ArgArray_Done(&words);
163         DEBUGF(FOR, ("For: Iterator %s List %s\n", forVar, sub));
164         free(sub);
165
166         forBuf = Buf_Init(0);
167         forLevel++;
168         return (TRUE);
169 }
170
171 /**
172  * For_Eval
173  *      Eat a line of the .for body looking for embedded .for loops
174  *      and the .endfor
175  */
176 Boolean
177 For_Eval(char *line)
178 {
179         char *ptr;
180
181         ptr = line;
182
183         if (*ptr == '.') {
184                 /*
185                  * Need to check for 'endfor' and 'for' to find the end
186                  * of our loop or to find embedded for loops.
187                  */
188                 for (ptr++; *ptr != '\0' && isspace((u_char)*ptr); ptr++)
189                         ;
190
191                 /* XXX the isspace is wrong */
192                 if (strncmp(ptr, "endfor", 6) == 0 &&
193                     (isspace((u_char)ptr[6]) || ptr[6] == '\0')) {
194                         DEBUGF(FOR, ("For: end for %d\n", forLevel));
195                         if (forLevel == 0) {
196                                 /* should not be here */
197                                 abort();
198                         }
199                         forLevel--;
200
201                 } else if (strncmp(ptr, "for", 3) == 0 &&
202                     isspace((u_char)ptr[3])) {
203                         forLevel++;
204                         DEBUGF(FOR, ("For: new loop %d\n", forLevel));
205                 }
206         }
207
208         if (forLevel != 0) {
209                 /*
210                  * Still in loop - append the line
211                  */
212                 Buf_Append(forBuf, line);
213                 Buf_AddByte(forBuf, (Byte)'\n');
214                 return (TRUE);
215         }
216
217         return (FALSE);
218 }
219
220 /*-
221  *-----------------------------------------------------------------------
222  * For_Run --
223  *      Run the for loop, immitating the actions of an include file
224  *
225  * Results:
226  *      None.
227  *
228  * Side Effects:
229  *      The values of the variables forLst, forVar and forBuf are freed.
230  *
231  *-----------------------------------------------------------------------
232  */
233 void
234 For_Run(int lineno)
235 {
236         Lst             values; /* list of values for the variable */
237         char            *var;   /* the variable's name */
238         Buffer          *buf;   /* the contents of the for loop */
239         const char      *val;   /* current value of loop variable */
240         LstNode         *ln;
241         char            *str;
242
243         if (forVar == NULL || forBuf == NULL)
244                 return;
245
246         /* copy the global variables to have them free for embedded fors */
247         var = forVar;
248         buf = forBuf;
249         Lst_Init(&values);
250         Lst_Concat(&values, &forLst, LST_CONCLINK);
251
252         forVar = NULL;
253         forBuf = NULL;
254
255         LST_FOREACH(ln, &values) {
256                 val = Lst_Datum(ln);
257                 Var_SetGlobal(var, val);
258
259                 DEBUGF(FOR, ("--- %s = %s\n", var, val));
260                 str = Buf_Peel(Var_SubstOnly(var, Buf_Data(buf), FALSE));
261
262                 Parse_FromString(str, lineno);
263                 Var_Delete(var, VAR_GLOBAL);
264         }
265
266         free(var);
267         Lst_Destroy(&values, free);
268         Buf_Destroy(buf, TRUE);
269 }