Changeset 51 in kBuild
- Timestamp:
- Apr 7, 2003 1:30:32 AM (21 years ago)
- Location:
- trunk/src
- Files:
-
- 21 edited
-
kmk/buf.c (modified) (24 diffs)
-
kmk/compat.c (modified) (22 diffs)
-
kmk/cond.c (modified) (42 diffs)
-
kmk/config.h (modified) (7 diffs)
-
kmk/dir.c (modified) (38 diffs)
-
kmk/for.c (modified) (11 diffs)
-
kmk/hash.c (modified) (17 diffs)
-
kmk/helpers.c (modified) (6 diffs)
-
kmk/job.c (modified) (88 diffs)
-
kmk/job.h (modified) (8 diffs)
-
kmk/main.c (modified) (24 diffs)
-
kmk/make.c (modified) (32 diffs)
-
kmk/make.h (modified) (15 diffs)
-
kmk/nonints.h (modified) (4 diffs)
-
kmk/parse.c (modified) (89 diffs)
-
kmk/str.c (modified) (14 diffs)
-
kmk/suff.c (modified) (85 diffs)
-
kmk/targ.c (modified) (27 diffs)
-
kmk/util.c (modified) (12 diffs)
-
kmk/var.c (modified) (74 diffs)
-
makefile.os2.icc.mk (modified) (7 diffs)
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/kmk/buf.c
r35 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93";41 static char sccsid[] = "@(#)buf.c 8.1 (Berkeley) 6/6/93"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/buf.c,v 1.11 1999/09/11 13:08:01 hoek Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * buf.c -- 50 * Functions for automatically-expanded buffers.51 * Functions for automatically-expanded buffers. 51 52 */ 52 53 … … 61 62 /* 62 63 * BufExpand -- 63 * Expand the given buffer to hold the given number of additional64 * bytes.65 * Makes sure there's room for an extra NULL byte at the end of the66 * buffer in case it holds a string.64 * Expand the given buffer to hold the given number of additional 65 * bytes. 66 * Makes sure there's room for an extra NULL byte at the end of the 67 * buffer in case it holds a string. 67 68 */ 68 69 #define BufExpand(bp,nb) \ 69 if (bp->left < (nb)+1) {\70 int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \71 Byte *newBuf = (Byte *) erealloc((bp)->buffer, newSize); \72 \73 (bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \74 (bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\75 (bp)->buffer = newBuf;\76 (bp)->size = newSize;\77 (bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);\78 }79 80 #define BUF_DEF_SIZE 256/* Default buffer size */81 #define BUF_ADD_INC 256/* Expansion increment when Adding */82 #define BUF_UNGET_INC 16/* Expansion increment when Ungetting */70 if (bp->left < (nb)+1) {\ 71 int newSize = (bp)->size + max((nb)+1,BUF_ADD_INC); \ 72 Byte *newBuf = (Byte *) erealloc((bp)->buffer, newSize); \ 73 \ 74 (bp)->inPtr = newBuf + ((bp)->inPtr - (bp)->buffer); \ 75 (bp)->outPtr = newBuf + ((bp)->outPtr - (bp)->buffer);\ 76 (bp)->buffer = newBuf;\ 77 (bp)->size = newSize;\ 78 (bp)->left = newSize - ((bp)->inPtr - (bp)->buffer);\ 79 } 80 81 #define BUF_DEF_SIZE 256 /* Default buffer size */ 82 #define BUF_ADD_INC 256 /* Expansion increment when Adding */ 83 #define BUF_UNGET_INC 16 /* Expansion increment when Ungetting */ 83 84 84 85 /*- 85 86 *----------------------------------------------------------------------- 86 87 * Buf_OvAddByte -- 87 * Add a single byte to the buffer. left is zero or negative.88 * 89 * Results: 90 * None.91 * 92 * Side Effects: 93 * The buffer may be expanded.88 * Add a single byte to the buffer. left is zero or negative. 89 * 90 * Results: 91 * None. 92 * 93 * Side Effects: 94 * The buffer may be expanded. 94 95 * 95 96 *----------------------------------------------------------------------- … … 117 118 *----------------------------------------------------------------------- 118 119 * Buf_AddBytes -- 119 * Add a number of bytes to the buffer.120 * 121 * Results: 122 * None.123 * 124 * Side Effects: 125 * Guess what?120 * Add a number of bytes to the buffer. 121 * 122 * Results: 123 * None. 124 * 125 * Side Effects: 126 * Guess what? 126 127 * 127 128 *----------------------------------------------------------------------- … … 130 131 Buf_AddBytes (bp, numBytes, bytesPtr) 131 132 register Buffer bp; 132 int numBytes;133 int numBytes; 133 134 const Byte *bytesPtr; 134 135 { … … 150 151 *----------------------------------------------------------------------- 151 152 * Buf_UngetByte -- 152 * Place the byte back at the beginning of the buffer.153 * 154 * Results: 155 * SUCCESS if the byte was added ok. FAILURE if not.156 * 157 * Side Effects: 158 * The byte is stuffed in the buffer and outPtr is decremented.153 * Place the byte back at the beginning of the buffer. 154 * 155 * Results: 156 * SUCCESS if the byte was added ok. FAILURE if not. 157 * 158 * Side Effects: 159 * The byte is stuffed in the buffer and outPtr is decremented. 159 160 * 160 161 *----------------------------------------------------------------------- … … 167 168 168 169 if (bp->outPtr != bp->buffer) { 169 bp->outPtr--;170 *bp->outPtr = byte;170 bp->outPtr--; 171 *bp->outPtr = byte; 171 172 } else if (bp->outPtr == bp->inPtr) { 172 *bp->inPtr = byte;173 bp->inPtr++;174 bp->left--;175 *bp->inPtr = 0;173 *bp->inPtr = byte; 174 bp->inPtr++; 175 bp->left--; 176 *bp->inPtr = 0; 176 177 } else { 177 /*178 * Yech. have to expand the buffer to stuff this thing in.179 * We use a different expansion constant because people don't180 * usually push back many bytes when they're doing it a byte at181 * a time...182 */183 intnumBytes = bp->inPtr - bp->outPtr;184 Byte*newBuf;185 186 newBuf = (Byte *)emalloc(bp->size + BUF_UNGET_INC);187 memcpy ((char *)(newBuf+BUF_UNGET_INC), (char *)bp->outPtr, numBytes+1);188 bp->outPtr = newBuf + BUF_UNGET_INC;189 bp->inPtr = bp->outPtr + numBytes;190 efree ((char *)bp->buffer);191 bp->buffer = newBuf;192 bp->size += BUF_UNGET_INC;193 bp->left = bp->size - (bp->inPtr - bp->buffer);194 bp->outPtr -= 1;195 *bp->outPtr = byte;178 /* 179 * Yech. have to expand the buffer to stuff this thing in. 180 * We use a different expansion constant because people don't 181 * usually push back many bytes when they're doing it a byte at 182 * a time... 183 */ 184 int numBytes = bp->inPtr - bp->outPtr; 185 Byte *newBuf; 186 187 newBuf = (Byte *)emalloc(bp->size + BUF_UNGET_INC); 188 memcpy ((char *)(newBuf+BUF_UNGET_INC), (char *)bp->outPtr, numBytes+1); 189 bp->outPtr = newBuf + BUF_UNGET_INC; 190 bp->inPtr = bp->outPtr + numBytes; 191 efree ((char *)bp->buffer); 192 bp->buffer = newBuf; 193 bp->size += BUF_UNGET_INC; 194 bp->left = bp->size - (bp->inPtr - bp->buffer); 195 bp->outPtr -= 1; 196 *bp->outPtr = byte; 196 197 } 197 198 } … … 201 202 *----------------------------------------------------------------------- 202 203 * Buf_UngetBytes -- 203 * Push back a series of bytes at the beginning of the buffer.204 * 205 * Results: 206 * None.207 * 208 * Side Effects: 209 * outPtr is decremented and the bytes copied into the buffer.204 * Push back a series of bytes at the beginning of the buffer. 205 * 206 * Results: 207 * None. 208 * 209 * Side Effects: 210 * outPtr is decremented and the bytes copied into the buffer. 210 211 * 211 212 *----------------------------------------------------------------------- … … 214 215 Buf_UngetBytes (bp, numBytes, bytesPtr) 215 216 register Buffer bp; 216 int numBytes;217 int numBytes; 217 218 Byte *bytesPtr; 218 219 { 219 220 220 221 if (bp->outPtr - bp->buffer >= numBytes) { 221 bp->outPtr -= numBytes;222 memcpy (bp->outPtr, bytesPtr, numBytes);222 bp->outPtr -= numBytes; 223 memcpy (bp->outPtr, bytesPtr, numBytes); 223 224 } else if (bp->outPtr == bp->inPtr) { 224 Buf_AddBytes (bp, numBytes, bytesPtr);225 Buf_AddBytes (bp, numBytes, bytesPtr); 225 226 } else { 226 intcurNumBytes = bp->inPtr - bp->outPtr;227 Byte*newBuf;228 intnewBytes = max(numBytes,BUF_UNGET_INC);229 230 newBuf = (Byte *)emalloc (bp->size + newBytes);231 memcpy((char *)(newBuf+newBytes), (char *)bp->outPtr, curNumBytes+1);232 bp->outPtr = newBuf + newBytes;233 bp->inPtr = bp->outPtr + curNumBytes;234 efree ((char *)bp->buffer);235 bp->buffer = newBuf;236 bp->size += newBytes;237 bp->left = bp->size - (bp->inPtr - bp->buffer);238 bp->outPtr -= numBytes;239 memcpy ((char *)bp->outPtr, (char *)bytesPtr, numBytes);227 int curNumBytes = bp->inPtr - bp->outPtr; 228 Byte *newBuf; 229 int newBytes = max(numBytes,BUF_UNGET_INC); 230 231 newBuf = (Byte *)emalloc (bp->size + newBytes); 232 memcpy((char *)(newBuf+newBytes), (char *)bp->outPtr, curNumBytes+1); 233 bp->outPtr = newBuf + newBytes; 234 bp->inPtr = bp->outPtr + curNumBytes; 235 efree ((char *)bp->buffer); 236 bp->buffer = newBuf; 237 bp->size += newBytes; 238 bp->left = bp->size - (bp->inPtr - bp->buffer); 239 bp->outPtr -= numBytes; 240 memcpy ((char *)bp->outPtr, (char *)bytesPtr, numBytes); 240 241 } 241 242 } … … 245 246 *----------------------------------------------------------------------- 246 247 * Buf_GetByte -- 247 * Return the next byte from the buffer. Actually returns an integer.248 * 249 * Results: 250 * Returns BUF_ERROR if there's no byte in the buffer, or the byte251 * itself if there is one.252 * 253 * Side Effects: 254 * outPtr is incremented and both outPtr and inPtr will be reset if255 * the buffer is emptied.248 * Return the next byte from the buffer. Actually returns an integer. 249 * 250 * Results: 251 * Returns BUF_ERROR if there's no byte in the buffer, or the byte 252 * itself if there is one. 253 * 254 * Side Effects: 255 * outPtr is incremented and both outPtr and inPtr will be reset if 256 * the buffer is emptied. 256 257 * 257 258 *----------------------------------------------------------------------- … … 261 262 register Buffer bp; 262 263 { 263 int res;264 int res; 264 265 265 266 if (bp->inPtr == bp->outPtr) { 266 return (BUF_ERROR);267 return (BUF_ERROR); 267 268 } else { 268 res = (int) *bp->outPtr;269 bp->outPtr += 1;270 if (bp->outPtr == bp->inPtr) {271 bp->outPtr = bp->inPtr = bp->buffer;272 bp->left = bp->size;273 *bp->inPtr = 0;274 }275 return (res);269 res = (int) *bp->outPtr; 270 bp->outPtr += 1; 271 if (bp->outPtr == bp->inPtr) { 272 bp->outPtr = bp->inPtr = bp->buffer; 273 bp->left = bp->size; 274 *bp->inPtr = 0; 275 } 276 return (res); 276 277 } 277 278 } … … 281 282 *----------------------------------------------------------------------- 282 283 * Buf_GetBytes -- 283 * Extract a number of bytes from the buffer.284 * 285 * Results: 286 * The number of bytes gotten.287 * 288 * Side Effects: 289 * The passed array is overwritten.284 * Extract a number of bytes from the buffer. 285 * 286 * Results: 287 * The number of bytes gotten. 288 * 289 * Side Effects: 290 * The passed array is overwritten. 290 291 * 291 292 *----------------------------------------------------------------------- … … 294 295 Buf_GetBytes (bp, numBytes, bytesPtr) 295 296 register Buffer bp; 296 int numBytes;297 int numBytes; 297 298 Byte *bytesPtr; 298 299 { 299 300 300 301 if (bp->inPtr - bp->outPtr < numBytes) { 301 numBytes = bp->inPtr - bp->outPtr;302 numBytes = bp->inPtr - bp->outPtr; 302 303 } 303 304 memcpy (bytesPtr, bp->outPtr, numBytes); … … 305 306 306 307 if (bp->outPtr == bp->inPtr) { 307 bp->outPtr = bp->inPtr = bp->buffer;308 bp->left = bp->size;309 *bp->inPtr = 0;308 bp->outPtr = bp->inPtr = bp->buffer; 309 bp->left = bp->size; 310 *bp->inPtr = 0; 310 311 } 311 312 return (numBytes); … … 316 317 *----------------------------------------------------------------------- 317 318 * Buf_GetAll -- 318 * Get all the available data at once.319 * 320 * Results: 321 * A pointer to the data and the number of bytes available.322 * 323 * Side Effects: 324 * None.319 * Get all the available data at once. 320 * 321 * Results: 322 * A pointer to the data and the number of bytes available. 323 * 324 * Side Effects: 325 * None. 325 326 * 326 327 *----------------------------------------------------------------------- … … 329 330 Buf_GetAll (bp, numBytesPtr) 330 331 register Buffer bp; 331 int *numBytesPtr;332 int *numBytesPtr; 332 333 { 333 334 334 335 if (numBytesPtr != (int *)NULL) { 335 *numBytesPtr = bp->inPtr - bp->outPtr;336 *numBytesPtr = bp->inPtr - bp->outPtr; 336 337 } 337 338 … … 343 344 *----------------------------------------------------------------------- 344 345 * Buf_Discard -- 345 * Throw away bytes in a buffer.346 * 347 * Results: 348 * None.349 * 350 * Side Effects: 351 * The bytes are discarded.346 * Throw away bytes in a buffer. 347 * 348 * Results: 349 * None. 350 * 351 * Side Effects: 352 * The bytes are discarded. 352 353 * 353 354 *----------------------------------------------------------------------- … … 356 357 Buf_Discard (bp, numBytes) 357 358 register Buffer bp; 358 int numBytes;359 int numBytes; 359 360 { 360 361 361 362 if (bp->inPtr - bp->outPtr <= numBytes) { 362 bp->inPtr = bp->outPtr = bp->buffer;363 bp->left = bp->size;364 *bp->inPtr = 0;363 bp->inPtr = bp->outPtr = bp->buffer; 364 bp->left = bp->size; 365 *bp->inPtr = 0; 365 366 } else { 366 bp->outPtr += numBytes;367 bp->outPtr += numBytes; 367 368 } 368 369 } … … 372 373 *----------------------------------------------------------------------- 373 374 * Buf_Size -- 374 * Returns the number of bytes in the given buffer. Doesn't include375 * the null-terminating byte.376 * 377 * Results: 378 * The number of bytes.379 * 380 * Side Effects: 381 * None.375 * Returns the number of bytes in the given buffer. Doesn't include 376 * the null-terminating byte. 377 * 378 * Results: 379 * The number of bytes. 380 * 381 * Side Effects: 382 * None. 382 383 * 383 384 *----------------------------------------------------------------------- … … 394 395 *----------------------------------------------------------------------- 395 396 * Buf_Init -- 396 * Initialize a buffer. If no initial size is given, a reasonable397 * default is used.398 * 399 * Results: 400 * A buffer to be given to other functions in this library.401 * 402 * Side Effects: 403 * The buffer is created, the space allocated and pointers404 * initialized.397 * Initialize a buffer. If no initial size is given, a reasonable 398 * default is used. 399 * 400 * Results: 401 * A buffer to be given to other functions in this library. 402 * 403 * Side Effects: 404 * The buffer is created, the space allocated and pointers 405 * initialized. 405 406 * 406 407 *----------------------------------------------------------------------- … … 408 409 Buffer 409 410 Buf_Init (size) 410 int size;/* Initial size for the buffer */411 { 412 Buffer bp; /* New Buffer */411 int size; /* Initial size for the buffer */ 412 { 413 Buffer bp; /* New Buffer */ 413 414 414 415 bp = (Buffer)emalloc(sizeof(*bp)); 415 416 416 417 if (size <= 0) { 417 size = BUF_DEF_SIZE;418 size = BUF_DEF_SIZE; 418 419 } 419 420 bp->left = bp->size = size; … … 429 430 *----------------------------------------------------------------------- 430 431 * Buf_Destroy -- 431 * Nuke a buffer and all its resources.432 * 433 * Results: 434 * None.435 * 436 * Side Effects: 437 * The buffer is freed.432 * Nuke a buffer and all its resources. 433 * 434 * Results: 435 * None. 436 * 437 * Side Effects: 438 * The buffer is freed. 438 439 * 439 440 *----------------------------------------------------------------------- … … 441 442 void 442 443 Buf_Destroy (buf, freeData) 443 Buffer buf; /* Buffer to destroy */444 Boolean freeData; /* TRUE if the data should be destroyed as well */444 Buffer buf; /* Buffer to destroy */ 445 Boolean freeData; /* TRUE if the data should be destroyed as well */ 445 446 { 446 447 447 448 if (freeData) { 448 efree ((char *)buf->buffer);449 efree ((char *)buf->buffer); 449 450 } 450 451 efree ((char *)buf); … … 468 469 void 469 470 Buf_ReplaceLastByte (buf, byte) 470 Buffer buf; /* buffer to augment */471 int byte; /* byte to be written */471 Buffer buf; /* buffer to augment */ 472 int byte; /* byte to be written */ 472 473 { 473 474 if (buf->inPtr == buf->outPtr) -
trunk/src/kmk/compat.c
r35 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94";41 static char sccsid[] = "@(#)compat.c 8.2 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/compat.c,v 1.16.2.2 2000/07/01 12:24:21 ps Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * compat.c -- 50 * The routines in this file implement the full-compatibility51 * mode of PMake. Most of the special functionality of PMake52 * is available in this mode. Things not supported:53 * - different shells.54 * - friendly variable substitution.51 * The routines in this file implement the full-compatibility 52 * mode of PMake. Most of the special functionality of PMake 53 * is available in this mode. Things not supported: 54 * - different shells. 55 * - friendly variable substitution. 55 56 * 56 57 * Interface: 57 * Compat_RunInitialize things for this module and recreate58 * thems as need creatin'58 * Compat_Run Initialize things for this module and recreate 59 * thems as need creatin' 59 60 */ 60 61 … … 87 88 */ 88 89 89 static char meta[256];90 91 static GNode *curTarg = NILGNODE;92 static GNode *ENDNode;90 static char meta[256]; 91 92 static GNode *curTarg = NILGNODE; 93 static GNode *ENDNode; 93 94 static void CompatInterrupt __P((int)); 94 95 static int CompatRunCommand __P((ClientData, ClientData)); … … 96 97 97 98 static char *sh_builtin[] = { 98 "alias", "cd", "eval", "exec", "exit", "read", "set", "ulimit",99 "unalias", "umask", "unset", "wait", ":", 0};99 "alias", "cd", "eval", "exec", "exit", "read", "set", "ulimit", 100 "unalias", "umask", "unset", "wait", ":", 0}; 100 101 101 102 /*- 102 103 *----------------------------------------------------------------------- 103 104 * CompatInterrupt -- 104 * Interrupt the creation of the current target and remove it if105 * it ain't precious.105 * Interrupt the creation of the current target and remove it if 106 * it ain't precious. 106 107 * 107 108 * Results: 108 * None.109 * None. 109 110 * 110 111 * Side Effects: 111 * The target is removed and the process exits. If .INTERRUPT exists,112 * its commands are run first WITH INTERRUPTS IGNORED..112 * The target is removed and the process exits. If .INTERRUPT exists, 113 * its commands are run first WITH INTERRUPTS IGNORED.. 113 114 * 114 115 *----------------------------------------------------------------------- … … 116 117 static void 117 118 CompatInterrupt (signo) 118 int signo;119 int signo; 119 120 { 120 121 GNode *gn; 121 122 122 123 if ((curTarg != NILGNODE) && !Targ_Precious (curTarg)) { 123 char*p1;124 char*file = Var_Value (TARGET, curTarg, &p1);125 126 if (!noExecute && eunlink(file) != -1) {127 printf ("*** %s removed\n", file);128 }129 efree(p1);130 131 /*132 * Run .INTERRUPT only if hit with interrupt signal133 */134 if (signo == SIGINT) {135 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);136 if (gn != NILGNODE) {137 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);138 }139 }124 char *p1; 125 char *file = Var_Value (TARGET, curTarg, &p1); 126 127 if (!noExecute && eunlink(file) != -1) { 128 printf ("*** %s removed\n", file); 129 } 130 efree(p1); 131 132 /* 133 * Run .INTERRUPT only if hit with interrupt signal 134 */ 135 if (signo == SIGINT) { 136 gn = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 137 if (gn != NILGNODE) { 138 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 139 } 140 } 140 141 141 142 } 142 143 #if !(defined(OS2) && defined(__IBMC__)) 143 144 if (signo == SIGQUIT) 144 exit(signo);145 exit(signo); 145 146 #endif 146 147 (void) signal(signo, SIG_DFL); … … 152 153 *----------------------------------------------------------------------- 153 154 * shellneed -- 154 * 155 * 155 156 * Results: 156 * Returns 1 if a specified line must be executed by the shell,157 * 0 if it can be run via execve, and -1 if the command is a no-op.157 * Returns 1 if a specified line must be executed by the shell, 158 * 0 if it can be run via execve, and -1 if the command is a no-op. 158 159 * 159 160 * Side Effects: 160 * None.161 * 161 * None. 162 * 162 163 *----------------------------------------------------------------------- 163 164 */ 164 165 static int 165 166 shellneed (cmd) 166 char *cmd;167 char *cmd; 167 168 { 168 char **av, **p;169 int ac;170 171 av = brk_string(cmd, &ac, TRUE);172 for(p = sh_builtin; *p != 0; p++)173 if (strcmp(av[1], *p) == 0)174 return (1);175 return (0);169 char **av, **p; 170 int ac; 171 172 av = brk_string(cmd, &ac, TRUE); 173 for(p = sh_builtin; *p != 0; p++) 174 if (strcmp(av[1], *p) == 0) 175 return (1); 176 return (0); 176 177 } 177 178 … … 180 181 *----------------------------------------------------------------------- 181 182 * CompatRunCommand -- 182 * Execute the next command for a target. If the command returns an183 * error, the node's made field is set to ERROR and creation stops.183 * Execute the next command for a target. If the command returns an 184 * error, the node's made field is set to ERROR and creation stops. 184 185 * 185 186 * Results: 186 * 0 if the command succeeded, 1 if an error occurred.187 * 0 if the command succeeded, 1 if an error occurred. 187 188 * 188 189 * Side Effects: 189 * The node's 'made' field may be set to ERROR.190 * The node's 'made' field may be set to ERROR. 190 191 * 191 192 *----------------------------------------------------------------------- … … 193 194 static int 194 195 CompatRunCommand (cmdp, gnp) 195 ClientData cmdp; /* Command to execute */196 ClientData gnp; /* Node from which the command came */196 ClientData cmdp; /* Command to execute */ 197 ClientData gnp; /* Node from which the command came */ 197 198 { 198 char *cmdStart;/* Start of expanded command */199 char *cmdStart; /* Start of expanded command */ 199 200 register char *cp; 200 Boolean silent,/* Don't print command */201 errCheck;/* Check errors */202 int reason;/* Reason for child's death */203 int status;/* Description of child's death */204 int cpid;/* Child actually found */205 ReturnStatus stat; /* Status of fork */206 LstNode cmdNode;/* Node where current command is located */207 char **av;/* Argument vector for thing to exec */208 int argc;/* Number of arguments in av or 0 if not209 * dynamically allocated */210 Boolean local;/* TRUE if command should be executed211 * locally */212 int internal;/* Various values.. */213 char *cmd = (char *) cmdp;214 GNode *gn = (GNode *) gnp;201 Boolean silent, /* Don't print command */ 202 errCheck; /* Check errors */ 203 int reason; /* Reason for child's death */ 204 int status; /* Description of child's death */ 205 int cpid; /* Child actually found */ 206 ReturnStatus stat; /* Status of fork */ 207 LstNode cmdNode; /* Node where current command is located */ 208 char **av; /* Argument vector for thing to exec */ 209 int argc; /* Number of arguments in av or 0 if not 210 * dynamically allocated */ 211 Boolean local; /* TRUE if command should be executed 212 * locally */ 213 int internal; /* Various values.. */ 214 char *cmd = (char *) cmdp; 215 GNode *gn = (GNode *) gnp; 215 216 216 217 /* … … 236 237 237 238 if (*cmdStart == '\0') { 238 efree(cmdStart);239 Error("%s expands to empty string", cmd);240 return(0);239 efree(cmdStart); 240 Error("%s expands to empty string", cmd); 241 return(0); 241 242 } else { 242 cmd = cmdStart;243 cmd = cmdStart; 243 244 } 244 245 Lst_Replace (cmdNode, (ClientData)cmdStart); 245 246 246 247 if ((gn->type & OP_SAVE_CMDS) && (gn != ENDNode)) { 247 (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart);248 return(0);248 (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); 249 return(0); 249 250 } else if (strcmp(cmdStart, "...") == 0) { 250 gn->type |= OP_SAVE_CMDS;251 return(0);251 gn->type |= OP_SAVE_CMDS; 252 return(0); 252 253 } 253 254 254 255 while ((*cmd == '@') || (*cmd == '-')) { 255 if (*cmd == '@') {256 silent = DEBUG(LOUD) ? FALSE : TRUE;257 } else {258 errCheck = FALSE;259 }260 cmd++;256 if (*cmd == '@') { 257 silent = DEBUG(LOUD) ? FALSE : TRUE; 258 } else { 259 errCheck = FALSE; 260 } 261 cmd++; 261 262 } 262 263 263 264 while (isspace((unsigned char)*cmd)) 264 cmd++;265 cmd++; 265 266 266 267 /* … … 270 271 */ 271 272 for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 272 continue;273 continue; 273 274 } 274 275 … … 278 279 */ 279 280 if (!silent || noExecute) { 280 printf ("%s\n", cmd);281 fflush(stdout);281 printf ("%s\n", cmd); 282 fflush(stdout); 282 283 } 283 284 … … 287 288 */ 288 289 if (noExecute) { 289 return (0);290 return (0); 290 291 } 291 292 292 293 if (*cp != '\0') { 293 /*294 * If *cp isn't the null character, we hit a "meta" character and295 * need to pass the command off to the shell. We give the shell the296 * -e flag as well as -c if it's supposed to exit when it hits an297 * error.298 */299 static char*shargv[4] = { "/bin/sh" };300 301 shargv[1] = (errCheck ? "-ec" : "-c");302 shargv[2] = cmd;303 shargv[3] = (char *)NULL;304 av = shargv;305 argc = 0;294 /* 295 * If *cp isn't the null character, we hit a "meta" character and 296 * need to pass the command off to the shell. We give the shell the 297 * -e flag as well as -c if it's supposed to exit when it hits an 298 * error. 299 */ 300 static char *shargv[4] = { "/bin/sh" }; 301 302 shargv[1] = (errCheck ? "-ec" : "-c"); 303 shargv[2] = cmd; 304 shargv[3] = (char *)NULL; 305 av = shargv; 306 argc = 0; 306 307 } else if ((internal = shellneed(cmd))) { 307 /*308 * This command must be passed by the shell for other reasons..309 * or.. possibly not at all.310 */311 static char*shargv[4] = { "/bin/sh" };312 313 if (internal == -1) {314 /* Command does not need to be executed */315 return (0);316 }317 318 shargv[1] = (errCheck ? "-ec" : "-c");319 shargv[2] = cmd;320 shargv[3] = (char *)NULL;321 av = shargv;322 argc = 0;308 /* 309 * This command must be passed by the shell for other reasons.. 310 * or.. possibly not at all. 311 */ 312 static char *shargv[4] = { "/bin/sh" }; 313 314 if (internal == -1) { 315 /* Command does not need to be executed */ 316 return (0); 317 } 318 319 shargv[1] = (errCheck ? "-ec" : "-c"); 320 shargv[2] = cmd; 321 shargv[3] = (char *)NULL; 322 av = shargv; 323 argc = 0; 323 324 } else { 324 /*325 * No meta-characters, so no need to exec a shell. Break the command326 * into words to form an argument vector we can execute.327 * brk_string sticks our name in av[0], so we have to328 * skip over it...329 */330 av = brk_string(cmd, &argc, TRUE);331 av += 1;325 /* 326 * No meta-characters, so no need to exec a shell. Break the command 327 * into words to form an argument vector we can execute. 328 * brk_string sticks our name in av[0], so we have to 329 * skip over it... 330 */ 331 av = brk_string(cmd, &argc, TRUE); 332 av += 1; 332 333 } 333 334 … … 342 343 cpid = vfork(); 343 344 if (cpid < 0) { 344 Fatal("Could not fork");345 Fatal("Could not fork"); 345 346 } 346 347 if (cpid == 0) { 347 if (local) {348 execvp(av[0], av);349 (void) write (2, av[0], strlen (av[0]));350 (void) write (2, ":", 1);351 (void) write (2, strerror(errno), strlen(strerror(errno)));352 (void) write (2, "\n", 1);353 } else {354 (void)execv(av[0], av);355 }356 exit(1);348 if (local) { 349 execvp(av[0], av); 350 (void) write (2, av[0], strlen (av[0])); 351 (void) write (2, ":", 1); 352 (void) write (2, strerror(errno), strlen(strerror(errno))); 353 (void) write (2, "\n", 1); 354 } else { 355 (void)execv(av[0], av); 356 } 357 exit(1); 357 358 } 358 359 #endif … … 365 366 */ 366 367 if (!DEBUG(GRAPH2)) { 367 efree(cmdStart);368 Lst_Replace (cmdNode, cmdp);368 efree(cmdStart); 369 Lst_Replace (cmdNode, cmdp); 369 370 } 370 371 … … 374 375 while (1) { 375 376 376 while ((stat = wait(&reason)) != cpid) {377 if (stat == -1 && errno != EINTR) {378 break;379 }380 }381 382 if (stat > -1) {383 if (WIFSTOPPED(reason)) {384 status = WSTOPSIG(reason);/* stopped */385 } else if (WIFEXITED(reason)) {386 status = WEXITSTATUS(reason);/* exited */387 if (status != 0) {388 printf ("*** Error code %d", status);389 }390 } else {391 status = WTERMSIG(reason);/* signaled */392 printf ("*** Signal %d", status);393 }394 395 396 if (!WIFEXITED(reason) || (status != 0)) {397 if (errCheck) {398 gn->made = ERROR;399 if (keepgoing) {400 /*401 * Abort the current target, but let others402 * continue.403 */404 printf (" (continuing)\n");405 }406 } else {407 /*408 * Continue executing commands for this target.409 * If we return 0, this will happen...410 */411 printf (" (ignored)\n");412 status = 0;413 }414 }415 break;416 } else {417 Fatal ("error in wait: %d", stat);418 /*NOTREACHED*/419 }377 while ((stat = wait(&reason)) != cpid) { 378 if (stat == -1 && errno != EINTR) { 379 break; 380 } 381 } 382 383 if (stat > -1) { 384 if (WIFSTOPPED(reason)) { 385 status = WSTOPSIG(reason); /* stopped */ 386 } else if (WIFEXITED(reason)) { 387 status = WEXITSTATUS(reason); /* exited */ 388 if (status != 0) { 389 printf ("*** Error code %d", status); 390 } 391 } else { 392 status = WTERMSIG(reason); /* signaled */ 393 printf ("*** Signal %d", status); 394 } 395 396 397 if (!WIFEXITED(reason) || (status != 0)) { 398 if (errCheck) { 399 gn->made = ERROR; 400 if (keepgoing) { 401 /* 402 * Abort the current target, but let others 403 * continue. 404 */ 405 printf (" (continuing)\n"); 406 } 407 } else { 408 /* 409 * Continue executing commands for this target. 410 * If we return 0, this will happen... 411 */ 412 printf (" (ignored)\n"); 413 status = 0; 414 } 415 } 416 break; 417 } else { 418 Fatal ("error in wait: %d", stat); 419 /*NOTREACHED*/ 420 } 420 421 } 421 422 … … 427 428 *----------------------------------------------------------------------- 428 429 * CompatMake -- 429 * Make a target.430 * Make a target. 430 431 * 431 432 * Results: 432 * 0433 * 0 433 434 * 434 435 * Side Effects: 435 * If an error is detected and not being ignored, the process exits.436 * If an error is detected and not being ignored, the process exits. 436 437 * 437 438 *----------------------------------------------------------------------- … … 439 440 static int 440 441 CompatMake (gnp, pgnp) 441 ClientData gnp;/* The node to make */442 ClientData pgnp; /* Parent to abort if necessary */442 ClientData gnp; /* The node to make */ 443 ClientData pgnp; /* Parent to abort if necessary */ 443 444 { 444 445 GNode *gn = (GNode *) gnp; 445 446 GNode *pgn = (GNode *) pgnp; 446 447 if (gn->type & OP_USE) { 447 Make_HandleUse(gn, pgn);448 Make_HandleUse(gn, pgn); 448 449 } else if (gn->made == UNMADE) { 449 /*450 * First mark ourselves to be made, then apply whatever transformations451 * the suffix module thinks are necessary. Once that's done, we can452 * descend and make all our children. If any of them has an error453 * but the -k flag was given, our 'make' field will be set FALSE again.454 * This is our signal to not attempt to do anything but abort our455 * parent as well.456 */457 gn->make = TRUE;458 gn->made = BEINGMADE;459 Suff_FindDeps (gn);460 Lst_ForEach (gn->children, CompatMake, (ClientData)gn);461 if (!gn->make) {462 gn->made = ABORTED;463 pgn->make = FALSE;464 return (0);465 }466 467 if (Lst_Member (gn->iParents, pgn) != NILLNODE) {468 char *p1;469 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);470 efree(p1);471 }472 473 /*474 * All the children were made ok. Now cmtime contains the modification475 * time of the newest child, we need to find out if we exist and when476 * we were modified last. The criteria for datedness are defined by the477 * Make_OODate function.478 */479 if (DEBUG(MAKE)) {480 printf("Examining %s...", gn->name);481 }482 if (! Make_OODate(gn)) {483 gn->made = UPTODATE;484 if (DEBUG(MAKE)) {485 printf("up-to-date.\n");486 }487 return (0);488 } else if (DEBUG(MAKE)) {489 printf("out-of-date.\n");490 }491 492 /*493 * If the user is just seeing if something is out-of-date, exit now494 * to tell him/her "yes".495 */496 if (queryFlag) {497 exit (-1);498 }499 500 /*501 * We need to be re-made. We also have to make sure we've got a $?502 * variable. To be nice, we also define the $> variable using503 * Make_DoAllVar().504 */505 Make_DoAllVar(gn);506 507 /*508 * Alter our type to tell if errors should be ignored or things509 * should not be printed so CompatRunCommand knows what to do.510 */511 if (Targ_Ignore (gn)) {512 gn->type |= OP_IGNORE;513 }514 if (Targ_Silent (gn)) {515 gn->type |= OP_SILENT;516 }517 518 if (Job_CheckCommands (gn, Fatal)) {519 /*520 * Our commands are ok, but we still have to worry about the -t521 * flag...522 */523 if (!touchFlag) {524 curTarg = gn;525 Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn);526 curTarg = NILGNODE;527 } else {528 Job_Touch (gn, gn->type & OP_SILENT);529 }530 } else {531 gn->made = ERROR;532 }533 534 if (gn->made != ERROR) {535 /*536 * If the node was made successfully, mark it so, update537 * its modification time and timestamp all its parents. Note538 * that for .ZEROTIME targets, the timestamping isn't done.539 * This is to keep its state from affecting that of its parent.540 */541 gn->made = MADE;450 /* 451 * First mark ourselves to be made, then apply whatever transformations 452 * the suffix module thinks are necessary. Once that's done, we can 453 * descend and make all our children. If any of them has an error 454 * but the -k flag was given, our 'make' field will be set FALSE again. 455 * This is our signal to not attempt to do anything but abort our 456 * parent as well. 457 */ 458 gn->make = TRUE; 459 gn->made = BEINGMADE; 460 Suff_FindDeps (gn); 461 Lst_ForEach (gn->children, CompatMake, (ClientData)gn); 462 if (!gn->make) { 463 gn->made = ABORTED; 464 pgn->make = FALSE; 465 return (0); 466 } 467 468 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 469 char *p1; 470 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); 471 efree(p1); 472 } 473 474 /* 475 * All the children were made ok. Now cmtime contains the modification 476 * time of the newest child, we need to find out if we exist and when 477 * we were modified last. The criteria for datedness are defined by the 478 * Make_OODate function. 479 */ 480 if (DEBUG(MAKE)) { 481 printf("Examining %s...", gn->name); 482 } 483 if (! Make_OODate(gn)) { 484 gn->made = UPTODATE; 485 if (DEBUG(MAKE)) { 486 printf("up-to-date.\n"); 487 } 488 return (0); 489 } else if (DEBUG(MAKE)) { 490 printf("out-of-date.\n"); 491 } 492 493 /* 494 * If the user is just seeing if something is out-of-date, exit now 495 * to tell him/her "yes". 496 */ 497 if (queryFlag) { 498 exit (-1); 499 } 500 501 /* 502 * We need to be re-made. We also have to make sure we've got a $? 503 * variable. To be nice, we also define the $> variable using 504 * Make_DoAllVar(). 505 */ 506 Make_DoAllVar(gn); 507 508 /* 509 * Alter our type to tell if errors should be ignored or things 510 * should not be printed so CompatRunCommand knows what to do. 511 */ 512 if (Targ_Ignore (gn)) { 513 gn->type |= OP_IGNORE; 514 } 515 if (Targ_Silent (gn)) { 516 gn->type |= OP_SILENT; 517 } 518 519 if (Job_CheckCommands (gn, Fatal)) { 520 /* 521 * Our commands are ok, but we still have to worry about the -t 522 * flag... 523 */ 524 if (!touchFlag) { 525 curTarg = gn; 526 Lst_ForEach (gn->commands, CompatRunCommand, (ClientData)gn); 527 curTarg = NILGNODE; 528 } else { 529 Job_Touch (gn, gn->type & OP_SILENT); 530 } 531 } else { 532 gn->made = ERROR; 533 } 534 535 if (gn->made != ERROR) { 536 /* 537 * If the node was made successfully, mark it so, update 538 * its modification time and timestamp all its parents. Note 539 * that for .ZEROTIME targets, the timestamping isn't done. 540 * This is to keep its state from affecting that of its parent. 541 */ 542 gn->made = MADE; 542 543 #ifndef RECHECK 543 /*544 * We can't re-stat the thing, but we can at least take care of545 * rules where a target depends on a source that actually creates546 * the target, but only if it has changed, e.g.547 *548 * parse.h : parse.o549 *550 * parse.o : parse.y551 *yacc -d parse.y552 *cc -c y.tab.c553 *mv y.tab.o parse.o554 *cmp -s y.tab.h parse.h || mv y.tab.h parse.h555 *556 * In this case, if the definitions produced by yacc haven't557 * changed from before, parse.h won't have been updated and558 * gn->mtime will reflect the current modification time for559 * parse.h. This is something of a kludge, I admit, but it's a560 * useful one..561 *562 * XXX: People like to use a rule like563 *564 * FRC:565 *566 * To force things that depend on FRC to be made, so we have to567 * check for gn->children being empty as well...568 */569 if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) {570 gn->mtime = now;571 }544 /* 545 * We can't re-stat the thing, but we can at least take care of 546 * rules where a target depends on a source that actually creates 547 * the target, but only if it has changed, e.g. 548 * 549 * parse.h : parse.o 550 * 551 * parse.o : parse.y 552 * yacc -d parse.y 553 * cc -c y.tab.c 554 * mv y.tab.o parse.o 555 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 556 * 557 * In this case, if the definitions produced by yacc haven't 558 * changed from before, parse.h won't have been updated and 559 * gn->mtime will reflect the current modification time for 560 * parse.h. This is something of a kludge, I admit, but it's a 561 * useful one.. 562 * 563 * XXX: People like to use a rule like 564 * 565 * FRC: 566 * 567 * To force things that depend on FRC to be made, so we have to 568 * check for gn->children being empty as well... 569 */ 570 if (!Lst_IsEmpty(gn->commands) || Lst_IsEmpty(gn->children)) { 571 gn->mtime = now; 572 } 572 573 #else 573 /*574 * This is what Make does and it's actually a good thing, as it575 * allows rules like576 *577 *cmp -s y.tab.h parse.h || cp y.tab.h parse.h578 *579 * to function as intended. Unfortunately, thanks to the stateless580 * nature of NFS (and the speed of this program), there are times581 * when the modification time of a file created on a remote582 * machine will not be modified before the stat() implied by583 * the Dir_MTime occurs, thus leading us to believe that the file584 * is unchanged, wreaking havoc with files that depend on this one.585 *586 * I have decided it is better to make too much than to make too587 * little, so this stuff is commented out unless you're sure it's588 * ok.589 * -- ardeb 1/12/88590 */591 if (noExecute || Dir_MTime(gn) == 0) {592 gn->mtime = now;593 }594 if (gn->cmtime > gn->mtime)595 gn->mtime = gn->cmtime;596 if (DEBUG(MAKE)) {597 printf("update time: %s\n", Targ_FmtTime(gn->mtime));598 }574 /* 575 * This is what Make does and it's actually a good thing, as it 576 * allows rules like 577 * 578 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 579 * 580 * to function as intended. Unfortunately, thanks to the stateless 581 * nature of NFS (and the speed of this program), there are times 582 * when the modification time of a file created on a remote 583 * machine will not be modified before the stat() implied by 584 * the Dir_MTime occurs, thus leading us to believe that the file 585 * is unchanged, wreaking havoc with files that depend on this one. 586 * 587 * I have decided it is better to make too much than to make too 588 * little, so this stuff is commented out unless you're sure it's 589 * ok. 590 * -- ardeb 1/12/88 591 */ 592 if (noExecute || Dir_MTime(gn) == 0) { 593 gn->mtime = now; 594 } 595 if (gn->cmtime > gn->mtime) 596 gn->mtime = gn->cmtime; 597 if (DEBUG(MAKE)) { 598 printf("update time: %s\n", Targ_FmtTime(gn->mtime)); 599 } 599 600 #endif 600 if (!(gn->type & OP_EXEC)) {601 pgn->childMade = TRUE;602 Make_TimeStamp(pgn, gn);603 }604 } else if (keepgoing) {605 pgn->make = FALSE;606 } else {607 char *p1;608 609 printf ("\n\nStop in %s.\n", Var_Value(".CURDIR", gn, &p1));610 efree(p1);611 exit (1);612 }601 if (!(gn->type & OP_EXEC)) { 602 pgn->childMade = TRUE; 603 Make_TimeStamp(pgn, gn); 604 } 605 } else if (keepgoing) { 606 pgn->make = FALSE; 607 } else { 608 char *p1; 609 610 printf ("\n\nStop in %s.\n", Var_Value(".CURDIR", gn, &p1)); 611 efree(p1); 612 exit (1); 613 } 613 614 } else if (gn->made == ERROR) { 614 /*615 * Already had an error when making this beastie. Tell the parent616 * to abort.617 */618 pgn->make = FALSE;615 /* 616 * Already had an error when making this beastie. Tell the parent 617 * to abort. 618 */ 619 pgn->make = FALSE; 619 620 } else { 620 if (Lst_Member (gn->iParents, pgn) != NILLNODE) {621 char *p1;622 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn);623 efree(p1);624 }625 switch(gn->made) {626 case BEINGMADE:627 Error("Graph cycles through %s\n", gn->name);628 gn->made = ERROR;629 pgn->make = FALSE;630 break;631 case MADE:632 if ((gn->type & OP_EXEC) == 0) {633 pgn->childMade = TRUE;634 Make_TimeStamp(pgn, gn);635 }636 break;637 case UPTODATE:638 if ((gn->type & OP_EXEC) == 0) {639 Make_TimeStamp(pgn, gn);640 }641 break;642 default:643 break;644 }621 if (Lst_Member (gn->iParents, pgn) != NILLNODE) { 622 char *p1; 623 Var_Set (IMPSRC, Var_Value(TARGET, gn, &p1), pgn); 624 efree(p1); 625 } 626 switch(gn->made) { 627 case BEINGMADE: 628 Error("Graph cycles through %s\n", gn->name); 629 gn->made = ERROR; 630 pgn->make = FALSE; 631 break; 632 case MADE: 633 if ((gn->type & OP_EXEC) == 0) { 634 pgn->childMade = TRUE; 635 Make_TimeStamp(pgn, gn); 636 } 637 break; 638 case UPTODATE: 639 if ((gn->type & OP_EXEC) == 0) { 640 Make_TimeStamp(pgn, gn); 641 } 642 break; 643 default: 644 break; 645 } 645 646 } 646 647 … … 652 653 *----------------------------------------------------------------------- 653 654 * Compat_Run -- 654 * Initialize this mode and start making.655 * Initialize this mode and start making. 655 656 * 656 657 * Results: 657 * None.658 * None. 658 659 * 659 660 * Side Effects: 660 * Guess what?661 * Guess what? 661 662 * 662 663 *----------------------------------------------------------------------- … … 664 665 void 665 666 Compat_Run(targs) 666 Lst targs; /* List of target nodes to re-create */667 Lst targs; /* List of target nodes to re-create */ 667 668 { 668 char *cp;/* Pointer to string of shell meta-characters */669 GNode *gn = NULL;/* Current root target */670 int errors; /* Number of targets not remade due to errors */669 char *cp; /* Pointer to string of shell meta-characters */ 670 GNode *gn = NULL;/* Current root target */ 671 int errors; /* Number of targets not remade due to errors */ 671 672 672 673 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 673 signal(SIGINT, CompatInterrupt);674 signal(SIGINT, CompatInterrupt); 674 675 } 675 676 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 676 signal(SIGTERM, CompatInterrupt);677 signal(SIGTERM, CompatInterrupt); 677 678 } 678 679 #if !(defined(OS2) && defined(__IBMC__)) 679 680 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 680 signal(SIGHUP, CompatInterrupt);681 signal(SIGHUP, CompatInterrupt); 681 682 } 682 683 #endif 683 684 #if !(defined(OS2) && defined(__IBMC__)) 684 685 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 685 signal(SIGQUIT, CompatInterrupt);686 signal(SIGQUIT, CompatInterrupt); 686 687 } 687 688 #endif 688 689 689 690 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 690 meta[(unsigned char) *cp] = 1;691 meta[(unsigned char) *cp] = 1; 691 692 } 692 693 /* … … 701 702 */ 702 703 if (!queryFlag) { 703 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE);704 if (gn != NILGNODE) {705 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn);704 gn = Targ_FindNode(".BEGIN", TARG_NOCREATE); 705 if (gn != NILGNODE) { 706 Lst_ForEach(gn->commands, CompatRunCommand, (ClientData)gn); 706 707 if (gn->made == ERROR) { 707 708 printf("\n\nStop.\n"); 708 709 exit(1); 709 710 } 710 }711 } 711 712 } 712 713 … … 715 716 * it to create the thing. CompatMake will leave the 'made' field of gn 716 717 * in one of several states: 717 * UPTODATEgn was already up-to-date718 * MADEgn was recreated successfully719 * ERRORAn error occurred while gn was being created720 * ABORTEDgn was not remade because one of its inferiors721 * could not be made due to errors.718 * UPTODATE gn was already up-to-date 719 * MADE gn was recreated successfully 720 * ERROR An error occurred while gn was being created 721 * ABORTED gn was not remade because one of its inferiors 722 * could not be made due to errors. 722 723 */ 723 724 errors = 0; 724 725 while (!Lst_IsEmpty (targs)) { 725 gn = (GNode *) Lst_DeQueue (targs);726 CompatMake (gn, gn);727 728 if (gn->made == UPTODATE) {729 printf ("`%s' is up to date.\n", gn->name);730 } else if (gn->made == ABORTED) {731 printf ("`%s' not remade because of errors.\n", gn->name);732 errors += 1;733 }726 gn = (GNode *) Lst_DeQueue (targs); 727 CompatMake (gn, gn); 728 729 if (gn->made == UPTODATE) { 730 printf ("`%s' is up to date.\n", gn->name); 731 } else if (gn->made == ABORTED) { 732 printf ("`%s' not remade because of errors.\n", gn->name); 733 errors += 1; 734 } 734 735 } 735 736 … … 738 739 */ 739 740 if (errors == 0) { 740 Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn);741 Lst_ForEach(ENDNode->commands, CompatRunCommand, (ClientData)gn); 741 742 } 742 743 } -
trunk/src/kmk/cond.c
r45 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94";41 static char sccsid[] = "@(#)cond.c 8.2 (Berkeley) 1/2/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/cond.c,v 1.12 1999/09/11 13:08:01 hoek Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * cond.c -- 50 * Functions to handle conditionals in a makefile.51 * Functions to handle conditionals in a makefile. 51 52 * 52 53 * Interface: 53 * Cond_EvalEvaluate the conditional in the passed line.54 * Cond_Eval Evaluate the conditional in the passed line. 54 55 * 55 56 */ … … 64 65 /* 65 66 * The parsing of conditional expressions is based on this grammar: 66 * E -> F || E67 * E -> F68 * F -> T && F69 * F -> T70 * T -> defined(variable)71 * T -> make(target)72 * T -> exists(file)73 * T -> empty(varspec)74 * T -> target(name)75 * T -> symbol76 * T -> $(varspec) op value77 * T -> $(varspec) == "string"78 * T -> $(varspec) != "string"79 * T -> ( E )80 * T -> ! T81 * op -> == | != | > | < | >= | <=67 * E -> F || E 68 * E -> F 69 * F -> T && F 70 * F -> T 71 * T -> defined(variable) 72 * T -> make(target) 73 * T -> exists(file) 74 * T -> empty(varspec) 75 * T -> target(name) 76 * T -> symbol 77 * T -> $(varspec) op value 78 * T -> $(varspec) == "string" 79 * T -> $(varspec) != "string" 80 * T -> ( E ) 81 * T -> ! T 82 * op -> == | != | > | < | >= | <= 82 83 * 83 84 * 'symbol' is some other symbol to which the default function (condDefProc) … … 114 115 115 116 static struct If { 116 char *form;/* Form of if */117 int formlen; /* Length of form */118 Boolean doNot;/* TRUE if default function should be negated */119 Boolean (*defProc) __P((int, char *)); /* Default function to apply */117 char *form; /* Form of if */ 118 int formlen; /* Length of form */ 119 Boolean doNot; /* TRUE if default function should be negated */ 120 Boolean (*defProc) __P((int, char *)); /* Default function to apply */ 120 121 } ifs[] = { 121 { "ifdef", 5,FALSE, CondDoDefined },122 { "ifndef", 6, TRUE,CondDoDefined },123 { "ifmake", 6,FALSE, CondDoMake },124 { "ifnmake", 7, TRUE,CondDoMake },125 { "if", 2,FALSE, CondDoDefined },126 { NULL, 0,FALSE, NULL }122 { "ifdef", 5, FALSE, CondDoDefined }, 123 { "ifndef", 6, TRUE, CondDoDefined }, 124 { "ifmake", 6, FALSE, CondDoMake }, 125 { "ifnmake", 7, TRUE, CondDoMake }, 126 { "if", 2, FALSE, CondDoDefined }, 127 { NULL, 0, FALSE, NULL } 127 128 }; 128 129 129 static Boolean condInvert;/* Invert the default function */130 static Boolean (*condDefProc)/* Default function to apply */131 __P((int, char *));132 static char *condExpr;/* The expression to parse */133 static Token condPushBack=None;/* Single push-back token used in134 * parsing */135 136 #define MAXIF 30/* greatest depth of #if'ing */137 138 static Boolean condStack[MAXIF];/* Stack of conditionals's values */139 static int condTop = MAXIF;/* Top-most conditional */140 static int skipIfLevel=0;/* Depth of skipped conditionals */141 static Boolean skipLine = FALSE;/* Whether the parse module is skipping142 * lines */130 static Boolean condInvert; /* Invert the default function */ 131 static Boolean (*condDefProc) /* Default function to apply */ 132 __P((int, char *)); 133 static char *condExpr; /* The expression to parse */ 134 static Token condPushBack=None; /* Single push-back token used in 135 * parsing */ 136 137 #define MAXIF 30 /* greatest depth of #if'ing */ 138 139 static Boolean condStack[MAXIF]; /* Stack of conditionals's values */ 140 static int condTop = MAXIF; /* Top-most conditional */ 141 static int skipIfLevel=0; /* Depth of skipped conditionals */ 142 static Boolean skipLine = FALSE; /* Whether the parse module is skipping 143 * lines */ 143 144 144 145 /*- 145 146 *----------------------------------------------------------------------- 146 147 * CondPushBack -- 147 * Push back the most recent token read. We only need one level of148 * this, so the thing is just stored in 'condPushback'.148 * Push back the most recent token read. We only need one level of 149 * this, so the thing is just stored in 'condPushback'. 149 150 * 150 151 * Results: 151 * None.152 * None. 152 153 * 153 154 * Side Effects: 154 * condPushback is overwritten.155 * condPushback is overwritten. 155 156 * 156 157 *----------------------------------------------------------------------- … … 158 159 static void 159 160 CondPushBack (t) 160 Token t;/* Token to push back into the "stream" */161 Token t; /* Token to push back into the "stream" */ 161 162 { 162 163 condPushBack = t; … … 167 168 *----------------------------------------------------------------------- 168 169 * CondGetArg -- 169 * Find the argument of a built-in function.170 * Find the argument of a built-in function. 170 171 * 171 172 * Results: 172 * The length of the argument and the address of the argument.173 * The length of the argument and the address of the argument. 173 174 * 174 175 * Side Effects: 175 * The pointer is set to point to the closing parenthesis of the176 * function call.176 * The pointer is set to point to the closing parenthesis of the 177 * function call. 177 178 * 178 179 *----------------------------------------------------------------------- … … 180 181 static int 181 182 CondGetArg (linePtr, argPtr, func, parens) 182 char **linePtr;183 char **argPtr;184 char *func;185 Boolean parens;/* TRUE if arg should be bounded by parens */183 char **linePtr; 184 char **argPtr; 185 char *func; 186 Boolean parens; /* TRUE if arg should be bounded by parens */ 186 187 { 187 188 register char *cp; 188 int argLen;189 int argLen; 189 190 register Buffer buf; 190 191 191 192 cp = *linePtr; 192 193 if (parens) { 193 while (*cp != '(' && *cp != '\0') {194 cp++;195 }196 if (*cp == '(') {197 cp++;198 }194 while (*cp != '(' && *cp != '\0') { 195 cp++; 196 } 197 if (*cp == '(') { 198 cp++; 199 } 199 200 } 200 201 201 202 if (*cp == '\0') { 202 /*203 * No arguments whatsoever. Because 'make' and 'defined' aren't really204 * "reserved words", we don't print a message. I think this is better205 * than hitting the user with a warning message every time s/he uses206 * the word 'make' or 'defined' at the beginning of a symbol...207 */208 *argPtr = cp;209 return (0);203 /* 204 * No arguments whatsoever. Because 'make' and 'defined' aren't really 205 * "reserved words", we don't print a message. I think this is better 206 * than hitting the user with a warning message every time s/he uses 207 * the word 'make' or 'defined' at the beginning of a symbol... 208 */ 209 *argPtr = cp; 210 return (0); 210 211 } 211 212 212 213 while (*cp == ' ' || *cp == '\t') { 213 cp++;214 cp++; 214 215 } 215 216 … … 221 222 222 223 while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { 223 if (*cp == '$') {224 /*225 * Parse the variable spec and install it as part of the argument226 * if it's valid. We tell Var_Parse to complain on an undefined227 * variable, so we don't do it too. Nor do we return an error,228 * though perhaps we should...229 */230 char*cp2;231 intlen;232 BooleandoFree;233 234 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree);235 236 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);237 if (doFree) {238 efree(cp2);239 }240 cp += len;241 } else {242 Buf_AddByte(buf, (Byte)*cp);243 cp++;244 }224 if (*cp == '$') { 225 /* 226 * Parse the variable spec and install it as part of the argument 227 * if it's valid. We tell Var_Parse to complain on an undefined 228 * variable, so we don't do it too. Nor do we return an error, 229 * though perhaps we should... 230 */ 231 char *cp2; 232 int len; 233 Boolean doFree; 234 235 cp2 = Var_Parse(cp, VAR_CMD, TRUE, &len, &doFree); 236 237 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 238 if (doFree) { 239 efree(cp2); 240 } 241 cp += len; 242 } else { 243 Buf_AddByte(buf, (Byte)*cp); 244 cp++; 245 } 245 246 } 246 247 … … 250 251 251 252 while (*cp == ' ' || *cp == '\t') { 252 cp++;253 cp++; 253 254 } 254 255 if (parens && *cp != ')') { 255 Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()",256 func);257 return (0);256 Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", 257 func); 258 return (0); 258 259 } else if (parens) { 259 /*260 * Advance pointer past close parenthesis.261 */262 cp++;260 /* 261 * Advance pointer past close parenthesis. 262 */ 263 cp++; 263 264 } 264 265 … … 271 272 *----------------------------------------------------------------------- 272 273 * CondDoDefined -- 273 * Handle the 'defined' function for conditionals.274 * Handle the 'defined' function for conditionals. 274 275 * 275 276 * Results: 276 * TRUE if the given variable is defined.277 * TRUE if the given variable is defined. 277 278 * 278 279 * Side Effects: 279 * None.280 * None. 280 281 * 281 282 *----------------------------------------------------------------------- … … 283 284 static Boolean 284 285 CondDoDefined (argLen, arg) 285 int argLen;286 int argLen; 286 287 char *arg; 287 288 { … … 292 293 arg[argLen] = '\0'; 293 294 if (Var_Value (arg, VAR_CMD, &p1) != (char *)NULL) { 294 result = TRUE;295 result = TRUE; 295 296 } else { 296 result = FALSE;297 result = FALSE; 297 298 } 298 299 efree(p1); … … 305 306 *----------------------------------------------------------------------- 306 307 * CondStrMatch -- 307 * Front-end for Str_Match so it returns 0 on match and non-zero308 * on mismatch. Callback function for CondDoMake via Lst_Find308 * Front-end for Str_Match so it returns 0 on match and non-zero 309 * on mismatch. Callback function for CondDoMake via Lst_Find 309 310 * 310 311 * Results: 311 * 0 if string matches pattern312 * 0 if string matches pattern 312 313 * 313 314 * Side Effects: 314 * None315 * None 315 316 * 316 317 *----------------------------------------------------------------------- … … 328 329 *----------------------------------------------------------------------- 329 330 * CondDoMake -- 330 * Handle the 'make' function for conditionals.331 * Handle the 'make' function for conditionals. 331 332 * 332 333 * Results: 333 * TRUE if the given target is being made.334 * TRUE if the given target is being made. 334 335 * 335 336 * Side Effects: 336 * None.337 * None. 337 338 * 338 339 *----------------------------------------------------------------------- … … 340 341 static Boolean 341 342 CondDoMake (argLen, arg) 342 int argLen;343 int argLen; 343 344 char *arg; 344 345 { … … 348 349 arg[argLen] = '\0'; 349 350 if (Lst_Find (create, (ClientData)arg, CondStrMatch) == NILLNODE) { 350 result = FALSE;351 result = FALSE; 351 352 } else { 352 result = TRUE;353 result = TRUE; 353 354 } 354 355 arg[argLen] = savec; … … 360 361 *----------------------------------------------------------------------- 361 362 * CondDoExists -- 362 * See if the given file exists.363 * See if the given file exists. 363 364 * 364 365 * Results: 365 * TRUE if the file exists and FALSE if it does not.366 * TRUE if the file exists and FALSE if it does not. 366 367 * 367 368 * Side Effects: 368 * None.369 * None. 369 370 * 370 371 *----------------------------------------------------------------------- … … 372 373 static Boolean 373 374 CondDoExists (argLen, arg) 374 int argLen;375 int argLen; 375 376 char *arg; 376 377 { … … 382 383 path = Dir_FindFile(arg, dirSearchPath); 383 384 if (path != (char *)NULL) { 384 result = TRUE;385 efree(path);385 result = TRUE; 386 efree(path); 386 387 } else { 387 result = FALSE;388 result = FALSE; 388 389 } 389 390 arg[argLen] = savec; … … 395 396 *----------------------------------------------------------------------- 396 397 * CondDoTarget -- 397 * See if the given node exists and is an actual target.398 * See if the given node exists and is an actual target. 398 399 * 399 400 * Results: 400 * TRUE if the node exists as a target and FALSE if it does not.401 * TRUE if the node exists as a target and FALSE if it does not. 401 402 * 402 403 * Side Effects: 403 * None.404 * None. 404 405 * 405 406 *----------------------------------------------------------------------- … … 407 408 static Boolean 408 409 CondDoTarget (argLen, arg) 409 int argLen;410 int argLen; 410 411 char *arg; 411 412 { … … 417 418 gn = Targ_FindNode(arg, TARG_NOCREATE); 418 419 if ((gn != NILGNODE) && !OP_NOP(gn->type)) { 419 result = TRUE;420 result = TRUE; 420 421 } else { 421 result = FALSE;422 result = FALSE; 422 423 } 423 424 arg[argLen] = savec; … … 430 431 *----------------------------------------------------------------------- 431 432 * CondCvtArg -- 432 * Convert the given number into a double. If the number begins433 * with 0x, it is interpreted as a hexadecimal integer434 * and converted to a double from there. All other strings just have435 * strtod called on them.433 * Convert the given number into a double. If the number begins 434 * with 0x, it is interpreted as a hexadecimal integer 435 * and converted to a double from there. All other strings just have 436 * strtod called on them. 436 437 * 437 438 * Results: 438 * Sets 'value' to double value of string.439 * Returns address of the first character after the last valid440 * character of the converted number.439 * Sets 'value' to double value of string. 440 * Returns address of the first character after the last valid 441 * character of the converted number. 441 442 * 442 443 * Side Effects: 443 * Can change 'value' even if string is not a valid number.444 * Can change 'value' even if string is not a valid number. 444 445 * 445 446 * … … 448 449 static char * 449 450 CondCvtArg(str, value) 450 register char *str;451 double *value;451 register char *str; 452 double *value; 452 453 { 453 454 if ((*str == '0') && (str[1] == 'x')) { 454 register long i;455 456 for (str += 2, i = 0; ; str++) {457 int x;458 if (isdigit((unsigned char) *str))459 x = *str - '0';460 else if (isxdigit((unsigned char) *str))461 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a';462 else {463 *value = (double) i;464 return str;465 }466 i = (i << 4) + x;467 }455 register long i; 456 457 for (str += 2, i = 0; ; str++) { 458 int x; 459 if (isdigit((unsigned char) *str)) 460 x = *str - '0'; 461 else if (isxdigit((unsigned char) *str)) 462 x = 10 + *str - isupper((unsigned char) *str) ? 'A' : 'a'; 463 else { 464 *value = (double) i; 465 return str; 466 } 467 i = (i << 4) + x; 468 } 468 469 } 469 470 else { 470 char *eptr;471 *value = strtod(str, &eptr);472 return eptr;471 char *eptr; 472 *value = strtod(str, &eptr); 473 return eptr; 473 474 } 474 475 } … … 478 479 *----------------------------------------------------------------------- 479 480 * CondToken -- 480 * Return the next token from the input.481 * Return the next token from the input. 481 482 * 482 483 * Results: 483 * A Token for the next lexical token in the stream.484 * A Token for the next lexical token in the stream. 484 485 * 485 486 * Side Effects: 486 * condPushback will be set back to None if it is used.487 * condPushback will be set back to None if it is used. 487 488 * 488 489 *----------------------------------------------------------------------- … … 492 493 Boolean doEval; 493 494 { 494 Token t;495 Token t; 495 496 496 497 if (condPushBack == None) { 497 while (*condExpr == ' ' || *condExpr == '\t') {498 condExpr++;499 }500 switch (*condExpr) {501 case '(':502 t = LParen;503 condExpr++;504 break;505 case ')':506 t = RParen;507 condExpr++;508 break;509 case '|':510 if (condExpr[1] == '|') {511 condExpr++;512 }513 condExpr++;514 t = Or;515 break;516 case '&':517 if (condExpr[1] == '&') {518 condExpr++;519 }520 condExpr++;521 t = And;522 break;523 case '!':524 t = Not;525 condExpr++;526 break;527 case '\n':528 case '\0':529 t = EndOfFile;530 break;498 while (*condExpr == ' ' || *condExpr == '\t') { 499 condExpr++; 500 } 501 switch (*condExpr) { 502 case '(': 503 t = LParen; 504 condExpr++; 505 break; 506 case ')': 507 t = RParen; 508 condExpr++; 509 break; 510 case '|': 511 if (condExpr[1] == '|') { 512 condExpr++; 513 } 514 condExpr++; 515 t = Or; 516 break; 517 case '&': 518 if (condExpr[1] == '&') { 519 condExpr++; 520 } 521 condExpr++; 522 t = And; 523 break; 524 case '!': 525 t = Not; 526 condExpr++; 527 break; 528 case '\n': 529 case '\0': 530 t = EndOfFile; 531 break; 531 532 532 533 #ifdef NMAKE 533 534 case '[': 534 535 /* @todo execute this command!!! */ 535 Parse_Error(PARSE_WARNING, "Unsupported NMAKE construct ([])");536 Parse_Error(PARSE_WARNING, "Unsupported NMAKE construct ([])"); 536 537 t = False; 537 538 condExpr += strlen(condExpr); … … 543 544 case '"': 544 545 #endif 545 case '$': {546 char*lhs;547 char*rhs;548 char*op;549 intvarSpecLen;550 BooleandoFree;546 case '$': { 547 char *lhs; 548 char *rhs; 549 char *op; 550 int varSpecLen; 551 Boolean doFree; 551 552 #ifdef NMAKE 552 553 Boolean fQuoted = (*condExpr == '"'); … … 555 556 #endif 556 557 557 /*558 * Parse the variable spec and skip over it, saving its559 * value in lhs.560 */561 t = Err;562 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree);558 /* 559 * Parse the variable spec and skip over it, saving its 560 * value in lhs. 561 */ 562 t = Err; 563 lhs = Var_Parse(condExpr, VAR_CMD, doEval,&varSpecLen,&doFree); 563 564 #ifdef NMAKE 564 565 if (lhs == var_Error) … … 568 569 } 569 570 #else 570 if (lhs == var_Error) {571 /*572 * Even if !doEval, we still report syntax errors, which573 * is what getting var_Error back with !doEval means.574 */575 return(Err);576 }571 if (lhs == var_Error) { 572 /* 573 * Even if !doEval, we still report syntax errors, which 574 * is what getting var_Error back with !doEval means. 575 */ 576 return(Err); 577 } 577 578 #endif 578 condExpr += varSpecLen;579 condExpr += varSpecLen; 579 580 580 581 #ifdef NMAKE … … 583 584 ) 584 585 #else 585 if (!isspace((unsigned char) *condExpr) &&586 strchr("!=><", *condExpr) == NULL)586 if (!isspace((unsigned char) *condExpr) && 587 strchr("!=><", *condExpr) == NULL) 587 588 #endif 588 589 { 589 Buffer buf;590 char *cp;591 592 buf = Buf_Init(0);593 594 for (cp = lhs; *cp; cp++)595 Buf_AddByte(buf, (Byte)*cp);596 597 if (doFree)598 efree(lhs);590 Buffer buf; 591 char *cp; 592 593 buf = Buf_Init(0); 594 595 for (cp = lhs; *cp; cp++) 596 Buf_AddByte(buf, (Byte)*cp); 597 598 if (doFree) 599 efree(lhs); 599 600 600 601 #ifdef NMAKE 601 602 //@todo entirely support escaped quotes and such nitty pick. 602 for (;*condExpr && (fQuoted ? *condExpr != '"' : !isspace((unsigned char) *condExpr)); condExpr++)603 Buf_AddByte(buf, (Byte)*condExpr);603 for (;*condExpr && (fQuoted ? *condExpr != '"' : !isspace((unsigned char) *condExpr)); condExpr++) 604 Buf_AddByte(buf, (Byte)*condExpr); 604 605 if (fQuoted && *condExpr == '"') 605 606 condExpr++; 606 607 #else 607 for (;*condExpr && !isspace((unsigned char) *condExpr); condExpr++)608 Buf_AddByte(buf, (Byte)*condExpr);608 for (;*condExpr && !isspace((unsigned char) *condExpr); condExpr++) 609 Buf_AddByte(buf, (Byte)*condExpr); 609 610 #endif 610 611 611 Buf_AddByte(buf, (Byte)'\0');612 lhs = (char *)Buf_GetAll(buf, &varSpecLen);613 Buf_Destroy(buf, FALSE);614 615 doFree = TRUE;616 }617 618 /*619 * Skip whitespace to get to the operator620 */612 Buf_AddByte(buf, (Byte)'\0'); 613 lhs = (char *)Buf_GetAll(buf, &varSpecLen); 614 Buf_Destroy(buf, FALSE); 615 616 doFree = TRUE; 617 } 618 619 /* 620 * Skip whitespace to get to the operator 621 */ 621 622 #ifdef NMAKE 622 623 if (fQuoted && *condExpr == '"') 623 624 condExpr++; 624 625 #endif 625 while (isspace((unsigned char) *condExpr))626 condExpr++;627 628 /*629 * Make sure the operator is a valid one. If it isn't a630 * known relational operator, pretend we got a631 * != 0 comparison.632 */633 op = condExpr;634 switch (*condExpr) {635 case '!':636 case '=':637 case '<':638 case '>':639 if (condExpr[1] == '=') {640 condExpr += 2;641 } else {642 condExpr += 1;643 }644 break;645 default:646 op = "!=";647 rhs = "0";648 649 goto do_compare;650 }651 while (isspace((unsigned char) *condExpr)) {652 condExpr++;653 }654 if (*condExpr == '\0') {655 Parse_Error(PARSE_WARNING,656 "Missing right-hand-side of operator");657 goto error;658 }659 rhs = condExpr;626 while (isspace((unsigned char) *condExpr)) 627 condExpr++; 628 629 /* 630 * Make sure the operator is a valid one. If it isn't a 631 * known relational operator, pretend we got a 632 * != 0 comparison. 633 */ 634 op = condExpr; 635 switch (*condExpr) { 636 case '!': 637 case '=': 638 case '<': 639 case '>': 640 if (condExpr[1] == '=') { 641 condExpr += 2; 642 } else { 643 condExpr += 1; 644 } 645 break; 646 default: 647 op = "!="; 648 rhs = "0"; 649 650 goto do_compare; 651 } 652 while (isspace((unsigned char) *condExpr)) { 653 condExpr++; 654 } 655 if (*condExpr == '\0') { 656 Parse_Error(PARSE_WARNING, 657 "Missing right-hand-side of operator"); 658 goto error; 659 } 660 rhs = condExpr; 660 661 do_compare: 661 if (*rhs == '"') {662 /*663 * Doing a string comparison. Only allow == and != for664 * operators.665 */666 char *string;667 char *cp, *cp2;668 intqt;669 Buffer buf;662 if (*rhs == '"') { 663 /* 664 * Doing a string comparison. Only allow == and != for 665 * operators. 666 */ 667 char *string; 668 char *cp, *cp2; 669 int qt; 670 Buffer buf; 670 671 671 672 do_string_compare: 672 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) {673 Parse_Error(PARSE_WARNING,674 "String comparison operator should be either == or !=");675 goto error;676 }677 678 buf = Buf_Init(0);679 qt = *rhs == '"' ? 1 : 0;680 681 for (cp = &rhs[qt];682 ((qt && (*cp != '"')) ||683 (!qt && strchr(" \t)", *cp) == NULL)) &&684 (*cp != '\0'); cp++) {685 if ((*cp == '\\') && (cp[1] != '\0')) {686 /*687 * Backslash escapes things -- skip over next688 * character, if it exists.689 */690 cp++;691 Buf_AddByte(buf, (Byte)*cp);692 } else if (*cp == '$') {693 intlen;694 Boolean freeIt;695 696 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt);697 if (cp2 != var_Error) {698 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);699 if (freeIt) {700 efree(cp2);701 }702 cp += len - 1;703 } else {704 Buf_AddByte(buf, (Byte)*cp);705 }706 } else {707 Buf_AddByte(buf, (Byte)*cp);708 }709 }710 711 Buf_AddByte(buf, (Byte)0);712 713 string = (char *)Buf_GetAll(buf, (int *)0);714 Buf_Destroy(buf, FALSE);715 716 if (DEBUG(COND)) {717 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n",718 lhs, string, op);719 }720 /*721 * Null-terminate rhs and perform the comparison.722 * t is set to the result.723 */724 if (*op == '=') {725 t = strcmp(lhs, string) ? False : True;726 } else {727 t = strcmp(lhs, string) ? True : False;728 }729 efree(string);730 if (rhs == condExpr) {731 if (!qt && *cp == ')')732 condExpr = cp;733 else734 condExpr = cp + 1;735 }736 } else {737 /*738 * rhs is either a float or an integer. Convert both the739 * lhs and the rhs to a double and compare the two.740 */741 doubleleft, right;742 char*string;743 744 if (*CondCvtArg(lhs, &left) != '\0')745 goto do_string_compare;746 if (*rhs == '$') {747 intlen;748 BooleanfreeIt;749 750 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt);751 if (string == var_Error) {752 right = 0.0;753 } else {754 if (*CondCvtArg(string, &right) != '\0') {755 if (freeIt)756 efree(string);757 goto do_string_compare;758 }759 if (freeIt)760 efree(string);761 if (rhs == condExpr)762 condExpr += len;763 }764 } else {765 char *c = CondCvtArg(rhs, &right);766 if (*c != '\0' && !isspace(*c))767 goto do_string_compare;768 if (rhs == condExpr) {769 /*770 * Skip over the right-hand side771 */772 while(!isspace((unsigned char) *condExpr) &&773 (*condExpr != '\0')) {774 condExpr++;775 }776 }777 }778 779 if (DEBUG(COND)) {780 printf("left = %f, right = %f, op = %.2s\n", left,781 right, op);782 }783 switch(op[0]) {784 case '!':785 if (op[1] != '=') {786 Parse_Error(PARSE_WARNING,787 "Unknown operator");788 goto error;789 }790 t = (left != right ? True : False);791 break;792 case '=':793 if (op[1] != '=') {794 Parse_Error(PARSE_WARNING,795 "Unknown operator");796 goto error;797 }798 t = (left == right ? True : False);799 break;800 case '<':801 if (op[1] == '=') {802 t = (left <= right ? True : False);803 } else {804 t = (left < right ? True : False);805 }806 break;807 case '>':808 if (op[1] == '=') {809 t = (left >= right ? True : False);810 } else {811 t = (left > right ? True : False);812 }813 break;814 }815 }673 if (((*op != '!') && (*op != '=')) || (op[1] != '=')) { 674 Parse_Error(PARSE_WARNING, 675 "String comparison operator should be either == or !="); 676 goto error; 677 } 678 679 buf = Buf_Init(0); 680 qt = *rhs == '"' ? 1 : 0; 681 682 for (cp = &rhs[qt]; 683 ((qt && (*cp != '"')) || 684 (!qt && strchr(" \t)", *cp) == NULL)) && 685 (*cp != '\0'); cp++) { 686 if ((*cp == '\\') && (cp[1] != '\0')) { 687 /* 688 * Backslash escapes things -- skip over next 689 * character, if it exists. 690 */ 691 cp++; 692 Buf_AddByte(buf, (Byte)*cp); 693 } else if (*cp == '$') { 694 int len; 695 Boolean freeIt; 696 697 cp2 = Var_Parse(cp, VAR_CMD, doEval,&len, &freeIt); 698 if (cp2 != var_Error) { 699 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 700 if (freeIt) { 701 efree(cp2); 702 } 703 cp += len - 1; 704 } else { 705 Buf_AddByte(buf, (Byte)*cp); 706 } 707 } else { 708 Buf_AddByte(buf, (Byte)*cp); 709 } 710 } 711 712 Buf_AddByte(buf, (Byte)0); 713 714 string = (char *)Buf_GetAll(buf, (int *)0); 715 Buf_Destroy(buf, FALSE); 716 717 if (DEBUG(COND)) { 718 printf("lhs = \"%s\", rhs = \"%s\", op = %.2s\n", 719 lhs, string, op); 720 } 721 /* 722 * Null-terminate rhs and perform the comparison. 723 * t is set to the result. 724 */ 725 if (*op == '=') { 726 t = strcmp(lhs, string) ? False : True; 727 } else { 728 t = strcmp(lhs, string) ? True : False; 729 } 730 efree(string); 731 if (rhs == condExpr) { 732 if (!qt && *cp == ')') 733 condExpr = cp; 734 else 735 condExpr = cp + 1; 736 } 737 } else { 738 /* 739 * rhs is either a float or an integer. Convert both the 740 * lhs and the rhs to a double and compare the two. 741 */ 742 double left, right; 743 char *string; 744 745 if (*CondCvtArg(lhs, &left) != '\0') 746 goto do_string_compare; 747 if (*rhs == '$') { 748 int len; 749 Boolean freeIt; 750 751 string = Var_Parse(rhs, VAR_CMD, doEval,&len,&freeIt); 752 if (string == var_Error) { 753 right = 0.0; 754 } else { 755 if (*CondCvtArg(string, &right) != '\0') { 756 if (freeIt) 757 efree(string); 758 goto do_string_compare; 759 } 760 if (freeIt) 761 efree(string); 762 if (rhs == condExpr) 763 condExpr += len; 764 } 765 } else { 766 char *c = CondCvtArg(rhs, &right); 767 if (*c != '\0' && !isspace(*c)) 768 goto do_string_compare; 769 if (rhs == condExpr) { 770 /* 771 * Skip over the right-hand side 772 */ 773 while(!isspace((unsigned char) *condExpr) && 774 (*condExpr != '\0')) { 775 condExpr++; 776 } 777 } 778 } 779 780 if (DEBUG(COND)) { 781 printf("left = %f, right = %f, op = %.2s\n", left, 782 right, op); 783 } 784 switch(op[0]) { 785 case '!': 786 if (op[1] != '=') { 787 Parse_Error(PARSE_WARNING, 788 "Unknown operator"); 789 goto error; 790 } 791 t = (left != right ? True : False); 792 break; 793 case '=': 794 if (op[1] != '=') { 795 Parse_Error(PARSE_WARNING, 796 "Unknown operator"); 797 goto error; 798 } 799 t = (left == right ? True : False); 800 break; 801 case '<': 802 if (op[1] == '=') { 803 t = (left <= right ? True : False); 804 } else { 805 t = (left < right ? True : False); 806 } 807 break; 808 case '>': 809 if (op[1] == '=') { 810 t = (left >= right ? True : False); 811 } else { 812 t = (left > right ? True : False); 813 } 814 break; 815 } 816 } 816 817 error: 817 if (doFree)818 efree(lhs);819 break;820 }821 default: {822 Boolean (*evalProc) __P((int, char *));823 Boolean invert = FALSE;824 char*arg;825 intarglen;826 827 if (strncmp (condExpr, "defined", 7) == 0) {828 /*829 * Use CondDoDefined to evaluate the argument and830 * CondGetArg to extract the argument from the 'function831 * call'.832 */833 evalProc = CondDoDefined;834 condExpr += 7;835 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE);836 if (arglen == 0) {837 condExpr -= 7;838 goto use_default;839 }840 } else if (strncmp (condExpr, "make", 4) == 0) {841 /*842 * Use CondDoMake to evaluate the argument and843 * CondGetArg to extract the argument from the 'function844 * call'.845 */846 evalProc = CondDoMake;847 condExpr += 4;848 arglen = CondGetArg (&condExpr, &arg, "make", TRUE);849 if (arglen == 0) {850 condExpr -= 4;851 goto use_default;852 }853 } else if (strncmp (condExpr, "exists", 6) == 0) {854 /*855 * Use CondDoExists to evaluate the argument and856 * CondGetArg to extract the argument from the857 * 'function call'.858 */859 evalProc = CondDoExists;860 condExpr += 6;861 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE);862 if (arglen == 0) {863 condExpr -= 6;864 goto use_default;865 }866 } else if (strncmp(condExpr, "empty", 5) == 0) {867 /*868 * Use Var_Parse to parse the spec in parens and return869 * True if the resulting string is empty.870 */871 intlength;872 Boolean doFree;873 char *val;874 875 condExpr += 5;876 877 for (arglen = 0;878 condExpr[arglen] != '(' && condExpr[arglen] != '\0';879 arglen += 1)880 continue;881 882 if (condExpr[arglen] != '\0') {883 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD,884 doEval, &length, &doFree);885 if (val == var_Error) {886 t = Err;887 } else {888 /*889 * A variable is empty when it just contains890 * spaces... 4/15/92, christos891 */892 char *p;893 for (p = val; *p && isspace((unsigned char)*p); p++)894 continue;895 t = (*p == '\0') ? True : False;896 }897 if (doFree) {898 efree(val);899 }900 /*901 * Advance condExpr to beyond the closing ). Note that902 * we subtract one from arglen + length b/c length903 * is calculated from condExpr[arglen - 1].904 */905 condExpr += arglen + length - 1;906 } else {907 condExpr -= 5;908 goto use_default;909 }910 break;911 } else if (strncmp (condExpr, "target", 6) == 0) {912 /*913 * Use CondDoTarget to evaluate the argument and914 * CondGetArg to extract the argument from the915 * 'function call'.916 */917 evalProc = CondDoTarget;918 condExpr += 6;919 arglen = CondGetArg(&condExpr, &arg, "target", TRUE);920 if (arglen == 0) {921 condExpr -= 6;922 goto use_default;923 }924 } else {925 /*926 * The symbol is itself the argument to the default927 * function. We advance condExpr to the end of the symbol928 * by hand (the next whitespace, closing paren or929 * binary operator) and set to invert the evaluation930 * function if condInvert is TRUE.931 */932 use_default:933 invert = condInvert;934 evalProc = condDefProc;935 arglen = CondGetArg(&condExpr, &arg, "", FALSE);936 }937 938 /*939 * Evaluate the argument using the set function. If invert940 * is TRUE, we invert the sense of the function.941 */942 t = (!doEval || (* evalProc) (arglen, arg) ?943 (invert ? False : True) :944 (invert ? True : False));945 efree(arg);946 break;947 }948 }818 if (doFree) 819 efree(lhs); 820 break; 821 } 822 default: { 823 Boolean (*evalProc) __P((int, char *)); 824 Boolean invert = FALSE; 825 char *arg; 826 int arglen; 827 828 if (strncmp (condExpr, "defined", 7) == 0) { 829 /* 830 * Use CondDoDefined to evaluate the argument and 831 * CondGetArg to extract the argument from the 'function 832 * call'. 833 */ 834 evalProc = CondDoDefined; 835 condExpr += 7; 836 arglen = CondGetArg (&condExpr, &arg, "defined", TRUE); 837 if (arglen == 0) { 838 condExpr -= 7; 839 goto use_default; 840 } 841 } else if (strncmp (condExpr, "make", 4) == 0) { 842 /* 843 * Use CondDoMake to evaluate the argument and 844 * CondGetArg to extract the argument from the 'function 845 * call'. 846 */ 847 evalProc = CondDoMake; 848 condExpr += 4; 849 arglen = CondGetArg (&condExpr, &arg, "make", TRUE); 850 if (arglen == 0) { 851 condExpr -= 4; 852 goto use_default; 853 } 854 } else if (strncmp (condExpr, "exists", 6) == 0) { 855 /* 856 * Use CondDoExists to evaluate the argument and 857 * CondGetArg to extract the argument from the 858 * 'function call'. 859 */ 860 evalProc = CondDoExists; 861 condExpr += 6; 862 arglen = CondGetArg(&condExpr, &arg, "exists", TRUE); 863 if (arglen == 0) { 864 condExpr -= 6; 865 goto use_default; 866 } 867 } else if (strncmp(condExpr, "empty", 5) == 0) { 868 /* 869 * Use Var_Parse to parse the spec in parens and return 870 * True if the resulting string is empty. 871 */ 872 int length; 873 Boolean doFree; 874 char *val; 875 876 condExpr += 5; 877 878 for (arglen = 0; 879 condExpr[arglen] != '(' && condExpr[arglen] != '\0'; 880 arglen += 1) 881 continue; 882 883 if (condExpr[arglen] != '\0') { 884 val = Var_Parse(&condExpr[arglen - 1], VAR_CMD, 885 doEval, &length, &doFree); 886 if (val == var_Error) { 887 t = Err; 888 } else { 889 /* 890 * A variable is empty when it just contains 891 * spaces... 4/15/92, christos 892 */ 893 char *p; 894 for (p = val; *p && isspace((unsigned char)*p); p++) 895 continue; 896 t = (*p == '\0') ? True : False; 897 } 898 if (doFree) { 899 efree(val); 900 } 901 /* 902 * Advance condExpr to beyond the closing ). Note that 903 * we subtract one from arglen + length b/c length 904 * is calculated from condExpr[arglen - 1]. 905 */ 906 condExpr += arglen + length - 1; 907 } else { 908 condExpr -= 5; 909 goto use_default; 910 } 911 break; 912 } else if (strncmp (condExpr, "target", 6) == 0) { 913 /* 914 * Use CondDoTarget to evaluate the argument and 915 * CondGetArg to extract the argument from the 916 * 'function call'. 917 */ 918 evalProc = CondDoTarget; 919 condExpr += 6; 920 arglen = CondGetArg(&condExpr, &arg, "target", TRUE); 921 if (arglen == 0) { 922 condExpr -= 6; 923 goto use_default; 924 } 925 } else { 926 /* 927 * The symbol is itself the argument to the default 928 * function. We advance condExpr to the end of the symbol 929 * by hand (the next whitespace, closing paren or 930 * binary operator) and set to invert the evaluation 931 * function if condInvert is TRUE. 932 */ 933 use_default: 934 invert = condInvert; 935 evalProc = condDefProc; 936 arglen = CondGetArg(&condExpr, &arg, "", FALSE); 937 } 938 939 /* 940 * Evaluate the argument using the set function. If invert 941 * is TRUE, we invert the sense of the function. 942 */ 943 t = (!doEval || (* evalProc) (arglen, arg) ? 944 (invert ? False : True) : 945 (invert ? True : False)); 946 efree(arg); 947 break; 948 } 949 } 949 950 } else { 950 t = condPushBack;951 condPushBack = None;951 t = condPushBack; 952 condPushBack = None; 952 953 } 953 954 return (t); … … 958 959 *----------------------------------------------------------------------- 959 960 * CondT -- 960 * Parse a single term in the expression. This consists of a terminal961 * symbol or Not and a terminal symbol (not including the binary962 * operators):963 * T -> defined(variable) | make(target) | exists(file) | symbol964 * T -> ! T | ( E )961 * Parse a single term in the expression. This consists of a terminal 962 * symbol or Not and a terminal symbol (not including the binary 963 * operators): 964 * T -> defined(variable) | make(target) | exists(file) | symbol 965 * T -> ! T | ( E ) 965 966 * 966 967 * Results: 967 * True, False or Err.968 * True, False or Err. 968 969 * 969 970 * Side Effects: 970 * Tokens are consumed.971 * Tokens are consumed. 971 972 * 972 973 *----------------------------------------------------------------------- … … 981 982 982 983 if (t == EndOfFile) { 983 /*984 * If we reached the end of the expression, the expression985 * is malformed...986 */987 t = Err;984 /* 985 * If we reached the end of the expression, the expression 986 * is malformed... 987 */ 988 t = Err; 988 989 } else if (t == LParen) { 989 /*990 * T -> ( E )991 */992 t = CondE(doEval);993 if (t != Err) {994 if (CondToken(doEval) != RParen) {995 t = Err;996 }997 }990 /* 991 * T -> ( E ) 992 */ 993 t = CondE(doEval); 994 if (t != Err) { 995 if (CondToken(doEval) != RParen) { 996 t = Err; 997 } 998 } 998 999 } else if (t == Not) { 999 t = CondT(doEval);1000 if (t == True) {1001 t = False;1002 } else if (t == False) {1003 t = True;1004 }1000 t = CondT(doEval); 1001 if (t == True) { 1002 t = False; 1003 } else if (t == False) { 1004 t = True; 1005 } 1005 1006 } 1006 1007 return (t); … … 1011 1012 *----------------------------------------------------------------------- 1012 1013 * CondF -- 1013 * Parse a conjunctive factor (nice name, wot?)1014 * F -> T && F | T1014 * Parse a conjunctive factor (nice name, wot?) 1015 * F -> T && F | T 1015 1016 * 1016 1017 * Results: 1017 * True, False or Err1018 * True, False or Err 1018 1019 * 1019 1020 * Side Effects: 1020 * Tokens are consumed.1021 * Tokens are consumed. 1021 1022 * 1022 1023 *----------------------------------------------------------------------- … … 1030 1031 l = CondT(doEval); 1031 1032 if (l != Err) { 1032 o = CondToken(doEval);1033 1034 if (o == And) {1035 /*1036 * F -> T && F1037 *1038 * If T is False, the whole thing will be False, but we have to1039 * parse the r.h.s. anyway (to throw it away).1040 * If T is True, the result is the r.h.s., be it an Err or no.1041 */1042 if (l == True) {1043 l = CondF(doEval);1044 } else {1045 (void) CondF(FALSE);1046 }1047 } else {1048 /*1049 * F -> T1050 */1051 CondPushBack (o);1052 }1033 o = CondToken(doEval); 1034 1035 if (o == And) { 1036 /* 1037 * F -> T && F 1038 * 1039 * If T is False, the whole thing will be False, but we have to 1040 * parse the r.h.s. anyway (to throw it away). 1041 * If T is True, the result is the r.h.s., be it an Err or no. 1042 */ 1043 if (l == True) { 1044 l = CondF(doEval); 1045 } else { 1046 (void) CondF(FALSE); 1047 } 1048 } else { 1049 /* 1050 * F -> T 1051 */ 1052 CondPushBack (o); 1053 } 1053 1054 } 1054 1055 return (l); … … 1059 1060 *----------------------------------------------------------------------- 1060 1061 * CondE -- 1061 * Main expression production.1062 * E -> F || E | F1062 * Main expression production. 1063 * E -> F || E | F 1063 1064 * 1064 1065 * Results: 1065 * True, False or Err.1066 * True, False or Err. 1066 1067 * 1067 1068 * Side Effects: 1068 * Tokens are, of course, consumed.1069 * Tokens are, of course, consumed. 1069 1070 * 1070 1071 *----------------------------------------------------------------------- … … 1078 1079 l = CondF(doEval); 1079 1080 if (l != Err) { 1080 o = CondToken(doEval);1081 1082 if (o == Or) {1083 /*1084 * E -> F || E1085 *1086 * A similar thing occurs for ||, except that here we make sure1087 * the l.h.s. is False before we bother to evaluate the r.h.s.1088 * Once again, if l is False, the result is the r.h.s. and once1089 * again if l is True, we parse the r.h.s. to throw it away.1090 */1091 if (l == False) {1092 l = CondE(doEval);1093 } else {1094 (void) CondE(FALSE);1095 }1096 } else {1097 /*1098 * E -> F1099 */1100 CondPushBack (o);1101 }1081 o = CondToken(doEval); 1082 1083 if (o == Or) { 1084 /* 1085 * E -> F || E 1086 * 1087 * A similar thing occurs for ||, except that here we make sure 1088 * the l.h.s. is False before we bother to evaluate the r.h.s. 1089 * Once again, if l is False, the result is the r.h.s. and once 1090 * again if l is True, we parse the r.h.s. to throw it away. 1091 */ 1092 if (l == False) { 1093 l = CondE(doEval); 1094 } else { 1095 (void) CondE(FALSE); 1096 } 1097 } else { 1098 /* 1099 * E -> F 1100 */ 1101 CondPushBack (o); 1102 } 1102 1103 } 1103 1104 return (l); … … 1108 1109 *----------------------------------------------------------------------- 1109 1110 * Cond_Eval -- 1110 * Evaluate the conditional in the passed line. The line1111 * looks like this:1112 * #<cond-type> <expr>1113 * where <cond-type> is any of if, ifmake, ifnmake, ifdef,1114 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef1115 * and <expr> consists of &&, ||, !, make(target), defined(variable)1116 * and parenthetical groupings thereof.1111 * Evaluate the conditional in the passed line. The line 1112 * looks like this: 1113 * #<cond-type> <expr> 1114 * where <cond-type> is any of if, ifmake, ifnmake, ifdef, 1115 * ifndef, elif, elifmake, elifnmake, elifdef, elifndef 1116 * and <expr> consists of &&, ||, !, make(target), defined(variable) 1117 * and parenthetical groupings thereof. 1117 1118 * 1118 1119 * Results: 1119 * COND_PARSEif should parse lines after the conditional1120 * COND_SKIPif should skip lines after the conditional1121 * COND_INVALIDif not a valid conditional.1120 * COND_PARSE if should parse lines after the conditional 1121 * COND_SKIP if should skip lines after the conditional 1122 * COND_INVALID if not a valid conditional. 1122 1123 * 1123 1124 * Side Effects: 1124 * None.1125 * None. 1125 1126 * 1126 1127 *----------------------------------------------------------------------- … … 1128 1129 int 1129 1130 Cond_Eval (line) 1130 char *line; /* Line to parse */1131 char *line; /* Line to parse */ 1131 1132 { 1132 struct If *ifp;1133 Boolean isElse;1134 Boolean value = FALSE;1135 int level;/* Level at which to report errors. */1133 struct If *ifp; 1134 Boolean isElse; 1135 Boolean value = FALSE; 1136 int level; /* Level at which to report errors. */ 1136 1137 1137 1138 level = PARSE_FATAL; 1138 1139 1139 1140 for (line++; *line == ' ' || *line == '\t'; line++) { 1140 continue;1141 continue; 1141 1142 } 1142 1143 … … 1146 1147 */ 1147 1148 if (line[0] == 'e' && line[1] == 'l') { 1148 line += 2;1149 isElse = TRUE;1149 line += 2; 1150 isElse = TRUE; 1150 1151 } else if (strncmp (line, "endif", 5) == 0) { 1151 /*1152 * End of a conditional section. If skipIfLevel is non-zero, that1153 * conditional was skipped, so lines following it should also be1154 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional1155 * was read so succeeding lines should be parsed (think about it...)1156 * so we return COND_PARSE, unless this endif isn't paired with1157 * a decent if.1158 */1159 if (skipIfLevel != 0) {1160 skipIfLevel -= 1;1161 return (COND_SKIP);1162 } else {1163 if (condTop == MAXIF) {1164 Parse_Error (level, "if-less endif");1165 return (COND_INVALID);1166 } else {1167 skipLine = FALSE;1168 condTop += 1;1169 return (COND_PARSE);1170 }1171 }1152 /* 1153 * End of a conditional section. If skipIfLevel is non-zero, that 1154 * conditional was skipped, so lines following it should also be 1155 * skipped. Hence, we return COND_SKIP. Otherwise, the conditional 1156 * was read so succeeding lines should be parsed (think about it...) 1157 * so we return COND_PARSE, unless this endif isn't paired with 1158 * a decent if. 1159 */ 1160 if (skipIfLevel != 0) { 1161 skipIfLevel -= 1; 1162 return (COND_SKIP); 1163 } else { 1164 if (condTop == MAXIF) { 1165 Parse_Error (level, "if-less endif"); 1166 return (COND_INVALID); 1167 } else { 1168 skipLine = FALSE; 1169 condTop += 1; 1170 return (COND_PARSE); 1171 } 1172 } 1172 1173 } else { 1173 isElse = FALSE;1174 isElse = FALSE; 1174 1175 } 1175 1176 … … 1179 1180 */ 1180 1181 for (ifp = ifs; ifp->form != (char *)0; ifp++) { 1181 if (strncmp (ifp->form, line, ifp->formlen) == 0) {1182 break;1183 }1182 if (strncmp (ifp->form, line, ifp->formlen) == 0) { 1183 break; 1184 } 1184 1185 } 1185 1186 1186 1187 if (ifp->form == (char *) 0) { 1187 /*1188 * Nothing fit. If the first word on the line is actually1189 * "else", it's a valid conditional whose value is the inverse1190 * of the previous if we parsed.1191 */1192 if (isElse && (line[0] == 's') && (line[1] == 'e')) {1193 if (condTop == MAXIF) {1194 Parse_Error (level, "if-less else");1195 return (COND_INVALID);1196 } else if (skipIfLevel == 0) {1197 value = !condStack[condTop];1198 } else {1199 return (COND_SKIP);1200 }1201 } else {1202 /*1203 * Not a valid conditional type. No error...1204 */1205 return (COND_INVALID);1206 }1188 /* 1189 * Nothing fit. If the first word on the line is actually 1190 * "else", it's a valid conditional whose value is the inverse 1191 * of the previous if we parsed. 1192 */ 1193 if (isElse && (line[0] == 's') && (line[1] == 'e')) { 1194 if (condTop == MAXIF) { 1195 Parse_Error (level, "if-less else"); 1196 return (COND_INVALID); 1197 } else if (skipIfLevel == 0) { 1198 value = !condStack[condTop]; 1199 } else { 1200 return (COND_SKIP); 1201 } 1202 } else { 1203 /* 1204 * Not a valid conditional type. No error... 1205 */ 1206 return (COND_INVALID); 1207 } 1207 1208 } else { 1208 if (isElse) {1209 if (condTop == MAXIF) {1210 Parse_Error (level, "if-less elif");1211 return (COND_INVALID);1212 } else if (skipIfLevel != 0) {1213 /*1214 * If skipping this conditional, just ignore the whole thing.1215 * If we don't, the user might be employing a variable that's1216 * undefined, for which there's an enclosing ifdef that1217 * we're skipping...1218 */1219 return(COND_SKIP);1220 }1221 } else if (skipLine) {1222 /*1223 * Don't even try to evaluate a conditional that's not an else if1224 * we're skipping things...1225 */1226 skipIfLevel += 1;1227 return(COND_SKIP);1228 }1229 1230 /*1231 * Initialize file-global variables for parsing1232 */1233 condDefProc = ifp->defProc;1234 condInvert = ifp->doNot;1235 1236 line += ifp->formlen;1237 1238 while (*line == ' ' || *line == '\t') {1239 line++;1240 }1241 1242 condExpr = line;1243 condPushBack = None;1244 1245 switch (CondE(TRUE)) {1246 case True:1247 if (CondToken(TRUE) == EndOfFile) {1248 value = TRUE;1249 break;1250 }1251 goto err;1252 /*FALLTHRU*/1253 case False:1254 if (CondToken(TRUE) == EndOfFile) {1255 value = FALSE;1256 break;1257 }1258 /*FALLTHRU*/1259 case Err:1260 err:1261 Parse_Error (level, "Malformed conditional (%s)",1262 line);1263 return (COND_INVALID);1264 default:1265 break;1266 }1209 if (isElse) { 1210 if (condTop == MAXIF) { 1211 Parse_Error (level, "if-less elif"); 1212 return (COND_INVALID); 1213 } else if (skipIfLevel != 0) { 1214 /* 1215 * If skipping this conditional, just ignore the whole thing. 1216 * If we don't, the user might be employing a variable that's 1217 * undefined, for which there's an enclosing ifdef that 1218 * we're skipping... 1219 */ 1220 return(COND_SKIP); 1221 } 1222 } else if (skipLine) { 1223 /* 1224 * Don't even try to evaluate a conditional that's not an else if 1225 * we're skipping things... 1226 */ 1227 skipIfLevel += 1; 1228 return(COND_SKIP); 1229 } 1230 1231 /* 1232 * Initialize file-global variables for parsing 1233 */ 1234 condDefProc = ifp->defProc; 1235 condInvert = ifp->doNot; 1236 1237 line += ifp->formlen; 1238 1239 while (*line == ' ' || *line == '\t') { 1240 line++; 1241 } 1242 1243 condExpr = line; 1244 condPushBack = None; 1245 1246 switch (CondE(TRUE)) { 1247 case True: 1248 if (CondToken(TRUE) == EndOfFile) { 1249 value = TRUE; 1250 break; 1251 } 1252 goto err; 1253 /*FALLTHRU*/ 1254 case False: 1255 if (CondToken(TRUE) == EndOfFile) { 1256 value = FALSE; 1257 break; 1258 } 1259 /*FALLTHRU*/ 1260 case Err: 1261 err: 1262 Parse_Error (level, "Malformed conditional (%s)", 1263 line); 1264 return (COND_INVALID); 1265 default: 1266 break; 1267 } 1267 1268 } 1268 1269 if (!isElse) { 1269 condTop -= 1;1270 condTop -= 1; 1270 1271 } else if ((skipIfLevel != 0) || condStack[condTop]) { 1271 /*1272 * If this is an else-type conditional, it should only take effect1273 * if its corresponding if was evaluated and FALSE. If its if was1274 * TRUE or skipped, we return COND_SKIP (and start skipping in case1275 * we weren't already), leaving the stack unmolested so later elif's1276 * don't screw up...1277 */1278 skipLine = TRUE;1279 return (COND_SKIP);1272 /* 1273 * If this is an else-type conditional, it should only take effect 1274 * if its corresponding if was evaluated and FALSE. If its if was 1275 * TRUE or skipped, we return COND_SKIP (and start skipping in case 1276 * we weren't already), leaving the stack unmolested so later elif's 1277 * don't screw up... 1278 */ 1279 skipLine = TRUE; 1280 return (COND_SKIP); 1280 1281 } 1281 1282 1282 1283 if (condTop < 0) { 1283 /*1284 * This is the one case where we can definitely proclaim a fatal1285 * error. If we don't, we're hosed.1286 */1287 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF);1288 return (COND_INVALID);1284 /* 1285 * This is the one case where we can definitely proclaim a fatal 1286 * error. If we don't, we're hosed. 1287 */ 1288 Parse_Error (PARSE_FATAL, "Too many nested if's. %d max.", MAXIF); 1289 return (COND_INVALID); 1289 1290 } else { 1290 condStack[condTop] = value;1291 skipLine = !value;1292 return (value ? COND_PARSE : COND_SKIP);1291 condStack[condTop] = value; 1292 skipLine = !value; 1293 return (value ? COND_PARSE : COND_SKIP); 1293 1294 } 1294 1295 } … … 1298 1299 *----------------------------------------------------------------------- 1299 1300 * Cond_End -- 1300 * Make sure everything's clean at the end of a makefile.1301 * Make sure everything's clean at the end of a makefile. 1301 1302 * 1302 1303 * Results: 1303 * None.1304 * None. 1304 1305 * 1305 1306 * Side Effects: 1306 * Parse_Error will be called if open conditionals are around.1307 * Parse_Error will be called if open conditionals are around. 1307 1308 * 1308 1309 *----------------------------------------------------------------------- … … 1312 1313 { 1313 1314 if (condTop != MAXIF) { 1314 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop,1315 MAXIF-condTop == 1 ? "" : "s");1315 Parse_Error(PARSE_FATAL, "%d open conditional%s", MAXIF-condTop, 1316 MAXIF-condTop == 1 ? "" : "s"); 1316 1317 } 1317 1318 condTop = MAXIF; -
trunk/src/kmk/config.h
r47 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 36 36 * SUCH DAMAGE. 37 37 * 38 * from: @(#)config.h8.1 (Berkeley) 6/6/9338 * from: @(#)config.h 8.1 (Berkeley) 6/6/93 39 39 * $FreeBSD: src/usr.bin/make/config.h,v 1.9 1999/09/10 20:51:59 julian Exp $ 40 40 */ 41 41 42 #define DEFSHELL 1/* Bourne shell */42 #define DEFSHELL 1 /* Bourne shell */ 43 43 44 44 /* 45 45 * DEFMAXJOBS 46 46 * DEFMAXLOCAL 47 * These control the default concurrency. On no occasion will more48 * than DEFMAXJOBS targets be created at once (locally or remotely)49 * DEFMAXLOCAL is the highest number of targets which will be50 * created on the local machine at once. Note that if you set this51 * to 0, nothing will ever happen...47 * These control the default concurrency. On no occasion will more 48 * than DEFMAXJOBS targets be created at once (locally or remotely) 49 * DEFMAXLOCAL is the highest number of targets which will be 50 * created on the local machine at once. Note that if you set this 51 * to 0, nothing will ever happen... 52 52 */ 53 #define DEFMAXJOBS 454 #define DEFMAXLOCAL 153 #define DEFMAXJOBS 4 54 #define DEFMAXLOCAL 1 55 55 56 56 /* 57 57 * INCLUDES 58 58 * LIBRARIES 59 * These control the handling of the .INCLUDES and .LIBS variables.60 * If INCLUDES is defined, the .INCLUDES variable will be filled61 * from the search paths of those suffixes which are marked by62 * .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS63 * See suff.c for more details.59 * These control the handling of the .INCLUDES and .LIBS variables. 60 * If INCLUDES is defined, the .INCLUDES variable will be filled 61 * from the search paths of those suffixes which are marked by 62 * .INCLUDES dependency lines. Similarly for LIBRARIES and .LIBS 63 * See suff.c for more details. 64 64 */ 65 65 #define INCLUDES … … 68 68 /* 69 69 * LIBSUFF 70 * Is the suffix used to denote libraries and is used by the Suff module71 * to find the search path on which to seek any -l<xx> targets.70 * Is the suffix used to denote libraries and is used by the Suff module 71 * to find the search path on which to seek any -l<xx> targets. 72 72 * 73 73 * RECHECK 74 * If defined, Make_Update will check a target for its current75 * modification time after it has been re-made, setting it to the76 * starting time of the make only if the target still doesn't exist.77 * Unfortunately, under NFS the modification time often doesn't78 * get updated in time, so a target will appear to not have been79 * re-made, causing later targets to appear up-to-date. On systems80 * that don't have this problem, you should defined this. Under81 * NFS you probably should not, unless you aren't exporting jobs.74 * If defined, Make_Update will check a target for its current 75 * modification time after it has been re-made, setting it to the 76 * starting time of the make only if the target still doesn't exist. 77 * Unfortunately, under NFS the modification time often doesn't 78 * get updated in time, so a target will appear to not have been 79 * re-made, causing later targets to appear up-to-date. On systems 80 * that don't have this problem, you should defined this. Under 81 * NFS you probably should not, unless you aren't exporting jobs. 82 82 */ 83 #define LIBSUFF".a"84 #define RECHECK83 #define LIBSUFF ".a" 84 #define RECHECK 85 85 86 86 /* 87 87 * POSIX 88 * Adhere to the POSIX 1003.2 draft for the make(1) program.89 * - Use MAKEFLAGS instead of MAKE to pick arguments from the90 * environment.91 * - Allow empty command lines if starting with tab.88 * Adhere to the POSIX 1003.2 draft for the make(1) program. 89 * - Use MAKEFLAGS instead of MAKE to pick arguments from the 90 * environment. 91 * - Allow empty command lines if starting with tab. 92 92 */ 93 93 #define POSIX … … 95 95 /* 96 96 * SYSVINCLUDE 97 * Recognize system V like include directives [include "filename"]97 * Recognize system V like include directives [include "filename"] 98 98 * SYSVVARSUB 99 * Recognize system V like ${VAR:x=y} variable substitutions99 * Recognize system V like ${VAR:x=y} variable substitutions 100 100 */ 101 101 #define SYSVINCLUDE … … 104 104 /* 105 105 * SUNSHCMD 106 * Recognize SunOS and Solaris:107 * VAR :sh= CMD# Assign VAR to the command substitution of CMD108 * ${VAR:sh}# Return the command substitution of the value109 * # of ${VAR}106 * Recognize SunOS and Solaris: 107 * VAR :sh= CMD # Assign VAR to the command substitution of CMD 108 * ${VAR:sh} # Return the command substitution of the value 109 * # of ${VAR} 110 110 */ 111 111 #define SUNSHCMD … … 120 120 # endif 121 121 #endif 122 123 124 125 122 126 123 … … 159 156 160 157 /* 158 * USE_BASEANDROOT_MODIFIERS 159 * If defined two extra variable modifiers B and R are added. 160 */ 161 #if defined(NMAKE) || defined(KMK) 162 #define USE_BASEANDROOT_MODIFIERS 1 163 #endif 164 165 166 /* 161 167 * USE_ISODATES 162 168 * If defined dates and times will be outputted in ISO format. -
trunk/src/kmk/dir.c
r46 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94";41 static char sccsid[] = "@(#)dir.c 8.2 (Berkeley) 1/2/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/dir.c,v 1.10.2.1 2001/02/13 03:13:57 will Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * dir.c -- 50 * Directory searching using wildcards and/or normal names...51 * Used both for source wildcarding in the Makefile and for finding52 * implicit sources.51 * Directory searching using wildcards and/or normal names... 52 * Used both for source wildcarding in the Makefile and for finding 53 * implicit sources. 53 54 * 54 55 * The interface for this module is: 55 * Dir_InitInitialize the module.56 * 57 * Dir_EndCleanup the module.58 * 59 * Dir_HasWildcards Returns TRUE if the name given it needs to60 * be wildcard-expanded.61 * 62 * Dir_ExpandGiven a pattern and a path, return a Lst of names63 * which match the pattern on the search path.64 * 65 * Dir_FindFileSearches for a file on a given search path.66 * If it exists, the entire path is returned.67 * Otherwise NULL is returned.68 * 69 * Dir_MTimeReturn the modification time of a node. The file70 * is searched for along the default search path.71 * The path and mtime fields of the node are filled72 * in.73 * 74 * Dir_AddDirAdd a directory to a search path.75 * 76 * Dir_MakeFlagsGiven a search path and a command flag, create77 * a string with each of the directories in the path78 * preceded by the command flag and all of them79 * separated by a space.80 * 81 * Dir_DestroyDestroy an element of a search path. Frees up all82 * things that can be freed for the element as long83 * as the element is no longer referenced by any other84 * search path.85 * Dir_ClearPathResets a search path to the empty list.56 * Dir_Init Initialize the module. 57 * 58 * Dir_End Cleanup the module. 59 * 60 * Dir_HasWildcards Returns TRUE if the name given it needs to 61 * be wildcard-expanded. 62 * 63 * Dir_Expand Given a pattern and a path, return a Lst of names 64 * which match the pattern on the search path. 65 * 66 * Dir_FindFile Searches for a file on a given search path. 67 * If it exists, the entire path is returned. 68 * Otherwise NULL is returned. 69 * 70 * Dir_MTime Return the modification time of a node. The file 71 * is searched for along the default search path. 72 * The path and mtime fields of the node are filled 73 * in. 74 * 75 * Dir_AddDir Add a directory to a search path. 76 * 77 * Dir_MakeFlags Given a search path and a command flag, create 78 * a string with each of the directories in the path 79 * preceded by the command flag and all of them 80 * separated by a space. 81 * 82 * Dir_Destroy Destroy an element of a search path. Frees up all 83 * things that can be freed for the element as long 84 * as the element is no longer referenced by any other 85 * search path. 86 * Dir_ClearPath Resets a search path to the empty list. 86 87 * 87 88 * For debugging: 88 * Dir_PrintDirectoriesPrint stats about the directory cache.89 * Dir_PrintDirectories Print stats about the directory cache. 89 90 */ 90 91 … … 98 99 99 100 /* 100 * A search path consists of a Lst of Path structures. A Path structure101 * has in it the name of the directory and a hash table of all the files102 * in the directory. This is used to cut down on the number of system103 * calls necessary to find implicit dependents and their like. Since104 * these searches are made before any actions are taken, we need not105 * worry about the directory changing due to creation commands. If this106 * hampers the style of some makefiles, they must be changed.107 * 108 * A list of all previously-read directories is kept in the109 * openDirectories Lst. This list is checked first before a directory110 * is opened.111 * 112 * The need for the caching of whole directories is brought about by113 * the multi-level transformation code in suff.c, which tends to search114 * for far more files than regular make does. In the initial115 * implementation, the amount of time spent performing "stat" calls was116 * truly astronomical. The problem with hashing at the start is,117 * of course, that pmake doesn't then detect changes to these directories118 * during the course of the make. Three possibilities suggest themselves:119 * 120 * 1) just use stat to test for a file's existence. As mentioned121 * above, this is very inefficient due to the number of checks122 * engendered by the multi-level transformation code.123 * 2) use readdir() and company to search the directories, keeping124 * them open between checks. I have tried this and while it125 * didn't slow down the process too much, it could severely126 * affect the amount of parallelism available as each directory127 * open would take another file descriptor out of play for128 * handling I/O for another job. Given that it is only recently129 * that UNIX OS's have taken to allowing more than 20 or 32130 * file descriptors for a process, this doesn't seem acceptable131 * to me.132 * 3) record the mtime of the directory in the Path structure and133 * verify the directory hasn't changed since the contents were134 * hashed. This will catch the creation or deletion of files,135 * but not the updating of files. However, since it is the136 * creation and deletion that is the problem, this could be137 * a good thing to do. Unfortunately, if the directory (say ".")138 * were fairly large and changed fairly frequently, the constant139 * rehashing could seriously degrade performance. It might be140 * good in such cases to keep track of the number of rehashes141 * and if the number goes over a (small) limit, resort to using142 * stat in its place.143 * 144 * An additional thing to consider is that pmake is used primarily145 * to create C programs and until recently pcc-based compilers refused146 * to allow you to specify where the resulting object file should be147 * placed. This forced all objects to be created in the current148 * directory. This isn't meant as a full excuse, just an explanation of149 * some of the reasons for the caching used here.150 * 151 * One more note: the location of a target's file is only performed152 * on the downward traversal of the graph and then only for terminal153 * nodes in the graph. This could be construed as wrong in some cases,154 * but prevents inadvertent modification of files when the "installed"155 * directory for a file is provided in the search path.156 * 157 * Another data structure maintained by this module is an mtime158 * cache used when the searching of cached directories fails to find159 * a file. In the past, Dir_FindFile would simply perform an access()160 * call in such a case to determine if the file could be found using161 * just the name given. When this hit, however, all that was gained162 * was the knowledge that the file existed. Given that an access() is163 * essentially a stat() without the copyout() call, and that the same164 * filesystem overhead would have to be incurred in Dir_MTime, it made165 * sense to replace the access() with a stat() and record the mtime166 * in a cache for when Dir_MTime was actually called.167 */ 168 169 Lst dirSearchPath; /* main search path */170 171 static Lst openDirectories; /* the list of all open directories */101 * A search path consists of a Lst of Path structures. A Path structure 102 * has in it the name of the directory and a hash table of all the files 103 * in the directory. This is used to cut down on the number of system 104 * calls necessary to find implicit dependents and their like. Since 105 * these searches are made before any actions are taken, we need not 106 * worry about the directory changing due to creation commands. If this 107 * hampers the style of some makefiles, they must be changed. 108 * 109 * A list of all previously-read directories is kept in the 110 * openDirectories Lst. This list is checked first before a directory 111 * is opened. 112 * 113 * The need for the caching of whole directories is brought about by 114 * the multi-level transformation code in suff.c, which tends to search 115 * for far more files than regular make does. In the initial 116 * implementation, the amount of time spent performing "stat" calls was 117 * truly astronomical. The problem with hashing at the start is, 118 * of course, that pmake doesn't then detect changes to these directories 119 * during the course of the make. Three possibilities suggest themselves: 120 * 121 * 1) just use stat to test for a file's existence. As mentioned 122 * above, this is very inefficient due to the number of checks 123 * engendered by the multi-level transformation code. 124 * 2) use readdir() and company to search the directories, keeping 125 * them open between checks. I have tried this and while it 126 * didn't slow down the process too much, it could severely 127 * affect the amount of parallelism available as each directory 128 * open would take another file descriptor out of play for 129 * handling I/O for another job. Given that it is only recently 130 * that UNIX OS's have taken to allowing more than 20 or 32 131 * file descriptors for a process, this doesn't seem acceptable 132 * to me. 133 * 3) record the mtime of the directory in the Path structure and 134 * verify the directory hasn't changed since the contents were 135 * hashed. This will catch the creation or deletion of files, 136 * but not the updating of files. However, since it is the 137 * creation and deletion that is the problem, this could be 138 * a good thing to do. Unfortunately, if the directory (say ".") 139 * were fairly large and changed fairly frequently, the constant 140 * rehashing could seriously degrade performance. It might be 141 * good in such cases to keep track of the number of rehashes 142 * and if the number goes over a (small) limit, resort to using 143 * stat in its place. 144 * 145 * An additional thing to consider is that pmake is used primarily 146 * to create C programs and until recently pcc-based compilers refused 147 * to allow you to specify where the resulting object file should be 148 * placed. This forced all objects to be created in the current 149 * directory. This isn't meant as a full excuse, just an explanation of 150 * some of the reasons for the caching used here. 151 * 152 * One more note: the location of a target's file is only performed 153 * on the downward traversal of the graph and then only for terminal 154 * nodes in the graph. This could be construed as wrong in some cases, 155 * but prevents inadvertent modification of files when the "installed" 156 * directory for a file is provided in the search path. 157 * 158 * Another data structure maintained by this module is an mtime 159 * cache used when the searching of cached directories fails to find 160 * a file. In the past, Dir_FindFile would simply perform an access() 161 * call in such a case to determine if the file could be found using 162 * just the name given. When this hit, however, all that was gained 163 * was the knowledge that the file existed. Given that an access() is 164 * essentially a stat() without the copyout() call, and that the same 165 * filesystem overhead would have to be incurred in Dir_MTime, it made 166 * sense to replace the access() with a stat() and record the mtime 167 * in a cache for when Dir_MTime was actually called. 168 */ 169 170 Lst dirSearchPath; /* main search path */ 171 172 static Lst openDirectories; /* the list of all open directories */ 172 173 173 174 /* … … 175 176 * mechanism. 176 177 */ 177 static int hits, /* Found in directory cache */178 misses,/* Sad, but not evil misses */179 nearmisses, /* Found under search path */180 bigmisses; /* Sought by itself */181 182 static Path *dot;/* contents of current directory */178 static int hits, /* Found in directory cache */ 179 misses, /* Sad, but not evil misses */ 180 nearmisses, /* Found under search path */ 181 bigmisses; /* Sought by itself */ 182 183 static Path *dot; /* contents of current directory */ 183 184 static Hash_Table mtimes; /* Results of doing a last-resort stat in 184 * Dir_FindFile -- if we have to go to the185 * system to find the file, we might as well186 * have its mtime on record. XXX: If this is done187 * way early, there's a chance other rules will188 * have already updated the file, in which case189 * we'll update it again. Generally, there won't190 * be two rules to update a single file, so this191 * should be ok, but... */185 * Dir_FindFile -- if we have to go to the 186 * system to find the file, we might as well 187 * have its mtime on record. XXX: If this is done 188 * way early, there's a chance other rules will 189 * have already updated the file, in which case 190 * we'll update it again. Generally, there won't 191 * be two rules to update a single file, so this 192 * should be ok, but... */ 192 193 193 194 … … 202 203 *----------------------------------------------------------------------- 203 204 * Dir_Init -- 204 * initialize things for this module205 * 206 * Results: 207 * none208 * 209 * Side Effects: 210 * some directories may be opened.205 * initialize things for this module 206 * 207 * Results: 208 * none 209 * 210 * Side Effects: 211 * some directories may be opened. 211 212 *----------------------------------------------------------------------- 212 213 */ … … 227 228 dot = (Path *) Lst_DeQueue (openDirectories); 228 229 if (dot == (Path *) NULL) 229 err(1, "cannot open current directory");230 err(1, "cannot open current directory"); 230 231 231 232 /* … … 239 240 *----------------------------------------------------------------------- 240 241 * Dir_End -- 241 * cleanup things for this module242 * 243 * Results: 244 * none245 * 246 * Side Effects: 247 * none242 * cleanup things for this module 243 * 244 * Results: 245 * none 246 * 247 * Side Effects: 248 * none 248 249 *----------------------------------------------------------------------- 249 250 */ … … 263 264 *----------------------------------------------------------------------- 264 265 * DirFindName -- 265 * See if the Path structure describes the same directory as the266 * given one by comparing their names. Called from Dir_AddDir via267 * Lst_Find when searching the list of open directories.268 * 269 * Results: 270 * 0 if it is the same. Non-zero otherwise271 * 272 * Side Effects: 273 * None266 * See if the Path structure describes the same directory as the 267 * given one by comparing their names. Called from Dir_AddDir via 268 * Lst_Find when searching the list of open directories. 269 * 270 * Results: 271 * 0 if it is the same. Non-zero otherwise 272 * 273 * Side Effects: 274 * None 274 275 *----------------------------------------------------------------------- 275 276 */ 276 277 static int 277 278 DirFindName (p, dname) 278 ClientData p; /* Current name */279 ClientData dname; /* Desired name */279 ClientData p; /* Current name */ 280 ClientData dname; /* Desired name */ 280 281 { 281 282 return (strcmp (((Path *)p)->name, (char *) dname)); … … 285 286 *----------------------------------------------------------------------- 286 287 * Dir_HasWildcards -- 287 * see if the given name has any wildcard characters in it288 * 289 * Results: 290 * returns TRUE if the word should be expanded, FALSE otherwise291 * 292 * Side Effects: 293 * none288 * see if the given name has any wildcard characters in it 289 * 290 * Results: 291 * returns TRUE if the word should be expanded, FALSE otherwise 292 * 293 * Side Effects: 294 * none 294 295 *----------------------------------------------------------------------- 295 296 */ 296 297 Boolean 297 298 Dir_HasWildcards (name) 298 char *name; /* name to check */299 char *name; /* name to check */ 299 300 { 300 301 register char *cp; 301 302 302 303 for (cp = name; *cp; cp++) { 303 switch(*cp) {304 case '{':305 case '[':306 case '?':307 case '*':308 return (TRUE);309 }304 switch(*cp) { 305 case '{': 306 case '[': 307 case '?': 308 case '*': 309 return (TRUE); 310 } 310 311 } 311 312 return (FALSE); … … 315 316 *----------------------------------------------------------------------- 316 317 * DirMatchFiles -- 317 * Given a pattern and a Path structure, see if any files318 * match the pattern and add their names to the 'expansions' list if319 * any do. This is incomplete -- it doesn't take care of patterns like320 * src / *src / *.c properly (just *.c on any of the directories), but it321 * will do for now.322 * 323 * Results: 324 * Always returns 0325 * 326 * Side Effects: 327 * File names are added to the expansions lst. The directory will be328 * fully hashed when this is done.318 * Given a pattern and a Path structure, see if any files 319 * match the pattern and add their names to the 'expansions' list if 320 * any do. This is incomplete -- it doesn't take care of patterns like 321 * src / *src / *.c properly (just *.c on any of the directories), but it 322 * will do for now. 323 * 324 * Results: 325 * Always returns 0 326 * 327 * Side Effects: 328 * File names are added to the expansions lst. The directory will be 329 * fully hashed when this is done. 329 330 *----------------------------------------------------------------------- 330 331 */ 331 332 static int 332 333 DirMatchFiles (pattern, p, expansions) 333 char *pattern;/* Pattern to look for */334 Path *p;/* Directory to search */335 Lst expansions;/* Place to store the results */336 { 337 Hash_Search search;/* Index into the directory's table */338 Hash_Entry *entry;/* Current entry in the table */339 Boolean isDot;/* TRUE if the directory being searched is . */334 char *pattern; /* Pattern to look for */ 335 Path *p; /* Directory to search */ 336 Lst expansions; /* Place to store the results */ 337 { 338 Hash_Search search; /* Index into the directory's table */ 339 Hash_Entry *entry; /* Current entry in the table */ 340 Boolean isDot; /* TRUE if the directory being searched is . */ 340 341 341 342 isDot = (*p->name == '.' && p->name[1] == '\0'); 342 343 343 344 for (entry = Hash_EnumFirst(&p->files, &search); 344 entry != (Hash_Entry *)NULL;345 entry = Hash_EnumNext(&search))345 entry != (Hash_Entry *)NULL; 346 entry = Hash_EnumNext(&search)) 346 347 { 347 /*348 * See if the file matches the given pattern. Note we follow the UNIX349 * convention that dot files will only be found if the pattern350 * begins with a dot (note also that as a side effect of the hashing351 * scheme, .* won't match . or .. since they aren't hashed).352 */353 if (Str_Match(entry->name, pattern) &&354 ((entry->name[0] != '.') ||355 (pattern[0] == '.')))356 {357 (void)Lst_AtEnd(expansions,358 (isDot ? estrdup(entry->name) :359 str_concat(p->name, entry->name,360 STR_ADDSLASH)));361 }348 /* 349 * See if the file matches the given pattern. Note we follow the UNIX 350 * convention that dot files will only be found if the pattern 351 * begins with a dot (note also that as a side effect of the hashing 352 * scheme, .* won't match . or .. since they aren't hashed). 353 */ 354 if (Str_Match(entry->name, pattern) && 355 ((entry->name[0] != '.') || 356 (pattern[0] == '.'))) 357 { 358 (void)Lst_AtEnd(expansions, 359 (isDot ? estrdup(entry->name) : 360 str_concat(p->name, entry->name, 361 STR_ADDSLASH))); 362 } 362 363 } 363 364 return (0); … … 367 368 *----------------------------------------------------------------------- 368 369 * DirExpandCurly -- 369 * Expand curly braces like the C shell. Does this recursively.370 * Note the special case: if after the piece of the curly brace is371 * done there are no wildcard characters in the result, the result is372 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE.373 * 374 * Results: 375 * None.376 * 377 * Side Effects: 378 * The given list is filled with the expansions...370 * Expand curly braces like the C shell. Does this recursively. 371 * Note the special case: if after the piece of the curly brace is 372 * done there are no wildcard characters in the result, the result is 373 * placed on the list WITHOUT CHECKING FOR ITS EXISTENCE. 374 * 375 * Results: 376 * None. 377 * 378 * Side Effects: 379 * The given list is filled with the expansions... 379 380 * 380 381 *----------------------------------------------------------------------- … … 382 383 static void 383 384 DirExpandCurly(word, brace, path, expansions) 384 char *word;/* Entire word to expand */385 char *brace;/* First curly brace in it */386 Lst path;/* Search path to use */387 Lst expansions;/* Place to store the expansions */388 { 389 char *end;/* Character after the closing brace */390 char *cp;/* Current position in brace clause */391 char *start;/* Start of current piece of brace clause */392 int bracelevel;/* Number of braces we've seen. If we see a393 * right brace when this is 0, we've hit the394 * end of the clause. */395 char *file;/* Current expansion */396 int otherLen;/* The length of the other pieces of the397 * expansion (chars before and after the398 * clause in 'word') */399 char *cp2;/* Pointer for checking for wildcards in400 * expansion before calling Dir_Expand */385 char *word; /* Entire word to expand */ 386 char *brace; /* First curly brace in it */ 387 Lst path; /* Search path to use */ 388 Lst expansions; /* Place to store the expansions */ 389 { 390 char *end; /* Character after the closing brace */ 391 char *cp; /* Current position in brace clause */ 392 char *start; /* Start of current piece of brace clause */ 393 int bracelevel; /* Number of braces we've seen. If we see a 394 * right brace when this is 0, we've hit the 395 * end of the clause. */ 396 char *file; /* Current expansion */ 397 int otherLen; /* The length of the other pieces of the 398 * expansion (chars before and after the 399 * clause in 'word') */ 400 char *cp2; /* Pointer for checking for wildcards in 401 * expansion before calling Dir_Expand */ 401 402 402 403 start = brace+1; … … 407 408 */ 408 409 for (end = start, bracelevel = 0; *end != '\0'; end++) { 409 if (*end == '{') {410 bracelevel++;411 } else if ((*end == '}') && (bracelevel-- == 0)) {412 break;413 }410 if (*end == '{') { 411 bracelevel++; 412 } else if ((*end == '}') && (bracelevel-- == 0)) { 413 break; 414 } 414 415 } 415 416 if (*end == '\0') { 416 Error("Unterminated {} clause \"%s\"", start);417 return;417 Error("Unterminated {} clause \"%s\"", start); 418 return; 418 419 } else { 419 end++;420 end++; 420 421 } 421 422 otherLen = brace - word + strlen(end); 422 423 423 424 for (cp = start; cp < end; cp++) { 424 /*425 * Find the end of this piece of the clause.426 */427 bracelevel = 0;428 while (*cp != ',') {429 if (*cp == '{') {430 bracelevel++;431 } else if ((*cp == '}') && (bracelevel-- <= 0)) {432 break;433 }434 cp++;435 }436 /*437 * Allocate room for the combination and install the three pieces.438 */439 file = emalloc(otherLen + cp - start + 1);440 if (brace != word) {441 strncpy(file, word, brace-word);442 }443 if (cp != start) {444 strncpy(&file[brace-word], start, cp-start);445 }446 strcpy(&file[(brace-word)+(cp-start)], end);447 448 /*449 * See if the result has any wildcards in it. If we find one, call450 * Dir_Expand right away, telling it to place the result on our list451 * of expansions.452 */453 for (cp2 = file; *cp2 != '\0'; cp2++) {454 switch(*cp2) {455 case '*':456 case '?':457 case '{':458 case '[':459 Dir_Expand(file, path, expansions);460 goto next;461 }462 }463 if (*cp2 == '\0') {464 /*465 * Hit the end w/o finding any wildcards, so stick the expansion466 * on the end of the list.467 */468 (void)Lst_AtEnd(expansions, file);469 } else {470 next:471 efree(file);472 }473 start = cp+1;425 /* 426 * Find the end of this piece of the clause. 427 */ 428 bracelevel = 0; 429 while (*cp != ',') { 430 if (*cp == '{') { 431 bracelevel++; 432 } else if ((*cp == '}') && (bracelevel-- <= 0)) { 433 break; 434 } 435 cp++; 436 } 437 /* 438 * Allocate room for the combination and install the three pieces. 439 */ 440 file = emalloc(otherLen + cp - start + 1); 441 if (brace != word) { 442 strncpy(file, word, brace-word); 443 } 444 if (cp != start) { 445 strncpy(&file[brace-word], start, cp-start); 446 } 447 strcpy(&file[(brace-word)+(cp-start)], end); 448 449 /* 450 * See if the result has any wildcards in it. If we find one, call 451 * Dir_Expand right away, telling it to place the result on our list 452 * of expansions. 453 */ 454 for (cp2 = file; *cp2 != '\0'; cp2++) { 455 switch(*cp2) { 456 case '*': 457 case '?': 458 case '{': 459 case '[': 460 Dir_Expand(file, path, expansions); 461 goto next; 462 } 463 } 464 if (*cp2 == '\0') { 465 /* 466 * Hit the end w/o finding any wildcards, so stick the expansion 467 * on the end of the list. 468 */ 469 (void)Lst_AtEnd(expansions, file); 470 } else { 471 next: 472 efree(file); 473 } 474 start = cp+1; 474 475 } 475 476 } … … 479 480 *----------------------------------------------------------------------- 480 481 * DirExpandInt -- 481 * Internal expand routine. Passes through the directories in the482 * path one by one, calling DirMatchFiles for each. NOTE: This still483 * doesn't handle patterns in directories...484 * 485 * Results: 486 * None.487 * 488 * Side Effects: 489 * Things are added to the expansions list.482 * Internal expand routine. Passes through the directories in the 483 * path one by one, calling DirMatchFiles for each. NOTE: This still 484 * doesn't handle patterns in directories... 485 * 486 * Results: 487 * None. 488 * 489 * Side Effects: 490 * Things are added to the expansions list. 490 491 * 491 492 *----------------------------------------------------------------------- … … 493 494 static void 494 495 DirExpandInt(word, path, expansions) 495 char *word;/* Word to expand */496 Lst path;/* Path on which to look */497 Lst expansions;/* Place to store the result */498 { 499 LstNode ln;/* Current node */500 Path *p;/* Directory in the node */496 char *word; /* Word to expand */ 497 Lst path; /* Path on which to look */ 498 Lst expansions; /* Place to store the result */ 499 { 500 LstNode ln; /* Current node */ 501 Path *p; /* Directory in the node */ 501 502 502 503 if (Lst_Open(path) == SUCCESS) { 503 while ((ln = Lst_Next(path)) != NILLNODE) {504 p = (Path *)Lst_Datum(ln);505 DirMatchFiles(word, p, expansions);506 }507 Lst_Close(path);504 while ((ln = Lst_Next(path)) != NILLNODE) { 505 p = (Path *)Lst_Datum(ln); 506 DirMatchFiles(word, p, expansions); 507 } 508 Lst_Close(path); 508 509 } 509 510 } … … 512 513 *----------------------------------------------------------------------- 513 514 * DirPrintWord -- 514 * Print a word in the list of expansions. Callback for Dir_Expand515 * when DEBUG(DIR), via Lst_ForEach.516 * 517 * Results: 518 * === 0519 * 520 * Side Effects: 521 * The passed word is printed, followed by a space.515 * Print a word in the list of expansions. Callback for Dir_Expand 516 * when DEBUG(DIR), via Lst_ForEach. 517 * 518 * Results: 519 * === 0 520 * 521 * Side Effects: 522 * The passed word is printed, followed by a space. 522 523 * 523 524 *----------------------------------------------------------------------- … … 536 537 *----------------------------------------------------------------------- 537 538 * Dir_Expand -- 538 * Expand the given word into a list of words by globbing it looking539 * in the directories on the given search path.540 * 541 * Results: 542 * A list of words consisting of the files which exist along the search543 * path matching the given pattern.544 * 545 * Side Effects: 546 * Directories may be opened. Who knows?539 * Expand the given word into a list of words by globbing it looking 540 * in the directories on the given search path. 541 * 542 * Results: 543 * A list of words consisting of the files which exist along the search 544 * path matching the given pattern. 545 * 546 * Side Effects: 547 * Directories may be opened. Who knows? 547 548 *----------------------------------------------------------------------- 548 549 */ … … 550 551 Dir_Expand (word, path, expansions) 551 552 char *word; /* the word to expand */ 552 Lst path; /* the list of directories in which to find553 * the resulting files */554 Lst expansions;/* the list on which to place the results */555 { 556 char *cp;553 Lst path; /* the list of directories in which to find 554 * the resulting files */ 555 Lst expansions; /* the list on which to place the results */ 556 { 557 char *cp; 557 558 558 559 if (DEBUG(DIR)) { 559 printf("expanding \"%s\"...", word);560 printf("expanding \"%s\"...", word); 560 561 } 561 562 562 563 cp = strchr(word, '{'); 563 564 if (cp) { 564 DirExpandCurly(word, cp, path, expansions);565 DirExpandCurly(word, cp, path, expansions); 565 566 } else { 566 cp = strchr(word, '/');567 if (cp) {568 /*569 * The thing has a directory component -- find the first wildcard570 * in the string.571 */572 for (cp = word; *cp; cp++) {573 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') {574 break;575 }576 }577 if (*cp == '{') {578 /*579 * This one will be fun.580 */581 DirExpandCurly(word, cp, path, expansions);582 return;583 } else if (*cp != '\0') {584 /*585 * Back up to the start of the component586 */587 char *dirpath;588 589 while (cp > word && *cp != '/') {590 cp--;591 }592 if (cp != word) {593 char sc;594 /*595 * If the glob isn't in the first component, try and find596 * all the components up to the one with a wildcard.597 */598 sc = cp[1];599 cp[1] = '\0';600 dirpath = Dir_FindFile(word, path);601 cp[1] = sc;602 /*603 * dirpath is null if can't find the leading component604 * XXX: Dir_FindFile won't find internal components.605 * i.e. if the path contains ../Etc/Object and we're606 * looking for Etc, it won't be found. Ah well.607 * Probably not important.608 */609 if (dirpath != (char *)NULL) {610 char *dp = &dirpath[strlen(dirpath) - 1];611 if (*dp == '/')612 *dp = '\0';613 path = Lst_Init(FALSE);614 Dir_AddDir(path, dirpath);615 DirExpandInt(cp+1, path, expansions);616 Lst_Destroy(path, NOFREE);617 }618 } else {619 /*620 * Start the search from the local directory621 */622 DirExpandInt(word, path, expansions);623 }624 } else {625 /*626 * Return the file -- this should never happen.627 */628 DirExpandInt(word, path, expansions);629 }630 } else {631 /*632 * First the files in dot633 */634 DirMatchFiles(word, dot, expansions);635 636 /*637 * Then the files in every other directory on the path.638 */639 DirExpandInt(word, path, expansions);640 }567 cp = strchr(word, '/'); 568 if (cp) { 569 /* 570 * The thing has a directory component -- find the first wildcard 571 * in the string. 572 */ 573 for (cp = word; *cp; cp++) { 574 if (*cp == '?' || *cp == '[' || *cp == '*' || *cp == '{') { 575 break; 576 } 577 } 578 if (*cp == '{') { 579 /* 580 * This one will be fun. 581 */ 582 DirExpandCurly(word, cp, path, expansions); 583 return; 584 } else if (*cp != '\0') { 585 /* 586 * Back up to the start of the component 587 */ 588 char *dirpath; 589 590 while (cp > word && *cp != '/') { 591 cp--; 592 } 593 if (cp != word) { 594 char sc; 595 /* 596 * If the glob isn't in the first component, try and find 597 * all the components up to the one with a wildcard. 598 */ 599 sc = cp[1]; 600 cp[1] = '\0'; 601 dirpath = Dir_FindFile(word, path); 602 cp[1] = sc; 603 /* 604 * dirpath is null if can't find the leading component 605 * XXX: Dir_FindFile won't find internal components. 606 * i.e. if the path contains ../Etc/Object and we're 607 * looking for Etc, it won't be found. Ah well. 608 * Probably not important. 609 */ 610 if (dirpath != (char *)NULL) { 611 char *dp = &dirpath[strlen(dirpath) - 1]; 612 if (*dp == '/') 613 *dp = '\0'; 614 path = Lst_Init(FALSE); 615 Dir_AddDir(path, dirpath); 616 DirExpandInt(cp+1, path, expansions); 617 Lst_Destroy(path, NOFREE); 618 } 619 } else { 620 /* 621 * Start the search from the local directory 622 */ 623 DirExpandInt(word, path, expansions); 624 } 625 } else { 626 /* 627 * Return the file -- this should never happen. 628 */ 629 DirExpandInt(word, path, expansions); 630 } 631 } else { 632 /* 633 * First the files in dot 634 */ 635 DirMatchFiles(word, dot, expansions); 636 637 /* 638 * Then the files in every other directory on the path. 639 */ 640 DirExpandInt(word, path, expansions); 641 } 641 642 } 642 643 if (DEBUG(DIR)) { 643 Lst_ForEach(expansions, DirPrintWord, (ClientData) 0);644 fputc('\n', stdout);644 Lst_ForEach(expansions, DirPrintWord, (ClientData) 0); 645 fputc('\n', stdout); 645 646 } 646 647 } … … 649 650 *----------------------------------------------------------------------- 650 651 * Dir_FindFile -- 651 * Find the file with the given name along the given search path.652 * 653 * Results: 654 * The path to the file or NULL. This path is guaranteed to be in a655 * different part of memory than name and so may be safely efree'd.656 * 657 * Side Effects: 658 * If the file is found in a directory which is not on the path659 * already (either 'name' is absolute or it is a relative path660 * [ dir1/.../dirn/file ] which exists below one of the directories661 * already on the search path), its directory is added to the end662 * of the path on the assumption that there will be more files in663 * that directory later on. Sometimes this is true. Sometimes not.652 * Find the file with the given name along the given search path. 653 * 654 * Results: 655 * The path to the file or NULL. This path is guaranteed to be in a 656 * different part of memory than name and so may be safely efree'd. 657 * 658 * Side Effects: 659 * If the file is found in a directory which is not on the path 660 * already (either 'name' is absolute or it is a relative path 661 * [ dir1/.../dirn/file ] which exists below one of the directories 662 * already on the search path), its directory is added to the end 663 * of the path on the assumption that there will be more files in 664 * that directory later on. Sometimes this is true. Sometimes not. 664 665 *----------------------------------------------------------------------- 665 666 */ 666 667 char * 667 668 Dir_FindFile (name, path) 668 char *name; /* the file to find */669 Lst path; /* the Lst of directories to search */670 { 671 register char *p1; /* pointer into p->name */672 register char *p2; /* pointer into name */673 LstNode ln; /* a list element */669 char *name; /* the file to find */ 670 Lst path; /* the Lst of directories to search */ 671 { 672 register char *p1; /* pointer into p->name */ 673 register char *p2; /* pointer into name */ 674 LstNode ln; /* a list element */ 674 675 register char *file; /* the current filename to check */ 675 register Path *p; /* current path member */676 register char *cp; /* index of first slash, if any */677 Boolean hasSlash; /* true if 'name' contains a / */678 struct stat stb;/* Buffer for stat, if necessary */679 Hash_Entry *entry; /* Entry for mtimes table */676 register Path *p; /* current path member */ 677 register char *cp; /* index of first slash, if any */ 678 Boolean hasSlash; /* true if 'name' contains a / */ 679 struct stat stb; /* Buffer for stat, if necessary */ 680 Hash_Entry *entry; /* Entry for mtimes table */ 680 681 681 682 #ifdef NMAKE … … 691 692 cp = strrchr (name, '/'); 692 693 if (cp) { 693 hasSlash = TRUE;694 cp += 1;694 hasSlash = TRUE; 695 cp += 1; 695 696 } else { 696 hasSlash = FALSE;697 cp = name;697 hasSlash = FALSE; 698 cp = name; 698 699 } 699 700 700 701 if (DEBUG(DIR)) { 701 printf("Searching for %s...", name);702 printf("Searching for %s...", name); 702 703 } 703 704 /* … … 708 709 */ 709 710 if ((!hasSlash || (cp - name == 2 && *name == '.')) && 710 (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) {711 if (DEBUG(DIR)) {712 printf("in '.'\n");713 }714 hits += 1;715 dot->hits += 1;716 return (estrdup (name));711 (Hash_FindEntry (&dot->files, cp) != (Hash_Entry *)NULL)) { 712 if (DEBUG(DIR)) { 713 printf("in '.'\n"); 714 } 715 hits += 1; 716 dot->hits += 1; 717 return (estrdup (name)); 717 718 } 718 719 719 720 if (Lst_Open (path) == FAILURE) { 720 if (DEBUG(DIR)) {721 printf("couldn't open path, file not found\n");722 }723 misses += 1;724 return ((char *) NULL);721 if (DEBUG(DIR)) { 722 printf("couldn't open path, file not found\n"); 723 } 724 misses += 1; 725 return ((char *) NULL); 725 726 } 726 727 … … 734 735 */ 735 736 while ((ln = Lst_Next (path)) != NILLNODE) { 736 p = (Path *) Lst_Datum (ln);737 if (DEBUG(DIR)) {738 printf("%s...", p->name);739 }740 if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) {741 if (DEBUG(DIR)) {742 printf("here...");743 }744 if (hasSlash) {745 /*746 * If the name had a slash, its initial components and p's747 * final components must match. This is false if a mismatch748 * is encountered before all of the initial components749 * have been checked (p2 > name at the end of the loop), or750 * we matched only part of one of the components of p751 * along with all the rest of them (*p1 != '/').752 */753 p1 = p->name + strlen (p->name) - 1;754 p2 = cp - 2;755 while (p2 >= name && p1 >= p->name && *p1 == *p2) {756 p1 -= 1; p2 -= 1;757 }758 if (p2 >= name || (p1 >= p->name && *p1 != '/')) {759 if (DEBUG(DIR)) {760 printf("component mismatch -- continuing...");761 }762 continue;763 }764 }765 file = str_concat (p->name, cp, STR_ADDSLASH);766 if (DEBUG(DIR)) {767 printf("returning %s\n", file);768 }769 Lst_Close (path);770 p->hits += 1;771 hits += 1;772 return (file);773 } else if (hasSlash) {774 /*775 * If the file has a leading path component and that component776 * exactly matches the entire name of the current search777 * directory, we assume the file doesn't exist and return NULL.778 */779 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) {780 continue;781 }782 if (*p1 == '\0' && p2 == cp - 1) {783 if (DEBUG(DIR)) {784 printf("must be here but isn't -- returing NULL\n");785 }786 Lst_Close (path);787 return ((char *) NULL);788 }789 }737 p = (Path *) Lst_Datum (ln); 738 if (DEBUG(DIR)) { 739 printf("%s...", p->name); 740 } 741 if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { 742 if (DEBUG(DIR)) { 743 printf("here..."); 744 } 745 if (hasSlash) { 746 /* 747 * If the name had a slash, its initial components and p's 748 * final components must match. This is false if a mismatch 749 * is encountered before all of the initial components 750 * have been checked (p2 > name at the end of the loop), or 751 * we matched only part of one of the components of p 752 * along with all the rest of them (*p1 != '/'). 753 */ 754 p1 = p->name + strlen (p->name) - 1; 755 p2 = cp - 2; 756 while (p2 >= name && p1 >= p->name && *p1 == *p2) { 757 p1 -= 1; p2 -= 1; 758 } 759 if (p2 >= name || (p1 >= p->name && *p1 != '/')) { 760 if (DEBUG(DIR)) { 761 printf("component mismatch -- continuing..."); 762 } 763 continue; 764 } 765 } 766 file = str_concat (p->name, cp, STR_ADDSLASH); 767 if (DEBUG(DIR)) { 768 printf("returning %s\n", file); 769 } 770 Lst_Close (path); 771 p->hits += 1; 772 hits += 1; 773 return (file); 774 } else if (hasSlash) { 775 /* 776 * If the file has a leading path component and that component 777 * exactly matches the entire name of the current search 778 * directory, we assume the file doesn't exist and return NULL. 779 */ 780 for (p1 = p->name, p2 = name; *p1 && *p1 == *p2; p1++, p2++) { 781 continue; 782 } 783 if (*p1 == '\0' && p2 == cp - 1) { 784 if (DEBUG(DIR)) { 785 printf("must be here but isn't -- returing NULL\n"); 786 } 787 Lst_Close (path); 788 return ((char *) NULL); 789 } 790 } 790 791 } 791 792 … … 803 804 */ 804 805 if (!hasSlash) { 805 if (DEBUG(DIR)) {806 printf("failed.\n");807 }808 misses += 1;809 return ((char *) NULL);806 if (DEBUG(DIR)) { 807 printf("failed.\n"); 808 } 809 misses += 1; 810 return ((char *) NULL); 810 811 } 811 812 812 813 if (*name != '/') { 813 BooleancheckedDot = FALSE;814 815 if (DEBUG(DIR)) {816 printf("failed. Trying subdirectories...");817 }818 (void) Lst_Open (path);819 while ((ln = Lst_Next (path)) != NILLNODE) {820 p = (Path *) Lst_Datum (ln);821 if (p != dot) {822 file = str_concat (p->name, name, STR_ADDSLASH);823 } else {824 /*825 * Checking in dot -- DON'T put a leading ./ on the thing.826 */827 file = estrdup(name);828 checkedDot = TRUE;829 }830 if (DEBUG(DIR)) {831 printf("checking %s...", file);832 }833 834 835 if (stat (file, &stb) == 0) {836 if (DEBUG(DIR)) {837 printf("got it.\n");838 }839 840 Lst_Close (path);841 842 /*843 * We've found another directory to search. We know there's844 * a slash in 'file' because we put one there. We nuke it after845 * finding it and call Dir_AddDir to add this new directory846 * onto the existing search path. Once that's done, we restore847 * the slash and triumphantly return the file name, knowing848 * that should a file in this directory every be referenced849 * again in such a manner, we will find it without having to do850 * numerous numbers of access calls. Hurrah!851 */852 cp = strrchr (file, '/');853 *cp = '\0';854 Dir_AddDir (path, file);855 *cp = '/';856 857 /*858 * Save the modification time so if it's needed, we don't have859 * to fetch it again.860 */861 if (DEBUG(DIR)) {862 printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),863 file);864 }865 entry = Hash_CreateEntry(&mtimes, (char *) file,866 (Boolean *)NULL);867 Hash_SetValue(entry, (long)stb.st_mtime);868 nearmisses += 1;869 return (file);870 } else {871 efree (file);872 }873 }874 875 if (DEBUG(DIR)) {876 printf("failed. ");877 }878 Lst_Close (path);879 880 if (checkedDot) {881 /*882 * Already checked by the given name, since . was in the path,883 * so no point in proceeding...884 */885 if (DEBUG(DIR)) {886 printf("Checked . already, returning NULL\n");887 }888 return(NULL);889 }814 Boolean checkedDot = FALSE; 815 816 if (DEBUG(DIR)) { 817 printf("failed. Trying subdirectories..."); 818 } 819 (void) Lst_Open (path); 820 while ((ln = Lst_Next (path)) != NILLNODE) { 821 p = (Path *) Lst_Datum (ln); 822 if (p != dot) { 823 file = str_concat (p->name, name, STR_ADDSLASH); 824 } else { 825 /* 826 * Checking in dot -- DON'T put a leading ./ on the thing. 827 */ 828 file = estrdup(name); 829 checkedDot = TRUE; 830 } 831 if (DEBUG(DIR)) { 832 printf("checking %s...", file); 833 } 834 835 836 if (stat (file, &stb) == 0) { 837 if (DEBUG(DIR)) { 838 printf("got it.\n"); 839 } 840 841 Lst_Close (path); 842 843 /* 844 * We've found another directory to search. We know there's 845 * a slash in 'file' because we put one there. We nuke it after 846 * finding it and call Dir_AddDir to add this new directory 847 * onto the existing search path. Once that's done, we restore 848 * the slash and triumphantly return the file name, knowing 849 * that should a file in this directory every be referenced 850 * again in such a manner, we will find it without having to do 851 * numerous numbers of access calls. Hurrah! 852 */ 853 cp = strrchr (file, '/'); 854 *cp = '\0'; 855 Dir_AddDir (path, file); 856 *cp = '/'; 857 858 /* 859 * Save the modification time so if it's needed, we don't have 860 * to fetch it again. 861 */ 862 if (DEBUG(DIR)) { 863 printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 864 file); 865 } 866 entry = Hash_CreateEntry(&mtimes, (char *) file, 867 (Boolean *)NULL); 868 Hash_SetValue(entry, (long)stb.st_mtime); 869 nearmisses += 1; 870 return (file); 871 } else { 872 efree (file); 873 } 874 } 875 876 if (DEBUG(DIR)) { 877 printf("failed. "); 878 } 879 Lst_Close (path); 880 881 if (checkedDot) { 882 /* 883 * Already checked by the given name, since . was in the path, 884 * so no point in proceeding... 885 */ 886 if (DEBUG(DIR)) { 887 printf("Checked . already, returning NULL\n"); 888 } 889 return(NULL); 890 } 890 891 } 891 892 … … 915 916 ln = Lst_Last (path); 916 917 if (ln == NILLNODE) { 917 return ((char *) NULL);918 return ((char *) NULL); 918 919 } else { 919 p = (Path *) Lst_Datum (ln);920 p = (Path *) Lst_Datum (ln); 920 921 } 921 922 922 923 if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { 923 return (estrdup (name));924 return (estrdup (name)); 924 925 } else { 925 return ((char *) NULL);926 return ((char *) NULL); 926 927 } 927 928 #else /* !notdef */ 928 929 if (DEBUG(DIR)) { 929 printf("Looking for \"%s\"...", name);930 printf("Looking for \"%s\"...", name); 930 931 } 931 932 … … 933 934 entry = Hash_FindEntry(&mtimes, name); 934 935 if (entry != (Hash_Entry *)NULL) { 935 if (DEBUG(DIR)) {936 printf("got it (in mtime cache)\n");937 }938 return(estrdup(name));936 if (DEBUG(DIR)) { 937 printf("got it (in mtime cache)\n"); 938 } 939 return(estrdup(name)); 939 940 } else if (stat (name, &stb) == 0) { 940 entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL);941 if (DEBUG(DIR)) {942 printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime),943 name);944 }945 Hash_SetValue(entry, (long)stb.st_mtime);946 return (estrdup (name));941 entry = Hash_CreateEntry(&mtimes, name, (Boolean *)NULL); 942 if (DEBUG(DIR)) { 943 printf("Caching %s for %s\n", Targ_FmtTime(stb.st_mtime), 944 name); 945 } 946 Hash_SetValue(entry, (long)stb.st_mtime); 947 return (estrdup (name)); 947 948 } else { 948 if (DEBUG(DIR)) {949 printf("failed. Returning NULL\n");950 }951 return ((char *)NULL);949 if (DEBUG(DIR)) { 950 printf("failed. Returning NULL\n"); 951 } 952 return ((char *)NULL); 952 953 } 953 954 #endif /* notdef */ … … 957 958 *----------------------------------------------------------------------- 958 959 * Dir_MTime -- 959 * Find the modification time of the file described by gn along the960 * search path dirSearchPath.961 * 962 * Results: 963 * The modification time or 0 if it doesn't exist964 * 965 * Side Effects: 966 * The modification time is placed in the node's mtime slot.967 * If the node didn't have a path entry before, and Dir_FindFile968 * found one for it, the full name is placed in the path slot.960 * Find the modification time of the file described by gn along the 961 * search path dirSearchPath. 962 * 963 * Results: 964 * The modification time or 0 if it doesn't exist 965 * 966 * Side Effects: 967 * The modification time is placed in the node's mtime slot. 968 * If the node didn't have a path entry before, and Dir_FindFile 969 * found one for it, the full name is placed in the path slot. 969 970 *----------------------------------------------------------------------- 970 971 */ 971 972 int 972 973 Dir_MTime (gn) 973 GNode *gn; /* the file whose modification time is974 * desired */974 GNode *gn; /* the file whose modification time is 975 * desired */ 975 976 { 976 977 char *fullName; /* the full pathname of name */ 977 struct stat stb;/* buffer for finding the mod time */978 Hash_Entry *entry;978 struct stat stb; /* buffer for finding the mod time */ 979 Hash_Entry *entry; 979 980 980 981 #ifdef USE_ARCHIVES 981 982 if (gn->type & OP_ARCHV) { 982 return Arch_MTime (gn);983 return Arch_MTime (gn); 983 984 } else 984 985 #endif 985 986 if (gn->path == (char *)NULL) { 986 fullName = Dir_FindFile (gn->name, dirSearchPath);987 fullName = Dir_FindFile (gn->name, dirSearchPath); 987 988 } else { 988 fullName = gn->path;989 fullName = gn->path; 989 990 } 990 991 991 992 if (fullName == (char *)NULL) { 992 fullName = estrdup(gn->name);993 fullName = estrdup(gn->name); 993 994 } 994 995 995 996 entry = Hash_FindEntry(&mtimes, fullName); 996 997 if (entry != (Hash_Entry *)NULL) { 997 /*998 * Only do this once -- the second time folks are checking to999 * see if the file was actually updated, so we need to actually go1000 * to the file system.1001 */1002 if (DEBUG(DIR)) {1003 printf("Using cached time %s for %s\n",1004 Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName);1005 }1006 stb.st_mtime = (time_t)(long)Hash_GetValue(entry);1007 Hash_DeleteEntry(&mtimes, entry);998 /* 999 * Only do this once -- the second time folks are checking to 1000 * see if the file was actually updated, so we need to actually go 1001 * to the file system. 1002 */ 1003 if (DEBUG(DIR)) { 1004 printf("Using cached time %s for %s\n", 1005 Targ_FmtTime((time_t)(long)Hash_GetValue(entry)), fullName); 1006 } 1007 stb.st_mtime = (time_t)(long)Hash_GetValue(entry); 1008 Hash_DeleteEntry(&mtimes, entry); 1008 1009 } else if (stat (fullName, &stb) < 0) { 1009 1010 #ifdef USE_ARCHIVES 1010 if (gn->type & OP_MEMBER) {1011 if (fullName != gn->path)1012 efree(fullName);1013 return Arch_MemMTime (gn);1014 } else1011 if (gn->type & OP_MEMBER) { 1012 if (fullName != gn->path) 1013 efree(fullName); 1014 return Arch_MemMTime (gn); 1015 } else 1015 1016 #endif 1016 stb.st_mtime = 0;1017 stb.st_mtime = 0; 1017 1018 } 1018 1019 if (fullName && gn->path == (char *)NULL) { 1019 gn->path = fullName;1020 gn->path = fullName; 1020 1021 } 1021 1022 … … 1027 1028 *----------------------------------------------------------------------- 1028 1029 * Dir_AddDir -- 1029 * Add the given name to the end of the given path. The order of1030 * the arguments is backwards so ParseDoDependency can do a1031 * Lst_ForEach of its list of paths...1032 * 1033 * Results: 1034 * none1035 * 1036 * Side Effects: 1037 * A structure is added to the list and the directory is1038 * read and hashed.1030 * Add the given name to the end of the given path. The order of 1031 * the arguments is backwards so ParseDoDependency can do a 1032 * Lst_ForEach of its list of paths... 1033 * 1034 * Results: 1035 * none 1036 * 1037 * Side Effects: 1038 * A structure is added to the list and the directory is 1039 * read and hashed. 1039 1040 *----------------------------------------------------------------------- 1040 1041 */ 1041 1042 void 1042 1043 Dir_AddDir (path, name) 1043 Lst path; /* the path to which the directory should be1044 * added */1044 Lst path; /* the path to which the directory should be 1045 * added */ 1045 1046 char *name; /* the name of the directory to add */ 1046 1047 { 1047 LstNode ln; /* node in case Path structure is found */1048 register Path *p; /* pointer to new Path structure */1049 DIR *d;/* for reading directory */1048 LstNode ln; /* node in case Path structure is found */ 1049 register Path *p; /* pointer to new Path structure */ 1050 DIR *d; /* for reading directory */ 1050 1051 register struct dirent *dp; /* entry in directory */ 1051 1052 1052 1053 ln = Lst_Find (openDirectories, (ClientData)name, DirFindName); 1053 1054 if (ln != NILLNODE) { 1054 p = (Path *)Lst_Datum (ln);1055 if (Lst_Member(path, (ClientData)p) == NILLNODE) {1056 p->refCount += 1;1057 (void)Lst_AtEnd (path, (ClientData)p);1058 }1055 p = (Path *)Lst_Datum (ln); 1056 if (Lst_Member(path, (ClientData)p) == NILLNODE) { 1057 p->refCount += 1; 1058 (void)Lst_AtEnd (path, (ClientData)p); 1059 } 1059 1060 } else { 1060 if (DEBUG(DIR)) {1061 printf("Caching %s...", name);1062 fflush(stdout);1063 }1064 1065 if ((d = opendir (name)) != (DIR *) NULL) {1066 p = (Path *) emalloc (sizeof (Path));1067 p->name = estrdup (name);1068 p->hits = 0;1069 p->refCount = 1;1070 Hash_InitTable (&p->files, -1);1071 1072 while ((dp = readdir (d)) != (struct dirent *) NULL) {1061 if (DEBUG(DIR)) { 1062 printf("Caching %s...", name); 1063 fflush(stdout); 1064 } 1065 1066 if ((d = opendir (name)) != (DIR *) NULL) { 1067 p = (Path *) emalloc (sizeof (Path)); 1068 p->name = estrdup (name); 1069 p->hits = 0; 1070 p->refCount = 1; 1071 Hash_InitTable (&p->files, -1); 1072 1073 while ((dp = readdir (d)) != (struct dirent *) NULL) { 1073 1074 #if defined(sun) && defined(d_ino) /* d_ino is a sunos4 #define for d_fileno */ 1074 /*1075 * The sun directory library doesn't check for a 0 inode1076 * (0-inode slots just take up space), so we have to do1077 * it ourselves.1078 */1079 if (dp->d_fileno == 0) {1080 continue;1081 }1075 /* 1076 * The sun directory library doesn't check for a 0 inode 1077 * (0-inode slots just take up space), so we have to do 1078 * it ourselves. 1079 */ 1080 if (dp->d_fileno == 0) { 1081 continue; 1082 } 1082 1083 #endif /* sun && d_ino */ 1083 1084 1084 /* Skip the '.' and '..' entries by checking for them1085 * specifically instead of assuming readdir() reuturns them in1086 * that order when first going through a directory. This is1087 * needed for XFS over NFS filesystems since SGI does not1088 * guarantee that these are * the first two entries returned1089 * from readdir().1090 */1091 if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name))1092 continue;1093 1094 (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL);1095 }1096 (void) closedir (d);1097 (void)Lst_AtEnd (openDirectories, (ClientData)p);1098 (void)Lst_AtEnd (path, (ClientData)p);1099 }1100 if (DEBUG(DIR)) {1101 printf("done\n");1102 }1085 /* Skip the '.' and '..' entries by checking for them 1086 * specifically instead of assuming readdir() reuturns them in 1087 * that order when first going through a directory. This is 1088 * needed for XFS over NFS filesystems since SGI does not 1089 * guarantee that these are * the first two entries returned 1090 * from readdir(). 1091 */ 1092 if (ISDOT(dp->d_name) || ISDOTDOT(dp->d_name)) 1093 continue; 1094 1095 (void)Hash_CreateEntry(&p->files, dp->d_name, (Boolean *)NULL); 1096 } 1097 (void) closedir (d); 1098 (void)Lst_AtEnd (openDirectories, (ClientData)p); 1099 (void)Lst_AtEnd (path, (ClientData)p); 1100 } 1101 if (DEBUG(DIR)) { 1102 printf("done\n"); 1103 } 1103 1104 } 1104 1105 } … … 1107 1108 *----------------------------------------------------------------------- 1108 1109 * Dir_CopyDir -- 1109 * Callback function for duplicating a search path via Lst_Duplicate.1110 * Ups the reference count for the directory.1111 * 1112 * Results: 1113 * Returns the Path it was given.1114 * 1115 * Side Effects: 1116 * The refCount of the path is incremented.1110 * Callback function for duplicating a search path via Lst_Duplicate. 1111 * Ups the reference count for the directory. 1112 * 1113 * Results: 1114 * Returns the Path it was given. 1115 * 1116 * Side Effects: 1117 * The refCount of the path is incremented. 1117 1118 * 1118 1119 *----------------------------------------------------------------------- … … 1130 1131 *----------------------------------------------------------------------- 1131 1132 * Dir_MakeFlags -- 1132 * Make a string by taking all the directories in the given search1133 * path and preceding them by the given flag. Used by the suffix1134 * module to create variables for compilers based on suffix search1135 * paths.1136 * 1137 * Results: 1138 * The string mentioned above. Note that there is no space between1139 * the given flag and each directory. The empty string is returned if1140 * Things don't go well.1141 * 1142 * Side Effects: 1143 * None1133 * Make a string by taking all the directories in the given search 1134 * path and preceding them by the given flag. Used by the suffix 1135 * module to create variables for compilers based on suffix search 1136 * paths. 1137 * 1138 * Results: 1139 * The string mentioned above. Note that there is no space between 1140 * the given flag and each directory. The empty string is returned if 1141 * Things don't go well. 1142 * 1143 * Side Effects: 1144 * None 1144 1145 *----------------------------------------------------------------------- 1145 1146 */ 1146 1147 char * 1147 1148 Dir_MakeFlags (flag, path) 1148 char *flag; /* flag which should precede each directory */1149 Lst path;/* list of directories */1150 { 1151 char *str;/* the string which will be returned */1152 char *tstr; /* the current directory preceded by 'flag' */1153 LstNode ln;/* the node of the current directory */1154 Path *p;/* the structure describing the current directory */1149 char *flag; /* flag which should precede each directory */ 1150 Lst path; /* list of directories */ 1151 { 1152 char *str; /* the string which will be returned */ 1153 char *tstr; /* the current directory preceded by 'flag' */ 1154 LstNode ln; /* the node of the current directory */ 1155 Path *p; /* the structure describing the current directory */ 1155 1156 1156 1157 str = estrdup (""); 1157 1158 1158 1159 if (Lst_Open (path) == SUCCESS) { 1159 while ((ln = Lst_Next (path)) != NILLNODE) {1160 p = (Path *) Lst_Datum (ln);1161 tstr = str_concat (flag, p->name, 0);1162 str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE);1163 }1164 Lst_Close (path);1160 while ((ln = Lst_Next (path)) != NILLNODE) { 1161 p = (Path *) Lst_Datum (ln); 1162 tstr = str_concat (flag, p->name, 0); 1163 str = str_concat (str, tstr, STR_ADDSPACE | STR_DOFREE); 1164 } 1165 Lst_Close (path); 1165 1166 } 1166 1167 … … 1171 1172 *----------------------------------------------------------------------- 1172 1173 * Dir_Destroy -- 1173 * Nuke a directory descriptor, if possible. Callback procedure1174 * for the suffixes module when destroying a search path.1175 * 1176 * Results: 1177 * None.1178 * 1179 * Side Effects: 1180 * If no other path references this directory (refCount == 0),1181 * the Path and all its data are freed.1174 * Nuke a directory descriptor, if possible. Callback procedure 1175 * for the suffixes module when destroying a search path. 1176 * 1177 * Results: 1178 * None. 1179 * 1180 * Side Effects: 1181 * If no other path references this directory (refCount == 0), 1182 * the Path and all its data are freed. 1182 1183 * 1183 1184 *----------------------------------------------------------------------- … … 1185 1186 void 1186 1187 Dir_Destroy (pp) 1187 ClientData pp;/* The directory descriptor to nuke */1188 { 1189 Path *p = (Path *) pp;1188 ClientData pp; /* The directory descriptor to nuke */ 1189 { 1190 Path *p = (Path *) pp; 1190 1191 p->refCount -= 1; 1191 1192 1192 1193 if (p->refCount == 0) { 1193 LstNodeln;1194 1195 ln = Lst_Member (openDirectories, (ClientData)p);1196 (void) Lst_Remove (openDirectories, ln);1197 1198 Hash_DeleteTable (&p->files);1199 efree((Address)p->name);1200 efree((Address)p);1194 LstNode ln; 1195 1196 ln = Lst_Member (openDirectories, (ClientData)p); 1197 (void) Lst_Remove (openDirectories, ln); 1198 1199 Hash_DeleteTable (&p->files); 1200 efree((Address)p->name); 1201 efree((Address)p); 1201 1202 } 1202 1203 } … … 1205 1206 *----------------------------------------------------------------------- 1206 1207 * Dir_ClearPath -- 1207 * Clear out all elements of the given search path. This is different1208 * from destroying the list, notice.1209 * 1210 * Results: 1211 * None.1212 * 1213 * Side Effects: 1214 * The path is set to the empty list.1208 * Clear out all elements of the given search path. This is different 1209 * from destroying the list, notice. 1210 * 1211 * Results: 1212 * None. 1213 * 1214 * Side Effects: 1215 * The path is set to the empty list. 1215 1216 * 1216 1217 *----------------------------------------------------------------------- … … 1218 1219 void 1219 1220 Dir_ClearPath(path) 1220 Lst path;/* Path to clear */1221 Lst path; /* Path to clear */ 1221 1222 { 1222 1223 Path *p; 1223 1224 while (!Lst_IsEmpty(path)) { 1224 p = (Path *)Lst_DeQueue(path);1225 Dir_Destroy((ClientData) p);1225 p = (Path *)Lst_DeQueue(path); 1226 Dir_Destroy((ClientData) p); 1226 1227 } 1227 1228 } … … 1231 1232 *----------------------------------------------------------------------- 1232 1233 * Dir_Concat -- 1233 * Concatenate two paths, adding the second to the end of the first.1234 * Makes sure to avoid duplicates.1235 * 1236 * Results: 1237 * None1238 * 1239 * Side Effects: 1240 * Reference counts for added dirs are upped.1234 * Concatenate two paths, adding the second to the end of the first. 1235 * Makes sure to avoid duplicates. 1236 * 1237 * Results: 1238 * None 1239 * 1240 * Side Effects: 1241 * Reference counts for added dirs are upped. 1241 1242 * 1242 1243 *----------------------------------------------------------------------- … … 1244 1245 void 1245 1246 Dir_Concat(path1, path2) 1246 Lst path1;/* Dest */1247 Lst path2;/* Source */1247 Lst path1; /* Dest */ 1248 Lst path2; /* Source */ 1248 1249 { 1249 1250 LstNode ln; … … 1251 1252 1252 1253 for (ln = Lst_First(path2); ln != NILLNODE; ln = Lst_Succ(ln)) { 1253 p = (Path *)Lst_Datum(ln);1254 if (Lst_Member(path1, (ClientData)p) == NILLNODE) {1255 p->refCount += 1;1256 (void)Lst_AtEnd(path1, (ClientData)p);1257 }1254 p = (Path *)Lst_Datum(ln); 1255 if (Lst_Member(path1, (ClientData)p) == NILLNODE) { 1256 p->refCount += 1; 1257 (void)Lst_AtEnd(path1, (ClientData)p); 1258 } 1258 1259 } 1259 1260 } … … 1263 1264 Dir_PrintDirectories() 1264 1265 { 1265 LstNode ln;1266 Path *p;1266 LstNode ln; 1267 Path *p; 1267 1268 1268 1269 printf ("#*** Directory Cache:\n"); 1269 1270 printf ("# Stats: %d hits %d misses %d near misses %d losers (%d%%)\n", 1270 hits, misses, nearmisses, bigmisses,1271 (hits+bigmisses+nearmisses ?1272 hits * 100 / (hits + bigmisses + nearmisses) : 0));1271 hits, misses, nearmisses, bigmisses, 1272 (hits+bigmisses+nearmisses ? 1273 hits * 100 / (hits + bigmisses + nearmisses) : 0)); 1273 1274 printf ("# %-20s referenced\thits\n", "directory"); 1274 1275 if (Lst_Open (openDirectories) == SUCCESS) { 1275 while ((ln = Lst_Next (openDirectories)) != NILLNODE) {1276 p = (Path *) Lst_Datum (ln);1277 printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits);1278 }1279 Lst_Close (openDirectories);1276 while ((ln = Lst_Next (openDirectories)) != NILLNODE) { 1277 p = (Path *) Lst_Datum (ln); 1278 printf ("# %-20s %10d\t%4d\n", p->name, p->refCount, p->hits); 1279 } 1280 Lst_Close (openDirectories); 1280 1281 } 1281 1282 } 1282 1283 1283 1284 static int DirPrintDir (p, dummy) 1284 ClientData p;1285 ClientData dummy;1285 ClientData p; 1286 ClientData dummy; 1286 1287 { 1287 1288 printf ("%s ", ((Path *) p)->name); … … 1291 1292 void 1292 1293 Dir_PrintPath (path) 1293 Lst path;1294 Lst path; 1294 1295 { 1295 1296 Lst_ForEach (path, DirPrintDir, (ClientData)0); -
trunk/src/kmk/for.c
r35 r51 13 13 * 3. All advertising materials mentioning features or use of this software 14 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of16 * California, Berkeley and its contributors.15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 17 * 4. Neither the name of the University nor the names of its contributors 18 18 * may be used to endorse or promote products derived from this software … … 34 34 #ifndef lint 35 35 #if 0 36 static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93";36 static char sccsid[] = "@(#)for.c 8.1 (Berkeley) 6/6/93"; 37 37 #else 38 38 static const char rcsid[] = 39 39 "$FreeBSD: src/usr.bin/make/for.c,v 1.10 1999/09/11 13:08:01 hoek Exp $"; 40 40 #endif 41 #define KLIBFILEDEF rcsid 41 42 #endif /* not lint */ 42 43 43 44 /*- 44 45 * for.c -- 45 * Functions to handle loops in a makefile.46 * Functions to handle loops in a makefile. 46 47 * 47 48 * Interface: 48 * For_EvalEvaluate the loop in the passed line.49 * For_RunRun accumulated loop49 * For_Eval Evaluate the loop in the passed line. 50 * For_Run Run accumulated loop 50 51 * 51 52 */ … … 71 72 */ 72 73 73 static int forLevel = 0; /* Nesting level*/74 static char *forVar; /* Iteration variable*/75 static Buffer forBuf; /* Commands in loop*/76 static Lst forLst; /* List of items*/74 static int forLevel = 0; /* Nesting level */ 75 static char *forVar; /* Iteration variable */ 76 static Buffer forBuf; /* Commands in loop */ 77 static Lst forLst; /* List of items */ 77 78 78 79 /* … … 80 81 */ 81 82 typedef struct _For { 82 Buffer buf; /* Unexpanded buffer*/83 char* var; /* Index name*/84 Lst lst; /* List of variables*/83 Buffer buf; /* Unexpanded buffer */ 84 char* var; /* Index name */ 85 Lst lst; /* List of variables */ 85 86 } For; 86 87 87 static int ForExec __P((ClientData, ClientData));88 static int ForExec __P((ClientData, ClientData)); 88 89 89 90 … … 94 95 *----------------------------------------------------------------------- 95 96 * For_Eval -- 96 * Evaluate the for loop in the passed line. The line97 * looks like this:98 * .for <variable> in <varlist>97 * Evaluate the for loop in the passed line. The line 98 * looks like this: 99 * .for <variable> in <varlist> 99 100 * 100 101 * Results: 101 * TRUE: We found a for loop, or we are inside a for loop102 * FALSE: We did not find a for loop, or we found the end of the for103 * for loop.102 * TRUE: We found a for loop, or we are inside a for loop 103 * FALSE: We did not find a for loop, or we found the end of the for 104 * for loop. 104 105 * 105 106 * Side Effects: 106 * None.107 * None. 107 108 * 108 109 *----------------------------------------------------------------------- … … 110 111 int 111 112 For_Eval (line) 112 char *line; /* Line to parse */113 char *line; /* Line to parse */ 113 114 { 114 char *ptr = line, *sub, *wrd;115 int level;/* Level at which to report errors. */115 char *ptr = line, *sub, *wrd; 116 int level; /* Level at which to report errors. */ 116 117 117 118 level = PARSE_FATAL; … … 119 120 120 121 if (forLevel == 0) { 121 Bufferbuf;122 intvarlen;123 124 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)125 continue;126 /*127 * If we are not in a for loop quickly determine if the statement is128 * a for.129 */130 if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' ||131 !isspace((unsigned char) ptr[3]))132 return FALSE;133 ptr += 3;134 135 /*136 * we found a for loop, and now we are going to parse it.137 */138 while (*ptr && isspace((unsigned char) *ptr))139 ptr++;140 141 /*142 * Grab the variable143 */144 buf = Buf_Init(0);145 for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++)146 continue;147 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd);148 149 forVar = (char *) Buf_GetAll(buf, &varlen);150 if (varlen == 0) {151 Parse_Error (level, "missing variable in for");152 return 0;153 }154 Buf_Destroy(buf, FALSE);155 156 while (*ptr && isspace((unsigned char) *ptr))157 ptr++;158 159 /*160 * Grab the `in'161 */162 if (ptr[0] != 'i' || ptr[1] != 'n' ||163 !isspace((unsigned char) ptr[2])) {164 Parse_Error (level, "missing `in' in for");165 printf("%s\n", ptr);166 return 0;167 }168 ptr += 3;169 170 while (*ptr && isspace((unsigned char) *ptr))171 ptr++;172 173 /*174 * Make a list with the remaining words175 */176 forLst = Lst_Init(FALSE);177 buf = Buf_Init(0);178 sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE);122 Buffer buf; 123 int varlen; 124 125 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) 126 continue; 127 /* 128 * If we are not in a for loop quickly determine if the statement is 129 * a for. 130 */ 131 if (ptr[0] != 'f' || ptr[1] != 'o' || ptr[2] != 'r' || 132 !isspace((unsigned char) ptr[3])) 133 return FALSE; 134 ptr += 3; 135 136 /* 137 * we found a for loop, and now we are going to parse it. 138 */ 139 while (*ptr && isspace((unsigned char) *ptr)) 140 ptr++; 141 142 /* 143 * Grab the variable 144 */ 145 buf = Buf_Init(0); 146 for (wrd = ptr; *ptr && !isspace((unsigned char) *ptr); ptr++) 147 continue; 148 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd); 149 150 forVar = (char *) Buf_GetAll(buf, &varlen); 151 if (varlen == 0) { 152 Parse_Error (level, "missing variable in for"); 153 return 0; 154 } 155 Buf_Destroy(buf, FALSE); 156 157 while (*ptr && isspace((unsigned char) *ptr)) 158 ptr++; 159 160 /* 161 * Grab the `in' 162 */ 163 if (ptr[0] != 'i' || ptr[1] != 'n' || 164 !isspace((unsigned char) ptr[2])) { 165 Parse_Error (level, "missing `in' in for"); 166 printf("%s\n", ptr); 167 return 0; 168 } 169 ptr += 3; 170 171 while (*ptr && isspace((unsigned char) *ptr)) 172 ptr++; 173 174 /* 175 * Make a list with the remaining words 176 */ 177 forLst = Lst_Init(FALSE); 178 buf = Buf_Init(0); 179 sub = Var_Subst(NULL, ptr, VAR_GLOBAL, FALSE); 179 180 180 181 #define ADDWORD() \ 181 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \182 Buf_AddByte(buf, (Byte) '\0'), \183 Lst_AtFront(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \184 Buf_Destroy(buf, FALSE)185 186 for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++)187 continue;188 189 for (wrd = ptr; *ptr; ptr++)190 if (isspace((unsigned char) *ptr)) {191 ADDWORD();192 buf = Buf_Init(0);193 while (*ptr && isspace((unsigned char) *ptr))194 ptr++;195 wrd = ptr--;196 }197 if (DEBUG(FOR))198 (void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub);199 if (ptr - wrd > 0)200 ADDWORD();201 else202 Buf_Destroy(buf, TRUE);203 efree((Address) sub);204 205 forBuf = Buf_Init(0);206 forLevel++;207 return 1;182 Buf_AddBytes(buf, ptr - wrd, (Byte *) wrd), \ 183 Buf_AddByte(buf, (Byte) '\0'), \ 184 Lst_AtFront(forLst, (ClientData) Buf_GetAll(buf, &varlen)), \ 185 Buf_Destroy(buf, FALSE) 186 187 for (ptr = sub; *ptr && isspace((unsigned char) *ptr); ptr++) 188 continue; 189 190 for (wrd = ptr; *ptr; ptr++) 191 if (isspace((unsigned char) *ptr)) { 192 ADDWORD(); 193 buf = Buf_Init(0); 194 while (*ptr && isspace((unsigned char) *ptr)) 195 ptr++; 196 wrd = ptr--; 197 } 198 if (DEBUG(FOR)) 199 (void) fprintf(stderr, "For: Iterator %s List %s\n", forVar, sub); 200 if (ptr - wrd > 0) 201 ADDWORD(); 202 else 203 Buf_Destroy(buf, TRUE); 204 efree((Address) sub); 205 206 forBuf = Buf_Init(0); 207 forLevel++; 208 return 1; 208 209 } 209 210 else if (*ptr == '.') { 210 211 211 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++)212 continue;213 214 if (strncmp(ptr, "endfor", 6) == 0 &&215 (isspace((unsigned char) ptr[6]) || !ptr[6])) {216 if (DEBUG(FOR))217 (void) fprintf(stderr, "For: end for %d\n", forLevel);218 if (--forLevel < 0) {219 Parse_Error (level, "for-less endfor");220 return 0;221 }222 }223 else if (strncmp(ptr, "for", 3) == 0 &&224 isspace((unsigned char) ptr[3])) {225 forLevel++;226 if (DEBUG(FOR))227 (void) fprintf(stderr, "For: new loop %d\n", forLevel);228 }212 for (ptr++; *ptr && isspace((unsigned char) *ptr); ptr++) 213 continue; 214 215 if (strncmp(ptr, "endfor", 6) == 0 && 216 (isspace((unsigned char) ptr[6]) || !ptr[6])) { 217 if (DEBUG(FOR)) 218 (void) fprintf(stderr, "For: end for %d\n", forLevel); 219 if (--forLevel < 0) { 220 Parse_Error (level, "for-less endfor"); 221 return 0; 222 } 223 } 224 else if (strncmp(ptr, "for", 3) == 0 && 225 isspace((unsigned char) ptr[3])) { 226 forLevel++; 227 if (DEBUG(FOR)) 228 (void) fprintf(stderr, "For: new loop %d\n", forLevel); 229 } 229 230 } 230 231 231 232 if (forLevel != 0) { 232 Buf_AddBytes(forBuf, strlen(line), (Byte *) line);233 Buf_AddByte(forBuf, (Byte) '\n');234 return 1;233 Buf_AddBytes(forBuf, strlen(line), (Byte *) line); 234 Buf_AddByte(forBuf, (Byte) '\n'); 235 return 1; 235 236 } 236 237 else { 237 return 0;238 return 0; 238 239 } 239 240 } … … 242 243 *----------------------------------------------------------------------- 243 244 * ForExec -- 244 * Expand the for loop for this index and push it in the Makefile245 * Expand the for loop for this index and push it in the Makefile 245 246 * 246 247 * Results: 247 * None.248 * None. 248 249 * 249 250 * Side Effects: 250 * None.251 * None. 251 252 * 252 253 *----------------------------------------------------------------------- … … 262 263 Var_Set(arg->var, name, VAR_GLOBAL); 263 264 if (DEBUG(FOR)) 264 (void) fprintf(stderr, "--- %s = %s\n", arg->var, name);265 (void) fprintf(stderr, "--- %s = %s\n", arg->var, name); 265 266 Parse_FromString(Var_Subst(arg->var, (char *) Buf_GetAll(arg->buf, &len), 266 VAR_GLOBAL, FALSE));267 VAR_GLOBAL, FALSE)); 267 268 Var_Delete(arg->var, VAR_GLOBAL); 268 269 … … 275 276 *----------------------------------------------------------------------- 276 277 * For_Run -- 277 * Run the for loop, immitating the actions of an include file278 * Run the for loop, immitating the actions of an include file 278 279 * 279 280 * Results: 280 * None.281 * None. 281 282 * 282 283 * Side Effects: 283 * None.284 * None. 284 285 * 285 286 *----------------------------------------------------------------------- … … 291 292 292 293 if (forVar == NULL || forBuf == NULL || forLst == NULL) 293 return;294 return; 294 295 arg.var = forVar; 295 296 arg.buf = forBuf; -
trunk/src/kmk/hash.c
r35 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93";41 static char sccsid[] = "@(#)hash.c 8.1 (Berkeley) 6/6/93"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/hash.c,v 1.9 1999/09/11 13:08:01 hoek Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /* hash.c -- 49 50 * 50 * This module contains routines to manipulate a hash table.51 * See hash.h for a definition of the structure of the hash52 * table. Hash tables grow automatically as the amount of53 * information increases.51 * This module contains routines to manipulate a hash table. 52 * See hash.h for a definition of the structure of the hash 53 * table. Hash tables grow automatically as the amount of 54 * information increases. 54 55 */ 55 56 #include "sprite.h" … … 76 77 * Hash_InitTable -- 77 78 * 78 * This routine just sets up the hash table.79 * 80 * Results: 81 * None.82 * 83 * Side Effects: 84 * Memory is allocated for the initial bucket area.79 * This routine just sets up the hash table. 80 * 81 * Results: 82 * None. 83 * 84 * Side Effects: 85 * Memory is allocated for the initial bucket area. 85 86 * 86 87 *--------------------------------------------------------- … … 89 90 void 90 91 Hash_InitTable(t, numBuckets) 91 register Hash_Table *t;/* Structure to use to hold table. */92 int numBuckets;/* How many buckets to create for starters.93 * This number is rounded up to a power of94 * two. If <= 0, a reasonable default is95 * chosen. The table will grow in size later96 * as needed. */97 { 98 register int i;99 register struct Hash_Entry **hp;100 101 /*102 * Round up the size to a power of two.103 */104 if (numBuckets <= 0)105 i = 16;106 else {107 for (i = 2; i < numBuckets; i <<= 1)108 continue;109 }110 t->numEntries = 0;111 t->size = i;112 t->mask = i - 1;113 t->bucketPtr = hp = (struct Hash_Entry **)emalloc(sizeof(*hp) * i);114 while (--i >= 0)115 *hp++ = NULL;92 register Hash_Table *t; /* Structure to use to hold table. */ 93 int numBuckets; /* How many buckets to create for starters. 94 * This number is rounded up to a power of 95 * two. If <= 0, a reasonable default is 96 * chosen. The table will grow in size later 97 * as needed. */ 98 { 99 register int i; 100 register struct Hash_Entry **hp; 101 102 /* 103 * Round up the size to a power of two. 104 */ 105 if (numBuckets <= 0) 106 i = 16; 107 else { 108 for (i = 2; i < numBuckets; i <<= 1) 109 continue; 110 } 111 t->numEntries = 0; 112 t->size = i; 113 t->mask = i - 1; 114 t->bucketPtr = hp = (struct Hash_Entry **)emalloc(sizeof(*hp) * i); 115 while (--i >= 0) 116 *hp++ = NULL; 116 117 } 117 118 … … 121 122 * Hash_DeleteTable -- 122 123 * 123 * This routine removes everything from a hash table124 * and frees up the memory space it occupied (except for125 * the space in the Hash_Table structure).126 * 127 * Results: 128 * None.129 * 130 * Side Effects: 131 * Lots of memory is freed up.124 * This routine removes everything from a hash table 125 * and frees up the memory space it occupied (except for 126 * the space in the Hash_Table structure). 127 * 128 * Results: 129 * None. 130 * 131 * Side Effects: 132 * Lots of memory is freed up. 132 133 * 133 134 *--------------------------------------------------------- … … 136 137 void 137 138 Hash_DeleteTable(t) 138 Hash_Table *t;139 { 140 register struct Hash_Entry **hp, *h, *nexth = NULL;141 register int i;142 143 for (hp = t->bucketPtr, i = t->size; --i >= 0;) {144 for (h = *hp++; h != NULL; h = nexth) {145 nexth = h->next;146 efree((char *)h);147 }148 }149 efree((char *)t->bucketPtr);150 151 /*152 * Set up the hash table to cause memory faults on any future access153 * attempts until re-initialization.154 */155 t->bucketPtr = NULL;139 Hash_Table *t; 140 { 141 register struct Hash_Entry **hp, *h, *nexth = NULL; 142 register int i; 143 144 for (hp = t->bucketPtr, i = t->size; --i >= 0;) { 145 for (h = *hp++; h != NULL; h = nexth) { 146 nexth = h->next; 147 efree((char *)h); 148 } 149 } 150 efree((char *)t->bucketPtr); 151 152 /* 153 * Set up the hash table to cause memory faults on any future access 154 * attempts until re-initialization. 155 */ 156 t->bucketPtr = NULL; 156 157 } 157 158 … … 161 162 * Hash_FindEntry -- 162 163 * 163 * Searches a hash table for an entry corresponding to key.164 * 165 * Results: 166 * The return value is a pointer to the entry for key,167 * if key was present in the table. If key was not168 * present, NULL is returned.169 * 170 * Side Effects: 171 * None.164 * Searches a hash table for an entry corresponding to key. 165 * 166 * Results: 167 * The return value is a pointer to the entry for key, 168 * if key was present in the table. If key was not 169 * present, NULL is returned. 170 * 171 * Side Effects: 172 * None. 172 173 * 173 174 *--------------------------------------------------------- … … 176 177 Hash_Entry * 177 178 Hash_FindEntry(t, key) 178 Hash_Table *t;/* Hash table to search. */179 char *key;/* A hash key. */180 { 181 register Hash_Entry *e;182 register unsigned h;183 register char *p;184 185 for (h = 0, p = key; *p;)186 h = (h << 5) - h + *p++;187 p = key;188 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next)189 if (e->namehash == h && strcmp(e->name, p) == 0)190 return (e);191 return (NULL);179 Hash_Table *t; /* Hash table to search. */ 180 char *key; /* A hash key. */ 181 { 182 register Hash_Entry *e; 183 register unsigned h; 184 register char *p; 185 186 for (h = 0, p = key; *p;) 187 h = (h << 5) - h + *p++; 188 p = key; 189 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) 190 if (e->namehash == h && strcmp(e->name, p) == 0) 191 return (e); 192 return (NULL); 192 193 } 193 194 … … 197 198 * Hash_CreateEntry -- 198 199 * 199 * Searches a hash table for an entry corresponding to200 * key. If no entry is found, then one is created.201 * 202 * Results: 203 * The return value is a pointer to the entry. If *newPtr204 * isn't NULL, then *newPtr is filled in with TRUE if a205 * new entry was created, and FALSE if an entry already existed206 * with the given key.207 * 208 * Side Effects: 209 * Memory may be allocated, and the hash buckets may be modified.200 * Searches a hash table for an entry corresponding to 201 * key. If no entry is found, then one is created. 202 * 203 * Results: 204 * The return value is a pointer to the entry. If *newPtr 205 * isn't NULL, then *newPtr is filled in with TRUE if a 206 * new entry was created, and FALSE if an entry already existed 207 * with the given key. 208 * 209 * Side Effects: 210 * Memory may be allocated, and the hash buckets may be modified. 210 211 *--------------------------------------------------------- 211 212 */ … … 213 214 Hash_Entry * 214 215 Hash_CreateEntry(t, key, newPtr) 215 register Hash_Table *t;/* Hash table to search. */216 char *key;/* A hash key. */217 Boolean *newPtr;/* Filled in with TRUE if new entry created,218 * FALSE otherwise. */219 { 220 register Hash_Entry *e;221 register unsigned h;222 register char *p;223 int keylen;224 struct Hash_Entry **hp;225 226 /*227 * Hash the key. As a side effect, save the length (strlen) of the228 * key in case we need to create the entry.229 */230 for (h = 0, p = key; *p;)231 h = (h << 5) - h + *p++;232 keylen = p - key;233 p = key;234 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) {235 if (e->namehash == h && strcmp(e->name, p) == 0) {236 if (newPtr != NULL)237 *newPtr = FALSE;238 return (e);239 }240 }241 242 /*243 * The desired entry isn't there. Before allocating a new entry,244 * expand the table if necessary (and this changes the resulting245 * bucket chain).246 */247 if (t->numEntries >= rebuildLimit * t->size)248 RebuildTable(t);249 e = (Hash_Entry *) emalloc(sizeof(*e) + keylen);250 hp = &t->bucketPtr[h & t->mask];251 e->next = *hp;252 *hp = e;253 e->clientData = NULL;254 e->namehash = h;255 (void) strcpy(e->name, p);256 t->numEntries++;257 258 if (newPtr != NULL)259 *newPtr = TRUE;260 return (e);216 register Hash_Table *t; /* Hash table to search. */ 217 char *key; /* A hash key. */ 218 Boolean *newPtr; /* Filled in with TRUE if new entry created, 219 * FALSE otherwise. */ 220 { 221 register Hash_Entry *e; 222 register unsigned h; 223 register char *p; 224 int keylen; 225 struct Hash_Entry **hp; 226 227 /* 228 * Hash the key. As a side effect, save the length (strlen) of the 229 * key in case we need to create the entry. 230 */ 231 for (h = 0, p = key; *p;) 232 h = (h << 5) - h + *p++; 233 keylen = p - key; 234 p = key; 235 for (e = t->bucketPtr[h & t->mask]; e != NULL; e = e->next) { 236 if (e->namehash == h && strcmp(e->name, p) == 0) { 237 if (newPtr != NULL) 238 *newPtr = FALSE; 239 return (e); 240 } 241 } 242 243 /* 244 * The desired entry isn't there. Before allocating a new entry, 245 * expand the table if necessary (and this changes the resulting 246 * bucket chain). 247 */ 248 if (t->numEntries >= rebuildLimit * t->size) 249 RebuildTable(t); 250 e = (Hash_Entry *) emalloc(sizeof(*e) + keylen); 251 hp = &t->bucketPtr[h & t->mask]; 252 e->next = *hp; 253 *hp = e; 254 e->clientData = NULL; 255 e->namehash = h; 256 (void) strcpy(e->name, p); 257 t->numEntries++; 258 259 if (newPtr != NULL) 260 *newPtr = TRUE; 261 return (e); 261 262 } 262 263 … … 266 267 * Hash_DeleteEntry -- 267 268 * 268 * Delete the given hash table entry and efree memory associated with269 * it.270 * 271 * Results: 272 * None.273 * 274 * Side Effects: 275 * Hash chain that entry lives in is modified and memory is freed.269 * Delete the given hash table entry and efree memory associated with 270 * it. 271 * 272 * Results: 273 * None. 274 * 275 * Side Effects: 276 * Hash chain that entry lives in is modified and memory is freed. 276 277 * 277 278 *--------------------------------------------------------- … … 280 281 void 281 282 Hash_DeleteEntry(t, e) 282 Hash_Table *t;283 Hash_Entry *e;284 { 285 register Hash_Entry **hp, *p;286 287 if (e == NULL)288 return;289 for (hp = &t->bucketPtr[e->namehash & t->mask];290 (p = *hp) != NULL; hp = &p->next) {291 if (p == e) {292 *hp = p->next;293 efree((char *)p);294 t->numEntries--;295 return;296 }297 }298 (void) write(2, "bad call to Hash_DeleteEntry\n", 29);299 abort();283 Hash_Table *t; 284 Hash_Entry *e; 285 { 286 register Hash_Entry **hp, *p; 287 288 if (e == NULL) 289 return; 290 for (hp = &t->bucketPtr[e->namehash & t->mask]; 291 (p = *hp) != NULL; hp = &p->next) { 292 if (p == e) { 293 *hp = p->next; 294 efree((char *)p); 295 t->numEntries--; 296 return; 297 } 298 } 299 (void) write(STDERR_FILENO, "bad call to Hash_DeleteEntry\n", 29); 300 abort(); 300 301 } 301 302 … … 304 305 * 305 306 * Hash_EnumFirst -- 306 * This procedure sets things up for a complete search307 * of all entries recorded in the hash table.308 * 309 * Results: 310 * The return value is the address of the first entry in311 * the hash table, or NULL if the table is empty.312 * 313 * Side Effects: 314 * The information in searchPtr is initialized so that successive315 * calls to Hash_Next will return successive HashEntry's316 * from the table.307 * This procedure sets things up for a complete search 308 * of all entries recorded in the hash table. 309 * 310 * Results: 311 * The return value is the address of the first entry in 312 * the hash table, or NULL if the table is empty. 313 * 314 * Side Effects: 315 * The information in searchPtr is initialized so that successive 316 * calls to Hash_Next will return successive HashEntry's 317 * from the table. 317 318 * 318 319 *--------------------------------------------------------- … … 321 322 Hash_Entry * 322 323 Hash_EnumFirst(t, searchPtr) 323 Hash_Table *t;/* Table to be searched. */324 register Hash_Search *searchPtr;/* Area in which to keep state325 * about search.*/326 { 327 searchPtr->tablePtr = t;328 searchPtr->nextIndex = 0;329 searchPtr->hashEntryPtr = NULL;330 return Hash_EnumNext(searchPtr);324 Hash_Table *t; /* Table to be searched. */ 325 register Hash_Search *searchPtr;/* Area in which to keep state 326 * about search.*/ 327 { 328 searchPtr->tablePtr = t; 329 searchPtr->nextIndex = 0; 330 searchPtr->hashEntryPtr = NULL; 331 return Hash_EnumNext(searchPtr); 331 332 } 332 333 … … 351 352 Hash_Entry * 352 353 Hash_EnumNext(searchPtr) 353 register Hash_Search *searchPtr; /* Area used to keep state about354 search. */355 { 356 register Hash_Entry *e;357 Hash_Table *t = searchPtr->tablePtr;358 359 /*360 * The hashEntryPtr field points to the most recently returned361 * entry, or is nil if we are starting up. If not nil, we have362 * to start at the next one in the chain.363 */364 e = searchPtr->hashEntryPtr;365 if (e != NULL)366 e = e->next;367 /*368 * If the chain ran out, or if we are starting up, we need to369 * find the next nonempty chain.370 */371 while (e == NULL) {372 if (searchPtr->nextIndex >= t->size)373 return (NULL);374 e = t->bucketPtr[searchPtr->nextIndex++];375 }376 searchPtr->hashEntryPtr = e;377 return (e);354 register Hash_Search *searchPtr; /* Area used to keep state about 355 search. */ 356 { 357 register Hash_Entry *e; 358 Hash_Table *t = searchPtr->tablePtr; 359 360 /* 361 * The hashEntryPtr field points to the most recently returned 362 * entry, or is nil if we are starting up. If not nil, we have 363 * to start at the next one in the chain. 364 */ 365 e = searchPtr->hashEntryPtr; 366 if (e != NULL) 367 e = e->next; 368 /* 369 * If the chain ran out, or if we are starting up, we need to 370 * find the next nonempty chain. 371 */ 372 while (e == NULL) { 373 if (searchPtr->nextIndex >= t->size) 374 return (NULL); 375 e = t->bucketPtr[searchPtr->nextIndex++]; 376 } 377 searchPtr->hashEntryPtr = e; 378 return (e); 378 379 } 379 380 … … 382 383 * 383 384 * RebuildTable -- 384 * This local routine makes a new hash table that385 * is larger than the old one.386 * 387 * Results: 388 * None.389 * 390 * Side Effects: 391 * The entire hash table is moved, so any bucket numbers392 * from the old table are invalid.385 * This local routine makes a new hash table that 386 * is larger than the old one. 387 * 388 * Results: 389 * None. 390 * 391 * Side Effects: 392 * The entire hash table is moved, so any bucket numbers 393 * from the old table are invalid. 393 394 * 394 395 *--------------------------------------------------------- … … 397 398 static void 398 399 RebuildTable(t) 399 register Hash_Table *t;400 { 401 register Hash_Entry *e, *next = NULL, **hp, **xp;402 register int i, mask;400 register Hash_Table *t; 401 { 402 register Hash_Entry *e, *next = NULL, **hp, **xp; 403 register int i, mask; 403 404 register Hash_Entry **oldhp; 404 int oldsize;405 406 oldhp = t->bucketPtr;407 oldsize = i = t->size;408 i <<= 1;409 t->size = i;410 t->mask = mask = i - 1;411 t->bucketPtr = hp = (struct Hash_Entry **) emalloc(sizeof(*hp) * i);412 while (--i >= 0)413 *hp++ = NULL;414 for (hp = oldhp, i = oldsize; --i >= 0;) {415 for (e = *hp++; e != NULL; e = next) {416 next = e->next;417 xp = &t->bucketPtr[e->namehash & mask];418 e->next = *xp;419 *xp = e;420 }421 }422 efree((char *)oldhp);423 } 405 int oldsize; 406 407 oldhp = t->bucketPtr; 408 oldsize = i = t->size; 409 i <<= 1; 410 t->size = i; 411 t->mask = mask = i - 1; 412 t->bucketPtr = hp = (struct Hash_Entry **) emalloc(sizeof(*hp) * i); 413 while (--i >= 0) 414 *hp++ = NULL; 415 for (hp = oldhp, i = oldsize; --i >= 0;) { 416 for (e = *hp++; e != NULL; e = next) { 417 next = e->next; 418 xp = &t->bucketPtr[e->namehash & mask]; 419 e->next = *xp; 420 *xp = e; 421 } 422 } 423 efree((char *)oldhp); 424 } -
trunk/src/kmk/helpers.c
r35 r51 18 18 #include <sys/stat.h> 19 19 #include <stdarg.h> 20 #include <stdio.h> 21 #include <err.h> 22 20 23 #ifdef OS2 21 24 #define INCL_BASE 22 25 #include <os2.h> 23 26 #endif 24 #include <stdio.h>25 #include <err.h>26 27 27 28 … … 34 35 char *realpath(const char *pszFileName, char *pszResolvedName) 35 36 { 36 #if 0 //def USE_KLIB //@todo37 #ifdef USE_KLIB 37 38 if (kPathCanonifyEx(pszFileName, NULL, '/', '/', pszResolvedName, KFILE_LENGTH)) 38 39 if (kPathExist(pszFileName)) … … 51 52 52 53 #ifdef OS2 53 void err(int flags, const char *pszFormat, ...)54 void err(int flags, const char *pszFormat, ...) 54 55 { 55 56 va_list args; … … 60 61 } 61 62 62 void errx(int flags, const char *pszFormat, ...)63 void errx(int flags, const char *pszFormat, ...) 63 64 { 64 65 va_list args; … … 69 70 } 70 71 71 void warnx(const char *pszFormat, ...)72 void warnx(const char *pszFormat, ...) 72 73 { 73 74 va_list args; … … 78 79 } 79 80 80 void warn(const char *pszFormat, ...)81 void warn(const char *pszFormat, ...) 81 82 { 82 83 va_list args; -
trunk/src/kmk/job.c
r46 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94";41 static char sccsid[] = "@(#)job.c 8.2 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/job.c,v 1.17.2.2 2001/02/13 03:13:57 will Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 … … 56 57 /*- 57 58 * job.c -- 58 * handle the creation etc. of our child processes.59 * handle the creation etc. of our child processes. 59 60 * 60 61 * Interface: 61 * Job_MakeStart the creation of the given target.62 * 63 * Job_CatchChildrenCheck for and handle the termination of any64 * children. This must be called reasonably65 * frequently to keep the whole make going at66 * a decent clip, since job table entries aren't67 * removed until their process is caught this way.68 * Its single argument is TRUE if the function69 * should block waiting for a child to terminate.70 * 71 * Job_CatchOutputPrint any output our children have produced.72 * Should also be called fairly frequently to73 * keep the user informed of what's going on.74 * If no output is waiting, it will block for75 * a time given by the SEL_* constants, below,76 * or until output is ready.77 * 78 * Job_InitCalled to intialize this module. in addition,79 * any commands attached to the .BEGIN target80 * are executed before this function returns.81 * Hence, the makefile must have been parsed82 * before this function is called.83 * 84 * Job_FullReturn TRUE if the job table is filled.85 * 86 * Job_EmptyReturn TRUE if the job table is completely87 * empty.88 * 89 * Job_ParseShellGiven the line following a .SHELL target, parse90 * the line as a shell specification. Returns91 * FAILURE if the spec was incorrect.92 * 93 * Job_EndPerform any final processing which needs doing.94 * This includes the execution of any commands95 * which have been/were attached to the .END96 * target. It should only be called when the97 * job table is empty.98 * 99 * Job_AbortAllAbort all currently running jobs. It doesn't100 * handle output or do anything for the jobs,101 * just kills them. It should only be called in102 * an emergency, as it were.103 * 104 * Job_CheckCommandsVerify that the commands for a target are105 * ok. Provide them if necessary and possible.106 * 107 * Job_TouchUpdate a target without really updating it.108 * 109 * Job_WaitWait for all currently-running jobs to finish.62 * Job_Make Start the creation of the given target. 63 * 64 * Job_CatchChildren Check for and handle the termination of any 65 * children. This must be called reasonably 66 * frequently to keep the whole make going at 67 * a decent clip, since job table entries aren't 68 * removed until their process is caught this way. 69 * Its single argument is TRUE if the function 70 * should block waiting for a child to terminate. 71 * 72 * Job_CatchOutput Print any output our children have produced. 73 * Should also be called fairly frequently to 74 * keep the user informed of what's going on. 75 * If no output is waiting, it will block for 76 * a time given by the SEL_* constants, below, 77 * or until output is ready. 78 * 79 * Job_Init Called to intialize this module. in addition, 80 * any commands attached to the .BEGIN target 81 * are executed before this function returns. 82 * Hence, the makefile must have been parsed 83 * before this function is called. 84 * 85 * Job_Full Return TRUE if the job table is filled. 86 * 87 * Job_Empty Return TRUE if the job table is completely 88 * empty. 89 * 90 * Job_ParseShell Given the line following a .SHELL target, parse 91 * the line as a shell specification. Returns 92 * FAILURE if the spec was incorrect. 93 * 94 * Job_End Perform any final processing which needs doing. 95 * This includes the execution of any commands 96 * which have been/were attached to the .END 97 * target. It should only be called when the 98 * job table is empty. 99 * 100 * Job_AbortAll Abort all currently running jobs. It doesn't 101 * handle output or do anything for the jobs, 102 * just kills them. It should only be called in 103 * an emergency, as it were. 104 * 105 * Job_CheckCommands Verify that the commands for a target are 106 * ok. Provide them if necessary and possible. 107 * 108 * Job_Touch Update a target without really updating it. 109 * 110 * Job_Wait Wait for all currently-running jobs to finish. 110 111 */ 111 112 … … 153 154 * error handling variables 154 155 */ 155 static int errors = 0;/* number of errors reported */156 static int aborting = 0;/* why is the make aborting? */157 #define ABORT_ERROR 1/* Because of an error */158 #define ABORT_INTERRUPT 2/* Because it was interrupted */159 #define ABORT_WAIT 3/* Waiting for jobs to finish */156 static int errors = 0; /* number of errors reported */ 157 static int aborting = 0; /* why is the make aborting? */ 158 #define ABORT_ERROR 1 /* Because of an error */ 159 #define ABORT_INTERRUPT 2 /* Because it was interrupted */ 160 #define ABORT_WAIT 3 /* Waiting for jobs to finish */ 160 161 161 162 /* … … 170 171 * all the time. 171 172 */ 172 static GNode *postCommands; /* node containing commands to execute when173 * everything else is done */174 static int numCommands;/* The number of commands actually printed175 * for a target. Should this number be176 * 0, no shell will be executed. */173 static GNode *postCommands; /* node containing commands to execute when 174 * everything else is done */ 175 static int numCommands; /* The number of commands actually printed 176 * for a target. Should this number be 177 * 0, no shell will be executed. */ 177 178 178 179 /* 179 180 * Return values from JobStart. 180 181 */ 181 #define JOB_RUNNING 0/* Job is running */182 #define JOB_ERROR 1/* Error in starting the job */183 #define JOB_FINISHED 2/* The job is already finished */184 #define JOB_STOPPED 3/* The job is stopped */182 #define JOB_RUNNING 0 /* Job is running */ 183 #define JOB_ERROR 1 /* Error in starting the job */ 184 #define JOB_FINISHED 2 /* The job is already finished */ 185 #define JOB_STOPPED 3 /* The job is stopped */ 185 186 186 187 /* … … 229 230 } 230 231 }; 231 static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to232 * which we pass all233 * commands in the Makefile.234 * It is set by the235 * Job_ParseShell function */236 static char *shellPath = NULL,/* full pathname of237 * executable image */238 *shellName;/* last component of shell */232 static Shell *commandShell = &shells[DEFSHELL];/* this is the shell to 233 * which we pass all 234 * commands in the Makefile. 235 * It is set by the 236 * Job_ParseShell function */ 237 static char *shellPath = NULL, /* full pathname of 238 * executable image */ 239 *shellName; /* last component of shell */ 239 240 #endif /*!KMK*/ 240 241 241 242 242 static int maxJobs;/* The most children we can run at once */243 static int maxLocal;/* The most local ones we can have */244 STATIC int nJobs;/* The number of children currently running */245 STATIC int nLocal;/* The number of local children */246 STATIC Lst jobs;/* The structures that describe them */247 STATIC Boolean jobFull;/* Flag to tell when the job table is full. It248 * is set TRUE when (1) the total number of249 * running jobs equals the maximum allowed or250 * (2) a job can only be run locally, but251 * nLocal equals maxLocal */243 static int maxJobs; /* The most children we can run at once */ 244 static int maxLocal; /* The most local ones we can have */ 245 STATIC int nJobs; /* The number of children currently running */ 246 STATIC int nLocal; /* The number of local children */ 247 STATIC Lst jobs; /* The structures that describe them */ 248 STATIC Boolean jobFull; /* Flag to tell when the job table is full. It 249 * is set TRUE when (1) the total number of 250 * running jobs equals the maximum allowed or 251 * (2) a job can only be run locally, but 252 * nLocal equals maxLocal */ 252 253 #ifndef RMT_WILL_WATCH 253 static fd_set outputs;/* Set of descriptors of pipes connected to254 * the output channels of children */255 #endif 256 257 STATIC GNode *lastNode;/* The node for which output was most recently258 * produced. */259 STATIC char *targFmt;/* Format string to use to head output from a260 * job when it's not the most-recent job heard261 * from */254 static fd_set outputs; /* Set of descriptors of pipes connected to 255 * the output channels of children */ 256 #endif 257 258 STATIC GNode *lastNode; /* The node for which output was most recently 259 * produced. */ 260 STATIC char *targFmt; /* Format string to use to head output from a 261 * job when it's not the most-recent job heard 262 * from */ 262 263 263 264 #ifdef REMOTE 264 265 # define TARG_FMT "--- %s at %s ---\n" /* Default format */ 265 266 # define MESSAGE(fp, gn) \ 266 (void) fprintf(fp, targFmt, gn->name, gn->rem.hname);267 (void) fprintf(fp, targFmt, gn->name, gn->rem.hname); 267 268 #else 268 269 # define TARG_FMT "--- %s ---\n" /* Default format */ 269 270 # define MESSAGE(fp, gn) \ 270 (void) fprintf(fp, targFmt, gn->name); 271 #endif 272 271 (void) fprintf(fp, targFmt, gn->name); 272 #endif 273 274 #ifdef SIGCONT 273 275 /* 274 276 * When JobStart attempts to run a job remotely but can't, and isn't allowed … … 277 279 * when the next job finishes. 278 280 */ 279 STATIC Lst stoppedJobs;/* Lst of Job structures describing280 * jobs that were stopped due to concurrency281 * limits or migration home */282 281 STATIC Lst stoppedJobs; /* Lst of Job structures describing 282 * jobs that were stopped due to concurrency 283 * limits or migration home */ 284 #endif /*SIGCONT*/ 283 285 284 286 #if defined(USE_PGRP) && defined(SYSV) 285 # define KILL(pid, sig) killpg(-(pid), (sig))287 # define KILL(pid, sig) killpg(-(pid), (sig)) 286 288 #else 287 289 # if defined(USE_PGRP) 288 # define KILL(pid, sig) killpg((pid), (sig))290 # define KILL(pid, sig) killpg((pid), (sig)) 289 291 # else 290 # define KILL(pid, sig) kill((pid), (sig))292 # define KILL(pid, sig) kill((pid), (sig)) 291 293 # endif 292 294 #endif … … 298 300 * really ugly, use dramamine sparingly. You have been warned. 299 301 */ 300 #define W_SETMASKED(st, val, fun) \301 {\302 int sh = (int) ~0;\303 int mask = fun(sh);\304 \305 for (sh = 0; ((mask >> sh) & 1) == 0; sh++)\306 continue;\307 *(st) = (*(st) & ~mask) | ((val) << sh);\308 }302 #define W_SETMASKED(st, val, fun) \ 303 { \ 304 int sh = (int) ~0; \ 305 int mask = fun(sh); \ 306 \ 307 for (sh = 0; ((mask >> sh) & 1) == 0; sh++) \ 308 continue; \ 309 *(st) = (*(st) & ~mask) | ((val) << sh); \ 310 } 309 311 310 312 #define W_SETTERMSIG(st, val) W_SETMASKED(st, val, WTERMSIG) … … 324 326 # endif 325 327 #else 328 #ifdef USE_KLIB 329 static void JobFinish __P((Job *, KPROCRES *)); 330 #else 326 331 static void JobFinish __P((Job *, int *)); 332 #endif 327 333 static void JobExec __P((Job *, char **)); 328 334 #endif 329 #ifndef KMK330 335 static void JobMakeArgv __P((Job *, char **)); 331 # endif336 #ifdef SIGCONT 332 337 static void JobRestart __P((Job *)); 338 #endif 333 339 static int JobStart __P((GNode *, int, Job *)); 334 340 static char *JobOutput __P((Job *, char *, char *, int)); … … 336 342 static Shell *JobMatchShell __P((char *)); 337 343 static void JobInterrupt __P((int, int)); 344 #ifdef SIGCONT 338 345 static void JobRestartJobs __P((void)); 346 #endif 339 347 340 348 /*- 341 349 *----------------------------------------------------------------------- 342 350 * JobCondPassSig -- 343 * Pass a signal to a job if the job is remote or if USE_PGRP344 * is defined.351 * Pass a signal to a job if the job is remote or if USE_PGRP 352 * is defined. 345 353 * 346 354 * Results: 347 * === 0355 * === 0 348 356 * 349 357 * Side Effects: 350 * None, except the job may bite it.358 * None, except the job may bite it. 351 359 * 352 360 *----------------------------------------------------------------------- … … 354 362 static int 355 363 JobCondPassSig(jobp, signop) 356 ClientData jobp;/* Job to biff */357 ClientData signop;/* Signal to send it */364 ClientData jobp; /* Job to biff */ 365 ClientData signop; /* Signal to send it */ 358 366 { 359 Job *job = (Job *) jobp;360 int signo = *(int *) signop;367 Job *job = (Job *) jobp; 368 int signo = *(int *) signop; 361 369 #ifdef RMT_WANTS_SIGNALS 362 370 if (job->flags & JOB_REMOTE) { 363 (void) Rmt_Signal(job, signo);371 (void) Rmt_Signal(job, signo); 364 372 } else { 365 KILL(job->pid, signo);373 KILL(job->pid, signo); 366 374 } 367 375 #else … … 371 379 */ 372 380 if (DEBUG(JOB)) { 373 (void) fprintf(stdout, 374 "JobCondPassSig passing signal %d to child %d.\n", 375 signo, job->pid); 376 (void) fflush(stdout); 377 } 381 (void) fprintf(stdout, 382 "JobCondPassSig passing signal %d to child %d.\n", 383 signo, job->pid); 384 (void) fflush(stdout); 385 } 386 #if defined(USE_KLIB) && (defined(OS2) || defined(WIN32)) 387 switch (signo) 388 { 389 case SIGINT: 390 kProcKill(job->pid, KPROCKILL_FLAGS_TREE | KPROCKILL_FLAGS_TYPE_INT); 391 break; 392 #ifdef SIGKILL 393 case SIGKILL: 394 #endif 395 case SIGTERM: 396 kProcKill(job->pid, KPROCKILL_FLAGS_TREE | KPROCKILL_FLAGS_TYPE_KILL); 397 break; 398 /* default: ignore signal as we don't really support it */ 399 } 400 #else 378 401 KILL(job->pid, signo); 402 #endif 379 403 #endif 380 404 return 0; … … 384 408 *----------------------------------------------------------------------- 385 409 * JobPassSig -- 386 * Pass a signal on to all remote jobs and to all local jobs if387 * USE_PGRP is defined, then die ourselves.410 * Pass a signal on to all remote jobs and to all local jobs if 411 * USE_PGRP is defined, then die ourselves. 388 412 * 389 413 * Results: 390 * None.414 * None. 391 415 * 392 416 * Side Effects: 393 * We die by the same signal.417 * We die by the same signal. 394 418 * 395 419 *----------------------------------------------------------------------- … … 397 421 static void 398 422 JobPassSig(signo) 399 int signo;/* The signal number we've received */423 int signo; /* The signal number we've received */ 400 424 { 401 sigset_t nmask, omask; 402 struct sigaction act; 425 #if defined(USE_KLIB) && (defined(OS2) || defined(WIN32)) 403 426 404 427 if (DEBUG(JOB)) { 405 (void)fprintf(stdout, "JobPassSig(%d) called.\n", signo);406 (void)fflush(stdout);428 fprintf(stdout, "JobPassSig(%d) called.\n", signo); 429 fflush(stdout); 407 430 } 408 431 Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); … … 414 437 */ 415 438 if (signo == SIGINT) { 416 JobInterrupt(TRUE, signo); 417 } else if ((signo == SIGHUP) || (signo == SIGTERM) || (signo == SIGQUIT)) { 418 JobInterrupt(FALSE, signo); 419 } 420 439 JobInterrupt(TRUE, signo); 440 } else if (signo == SIGTERM) { 441 JobInterrupt(FALSE, signo); 442 } 443 444 445 if (DEBUG(JOB)) { 446 fprintf(stdout, 447 "JobPassSig passing signal to self, mask = %x.\n", 448 ~0 & ~(1 << (signo-1))); 449 fflush(stdout); 450 } 451 signal(signo, SIG_DFL); 452 raise(signo); 453 454 #ifdef SIGCONT 455 signo = SIGCONT; 456 Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); 457 #endif 458 459 460 #else /* Not KLIB + OS2/Win32 */ 461 sigset_t nmask, omask; 462 struct sigaction act; 463 464 465 if (DEBUG(JOB)) { 466 (void) fprintf(stdout, "JobPassSig(%d) called.\n", signo); 467 (void) fflush(stdout); 468 } 469 Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); 470 471 /* 472 * Deal with proper cleanup based on the signal received. We only run 473 * the .INTERRUPT target if the signal was in fact an interrupt. The other 474 * three termination signals are more of a "get out *now*" command. 475 */ 476 if (signo == SIGINT) { 477 JobInterrupt(TRUE, signo); 478 } else if ( 0 479 #ifdef SIGHUP /* not all systems supports this signal */ 480 || (signo == SIGHUP) 481 #endif 482 || (signo == SIGTERM) 483 #ifdef SIGQUIT /* not all systems supports this signal */ 484 || (signo == SIGQUIT) 485 #endif 486 ) { 487 JobInterrupt(FALSE, signo); 488 } 489 490 #ifdef SIGQUIT /* not all systems supports this signal */ 421 491 /* 422 492 * Leave gracefully if SIGQUIT, rather than core dumping. 423 493 */ 424 494 if (signo == SIGQUIT) { 425 signo = SIGINT; 426 } 427 495 signo = SIGINT; 496 } 497 #endif 498 499 #if !defined(USE_KLIB) || !(defined(OS2) || defined(WIN32)) 428 500 /* 429 501 * Send ourselves the signal now we've given the message to everyone else. … … 439 511 act.sa_flags = 0; 440 512 sigaction(signo, &act, NULL); 513 #endif 441 514 442 515 if (DEBUG(JOB)) { 443 (void) fprintf(stdout,444 "JobPassSig passing signal to self, mask = %x.\n",445 ~0 & ~(1 << (signo-1)));446 (void) fflush(stdout);516 (void) fprintf(stdout, 517 "JobPassSig passing signal to self, mask = %x.\n", 518 ~0 & ~(1 << (signo-1))); 519 (void) fflush(stdout); 447 520 } 448 521 (void) signal(signo, SIG_DFL); … … 453 526 Lst_ForEach(jobs, JobCondPassSig, (ClientData) &signo); 454 527 528 #if !defined(USE_KLIB) || !(defined(OS2) || defined(WIN32)) 455 529 (void) sigprocmask(SIG_SETMASK, &omask, NULL); 456 530 sigprocmask(SIG_SETMASK, &omask, NULL); 457 531 act.sa_handler = JobPassSig; 458 532 sigaction(signo, &act, NULL); 533 #endif 534 #endif /* KLIB + OS2/Win32 */ 459 535 } 460 536 … … 462 538 *----------------------------------------------------------------------- 463 539 * JobCmpPid -- 464 * Compare the pid of the job with the given pid and return 0 if they465 * are equal. This function is called from Job_CatchChildren via466 * Lst_Find to find the job descriptor of the finished job.540 * Compare the pid of the job with the given pid and return 0 if they 541 * are equal. This function is called from Job_CatchChildren via 542 * Lst_Find to find the job descriptor of the finished job. 467 543 * 468 544 * Results: 469 * 0 if the pid's match545 * 0 if the pid's match 470 546 * 471 547 * Side Effects: 472 * None548 * None 473 549 *----------------------------------------------------------------------- 474 550 */ 475 551 static int 476 552 JobCmpPid(job, pid) 477 ClientData job; /* job to examine */478 ClientData pid; /* process id desired */553 ClientData job; /* job to examine */ 554 ClientData pid; /* process id desired */ 479 555 { 480 556 return *(int *) pid - ((Job *) job)->pid; … … 485 561 *----------------------------------------------------------------------- 486 562 * JobCmpRmtID -- 487 * Compare the rmtID of the job with the given rmtID and return 0 if they488 * are equal.563 * Compare the rmtID of the job with the given rmtID and return 0 if they 564 * are equal. 489 565 * 490 566 * Results: 491 * 0 if the rmtID's match567 * 0 if the rmtID's match 492 568 * 493 569 * Side Effects: 494 * None.570 * None. 495 571 *----------------------------------------------------------------------- 496 572 */ 497 573 static int 498 574 JobCmpRmtID(job, rmtID) 499 ClientData job; /* job to examine */500 ClientData rmtID; /* remote id desired */575 ClientData job; /* job to examine */ 576 ClientData rmtID; /* remote id desired */ 501 577 { 502 578 return(*(int *) rmtID - *(int *) job->rmtID); … … 507 583 *----------------------------------------------------------------------- 508 584 * JobPrintCommand -- 509 * Put out another command for the given job. If the command starts510 * with an @ or a - we process it specially. In the former case,511 * so long as the -s and -n flags weren't given to make, we stick512 * a shell-specific echoOff command in the script. In the latter,513 * we ignore errors for the entire job, unless the shell has error514 * control.515 * If the command is just "..." we take all future commands for this516 * job to be commands to be executed once the entire graph has been517 * made and return non-zero to signal that the end of the commands518 * was reached. These commands are later attached to the postCommands519 * node and executed by Job_End when all things are done.520 * This function is called from JobStart via Lst_ForEach.585 * Put out another command for the given job. If the command starts 586 * with an @ or a - we process it specially. In the former case, 587 * so long as the -s and -n flags weren't given to make, we stick 588 * a shell-specific echoOff command in the script. In the latter, 589 * we ignore errors for the entire job, unless the shell has error 590 * control. 591 * If the command is just "..." we take all future commands for this 592 * job to be commands to be executed once the entire graph has been 593 * made and return non-zero to signal that the end of the commands 594 * was reached. These commands are later attached to the postCommands 595 * node and executed by Job_End when all things are done. 596 * This function is called from JobStart via Lst_ForEach. 521 597 * 522 598 * Results: 523 * Always 0, unless the command was "..."599 * Always 0, unless the command was "..." 524 600 * 525 601 * Side Effects: 526 * If the command begins with a '-' and the shell has no error control,527 * the JOB_IGNERR flag is set in the job descriptor.528 * If the command is "..." and we're not ignoring such things,529 * tailCmds is set to the successor node of the cmd.530 * numCommands is incremented if the command is actually printed.602 * If the command begins with a '-' and the shell has no error control, 603 * the JOB_IGNERR flag is set in the job descriptor. 604 * If the command is "..." and we're not ignoring such things, 605 * tailCmds is set to the successor node of the cmd. 606 * numCommands is incremented if the command is actually printed. 531 607 *----------------------------------------------------------------------- 532 608 */ 533 609 static int 534 610 JobPrintCommand(cmdp, jobp) 535 ClientData cmdp; /* command string to print */536 ClientData jobp; /* job for which to print it */611 ClientData cmdp; /* command string to print */ 612 ClientData jobp; /* job for which to print it */ 537 613 { 538 Boolean noSpecials;/* true if we shouldn't worry about539 * inserting special commands into540 * the input stream. */614 Boolean noSpecials; /* true if we shouldn't worry about 615 * inserting special commands into 616 * the input stream. */ 541 617 Boolean shutUp = FALSE; /* true if we put a no echo command 542 * into the command file */543 Boolean errOff = FALSE; /* true if we turned error checking544 * off before printing the command545 * and need to turn it back on */546 char *cmdTemplate;/* Template to use when printing the547 * command */548 char *cmdStart;/* Start of expanded command */549 LstNode cmdNode;/* Node for replacing the command */550 char *cmd = (char *) cmdp;618 * into the command file */ 619 Boolean errOff = FALSE; /* true if we turned error checking 620 * off before printing the command 621 * and need to turn it back on */ 622 char *cmdTemplate; /* Template to use when printing the 623 * command */ 624 char *cmdStart; /* Start of expanded command */ 625 LstNode cmdNode; /* Node for replacing the command */ 626 char *cmd = (char *) cmdp; 551 627 Job *job = (Job *) jobp; 552 628 … … 554 630 555 631 if (strcmp(cmd, "...") == 0) { 556 job->node->type |= OP_SAVE_CMDS;557 if ((job->flags & JOB_IGNDOTS) == 0) {558 job->tailCmds = Lst_Succ(Lst_Member(job->node->commands,559 (ClientData)cmd));560 return 1;561 }562 return 0;563 } 564 565 #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \566 (void) fprintf(stdout, fmt, arg);\567 (void) fflush(stdout);\568 } \569 (void) fprintf(job->cmdFILE, fmt, arg); \632 job->node->type |= OP_SAVE_CMDS; 633 if ((job->flags & JOB_IGNDOTS) == 0) { 634 job->tailCmds = Lst_Succ(Lst_Member(job->node->commands, 635 (ClientData)cmd)); 636 return 1; 637 } 638 return 0; 639 } 640 641 #define DBPRINTF(fmt, arg) if (DEBUG(JOB)) { \ 642 (void) fprintf(stdout, fmt, arg); \ 643 (void) fflush(stdout); \ 644 } \ 645 (void) fprintf(job->cmdFILE, fmt, arg); \ 570 646 (void) fflush(job->cmdFILE); 571 647 … … 586 662 */ 587 663 while (*cmd == '@' || *cmd == '-') { 588 if (*cmd == '@') {589 shutUp = DEBUG(LOUD) ? FALSE : TRUE;590 } else {591 errOff = TRUE;592 }593 cmd++;664 if (*cmd == '@') { 665 shutUp = DEBUG(LOUD) ? FALSE : TRUE; 666 } else { 667 errOff = TRUE; 668 } 669 cmd++; 594 670 } 595 671 596 672 while (isspace((unsigned char) *cmd)) 597 cmd++;673 cmd++; 598 674 599 675 #ifndef KMK 600 676 if (shutUp) { 601 if (!(job->flags & JOB_SILENT) && !noSpecials &&602 commandShell->hasEchoCtl) {603 DBPRINTF("%s\n", commandShell->echoOff);604 } else {605 shutUp = FALSE;606 }677 if (!(job->flags & JOB_SILENT) && !noSpecials && 678 commandShell->hasEchoCtl) { 679 DBPRINTF("%s\n", commandShell->echoOff); 680 } else { 681 shutUp = FALSE; 682 } 607 683 } 608 684 #endif 609 685 610 686 if (errOff) { 611 if ( !(job->flags & JOB_IGNERR) && !noSpecials) {687 if ( !(job->flags & JOB_IGNERR) && !noSpecials) { 612 688 #ifdef KMK 613 689 errOff = FALSE; 614 690 #else 615 if (commandShell->hasErrCtl) {616 /*617 * we don't want the error-control commands showing618 * up either, so we turn off echoing while executing619 * them. We could put another field in the shell620 * structure to tell JobDoOutput to look for this621 * string too, but why make it any more complex than622 * it already is?623 */624 if (!(job->flags & JOB_SILENT) && !shutUp &&625 commandShell->hasEchoCtl) {626 DBPRINTF("%s\n", commandShell->echoOff);627 DBPRINTF("%s\n", commandShell->ignErr);628 DBPRINTF("%s\n", commandShell->echoOn);629 } else {630 DBPRINTF("%s\n", commandShell->ignErr);631 }632 } else if (commandShell->ignErr &&633 (*commandShell->ignErr != '\0'))634 {635 /*636 * The shell has no error control, so we need to be637 * weird to get it to ignore any errors from the command.638 * If echoing is turned on, we turn it off and use the639 * errCheck template to echo the command. Leave echoing640 * off so the user doesn't see the weirdness we go through641 * to ignore errors. Set cmdTemplate to use the weirdness642 * instead of the simple "%s\n" template.643 */644 if (!(job->flags & JOB_SILENT) && !shutUp &&645 commandShell->hasEchoCtl) {646 DBPRINTF("%s\n", commandShell->echoOff);647 DBPRINTF(commandShell->errCheck, cmd);648 shutUp = TRUE;649 }650 cmdTemplate = commandShell->ignErr;651 /*652 * The error ignoration (hee hee) is already taken care653 * of by the ignErr template, so pretend error checking654 * is still on.655 */656 errOff = FALSE;657 } else {658 errOff = FALSE;659 }691 if (commandShell->hasErrCtl) { 692 /* 693 * we don't want the error-control commands showing 694 * up either, so we turn off echoing while executing 695 * them. We could put another field in the shell 696 * structure to tell JobDoOutput to look for this 697 * string too, but why make it any more complex than 698 * it already is? 699 */ 700 if (!(job->flags & JOB_SILENT) && !shutUp && 701 commandShell->hasEchoCtl) { 702 DBPRINTF("%s\n", commandShell->echoOff); 703 DBPRINTF("%s\n", commandShell->ignErr); 704 DBPRINTF("%s\n", commandShell->echoOn); 705 } else { 706 DBPRINTF("%s\n", commandShell->ignErr); 707 } 708 } else if (commandShell->ignErr && 709 (*commandShell->ignErr != '\0')) 710 { 711 /* 712 * The shell has no error control, so we need to be 713 * weird to get it to ignore any errors from the command. 714 * If echoing is turned on, we turn it off and use the 715 * errCheck template to echo the command. Leave echoing 716 * off so the user doesn't see the weirdness we go through 717 * to ignore errors. Set cmdTemplate to use the weirdness 718 * instead of the simple "%s\n" template. 719 */ 720 if (!(job->flags & JOB_SILENT) && !shutUp && 721 commandShell->hasEchoCtl) { 722 DBPRINTF("%s\n", commandShell->echoOff); 723 DBPRINTF(commandShell->errCheck, cmd); 724 shutUp = TRUE; 725 } 726 cmdTemplate = commandShell->ignErr; 727 /* 728 * The error ignoration (hee hee) is already taken care 729 * of by the ignErr template, so pretend error checking 730 * is still on. 731 */ 732 errOff = FALSE; 733 } else { 734 errOff = FALSE; 735 } 660 736 #endif 661 } else {662 errOff = FALSE;663 }737 } else { 738 errOff = FALSE; 739 } 664 740 } 665 741 … … 668 744 #ifndef KMK /*todo*/ 669 745 if (errOff) { 670 /*671 * If echoing is already off, there's no point in issuing the672 * echoOff command. Otherwise we issue it and pretend it was on673 * for the whole command...674 */675 if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){676 DBPRINTF("%s\n", commandShell->echoOff);677 shutUp = TRUE;678 }679 DBPRINTF("%s\n", commandShell->errCheck);746 /* 747 * If echoing is already off, there's no point in issuing the 748 * echoOff command. Otherwise we issue it and pretend it was on 749 * for the whole command... 750 */ 751 if (!shutUp && !(job->flags & JOB_SILENT) && commandShell->hasEchoCtl){ 752 DBPRINTF("%s\n", commandShell->echoOff); 753 shutUp = TRUE; 754 } 755 DBPRINTF("%s\n", commandShell->errCheck); 680 756 } 681 757 if (shutUp) { 682 DBPRINTF("%s\n", commandShell->echoOn);758 DBPRINTF("%s\n", commandShell->echoOn); 683 759 } 684 760 #endif … … 689 765 *----------------------------------------------------------------------- 690 766 * JobSaveCommand -- 691 * Save a command to be executed when everything else is done.692 * Callback function for JobFinish...767 * Save a command to be executed when everything else is done. 768 * Callback function for JobFinish... 693 769 * 694 770 * Results: 695 * Always returns 0771 * Always returns 0 696 772 * 697 773 * Side Effects: 698 * The command is tacked onto the end of postCommands's commands list.774 * The command is tacked onto the end of postCommands's commands list. 699 775 * 700 776 *----------------------------------------------------------------------- … … 714 790 *----------------------------------------------------------------------- 715 791 * JobClose -- 716 * Called to close both input and output pipes when a job is finished.792 * Called to close both input and output pipes when a job is finished. 717 793 * 718 794 * Results: 719 * Nada795 * Nada 720 796 * 721 797 * Side Effects: 722 * The file descriptors associated with the job are closed.798 * The file descriptors associated with the job are closed. 723 799 * 724 800 *----------------------------------------------------------------------- … … 728 804 Job *job; 729 805 { 806 #ifdef USE_PIPES 730 807 if (usePipes) { 731 808 #ifdef RMT_WILL_WATCH 732 Rmt_Ignore(job->inPipe);809 Rmt_Ignore(job->inPipe); 733 810 #else 734 FD_CLR(job->inPipe, &outputs);735 #endif 736 if (job->outPipe != job->inPipe) {737 (void) close(job->outPipe);738 }739 JobDoOutput(job, TRUE);740 (void) close(job->inPipe);811 FD_CLR(job->inPipe, &outputs); 812 #endif 813 if (job->outPipe != job->inPipe) { 814 (void) close(job->outPipe); 815 } 816 JobDoOutput(job, TRUE); 817 (void) close(job->inPipe); 741 818 } else { 742 (void) close(job->outFd); 743 JobDoOutput(job, TRUE); 744 } 819 (void) close(job->outFd); 820 JobDoOutput(job, TRUE); 821 } 822 823 #else /* Don't use Pipes */ 824 close(job->outFd); 825 JobDoOutput(job, TRUE); 826 #endif /* USE_PIPES */ 745 827 } 746 828 … … 748 830 *----------------------------------------------------------------------- 749 831 * JobFinish -- 750 * Do final processing for the given job including updating751 * parents and starting new jobs as available/necessary. Note752 * that we pay no attention to the JOB_IGNERR flag here.753 * This is because when we're called because of a noexecute flag754 * or something, jstat.w_status is 0 and when called from755 * Job_CatchChildren, the status is zeroed if it s/b ignored.832 * Do final processing for the given job including updating 833 * parents and starting new jobs as available/necessary. Note 834 * that we pay no attention to the JOB_IGNERR flag here. 835 * This is because when we're called because of a noexecute flag 836 * or something, jstat.w_status is 0 and when called from 837 * Job_CatchChildren, the status is zeroed if it s/b ignored. 756 838 * 757 839 * Results: 758 * None840 * None 759 841 * 760 842 * Side Effects: 761 * Some nodes may be put on the toBeMade queue.762 * Final commands for the job are placed on postCommands.763 * 764 * If we got an error and are aborting (aborting == ABORT_ERROR) and765 * the job list is now empty, we are done for the day.766 * If we recognized an error (errors !=0), we set the aborting flag767 * to ABORT_ERROR so no more jobs will be started.843 * Some nodes may be put on the toBeMade queue. 844 * Final commands for the job are placed on postCommands. 845 * 846 * If we got an error and are aborting (aborting == ABORT_ERROR) and 847 * the job list is now empty, we are done for the day. 848 * If we recognized an error (errors !=0), we set the aborting flag 849 * to ABORT_ERROR so no more jobs will be started. 768 850 *----------------------------------------------------------------------- 769 851 */ … … 771 853 static void 772 854 JobFinish(job, status) 773 Job *job; /* job to finish */ 774 int *status; /* sub-why job went away */ 855 Job *job; /* job to finish */ 856 #ifdef USE_KLIB 857 KPROCRES *status; /* sub-why job went away */ 858 #else 859 int *status; /* sub-why job went away */ 860 #endif 775 861 { 776 Boolean done; 862 #ifdef USE_KLIB 863 Boolean done; 864 865 if ( ( (status->fFlags & KPROCRES_FLAGS_NORMAL) && status->uExitCode != 0 && !(job->flags & JOB_IGNERR) ) 866 || !(status->fFlags & KPROCRES_FLAGS_NORMAL) 867 ) 868 { 869 /* 870 * If it exited non-zero and either we're doing things our 871 * way or we're not ignoring errors, the job is finished. 872 * Similarly, if the shell died because of a signal 873 * the job is also finished. In these 874 * cases, finish out the job's output before printing the exit 875 * status... 876 */ 877 JobClose(job); 878 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 879 (void) fclose(job->cmdFILE); 880 job->cmdFILE = NULL; 881 } 882 done = TRUE; 883 } else if (status->fFlags & KPROCRES_FLAGS_NORMAL) { 884 /* 885 * Deal with ignored errors in -B mode. We need to print a message 886 * telling of the ignored error as well as setting status.w_status 887 * to 0 so the next command gets run. To do this, we set done to be 888 * TRUE if in -B mode and the job exited non-zero. 889 */ 890 done = status->uExitCode != 0; 891 /* 892 * Old comment said: "Note we don't 893 * want to close down any of the streams until we know we're at the 894 * end." 895 * But we do. Otherwise when are we going to print the rest of the 896 * stuff? 897 */ 898 JobClose(job); 899 } else { 900 /* 901 * No need to close things down or anything. 902 */ 903 done = FALSE; 904 } 905 906 if ( done 907 || DEBUG(JOB)) 908 { 909 FILE *out = stdout; 910 if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) 911 { 912 /* 913 * If output is going to a file and this job is ignoring 914 * errors, arrange to have the exit status sent to the 915 * output file as well. 916 */ 917 out = fdopen(job->outFd, "w"); 918 } 919 920 if (status->fFlags & KPROCRES_FLAGS_NORMAL) 921 { 922 if (DEBUG(JOB)) 923 { 924 fprintf(stdout, "Process %d exited.\n", job->pid); 925 fflush(stdout); 926 } 927 if (status->uExitCode != 0) 928 { 929 #ifdef USE_PIPES 930 if (usePipes && job->node != lastNode) 931 { 932 MESSAGE(out, job->node); 933 lastNode = job->node; 934 } 935 #endif 936 fprintf(out, "*** Error code %d%s\n", 937 status->uExitCode, 938 (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 939 940 if (job->flags & JOB_IGNERR) 941 status->uExitCode = 0; 942 } 943 else if (DEBUG(JOB)) 944 { 945 #ifdef USE_PIPES 946 if (usePipes && job->node != lastNode) 947 { 948 MESSAGE(out, job->node); 949 lastNode = job->node; 950 } 951 #endif 952 fprintf(out, "*** Completed successfully\n"); 953 } 954 } 955 else 956 { 957 #ifdef USE_PIPES 958 if (usePipes && job->node != lastNode) 959 { 960 MESSAGE(out, job->node); 961 lastNode = job->node; 962 } 963 #endif 964 fprintf(out, "*** Abnormal End\n"); 965 } 966 967 fflush(out); 968 } 969 970 /* 971 * Now handle the -B-mode stuff. If the beast still isn't finished, 972 * try and restart the job on the next command. If JobStart says it's 973 * ok, it's ok. If there's an error, this puppy is done. 974 */ 975 if ( compatMake 976 && (status->fFlags & KPROCRES_FLAGS_NORMAL) 977 && !Lst_IsAtEnd(job->node->commands) 978 ) 979 { 980 switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) 981 { 982 case JOB_RUNNING: 983 done = FALSE; 984 break; 985 case JOB_ERROR: 986 done = TRUE; 987 status->uExitCode = EXIT_FAILURE; 988 break; 989 case JOB_FINISHED: 990 /* 991 * If we got back a JOB_FINISHED code, JobStart has already 992 * called Make_Update and freed the job descriptor. We set 993 * done to false here to avoid fake cycles and double frees. 994 * JobStart needs to do the update so we can proceed up the 995 * graph when given the -n flag.. 996 */ 997 done = FALSE; 998 break; 999 } 1000 } else { 1001 done = TRUE; 1002 } 1003 1004 1005 if ( done 1006 && aborting != ABORT_ERROR 1007 && aborting != ABORT_INTERRUPT 1008 && (status->fFlags & KPROCRES_FLAGS_NORMAL) 1009 && status->uExitCode == 0 1010 ) 1011 { 1012 /* 1013 * As long as we aren't aborting and the job didn't return a non-zero 1014 * status that we shouldn't ignore, we call Make_Update to update 1015 * the parents. In addition, any saved commands for the node are placed 1016 * on the .END target. 1017 */ 1018 if (job->tailCmds != NILLNODE) { 1019 Lst_ForEachFrom(job->node->commands, job->tailCmds, 1020 JobSaveCommand, 1021 (ClientData)job->node); 1022 } 1023 job->node->made = MADE; 1024 Make_Update(job->node); 1025 efree((Address)job); 1026 } 1027 else if (!(status->fFlags & KPROCRES_FLAGS_NORMAL) || status->uExitCode != 0) 1028 { 1029 errors += 1; 1030 efree((Address)job); 1031 } 1032 1033 /* 1034 * Set aborting if any error. 1035 */ 1036 if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) 1037 { 1038 /* 1039 * If we found any errors in this batch of children and the -k flag 1040 * wasn't given, we set the aborting flag so no more jobs get 1041 * started. 1042 */ 1043 aborting = ABORT_ERROR; 1044 } 1045 1046 if ((aborting == ABORT_ERROR) && Job_Empty()) 1047 { 1048 /* 1049 * If we are aborting and the job table is now empty, we finish. 1050 */ 1051 Finish(errors); 1052 } 1053 1054 1055 #else /* Don't use kLib */ 1056 Boolean done; 777 1057 778 1058 if ((WIFEXITED(*status) && 779 (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) ||780 (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT)))1059 (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || 1060 (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) 781 1061 { 782 /*783 * If it exited non-zero and either we're doing things our784 * way or we're not ignoring errors, the job is finished.785 * Similarly, if the shell died because of a signal786 * the job is also finished. In these787 * cases, finish out the job's output before printing the exit788 * status...789 */1062 /* 1063 * If it exited non-zero and either we're doing things our 1064 * way or we're not ignoring errors, the job is finished. 1065 * Similarly, if the shell died because of a signal 1066 * the job is also finished. In these 1067 * cases, finish out the job's output before printing the exit 1068 * status... 1069 */ 790 1070 #ifdef REMOTE 791 KILL(job->pid, SIGCONT);792 #endif 793 JobClose(job);794 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {795 (void) fclose(job->cmdFILE);796 }797 done = TRUE;1071 KILL(job->pid, SIGCONT); 1072 #endif 1073 JobClose(job); 1074 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1075 (void) fclose(job->cmdFILE); 1076 } 1077 done = TRUE; 798 1078 #ifdef REMOTE 799 if (job->flags & JOB_REMOTE)800 Rmt_Done(job->rmtID, job->node);1079 if (job->flags & JOB_REMOTE) 1080 Rmt_Done(job->rmtID, job->node); 801 1081 #endif 802 1082 } else if (WIFEXITED(*status)) { 803 /*804 * Deal with ignored errors in -B mode. We need to print a message805 * telling of the ignored error as well as setting status.w_status806 * to 0 so the next command gets run. To do this, we set done to be807 * TRUE if in -B mode and the job exited non-zero.808 */809 done = WEXITSTATUS(*status) != 0;810 /*811 * Old comment said: "Note we don't812 * want to close down any of the streams until we know we're at the813 * end."814 * But we do. Otherwise when are we going to print the rest of the815 * stuff?816 */817 JobClose(job);1083 /* 1084 * Deal with ignored errors in -B mode. We need to print a message 1085 * telling of the ignored error as well as setting status.w_status 1086 * to 0 so the next command gets run. To do this, we set done to be 1087 * TRUE if in -B mode and the job exited non-zero. 1088 */ 1089 done = WEXITSTATUS(*status) != 0; 1090 /* 1091 * Old comment said: "Note we don't 1092 * want to close down any of the streams until we know we're at the 1093 * end." 1094 * But we do. Otherwise when are we going to print the rest of the 1095 * stuff? 1096 */ 1097 JobClose(job); 818 1098 #ifdef REMOTE 819 if (job->flags & JOB_REMOTE)820 Rmt_Done(job->rmtID, job->node);1099 if (job->flags & JOB_REMOTE) 1100 Rmt_Done(job->rmtID, job->node); 821 1101 #endif /* REMOTE */ 822 1102 } else { 823 /*824 * No need to close things down or anything.825 */826 done = FALSE;1103 /* 1104 * No need to close things down or anything. 1105 */ 1106 done = FALSE; 827 1107 } 828 1108 829 1109 if (done || 830 WIFSTOPPED(*status) ||831 (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) ||832 DEBUG(JOB))1110 WIFSTOPPED(*status) || 1111 (WIFSIGNALED(*status) && (WTERMSIG(*status) == SIGCONT)) || 1112 DEBUG(JOB)) 833 1113 { 834 FILE *out; 835 836 if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { 837 /* 838 * If output is going to a file and this job is ignoring 839 * errors, arrange to have the exit status sent to the 840 * output file as well. 841 */ 842 out = fdopen(job->outFd, "w"); 843 } else { 844 out = stdout; 845 } 846 847 if (WIFEXITED(*status)) { 848 if (DEBUG(JOB)) { 849 (void) fprintf(stdout, "Process %d exited.\n", job->pid); 850 (void) fflush(stdout); 851 } 852 if (WEXITSTATUS(*status) != 0) { 853 if (usePipes && job->node != lastNode) { 854 MESSAGE(out, job->node); 855 lastNode = job->node; 856 } 857 (void) fprintf(out, "*** Error code %d%s\n", 858 WEXITSTATUS(*status), 859 (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 860 861 if (job->flags & JOB_IGNERR) { 862 *status = 0; 863 } 864 } else if (DEBUG(JOB)) { 865 if (usePipes && job->node != lastNode) { 866 MESSAGE(out, job->node); 867 lastNode = job->node; 868 } 869 (void) fprintf(out, "*** Completed successfully\n"); 870 } 871 } else if (WIFSTOPPED(*status)) { 872 if (DEBUG(JOB)) { 873 (void) fprintf(stdout, "Process %d stopped.\n", job->pid); 874 (void) fflush(stdout); 875 } 876 if (usePipes && job->node != lastNode) { 877 MESSAGE(out, job->node); 878 lastNode = job->node; 879 } 880 if (!(job->flags & JOB_REMIGRATE)) { 881 (void) fprintf(out, "*** Stopped -- signal %d\n", 882 WSTOPSIG(*status)); 883 } 884 job->flags |= JOB_RESUME; 885 (void)Lst_AtEnd(stoppedJobs, (ClientData)job); 886 #ifdef REMOTE 887 if (job->flags & JOB_REMIGRATE) 888 JobRestart(job); 889 #endif 890 (void) fflush(out); 891 return; 892 } else if (WTERMSIG(*status) == SIGCONT) { 893 /* 894 * If the beastie has continued, shift the Job from the stopped 895 * list to the running one (or re-stop it if concurrency is 896 * exceeded) and go and get another child. 897 */ 898 if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { 899 if (usePipes && job->node != lastNode) { 900 MESSAGE(out, job->node); 901 lastNode = job->node; 902 } 903 (void) fprintf(out, "*** Continued\n"); 904 } 905 if (!(job->flags & JOB_CONTINUING)) { 906 if (DEBUG(JOB)) { 907 (void) fprintf(stdout, 908 "Warning: process %d was not continuing.\n", 909 job->pid); 910 (void) fflush(stdout); 911 } 1114 FILE *out; 1115 1116 if (compatMake && !usePipes && (job->flags & JOB_IGNERR)) { 1117 /* 1118 * If output is going to a file and this job is ignoring 1119 * errors, arrange to have the exit status sent to the 1120 * output file as well. 1121 */ 1122 out = fdopen(job->outFd, "w"); 1123 } else { 1124 out = stdout; 1125 } 1126 1127 if (WIFEXITED(*status)) { 1128 if (DEBUG(JOB)) { 1129 (void) fprintf(stdout, "Process %d exited.\n", job->pid); 1130 (void) fflush(stdout); 1131 } 1132 if (WEXITSTATUS(*status) != 0) { 1133 #ifdef USE_PIPES 1134 if (usePipes && job->node != lastNode) { 1135 MESSAGE(out, job->node); 1136 lastNode = job->node; 1137 } 1138 #endif 1139 (void) fprintf(out, "*** Error code %d%s\n", 1140 WEXITSTATUS(*status), 1141 (job->flags & JOB_IGNERR) ? "(ignored)" : ""); 1142 1143 if (job->flags & JOB_IGNERR) { 1144 *status = 0; 1145 } 1146 } else if (DEBUG(JOB)) { 1147 #ifdef USE_PIPES 1148 if (usePipes && job->node != lastNode) { 1149 MESSAGE(out, job->node); 1150 lastNode = job->node; 1151 } 1152 #endif 1153 (void) fprintf(out, "*** Completed successfully\n"); 1154 } 1155 } else if (WIFSTOPPED(*status)) { 1156 if (DEBUG(JOB)) { 1157 (void) fprintf(stdout, "Process %d stopped.\n", job->pid); 1158 (void) fflush(stdout); 1159 } 1160 #ifdef USE_PIPES 1161 if (usePipes && job->node != lastNode) { 1162 MESSAGE(out, job->node); 1163 lastNode = job->node; 1164 } 1165 #endif 1166 if (!(job->flags & JOB_REMIGRATE)) { 1167 (void) fprintf(out, "*** Stopped -- signal %d\n", 1168 WSTOPSIG(*status)); 1169 } 1170 job->flags |= JOB_RESUME; 1171 (void)Lst_AtEnd(stoppedJobs, (ClientData)job); 1172 #if defined(REMOTE) && defined(SIGCONT) 1173 if (job->flags & JOB_REMIGRATE) 1174 JobRestart(job); 1175 #endif 1176 (void) fflush(out); 1177 return; 1178 } else if (WTERMSIG(*status) == SIGCONT) { 1179 /* 1180 * If the beastie has continued, shift the Job from the stopped 1181 * list to the running one (or re-stop it if concurrency is 1182 * exceeded) and go and get another child. 1183 */ 1184 if (job->flags & (JOB_RESUME|JOB_REMIGRATE|JOB_RESTART)) { 1185 #ifdef USE_PIPES 1186 if (usePipes && job->node != lastNode) { 1187 MESSAGE(out, job->node); 1188 lastNode = job->node; 1189 } 1190 #endif 1191 (void) fprintf(out, "*** Continued\n"); 1192 } 1193 if (!(job->flags & JOB_CONTINUING)) { 1194 if (DEBUG(JOB)) { 1195 (void) fprintf(stdout, 1196 "Warning: process %d was not continuing.\n", 1197 job->pid); 1198 (void) fflush(stdout); 1199 } 1200 #ifdef SIGCONT 912 1201 #ifdef notdef 913 /* 914 * We don't really want to restart a job from scratch just 915 * because it continued, especially not without killing the 916 * continuing process! That's why this is ifdef'ed out. 917 * FD - 9/17/90 918 */ 919 JobRestart(job); 920 #endif 921 } 922 job->flags &= ~JOB_CONTINUING; 923 Lst_AtEnd(jobs, (ClientData)job); 924 nJobs += 1; 925 if (!(job->flags & JOB_REMOTE)) { 926 if (DEBUG(JOB)) { 927 (void) fprintf(stdout, 928 "Process %d is continuing locally.\n", 929 job->pid); 930 (void) fflush(stdout); 931 } 932 nLocal += 1; 933 } 934 if (nJobs == maxJobs) { 935 jobFull = TRUE; 936 if (DEBUG(JOB)) { 937 (void) fprintf(stdout, "Job queue is full.\n"); 938 (void) fflush(stdout); 939 } 940 } 941 (void) fflush(out); 942 return; 943 } else { 944 if (usePipes && job->node != lastNode) { 945 MESSAGE(out, job->node); 946 lastNode = job->node; 947 } 948 (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 949 } 950 951 (void) fflush(out); 1202 /* 1203 * We don't really want to restart a job from scratch just 1204 * because it continued, especially not without killing the 1205 * continuing process! That's why this is ifdef'ed out. 1206 * FD - 9/17/90 1207 */ 1208 JobRestart(job); 1209 #endif 1210 #endif 1211 } 1212 job->flags &= ~JOB_CONTINUING; 1213 Lst_AtEnd(jobs, (ClientData)job); 1214 nJobs += 1; 1215 if (!(job->flags & JOB_REMOTE)) { 1216 if (DEBUG(JOB)) { 1217 (void) fprintf(stdout, 1218 "Process %d is continuing locally.\n", 1219 job->pid); 1220 (void) fflush(stdout); 1221 } 1222 nLocal += 1; 1223 } 1224 if (nJobs == maxJobs) { 1225 jobFull = TRUE; 1226 if (DEBUG(JOB)) { 1227 (void) fprintf(stdout, "Job queue is full.\n"); 1228 (void) fflush(stdout); 1229 } 1230 } 1231 (void) fflush(out); 1232 return; 1233 } else { 1234 #ifdef USE_PIPES 1235 if (usePipes && job->node != lastNode) { 1236 MESSAGE(out, job->node); 1237 lastNode = job->node; 1238 } 1239 #endif 1240 (void) fprintf(out, "*** Signal %d\n", WTERMSIG(*status)); 1241 } 1242 1243 (void) fflush(out); 952 1244 } 953 1245 … … 958 1250 */ 959 1251 if (compatMake && (WIFEXITED(*status) && 960 !Lst_IsAtEnd(job->node->commands))) {961 switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) {962 case JOB_RUNNING:963 done = FALSE;964 break;965 case JOB_ERROR:966 done = TRUE;967 W_SETEXITSTATUS(status, 1);968 break;969 case JOB_FINISHED:970 /*971 * If we got back a JOB_FINISHED code, JobStart has already972 * called Make_Update and freed the job descriptor. We set973 * done to false here to avoid fake cycles and double frees.974 * JobStart needs to do the update so we can proceed up the975 * graph when given the -n flag..976 */977 done = FALSE;978 break;979 }1252 !Lst_IsAtEnd(job->node->commands))) { 1253 switch (JobStart(job->node, job->flags & JOB_IGNDOTS, job)) { 1254 case JOB_RUNNING: 1255 done = FALSE; 1256 break; 1257 case JOB_ERROR: 1258 done = TRUE; 1259 W_SETEXITSTATUS(status, 1); 1260 break; 1261 case JOB_FINISHED: 1262 /* 1263 * If we got back a JOB_FINISHED code, JobStart has already 1264 * called Make_Update and freed the job descriptor. We set 1265 * done to false here to avoid fake cycles and double frees. 1266 * JobStart needs to do the update so we can proceed up the 1267 * graph when given the -n flag.. 1268 */ 1269 done = FALSE; 1270 break; 1271 } 980 1272 } else { 981 done = TRUE;1273 done = TRUE; 982 1274 } 983 1275 984 1276 985 1277 if (done && 986 (aborting != ABORT_ERROR) &&987 (aborting != ABORT_INTERRUPT) &&988 (*status == 0))1278 (aborting != ABORT_ERROR) && 1279 (aborting != ABORT_INTERRUPT) && 1280 (*status == 0)) 989 1281 { 990 /*991 * As long as we aren't aborting and the job didn't return a non-zero992 * status that we shouldn't ignore, we call Make_Update to update993 * the parents. In addition, any saved commands for the node are placed994 * on the .END target.995 */996 if (job->tailCmds != NILLNODE) {997 Lst_ForEachFrom(job->node->commands, job->tailCmds,998 JobSaveCommand,999 (ClientData)job->node);1000 }1001 job->node->made = MADE;1002 Make_Update(job->node);1003 efree((Address)job);1282 /* 1283 * As long as we aren't aborting and the job didn't return a non-zero 1284 * status that we shouldn't ignore, we call Make_Update to update 1285 * the parents. In addition, any saved commands for the node are placed 1286 * on the .END target. 1287 */ 1288 if (job->tailCmds != NILLNODE) { 1289 Lst_ForEachFrom(job->node->commands, job->tailCmds, 1290 JobSaveCommand, 1291 (ClientData)job->node); 1292 } 1293 job->node->made = MADE; 1294 Make_Update(job->node); 1295 efree((Address)job); 1004 1296 } else if (*status != 0) { 1005 errors += 1; 1006 efree((Address)job); 1007 } 1008 1297 errors += 1; 1298 efree((Address)job); 1299 } 1300 1301 #ifdef SIGCONT 1009 1302 JobRestartJobs(); 1303 #endif 1010 1304 1011 1305 /* … … 1013 1307 */ 1014 1308 if (errors && !keepgoing && (aborting != ABORT_INTERRUPT)) { 1015 /*1016 * If we found any errors in this batch of children and the -k flag1017 * wasn't given, we set the aborting flag so no more jobs get1018 * started.1019 */1020 aborting = ABORT_ERROR;1309 /* 1310 * If we found any errors in this batch of children and the -k flag 1311 * wasn't given, we set the aborting flag so no more jobs get 1312 * started. 1313 */ 1314 aborting = ABORT_ERROR; 1021 1315 } 1022 1316 1023 1317 if ((aborting == ABORT_ERROR) && Job_Empty()) 1024 /* 1025 * If we are aborting and the job table is now empty, we finish. 1026 */ 1027 Finish(errors); 1318 /* 1319 * If we are aborting and the job table is now empty, we finish. 1320 */ 1321 Finish(errors); 1322 #endif /* USE_KLIB */ 1028 1323 } 1029 1324 … … 1031 1326 *----------------------------------------------------------------------- 1032 1327 * Job_Touch -- 1033 * Touch the given target. Called by JobStart when the -t flag was1034 * given1328 * Touch the given target. Called by JobStart when the -t flag was 1329 * given 1035 1330 * 1036 1331 * Results: 1037 * None1332 * None 1038 1333 * 1039 1334 * Side Effects: 1040 * The data modification of the file is changed. In addition, if the1041 * file did not exist, it is created.1335 * The data modification of the file is changed. In addition, if the 1336 * file did not exist, it is created. 1042 1337 *----------------------------------------------------------------------- 1043 1338 */ 1044 1339 void 1045 1340 Job_Touch(gn, silent) 1046 GNode *gn; /* the node of the file to touch */1047 Boolean silent;/* TRUE if should not print messages */1341 GNode *gn; /* the node of the file to touch */ 1342 Boolean silent; /* TRUE if should not print messages */ 1048 1343 { 1049 int streamID;/* ID of stream opened to do the touch */1050 struct utimbuf times; /* Times for utime() call */1344 int streamID; /* ID of stream opened to do the touch */ 1345 struct utimbuf times; /* Times for utime() call */ 1051 1346 1052 1347 if (gn->type & (OP_JOIN|OP_USE|OP_EXEC|OP_OPTIONAL)) { 1053 /*1054 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets1055 * and, as such, shouldn't really be created.1056 */1057 return;1348 /* 1349 * .JOIN, .USE, .ZEROTIME and .OPTIONAL targets are "virtual" targets 1350 * and, as such, shouldn't really be created. 1351 */ 1352 return; 1058 1353 } 1059 1354 1060 1355 if (!silent) { 1061 (void) fprintf(stdout, "touch %s\n", gn->name);1062 (void) fflush(stdout);1356 (void) fprintf(stdout, "touch %s\n", gn->name); 1357 (void) fflush(stdout); 1063 1358 } 1064 1359 1065 1360 if (noExecute) { 1066 return;1361 return; 1067 1362 } 1068 1363 1069 1364 #ifdef USE_ARCHIVES 1070 1365 if (gn->type & OP_ARCHV) { 1071 Arch_Touch(gn);1366 Arch_Touch(gn); 1072 1367 } else if (gn->type & OP_LIB) { 1073 Arch_TouchLib(gn);1368 Arch_TouchLib(gn); 1074 1369 } else { 1075 1370 #else … … 1077 1372 #endif 1078 1373 1079 char*file = gn->path ? gn->path : gn->name;1080 1081 times.actime = times.modtime = now;1082 if (utime(file, ×) < 0){1083 streamID = open(file, O_RDWR | O_CREAT, 0666);1084 1085 if (streamID >= 0) {1086 charc;1087 1088 /*1089 * Read and write a byte to the file to change the1090 * modification time, then close the file.1091 */1092 if (read(streamID, &c, 1) == 1) {1093 (void) lseek(streamID, 0L, SEEK_SET);1094 (void) write(streamID, &c, 1);1095 }1096 1097 (void) close(streamID);1098 } else {1099 (void) fprintf(stdout, "*** couldn't touch %s: %s",1100 file, strerror(errno));1101 (void) fflush(stdout);1102 }1103 }1374 char *file = gn->path ? gn->path : gn->name; 1375 1376 times.actime = times.modtime = now; 1377 if (utime(file, ×) < 0){ 1378 streamID = open(file, O_RDWR | O_CREAT, 0666); 1379 1380 if (streamID >= 0) { 1381 char c; 1382 1383 /* 1384 * Read and write a byte to the file to change the 1385 * modification time, then close the file. 1386 */ 1387 if (read(streamID, &c, 1) == 1) { 1388 (void) lseek(streamID, 0L, SEEK_SET); 1389 (void) write(streamID, &c, 1); 1390 } 1391 1392 (void) close(streamID); 1393 } else { 1394 (void) fprintf(stdout, "*** couldn't touch %s: %s", 1395 file, strerror(errno)); 1396 (void) fflush(stdout); 1397 } 1398 } 1104 1399 } 1105 1400 } … … 1108 1403 *----------------------------------------------------------------------- 1109 1404 * Job_CheckCommands -- 1110 * Make sure the given node has all the commands it needs.1405 * Make sure the given node has all the commands it needs. 1111 1406 * 1112 1407 * Results: 1113 * TRUE if the commands list is/was ok.1408 * TRUE if the commands list is/was ok. 1114 1409 * 1115 1410 * Side Effects: 1116 * The node will have commands from the .DEFAULT rule added to it1117 * if it needs them.1411 * The node will have commands from the .DEFAULT rule added to it 1412 * if it needs them. 1118 1413 *----------------------------------------------------------------------- 1119 1414 */ 1120 1415 Boolean 1121 1416 Job_CheckCommands(gn, abortProc) 1122 GNode *gn; /* The target whose commands need1123 * verifying */1124 void (*abortProc) __P((char *, ...));1125 /* Function to abort with message */1417 GNode *gn; /* The target whose commands need 1418 * verifying */ 1419 void (*abortProc) __P((char *, ...)); 1420 /* Function to abort with message */ 1126 1421 { 1127 1422 if (OP_NOP(gn->type) && Lst_IsEmpty(gn->commands) … … 1131 1426 ) 1132 1427 { 1133 /*1134 * No commands. Look for .DEFAULT rule from which we might infer1135 * commands1136 */1137 if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) {1138 char *p1;1139 /*1140 * Make only looks for a .DEFAULT if the node was never the1141 * target of an operator, so that's what we do too. If1142 * a .DEFAULT was given, we substitute its commands for gn's1143 * commands and set the IMPSRC variable to be the target's name1144 * The DEFAULT node acts like a transformation rule, in that1145 * gn also inherits any attributes or sources attached to1146 * .DEFAULT itself.1147 */1148 Make_HandleUse(DEFAULT, gn);1149 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn);1150 efree(p1);1151 } else if (Dir_MTime(gn) == 0) {1152 /*1153 * The node wasn't the target of an operator we have no .DEFAULT1154 * rule to go on and the target doesn't already exist. There's1155 * nothing more we can do for this branch. If the -k flag wasn't1156 * given, we stop in our tracks, otherwise we just don't update1157 * this node's parents so they never get examined.1158 */1159 static const char msg[] = MAKE_NAME ": don't know how to make";1160 1161 if (gn->type & OP_OPTIONAL) {1162 (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name);1163 (void) fflush(stdout);1164 } else if (keepgoing) {1165 (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name);1166 (void) fflush(stdout);1167 return FALSE;1168 } else {1428 /* 1429 * No commands. Look for .DEFAULT rule from which we might infer 1430 * commands 1431 */ 1432 if ((DEFAULT != NILGNODE) && !Lst_IsEmpty(DEFAULT->commands)) { 1433 char *p1; 1434 /* 1435 * Make only looks for a .DEFAULT if the node was never the 1436 * target of an operator, so that's what we do too. If 1437 * a .DEFAULT was given, we substitute its commands for gn's 1438 * commands and set the IMPSRC variable to be the target's name 1439 * The DEFAULT node acts like a transformation rule, in that 1440 * gn also inherits any attributes or sources attached to 1441 * .DEFAULT itself. 1442 */ 1443 Make_HandleUse(DEFAULT, gn); 1444 Var_Set(IMPSRC, Var_Value(TARGET, gn, &p1), gn); 1445 efree(p1); 1446 } else if (Dir_MTime(gn) == 0) { 1447 /* 1448 * The node wasn't the target of an operator we have no .DEFAULT 1449 * rule to go on and the target doesn't already exist. There's 1450 * nothing more we can do for this branch. If the -k flag wasn't 1451 * given, we stop in our tracks, otherwise we just don't update 1452 * this node's parents so they never get examined. 1453 */ 1454 static const char msg[] = MAKE_NAME ": don't know how to make"; 1455 1456 if (gn->type & OP_OPTIONAL) { 1457 (void) fprintf(stdout, "%s %s(ignored)\n", msg, gn->name); 1458 (void) fflush(stdout); 1459 } else if (keepgoing) { 1460 (void) fprintf(stdout, "%s %s(continuing)\n", msg, gn->name); 1461 (void) fflush(stdout); 1462 return FALSE; 1463 } else { 1169 1464 #if OLD_JOKE 1170 if (strcmp(gn->name,"love") == 0)1171 (*abortProc)("Not war.");1465 if (strcmp(gn->name,"love") == 0) 1466 (*abortProc)("Not war."); 1172 1467 #if defined(NMAKE) || defined(KMK) 1173 1468 else if (strcmp(gn->name,"fire") == 0) 1174 (*abortProc)("No match.");1469 (*abortProc)("No match."); 1175 1470 #endif 1176 1471 else 1177 1472 #endif 1178 (*abortProc)("%s %s. Stop", msg, gn->name);1179 return FALSE;1180 }1181 }1473 (*abortProc)("%s %s. Stop", msg, gn->name); 1474 return FALSE; 1475 } 1476 } 1182 1477 } 1183 1478 return TRUE; … … 1187 1482 *----------------------------------------------------------------------- 1188 1483 * JobLocalInput -- 1189 * Handle a pipe becoming readable. Callback function for Rmt_Watch1484 * Handle a pipe becoming readable. Callback function for Rmt_Watch 1190 1485 * 1191 1486 * Results: 1192 * None1487 * None 1193 1488 * 1194 1489 * Side Effects: 1195 * JobDoOutput is called.1490 * JobDoOutput is called. 1196 1491 * 1197 1492 *----------------------------------------------------------------------- … … 1200 1495 static void 1201 1496 JobLocalInput(stream, job) 1202 int stream;/* Stream that's ready (ignored) */1203 Job *job;/* Job to which the stream belongs */1497 int stream; /* Stream that's ready (ignored) */ 1498 Job *job; /* Job to which the stream belongs */ 1204 1499 { 1205 1500 JobDoOutput(job, FALSE); … … 1210 1505 *----------------------------------------------------------------------- 1211 1506 * JobExec -- 1212 * Execute the shell for the given job. Called from JobStart and1213 * JobRestart.1507 * Execute the shell for the given job. Called from JobStart and 1508 * JobRestart. 1214 1509 * 1215 1510 * Results: 1216 * None.1511 * None. 1217 1512 * 1218 1513 * Side Effects: 1219 * A shell is executed, outputs is altered and the Job structure added1220 * to the job table.1514 * A shell is executed, outputs is altered and the Job structure added 1515 * to the job table. 1221 1516 * 1222 1517 *----------------------------------------------------------------------- … … 1224 1519 static void 1225 1520 JobExec(job, argv) 1226 Job *job;/* Job to execute */1227 char **argv;1521 Job *job; /* Job to execute */ 1522 char **argv; 1228 1523 { 1229 int cpid; /* ID of new child */ 1524 #ifdef USE_KLIB 1525 int cpid; /* ID of new child */ 1526 int rc; 1527 1528 if (DEBUG(JOB)) 1529 { 1530 int i; 1531 fprintf(stdout, "Running %s %sly\n", job->node->name, 1532 job->flags&JOB_REMOTE?"remote":"local"); 1533 fprintf(stdout, "\tCommand: "); 1534 for (i = 0; argv[i] != NULL; i++) 1535 fprintf(stdout, "%s ", argv[i]); 1536 fprintf(stdout, "\n"); 1537 fflush(stdout); 1538 } 1539 1540 /* 1541 * Some jobs produce no output and it's disconcerting to have 1542 * no feedback of their running (since they produce no output, the 1543 * banner with their name in it never appears). This is an attempt to 1544 * provide that feedback, even if nothing follows it. 1545 */ 1546 if ( lastNode != job->node 1547 && (job->flags & JOB_FIRST) 1548 && !(job->flags & JOB_SILENT) 1549 ) 1550 { 1551 MESSAGE(stdout, job->node); 1552 lastNode = job->node; 1553 } 1554 1555 /* 1556 * Create process with assigned output+stderr pipe. 1557 */ 1558 if (job->cmdFILE) 1559 fseek(job->cmdFILE, 0, SEEK_SET); 1560 rc = kProcCreate(argv, 1561 NULL, 1562 NULL, 1563 NULL, 1564 KPROCCREATE_FLAGS_SPAWN, 1565 job->cmdFILE ? FILENO(job->cmdFILE) : KFILE_NULL, 1566 usePipes ? job->outPipe : job->outFd, /* stdout */ 1567 usePipes ? job->outPipe : job->outFd, /* stderr */ 1568 &cpid, 1569 NULL); 1570 if (!rc) 1571 { 1572 job->pid = cpid; 1573 1574 #ifdef USE_PIPES 1575 if (usePipes && (job->flags & JOB_FIRST) ) 1576 { 1577 /* 1578 * The first time a job is run for a node, we set the current 1579 * position in the buffer to the beginning and mark another 1580 * stream to watch in the outputs mask 1581 */ 1582 job->curPos = 0; 1583 FD_SET(job->inPipe, &outputs); 1584 } 1585 #endif /* USE_PIPES */ 1586 1587 if (job->flags & JOB_REMOTE) { 1588 job->rmtID = 0; 1589 } else { 1590 nLocal += 1; 1591 /* 1592 * XXX: Used to not happen if REMOTE. Why? 1593 */ 1594 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1595 fclose(job->cmdFILE); 1596 job->cmdFILE = NULL; 1597 } 1598 } 1599 1600 /* 1601 * Now the job is actually running, add it to the table. 1602 */ 1603 nJobs += 1; 1604 (void) Lst_AtEnd(jobs, (ClientData)job); 1605 if (nJobs == maxJobs) 1606 { 1607 jobFull = TRUE; 1608 } 1609 } 1610 else 1611 Punt("Cannot start child (%d)", rc); 1612 1613 1614 1615 #else /* Don't use kLib */ 1616 int cpid; /* ID of new child */ 1230 1617 1231 1618 if (DEBUG(JOB)) { 1232 inti;1233 1234 (void) fprintf(stdout, "Running %s %sly\n", job->node->name,1235 job->flags&JOB_REMOTE?"remote":"local");1236 (void) fprintf(stdout, "\tCommand: ");1237 for (i = 0; argv[i] != NULL; i++) {1238 (void) fprintf(stdout, "%s ", argv[i]);1239 }1240 (void) fprintf(stdout, "\n");1241 (void) fflush(stdout);1619 int i; 1620 1621 (void) fprintf(stdout, "Running %s %sly\n", job->node->name, 1622 job->flags&JOB_REMOTE?"remote":"local"); 1623 (void) fprintf(stdout, "\tCommand: "); 1624 for (i = 0; argv[i] != NULL; i++) { 1625 (void) fprintf(stdout, "%s ", argv[i]); 1626 } 1627 (void) fprintf(stdout, "\n"); 1628 (void) fflush(stdout); 1242 1629 } 1243 1630 … … 1249 1636 */ 1250 1637 if ((lastNode != job->node) && (job->flags & JOB_FIRST) && 1251 !(job->flags & JOB_SILENT)) {1252 MESSAGE(stdout, job->node);1253 lastNode = job->node;1638 !(job->flags & JOB_SILENT)) { 1639 MESSAGE(stdout, job->node); 1640 lastNode = job->node; 1254 1641 } 1255 1642 1256 1643 #ifdef RMT_NO_EXEC 1257 1644 if (job->flags & JOB_REMOTE) { 1258 goto jobExecFinish;1645 goto jobExecFinish; 1259 1646 } 1260 1647 #endif /* RMT_NO_EXEC */ … … 1265 1652 if ((cpid = vfork()) == -1) { 1266 1653 #endif 1267 Punt("Cannot fork");1654 Punt("Cannot fork"); 1268 1655 } else if (cpid == 0) { 1269 1656 1270 /*1271 * Must duplicate the input stream down to the child's input and1272 * reset it to the beginning (again). Since the stream was marked1273 * close-on-exec, we must clear that bit in the new input.1274 */1275 if (dup2(FILENO(job->cmdFILE), 0) == -1)1276 Punt("Cannot dup2: %s", strerror(errno));1277 (void) fcntl(0, F_SETFD, 0);1278 (void) lseek(0, 0, SEEK_SET);1279 1280 if (usePipes) {1281 /*1282 * Set up the child's output to be routed through the pipe1283 * we've created for it.1284 */1285 if (dup2(job->outPipe, 1) == -1)1286 Punt("Cannot dup2: %s", strerror(errno));1287 } else {1288 /*1289 * We're capturing output in a file, so we duplicate the1290 * descriptor to the temporary file into the standard1291 * output.1292 */1293 if (dup2(job->outFd, 1) == -1)1294 Punt("Cannot dup2: %s", strerror(errno));1295 }1296 /*1297 * The output channels are marked close on exec. This bit was1298 * duplicated by the dup2 (on some systems), so we have to clear1299 * it before routing the shell's error output to the same place as1300 * its standard output.1301 */1302 (void) fcntl(1, F_SETFD, 0);1303 if (dup2(1, 2) == -1)1304 Punt("Cannot dup2: %s", strerror(errno));1657 /* 1658 * Must duplicate the input stream down to the child's input and 1659 * reset it to the beginning (again). Since the stream was marked 1660 * close-on-exec, we must clear that bit in the new input. 1661 */ 1662 if (dup2(FILENO(job->cmdFILE), 0) == -1) 1663 Punt("Cannot dup2: %s", strerror(errno)); 1664 (void) fcntl(0, F_SETFD, 0); 1665 (void) lseek(0, 0, SEEK_SET); 1666 1667 if (usePipes) { 1668 /* 1669 * Set up the child's output to be routed through the pipe 1670 * we've created for it. 1671 */ 1672 if (dup2(job->outPipe, STDOUT_FILENO) == -1) 1673 Punt("Cannot dup2: %s", strerror(errno)); 1674 } else { 1675 /* 1676 * We're capturing output in a file, so we duplicate the 1677 * descriptor to the temporary file into the standard 1678 * output. 1679 */ 1680 if (dup2(job->outFd, STDOUT_FILENO) == -1) 1681 Punt("Cannot dup2: %s", strerror(errno)); 1682 } 1683 /* 1684 * The output channels are marked close on exec. This bit was 1685 * duplicated by the dup2 (on some systems), so we have to clear 1686 * it before routing the shell's error output to the same place as 1687 * its standard output. 1688 */ 1689 (void) fcntl(1, F_SETFD, 0); 1690 if (dup2(STDOUT_FILENO, STDERR_FILENO) == -1) 1691 Punt("Cannot dup2: %s", strerror(errno)); 1305 1692 1306 1693 #ifdef USE_PGRP 1307 /*1308 * We want to switch the child into a different process family so1309 * we can kill it and all its descendants in one fell swoop,1310 * by killing its process family, but not commit suicide.1311 */1694 /* 1695 * We want to switch the child into a different process family so 1696 * we can kill it and all its descendants in one fell swoop, 1697 * by killing its process family, but not commit suicide. 1698 */ 1312 1699 # if defined(SYSV) 1313 (void) setsid();1700 (void) setsid(); 1314 1701 # else 1315 (void) setpgid(0, getpid());1702 (void) setpgid(0, getpid()); 1316 1703 # endif 1317 1704 #endif /* USE_PGRP */ 1318 1705 1319 1706 #ifdef REMOTE 1320 if (job->flags & JOB_REMOTE) {1321 Rmt_Exec(shellPath, argv, FALSE);1322 } else1707 if (job->flags & JOB_REMOTE) { 1708 Rmt_Exec(shellPath, argv, FALSE); 1709 } else 1323 1710 #endif /* REMOTE */ 1324 1711 #ifdef KMK 1325 (void) execv(argv[0], argv);1712 (void) execv(argv[0], argv); 1326 1713 #else 1327 (void) execv(shellPath, argv);1328 #endif 1329 1330 (void) write(2, "Could not execute shell\n",1331 sizeof("Could not execute shell"));1332 _exit(1);1714 (void) execv(shellPath, argv); 1715 #endif 1716 1717 (void) write(2, "Could not execute shell\n", 1718 sizeof("Could not execute shell")); 1719 _exit(1); 1333 1720 } else { 1334 1721 #ifdef REMOTE 1335 long omask = sigblock(sigmask(SIGCHLD)); 1336 #endif 1337 job->pid = cpid; 1338 1339 if (usePipes && (job->flags & JOB_FIRST) ) { 1340 /* 1341 * The first time a job is run for a node, we set the current 1342 * position in the buffer to the beginning and mark another 1343 * stream to watch in the outputs mask 1344 */ 1345 job->curPos = 0; 1722 long omask = sigblock(sigmask(SIGCHLD)); 1723 #endif 1724 job->pid = cpid; 1725 1726 #ifdef USE_PIPES 1727 if (usePipes && (job->flags & JOB_FIRST) ) { 1728 /* 1729 * The first time a job is run for a node, we set the current 1730 * position in the buffer to the beginning and mark another 1731 * stream to watch in the outputs mask 1732 */ 1733 job->curPos = 0; 1346 1734 1347 1735 #ifdef RMT_WILL_WATCH 1348 Rmt_Watch(job->inPipe, JobLocalInput, job);1736 Rmt_Watch(job->inPipe, JobLocalInput, job); 1349 1737 #else 1350 FD_SET(job->inPipe, &outputs);1738 FD_SET(job->inPipe, &outputs); 1351 1739 #endif /* RMT_WILL_WATCH */ 1352 } 1353 1354 if (job->flags & JOB_REMOTE) { 1740 } 1741 #endif /* USE_PIPES */ 1742 1743 if (job->flags & JOB_REMOTE) { 1355 1744 #ifndef REMOTE 1356 job->rmtID = 0;1745 job->rmtID = 0; 1357 1746 #else 1358 job->rmtID = Rmt_LastID(job->pid);1747 job->rmtID = Rmt_LastID(job->pid); 1359 1748 #endif /* REMOTE */ 1360 } else {1361 nLocal += 1;1362 /*1363 * XXX: Used to not happen if REMOTE. Why?1364 */1365 if (job->cmdFILE != NULL && job->cmdFILE != stdout) {1366 (void) fclose(job->cmdFILE);1367 job->cmdFILE = NULL;1368 }1369 }1749 } else { 1750 nLocal += 1; 1751 /* 1752 * XXX: Used to not happen if REMOTE. Why? 1753 */ 1754 if (job->cmdFILE != NULL && job->cmdFILE != stdout) { 1755 (void) fclose(job->cmdFILE); 1756 job->cmdFILE = NULL; 1757 } 1758 } 1370 1759 #ifdef REMOTE 1371 (void) sigsetmask(omask);1760 (void) sigsetmask(omask); 1372 1761 #endif 1373 1762 } … … 1382 1771 (void) Lst_AtEnd(jobs, (ClientData)job); 1383 1772 if (nJobs == maxJobs) { 1384 jobFull = TRUE; 1385 } 1773 jobFull = TRUE; 1774 } 1775 #endif /* USE_KLIB */ 1386 1776 } 1387 1777 … … 1390 1780 *----------------------------------------------------------------------- 1391 1781 * JobMakeArgv -- 1392 * Create the argv needed to execute the shell for a given job.1782 * Create the argv needed to execute the shell for a given job. 1393 1783 * 1394 1784 * … … 1401 1791 static void 1402 1792 JobMakeArgv(job, argv) 1403 Job *job;1404 char **argv;1793 Job *job; 1794 char **argv; 1405 1795 { 1406 int argc; 1407 static char args[10]; /* For merged arguments */ 1408 1409 #ifndef _PATH_DEFSHELLDIR 1410 /* @todo! */ 1411 argv[0] = "c:\\os2\\cmd.exe"; 1412 argc = 1; 1413 #else 1796 #ifdef KMK 1797 int argc; 1798 1799 argv[0] = argv0; 1800 argv[1] = "--kShell"; 1801 argc = 2; 1802 if (!(job->flags & JOB_IGNERR)) 1803 argv[argc++] = "-e"; 1804 if (!(job->flags & JOB_SILENT)) 1805 argv[argc++] = "-v"; 1806 argv[argc] = NULL; 1807 1808 #else /* not kMk */ 1809 int argc; 1810 static char args[10]; /* For merged arguments */ 1811 1414 1812 argv[0] = shellName; 1415 1813 argc = 1; 1416 1814 1417 1815 if ((commandShell->exit && (*commandShell->exit != '-')) || 1418 (commandShell->echo && (*commandShell->echo != '-')))1816 (commandShell->echo && (*commandShell->echo != '-'))) 1419 1817 { 1420 /*1421 * At least one of the flags doesn't have a minus before it, so1422 * merge them together. Have to do this because the *(&(@*#*&#$#1423 * Bourne shell thinks its second argument is a file to source.1424 * Grrrr. Note the ten-character limitation on the combined arguments.1425 */1426 (void)sprintf(args, "-%s%s",1427 ((job->flags & JOB_IGNERR) ? "" :1428 (commandShell->exit ? commandShell->exit : "")),1429 ((job->flags & JOB_SILENT) ? "" :1430 (commandShell->echo ? commandShell->echo : "")));1431 1432 if (args[1]) {1433 argv[argc] = args;1434 argc++;1435 }1818 /* 1819 * At least one of the flags doesn't have a minus before it, so 1820 * merge them together. Have to do this because the *(&(@*#*&#$# 1821 * Bourne shell thinks its second argument is a file to source. 1822 * Grrrr. Note the ten-character limitation on the combined arguments. 1823 */ 1824 (void)sprintf(args, "-%s%s", 1825 ((job->flags & JOB_IGNERR) ? "" : 1826 (commandShell->exit ? commandShell->exit : "")), 1827 ((job->flags & JOB_SILENT) ? "" : 1828 (commandShell->echo ? commandShell->echo : ""))); 1829 1830 if (args[1]) { 1831 argv[argc] = args; 1832 argc++; 1833 } 1436 1834 } else { 1437 if (!(job->flags & JOB_IGNERR) && commandShell->exit) {1438 argv[argc] = commandShell->exit;1439 argc++;1440 }1441 if (!(job->flags & JOB_SILENT) && commandShell->echo) {1442 argv[argc] = commandShell->echo;1443 argc++;1444 }1835 if (!(job->flags & JOB_IGNERR) && commandShell->exit) { 1836 argv[argc] = commandShell->exit; 1837 argc++; 1838 } 1839 if (!(job->flags & JOB_SILENT) && commandShell->echo) { 1840 argv[argc] = commandShell->echo; 1841 argc++; 1842 } 1445 1843 } 1446 1844 argv[argc] = NULL; 1447 #endif 1845 #endif /* KMK */ 1448 1846 } 1449 1847 1450 1848 1849 #ifdef SIGCONT 1451 1850 /*- 1452 1851 *----------------------------------------------------------------------- 1453 1852 * JobRestart -- 1454 * Restart a job that stopped for some reason.1853 * Restart a job that stopped for some reason. 1455 1854 * 1456 1855 * Results: 1457 * None.1856 * None. 1458 1857 * 1459 1858 * Side Effects: 1460 * jobFull will be set if the job couldn't be run.1859 * jobFull will be set if the job couldn't be run. 1461 1860 * 1462 1861 *----------------------------------------------------------------------- … … 1464 1863 static void 1465 1864 JobRestart(job) 1466 Job *job;/* Job to restart */1865 Job *job; /* Job to restart */ 1467 1866 { 1468 1867 #ifdef REMOTE … … 1471 1870 1472 1871 if (job->flags & JOB_REMIGRATE) { 1473 if (1872 if ( 1474 1873 #ifdef REMOTE 1475 verboseRemigrates ||1476 #endif 1477 DEBUG(JOB)) {1478 (void) fprintf(stdout, "*** remigrating %x(%s)\n",1479 job->pid, job->node->name);1480 (void) fflush(stdout);1481 }1874 verboseRemigrates || 1875 #endif 1876 DEBUG(JOB)) { 1877 (void) fprintf(stdout, "*** remigrating %x(%s)\n", 1878 job->pid, job->node->name); 1879 (void) fflush(stdout); 1880 } 1482 1881 1483 1882 #ifdef REMOTE 1484 if (!Rmt_ReExport(job->pid, job->node, &host)) {1485 if (verboseRemigrates || DEBUG(JOB)) {1486 (void) fprintf(stdout, "*** couldn't migrate...\n");1487 (void) fflush(stdout);1488 }1489 #endif 1490 if (nLocal != maxLocal) {1491 /*1492 * Job cannot be remigrated, but there's room on the local1493 * machine, so resume the job and note that another1494 * local job has started.1495 */1496 if (1883 if (!Rmt_ReExport(job->pid, job->node, &host)) { 1884 if (verboseRemigrates || DEBUG(JOB)) { 1885 (void) fprintf(stdout, "*** couldn't migrate...\n"); 1886 (void) fflush(stdout); 1887 } 1888 #endif 1889 if (nLocal != maxLocal) { 1890 /* 1891 * Job cannot be remigrated, but there's room on the local 1892 * machine, so resume the job and note that another 1893 * local job has started. 1894 */ 1895 if ( 1497 1896 #ifdef REMOTE 1498 verboseRemigrates ||1499 #endif 1500 DEBUG(JOB)) {1501 (void) fprintf(stdout, "*** resuming on local machine\n");1502 (void) fflush(stdout);1503 }1504 KILL(job->pid, SIGCONT);1505 nLocal +=1;1897 verboseRemigrates || 1898 #endif 1899 DEBUG(JOB)) { 1900 (void) fprintf(stdout, "*** resuming on local machine\n"); 1901 (void) fflush(stdout); 1902 } 1903 KILL(job->pid, SIGCONT); 1904 nLocal +=1; 1506 1905 #ifdef REMOTE 1507 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE);1508 job->flags |= JOB_CONTINUING;1906 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); 1907 job->flags |= JOB_CONTINUING; 1509 1908 #else 1510 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);1511 #endif 1512 } else {1513 /*1514 * Job cannot be restarted. Mark the table as full and1515 * place the job back on the list of stopped jobs.1516 */1517 if (1909 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 1910 #endif 1911 } else { 1912 /* 1913 * Job cannot be restarted. Mark the table as full and 1914 * place the job back on the list of stopped jobs. 1915 */ 1916 if ( 1518 1917 #ifdef REMOTE 1519 verboseRemigrates ||1520 #endif 1521 DEBUG(JOB)) {1522 (void) fprintf(stdout, "*** holding\n");1523 (void) fflush(stdout);1524 }1525 (void)Lst_AtFront(stoppedJobs, (ClientData)job);1526 jobFull = TRUE;1527 if (DEBUG(JOB)) {1528 (void) fprintf(stdout, "Job queue is full.\n");1529 (void) fflush(stdout);1530 }1531 return;1532 }1918 verboseRemigrates || 1919 #endif 1920 DEBUG(JOB)) { 1921 (void) fprintf(stdout, "*** holding\n"); 1922 (void) fflush(stdout); 1923 } 1924 (void)Lst_AtFront(stoppedJobs, (ClientData)job); 1925 jobFull = TRUE; 1926 if (DEBUG(JOB)) { 1927 (void) fprintf(stdout, "Job queue is full.\n"); 1928 (void) fflush(stdout); 1929 } 1930 return; 1931 } 1533 1932 #ifdef REMOTE 1534 } else {1535 /*1536 * Clear out the remigrate and resume flags. Set the continuing1537 * flag so we know later on that the process isn't exiting just1538 * because of a signal.1539 */1540 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME);1541 job->flags |= JOB_CONTINUING;1542 job->rmtID = host;1543 }1544 #endif 1545 1546 (void)Lst_AtEnd(jobs, (ClientData)job);1547 nJobs += 1;1548 if (nJobs == maxJobs) {1549 jobFull = TRUE;1550 if (DEBUG(JOB)) {1551 (void) fprintf(stdout, "Job queue is full.\n");1552 (void) fflush(stdout);1553 }1554 }1933 } else { 1934 /* 1935 * Clear out the remigrate and resume flags. Set the continuing 1936 * flag so we know later on that the process isn't exiting just 1937 * because of a signal. 1938 */ 1939 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME); 1940 job->flags |= JOB_CONTINUING; 1941 job->rmtID = host; 1942 } 1943 #endif 1944 1945 (void)Lst_AtEnd(jobs, (ClientData)job); 1946 nJobs += 1; 1947 if (nJobs == maxJobs) { 1948 jobFull = TRUE; 1949 if (DEBUG(JOB)) { 1950 (void) fprintf(stdout, "Job queue is full.\n"); 1951 (void) fflush(stdout); 1952 } 1953 } 1555 1954 } else if (job->flags & JOB_RESTART) { 1556 /*1557 * Set up the control arguments to the shell. This is based on the1558 * flags set earlier for this job. If the JOB_IGNERR flag is clear,1559 * the 'exit' flag of the commandShell is used to cause it to exit1560 * upon receiving an error. If the JOB_SILENT flag is clear, the1561 * 'echo' flag of the commandShell is used to get it to start echoing1562 * as soon as it starts processing commands.1563 */1564 char*argv[4];1565 1566 JobMakeArgv(job, argv);1567 1568 if (DEBUG(JOB)) {1569 (void) fprintf(stdout, "Restarting %s...", job->node->name);1570 (void) fflush(stdout);1571 }1955 /* 1956 * Set up the control arguments to the shell. This is based on the 1957 * flags set earlier for this job. If the JOB_IGNERR flag is clear, 1958 * the 'exit' flag of the commandShell is used to cause it to exit 1959 * upon receiving an error. If the JOB_SILENT flag is clear, the 1960 * 'echo' flag of the commandShell is used to get it to start echoing 1961 * as soon as it starts processing commands. 1962 */ 1963 char *argv[4]; 1964 1965 JobMakeArgv(job, argv); 1966 1967 if (DEBUG(JOB)) { 1968 (void) fprintf(stdout, "Restarting %s...", job->node->name); 1969 (void) fflush(stdout); 1970 } 1572 1971 #ifdef REMOTE 1573 if ((job->node->type&OP_NOEXPORT) ||1574 (nLocal < maxLocal && runLocalFirst)1972 if ((job->node->type&OP_NOEXPORT) || 1973 (nLocal < maxLocal && runLocalFirst) 1575 1974 # ifdef RMT_NO_EXEC 1576 || !Rmt_Export(shellPath, argv, job)1975 || !Rmt_Export(shellPath, argv, job) 1577 1976 # else 1578 || !Rmt_Begin(shellPath, argv, job->node)1977 || !Rmt_Begin(shellPath, argv, job->node) 1579 1978 # endif 1580 1979 #endif 1581 {1582 if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) {1583 /*1584 * Can't be exported and not allowed to run locally -- put it1585 * back on the hold queue and mark the table full1586 */1587 if (DEBUG(JOB)) {1588 (void) fprintf(stdout, "holding\n");1589 (void) fflush(stdout);1590 }1591 (void)Lst_AtFront(stoppedJobs, (ClientData)job);1592 jobFull = TRUE;1593 if (DEBUG(JOB)) {1594 (void) fprintf(stdout, "Job queue is full.\n");1595 (void) fflush(stdout);1596 }1597 return;1598 } else {1599 /*1600 * Job may be run locally.1601 */1602 if (DEBUG(JOB)) {1603 (void) fprintf(stdout, "running locally\n");1604 (void) fflush(stdout);1605 }1606 job->flags &= ~JOB_REMOTE;1607 }1608 }1980 { 1981 if (((nLocal >= maxLocal) && !(job->flags & JOB_SPECIAL))) { 1982 /* 1983 * Can't be exported and not allowed to run locally -- put it 1984 * back on the hold queue and mark the table full 1985 */ 1986 if (DEBUG(JOB)) { 1987 (void) fprintf(stdout, "holding\n"); 1988 (void) fflush(stdout); 1989 } 1990 (void)Lst_AtFront(stoppedJobs, (ClientData)job); 1991 jobFull = TRUE; 1992 if (DEBUG(JOB)) { 1993 (void) fprintf(stdout, "Job queue is full.\n"); 1994 (void) fflush(stdout); 1995 } 1996 return; 1997 } else { 1998 /* 1999 * Job may be run locally. 2000 */ 2001 if (DEBUG(JOB)) { 2002 (void) fprintf(stdout, "running locally\n"); 2003 (void) fflush(stdout); 2004 } 2005 job->flags &= ~JOB_REMOTE; 2006 } 2007 } 1609 2008 #ifdef REMOTE 1610 else {1611 /*1612 * Can be exported. Hooray!1613 */1614 if (DEBUG(JOB)) {1615 (void) fprintf(stdout, "exporting\n");1616 (void) fflush(stdout);1617 }1618 job->flags |= JOB_REMOTE;1619 }1620 #endif 1621 JobExec(job, argv);2009 else { 2010 /* 2011 * Can be exported. Hooray! 2012 */ 2013 if (DEBUG(JOB)) { 2014 (void) fprintf(stdout, "exporting\n"); 2015 (void) fflush(stdout); 2016 } 2017 job->flags |= JOB_REMOTE; 2018 } 2019 #endif 2020 JobExec(job, argv); 1622 2021 } else { 1623 /*1624 * The job has stopped and needs to be restarted. Why it stopped,1625 * we don't know...1626 */1627 if (DEBUG(JOB)) {1628 (void) fprintf(stdout, "Resuming %s...", job->node->name);1629 (void) fflush(stdout);1630 }1631 if (((job->flags & JOB_REMOTE) ||1632 (nLocal < maxLocal) ||2022 /* 2023 * The job has stopped and needs to be restarted. Why it stopped, 2024 * we don't know... 2025 */ 2026 if (DEBUG(JOB)) { 2027 (void) fprintf(stdout, "Resuming %s...", job->node->name); 2028 (void) fflush(stdout); 2029 } 2030 if (((job->flags & JOB_REMOTE) || 2031 (nLocal < maxLocal) || 1633 2032 #ifdef REMOTE 1634 (((job->flags & JOB_SPECIAL) &&1635 (job->node->type & OP_NOEXPORT)) &&1636 (maxLocal == 0))) &&2033 (((job->flags & JOB_SPECIAL) && 2034 (job->node->type & OP_NOEXPORT)) && 2035 (maxLocal == 0))) && 1637 2036 #else 1638 ((job->flags & JOB_SPECIAL) &&1639 (maxLocal == 0))) &&1640 #endif 1641 (nJobs != maxJobs))1642 {1643 /*1644 * If the job is remote, it's ok to resume it as long as the1645 * maximum concurrency won't be exceeded. If it's local and1646 * we haven't reached the local concurrency limit already (or the1647 * job must be run locally and maxLocal is 0), it's also ok to1648 * resume it.1649 */1650 Boolean error;1651 int status;2037 ((job->flags & JOB_SPECIAL) && 2038 (maxLocal == 0))) && 2039 #endif 2040 (nJobs != maxJobs)) 2041 { 2042 /* 2043 * If the job is remote, it's ok to resume it as long as the 2044 * maximum concurrency won't be exceeded. If it's local and 2045 * we haven't reached the local concurrency limit already (or the 2046 * job must be run locally and maxLocal is 0), it's also ok to 2047 * resume it. 2048 */ 2049 Boolean error; 2050 int status; 1652 2051 1653 2052 #ifdef RMT_WANTS_SIGNALS 1654 if (job->flags & JOB_REMOTE) {1655 error = !Rmt_Signal(job, SIGCONT);1656 } else1657 #endif /* RMT_WANTS_SIGNALS */1658 error = (KILL(job->pid, SIGCONT) != 0);1659 1660 if (!error) {1661 /*1662 * Make sure the user knows we've continued the beast and1663 * actually put the thing in the job table.1664 */1665 job->flags |= JOB_CONTINUING;1666 W_SETTERMSIG(&status, SIGCONT);1667 JobFinish(job, &status);1668 1669 job->flags &= ~(JOB_RESUME|JOB_CONTINUING);1670 if (DEBUG(JOB)) {1671 (void) fprintf(stdout, "done\n");1672 (void) fflush(stdout);1673 }1674 } else {1675 Error("couldn't resume %s: %s",1676 job->node->name, strerror(errno));1677 status = 0;1678 W_SETEXITSTATUS(&status, 1);1679 JobFinish(job, &status);1680 }1681 } else {1682 /*1683 * Job cannot be restarted. Mark the table as full and1684 * place the job back on the list of stopped jobs.1685 */1686 if (DEBUG(JOB)) {1687 (void) fprintf(stdout, "table full\n");1688 (void) fflush(stdout);1689 }1690 (void) Lst_AtFront(stoppedJobs, (ClientData)job);1691 jobFull = TRUE;1692 if (DEBUG(JOB)) {1693 (void) fprintf(stdout, "Job queue is full.\n");1694 (void) fflush(stdout);1695 }1696 }2053 if (job->flags & JOB_REMOTE) { 2054 error = !Rmt_Signal(job, SIGCONT); 2055 } else 2056 #endif /* RMT_WANTS_SIGNALS */ 2057 error = (KILL(job->pid, SIGCONT) != 0); 2058 2059 if (!error) { 2060 /* 2061 * Make sure the user knows we've continued the beast and 2062 * actually put the thing in the job table. 2063 */ 2064 job->flags |= JOB_CONTINUING; 2065 W_SETTERMSIG(&status, SIGCONT); 2066 JobFinish(job, &status); 2067 2068 job->flags &= ~(JOB_RESUME|JOB_CONTINUING); 2069 if (DEBUG(JOB)) { 2070 (void) fprintf(stdout, "done\n"); 2071 (void) fflush(stdout); 2072 } 2073 } else { 2074 Error("couldn't resume %s: %s", 2075 job->node->name, strerror(errno)); 2076 status = 0; 2077 W_SETEXITSTATUS(&status, 1); 2078 JobFinish(job, &status); 2079 } 2080 } else { 2081 /* 2082 * Job cannot be restarted. Mark the table as full and 2083 * place the job back on the list of stopped jobs. 2084 */ 2085 if (DEBUG(JOB)) { 2086 (void) fprintf(stdout, "table full\n"); 2087 (void) fflush(stdout); 2088 } 2089 (void) Lst_AtFront(stoppedJobs, (ClientData)job); 2090 jobFull = TRUE; 2091 if (DEBUG(JOB)) { 2092 (void) fprintf(stdout, "Job queue is full.\n"); 2093 (void) fflush(stdout); 2094 } 2095 } 1697 2096 } 1698 2097 } 2098 #endif 1699 2099 1700 2100 /*- 1701 2101 *----------------------------------------------------------------------- 1702 2102 * JobStart -- 1703 * Start a target-creation process going for the target described1704 * by the graph node gn.2103 * Start a target-creation process going for the target described 2104 * by the graph node gn. 1705 2105 * 1706 2106 * Results: 1707 * JOB_ERROR if there was an error in the commands, JOB_FINISHED1708 * if there isn't actually anything left to do for the job and1709 * JOB_RUNNING if the job has been started.2107 * JOB_ERROR if there was an error in the commands, JOB_FINISHED 2108 * if there isn't actually anything left to do for the job and 2109 * JOB_RUNNING if the job has been started. 1710 2110 * 1711 2111 * Side Effects: 1712 * A new Job node is created and added to the list of running1713 * jobs. PMake is forked and a child shell created.2112 * A new Job node is created and added to the list of running 2113 * jobs. PMake is forked and a child shell created. 1714 2114 *----------------------------------------------------------------------- 1715 2115 */ 1716 2116 static int 1717 2117 JobStart(gn, flags, previous) 1718 GNode *gn; /* target to create */1719 int flags; /* flags for the job to override normal ones.1720 * e.g. JOB_SPECIAL or JOB_IGNDOTS */1721 Job *previous; /* The previous Job structure for this node,1722 * if any. */2118 GNode *gn; /* target to create */ 2119 int flags; /* flags for the job to override normal ones. 2120 * e.g. JOB_SPECIAL or JOB_IGNDOTS */ 2121 Job *previous; /* The previous Job structure for this node, 2122 * if any. */ 1723 2123 { 1724 2124 register Job *job; /* new job descriptor */ 1725 char *argv[4]; /* Argument vector to shell */1726 Boolean cmdsOK; /* true if the nodes commands were all right */1727 Boolean local; /* Set true if the job was run locally */1728 Boolean noExec; /* Set true if we decide not to run the job */1729 int tfd;/* File descriptor for temp file */2125 char *argv[4]; /* Argument vector to shell */ 2126 Boolean cmdsOK; /* true if the nodes commands were all right */ 2127 Boolean local; /* Set true if the job was run locally */ 2128 Boolean noExec; /* Set true if we decide not to run the job */ 2129 int tfd; /* File descriptor for temp file */ 1730 2130 1731 2131 if (previous != NULL) { 1732 previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE);1733 job = previous;2132 previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); 2133 job = previous; 1734 2134 } else { 1735 job = (Job *) emalloc(sizeof(Job));1736 if (job == NULL) {1737 Punt("JobStart out of memory");1738 }1739 flags |= JOB_FIRST;2135 job = (Job *) emalloc(sizeof(Job)); 2136 if (job == NULL) { 2137 Punt("JobStart out of memory"); 2138 } 2139 flags |= JOB_FIRST; 1740 2140 } 1741 2141 … … 1750 2150 job->flags = 0; 1751 2151 if (Targ_Ignore(gn)) { 1752 job->flags |= JOB_IGNERR;2152 job->flags |= JOB_IGNERR; 1753 2153 } 1754 2154 if (Targ_Silent(gn)) { 1755 job->flags |= JOB_SILENT;2155 job->flags |= JOB_SILENT; 1756 2156 } 1757 2157 job->flags |= flags; … … 1762 2162 */ 1763 2163 if (!compatMake && job->flags & JOB_FIRST) { 1764 cmdsOK = Job_CheckCommands(gn, Error);2164 cmdsOK = Job_CheckCommands(gn, Error); 1765 2165 } else { 1766 cmdsOK = TRUE;2166 cmdsOK = TRUE; 1767 2167 } 1768 2168 … … 1774 2174 */ 1775 2175 if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 1776 /*1777 * We're serious here, but if the commands were bogus, we're1778 * also dead...1779 */1780 if (!cmdsOK) {1781 DieHorribly();1782 }1783 1784 (void) strcpy(tfile, TMPPAT);1785 if ((tfd = mkstemp(tfile)) == -1)1786 Punt("Cannot create temp file: %s", strerror(errno));1787 job->cmdFILE = fdopen(tfd, "w+");1788 eunlink(tfile);1789 if (job->cmdFILE == NULL) {1790 close(tfd);1791 Punt("Could not open %s", tfile);1792 }1793 (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1);1794 /*1795 * Send the commands to the command file, flush all its buffers then1796 * rewind and remove the thing.1797 */1798 noExec = FALSE;1799 1800 /*1801 * used to be backwards; replace when start doing multiple commands1802 * per shell.1803 */1804 if (compatMake) {1805 /*1806 * Be compatible: If this is the first time for this node,1807 * verify its commands are ok and open the commands list for1808 * sequential access by later invocations of JobStart.1809 * Once that is done, we take the next command off the list1810 * and print it to the command file. If the command was an1811 * ellipsis, note that there's nothing more to execute.1812 */1813 if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){1814 cmdsOK = FALSE;1815 } else {1816 LstNodeln = Lst_Next(gn->commands);1817 1818 if ((ln == NILLNODE) ||1819 JobPrintCommand((ClientData) Lst_Datum(ln),1820 (ClientData) job))1821 {1822 noExec = TRUE;1823 Lst_Close(gn->commands);1824 }1825 if (noExec && !(job->flags & JOB_FIRST)) {1826 /*1827 * If we're not going to execute anything, the job1828 * is done and we need to close down the various1829 * file descriptors we've opened for output, then1830 * call JobDoOutput to catch the final characters or1831 * send the file to the screen... Note that the i/o streams1832 * are only open if this isn't the first job.1833 * Note also that this could not be done in1834 * Job_CatchChildren b/c it wasn't clear if there were1835 * more commands to execute or not...1836 */1837 JobClose(job);1838 }1839 }1840 } else {1841 /*1842 * We can do all the commands at once. hooray for sanity1843 */1844 numCommands = 0;1845 Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);1846 1847 /*1848 * If we didn't print out any commands to the shell script,1849 * there's not much point in executing the shell, is there?1850 */1851 if (numCommands == 0) {1852 noExec = TRUE;1853 }1854 }2176 /* 2177 * We're serious here, but if the commands were bogus, we're 2178 * also dead... 2179 */ 2180 if (!cmdsOK) { 2181 DieHorribly(); 2182 } 2183 2184 (void) strcpy(tfile, TMPPAT); 2185 if ((tfd = mkstemp(tfile)) == -1) 2186 Punt("Cannot create temp file: %s", strerror(errno)); 2187 job->cmdFILE = fdopen(tfd, "w+"); 2188 eunlink(tfile); 2189 if (job->cmdFILE == NULL) { 2190 close(tfd); 2191 Punt("Could not open %s", tfile); 2192 } 2193 (void) fcntl(FILENO(job->cmdFILE), F_SETFD, 1); 2194 /* 2195 * Send the commands to the command file, flush all its buffers then 2196 * rewind and remove the thing. 2197 */ 2198 noExec = FALSE; 2199 2200 /* 2201 * used to be backwards; replace when start doing multiple commands 2202 * per shell. 2203 */ 2204 if (compatMake) { 2205 /* 2206 * Be compatible: If this is the first time for this node, 2207 * verify its commands are ok and open the commands list for 2208 * sequential access by later invocations of JobStart. 2209 * Once that is done, we take the next command off the list 2210 * and print it to the command file. If the command was an 2211 * ellipsis, note that there's nothing more to execute. 2212 */ 2213 if ((job->flags&JOB_FIRST) && (Lst_Open(gn->commands) != SUCCESS)){ 2214 cmdsOK = FALSE; 2215 } else { 2216 LstNode ln = Lst_Next(gn->commands); 2217 2218 if ((ln == NILLNODE) || 2219 JobPrintCommand((ClientData) Lst_Datum(ln), 2220 (ClientData) job)) 2221 { 2222 noExec = TRUE; 2223 Lst_Close(gn->commands); 2224 } 2225 if (noExec && !(job->flags & JOB_FIRST)) { 2226 /* 2227 * If we're not going to execute anything, the job 2228 * is done and we need to close down the various 2229 * file descriptors we've opened for output, then 2230 * call JobDoOutput to catch the final characters or 2231 * send the file to the screen... Note that the i/o streams 2232 * are only open if this isn't the first job. 2233 * Note also that this could not be done in 2234 * Job_CatchChildren b/c it wasn't clear if there were 2235 * more commands to execute or not... 2236 */ 2237 JobClose(job); 2238 } 2239 } 2240 } else { 2241 /* 2242 * We can do all the commands at once. hooray for sanity 2243 */ 2244 numCommands = 0; 2245 Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job); 2246 2247 /* 2248 * If we didn't print out any commands to the shell script, 2249 * there's not much point in executing the shell, is there? 2250 */ 2251 if (numCommands == 0) { 2252 noExec = TRUE; 2253 } 2254 } 1855 2255 } else if (noExecute) { 1856 /*1857 * Not executing anything -- just print all the commands to stdout1858 * in one fell swoop. This will still set up job->tailCmds correctly.1859 */1860 if (lastNode != gn) {1861 MESSAGE(stdout, gn);1862 lastNode = gn;1863 }1864 job->cmdFILE = stdout;1865 /*1866 * Only print the commands if they're ok, but don't die if they're1867 * not -- just let the user know they're bad and keep going. It1868 * doesn't do any harm in this case and may do some good.1869 */1870 if (cmdsOK) {1871 Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job);1872 }1873 /*1874 * Don't execute the shell, thank you.1875 */1876 noExec = TRUE;2256 /* 2257 * Not executing anything -- just print all the commands to stdout 2258 * in one fell swoop. This will still set up job->tailCmds correctly. 2259 */ 2260 if (lastNode != gn) { 2261 MESSAGE(stdout, gn); 2262 lastNode = gn; 2263 } 2264 job->cmdFILE = stdout; 2265 /* 2266 * Only print the commands if they're ok, but don't die if they're 2267 * not -- just let the user know they're bad and keep going. It 2268 * doesn't do any harm in this case and may do some good. 2269 */ 2270 if (cmdsOK) { 2271 Lst_ForEach(gn->commands, JobPrintCommand, (ClientData)job); 2272 } 2273 /* 2274 * Don't execute the shell, thank you. 2275 */ 2276 noExec = TRUE; 1877 2277 } else { 1878 /*1879 * Just touch the target and note that no shell should be executed.1880 * Set cmdFILE to stdout to make life easier. Check the commands, too,1881 * but don't die if they're no good -- it does no harm to keep working1882 * up the graph.1883 */1884 job->cmdFILE = stdout;1885 Job_Touch(gn, job->flags&JOB_SILENT);1886 noExec = TRUE;2278 /* 2279 * Just touch the target and note that no shell should be executed. 2280 * Set cmdFILE to stdout to make life easier. Check the commands, too, 2281 * but don't die if they're no good -- it does no harm to keep working 2282 * up the graph. 2283 */ 2284 job->cmdFILE = stdout; 2285 Job_Touch(gn, job->flags&JOB_SILENT); 2286 noExec = TRUE; 1887 2287 } 1888 2288 … … 1891 2291 */ 1892 2292 if (noExec) { 1893 /*1894 * Unlink and close the command file if we opened one1895 */1896 if (job->cmdFILE != stdout) {1897 if (job->cmdFILE != NULL)1898 (void) fclose(job->cmdFILE);1899 } else {1900 (void) fflush(stdout);1901 }1902 1903 /*1904 * We only want to work our way up the graph if we aren't here because1905 * the commands for the job were no good.1906 */1907 if (cmdsOK) {1908 if (aborting == 0) {1909 if (job->tailCmds != NILLNODE) {1910 Lst_ForEachFrom(job->node->commands, job->tailCmds,1911 JobSaveCommand,1912 (ClientData)job->node);1913 }1914 job->node->made = MADE;1915 Make_Update(job->node);1916 }1917 efree((Address)job);1918 return(JOB_FINISHED);1919 } else {1920 efree((Address)job);1921 return(JOB_ERROR);1922 }2293 /* 2294 * Unlink and close the command file if we opened one 2295 */ 2296 if (job->cmdFILE != stdout) { 2297 if (job->cmdFILE != NULL) 2298 (void) fclose(job->cmdFILE); 2299 } else { 2300 (void) fflush(stdout); 2301 } 2302 2303 /* 2304 * We only want to work our way up the graph if we aren't here because 2305 * the commands for the job were no good. 2306 */ 2307 if (cmdsOK) { 2308 if (aborting == 0) { 2309 if (job->tailCmds != NILLNODE) { 2310 Lst_ForEachFrom(job->node->commands, job->tailCmds, 2311 JobSaveCommand, 2312 (ClientData)job->node); 2313 } 2314 job->node->made = MADE; 2315 Make_Update(job->node); 2316 } 2317 efree((Address)job); 2318 return(JOB_FINISHED); 2319 } else { 2320 efree((Address)job); 2321 return(JOB_ERROR); 2322 } 1923 2323 } else { 1924 (void) fflush(job->cmdFILE);2324 (void) fflush(job->cmdFILE); 1925 2325 } 1926 2326 … … 1937 2337 */ 1938 2338 if (!compatMake || (job->flags & JOB_FIRST)) { 1939 if (usePipes) { 1940 int fd[2]; 1941 if (pipe(fd) == -1) 1942 Punt("Cannot create pipe: %s", strerror(errno)); 1943 job->inPipe = fd[0]; 1944 job->outPipe = fd[1]; 1945 (void) fcntl(job->inPipe, F_SETFD, 1); 1946 (void) fcntl(job->outPipe, F_SETFD, 1); 1947 } else { 1948 (void) fprintf(stdout, "Remaking `%s'\n", gn->name); 1949 (void) fflush(stdout); 1950 (void) strcpy(job->outFile, TMPPAT); 1951 if ((job->outFd = mkstemp(job->outFile)) == -1) 1952 Punt("cannot create temp file: %s", strerror(errno)); 1953 (void) fcntl(job->outFd, F_SETFD, 1); 1954 } 2339 #ifdef USE_PIPES 2340 if (usePipes) { 2341 int fd[2]; 2342 if (pipe(fd) == -1) 2343 Punt("Cannot create pipe: %s", strerror(errno)); 2344 job->inPipe = fd[0]; 2345 job->outPipe = fd[1]; 2346 (void) fcntl(job->inPipe, F_SETFD, 1); 2347 (void) fcntl(job->outPipe, F_SETFD, 1); 2348 } 2349 else 2350 #endif /* USE_PIPES */ 2351 { 2352 (void) fprintf(stdout, "Remaking `%s'\n", gn->name); 2353 (void) fflush(stdout); 2354 (void) strcpy(job->outFile, TMPPAT); 2355 if ((job->outFd = mkstemp(job->outFile)) == -1) 2356 Punt("cannot create temp file: %s", strerror(errno)); 2357 (void) fcntl(job->outFd, F_SETFD, 1); 2358 } 1955 2359 } 1956 2360 … … 1958 2362 if (!(gn->type & OP_NOEXPORT) && !(runLocalFirst && nLocal < maxLocal)) { 1959 2363 #ifdef RMT_NO_EXEC 1960 local = !Rmt_Export(shellPath, argv, job);2364 local = !Rmt_Export(shellPath, argv, job); 1961 2365 #else 1962 local = !Rmt_Begin(shellPath, argv, job->node);2366 local = !Rmt_Begin(shellPath, argv, job->node); 1963 2367 #endif /* RMT_NO_EXEC */ 1964 if (!local) {1965 job->flags |= JOB_REMOTE;1966 }2368 if (!local) { 2369 job->flags |= JOB_REMOTE; 2370 } 1967 2371 } else 1968 2372 #endif 1969 local = TRUE;2373 local = TRUE; 1970 2374 1971 2375 if (local && (((nLocal >= maxLocal) && 1972 !(job->flags & JOB_SPECIAL) &&2376 !(job->flags & JOB_SPECIAL) && 1973 2377 #ifdef REMOTE 1974 (!(gn->type & OP_NOEXPORT) || (maxLocal != 0))2378 (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) 1975 2379 #else 1976 (maxLocal != 0)1977 #endif 1978 )))2380 (maxLocal != 0) 2381 #endif 2382 ))) 1979 2383 { 1980 /*1981 * The job can only be run locally, but we've hit the limit of1982 * local concurrency, so put the job on hold until some other job1983 * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END)1984 * may be run locally even when the local limit has been reached1985 * (e.g. when maxLocal == 0), though they will be exported if at1986 * all possible. In addition, any target marked with .NOEXPORT will1987 * be run locally if maxLocal is 0.1988 */1989 jobFull = TRUE;1990 1991 if (DEBUG(JOB)) {1992 (void) fprintf(stdout, "Can only run job locally.\n");1993 (void) fflush(stdout);1994 }1995 job->flags |= JOB_RESTART;1996 (void) Lst_AtEnd(stoppedJobs, (ClientData)job);2384 /* 2385 * The job can only be run locally, but we've hit the limit of 2386 * local concurrency, so put the job on hold until some other job 2387 * finishes. Note that the special jobs (.BEGIN, .INTERRUPT and .END) 2388 * may be run locally even when the local limit has been reached 2389 * (e.g. when maxLocal == 0), though they will be exported if at 2390 * all possible. In addition, any target marked with .NOEXPORT will 2391 * be run locally if maxLocal is 0. 2392 */ 2393 jobFull = TRUE; 2394 2395 if (DEBUG(JOB)) { 2396 (void) fprintf(stdout, "Can only run job locally.\n"); 2397 (void) fflush(stdout); 2398 } 2399 job->flags |= JOB_RESTART; 2400 (void) Lst_AtEnd(stoppedJobs, (ClientData)job); 1997 2401 } else { 1998 if ((nLocal >= maxLocal) && local) {1999 /*2000 * If we're running this job locally as a special case (see above),2001 * at least say the table is full.2002 */2003 jobFull = TRUE;2004 if (DEBUG(JOB)) {2005 (void) fprintf(stdout, "Local job queue is full.\n");2006 (void) fflush(stdout);2007 }2008 }2009 JobExec(job, argv);2402 if ((nLocal >= maxLocal) && local) { 2403 /* 2404 * If we're running this job locally as a special case (see above), 2405 * at least say the table is full. 2406 */ 2407 jobFull = TRUE; 2408 if (DEBUG(JOB)) { 2409 (void) fprintf(stdout, "Local job queue is full.\n"); 2410 (void) fflush(stdout); 2411 } 2412 } 2413 JobExec(job, argv); 2010 2414 } 2011 2415 return(JOB_RUNNING); … … 2022 2426 #ifndef KMK /* @Todo */ 2023 2427 if (commandShell->noPrint) { 2024 ecp = Str_FindSubstring(cp, commandShell->noPrint);2025 while (ecp != NULL) {2026 if (cp != ecp) {2027 *ecp = '\0';2028 if (msg && job->node != lastNode) {2029 MESSAGE(stdout, job->node);2030 lastNode = job->node;2031 }2032 /*2033 * The only way there wouldn't be a newline after2034 * this line is if it were the last in the buffer.2035 * however, since the non-printable comes after it,2036 * there must be a newline, so we don't print one.2037 */2038 (void) fprintf(stdout, "%s", cp);2039 (void) fflush(stdout);2040 }2041 cp = ecp + commandShell->noPLen;2042 if (cp != endp) {2043 /*2044 * Still more to print, look again after skipping2045 * the whitespace following the non-printable2046 * command....2047 */2048 cp++;2049 while (*cp == ' ' || *cp == '\t' || *cp == '\n') {2050 cp++;2051 }2052 ecp = Str_FindSubstring(cp, commandShell->noPrint);2053 } else {2054 return cp;2055 }2056 }2428 ecp = Str_FindSubstring(cp, commandShell->noPrint); 2429 while (ecp != NULL) { 2430 if (cp != ecp) { 2431 *ecp = '\0'; 2432 if (msg && job->node != lastNode) { 2433 MESSAGE(stdout, job->node); 2434 lastNode = job->node; 2435 } 2436 /* 2437 * The only way there wouldn't be a newline after 2438 * this line is if it were the last in the buffer. 2439 * however, since the non-printable comes after it, 2440 * there must be a newline, so we don't print one. 2441 */ 2442 (void) fprintf(stdout, "%s", cp); 2443 (void) fflush(stdout); 2444 } 2445 cp = ecp + commandShell->noPLen; 2446 if (cp != endp) { 2447 /* 2448 * Still more to print, look again after skipping 2449 * the whitespace following the non-printable 2450 * command.... 2451 */ 2452 cp++; 2453 while (*cp == ' ' || *cp == '\t' || *cp == '\n') { 2454 cp++; 2455 } 2456 ecp = Str_FindSubstring(cp, commandShell->noPrint); 2457 } else { 2458 return cp; 2459 } 2460 } 2057 2461 } 2058 2462 #endif /*!KMK*/ … … 2063 2467 *----------------------------------------------------------------------- 2064 2468 * JobDoOutput -- 2065 * This function is called at different times depending on2066 * whether the user has specified that output is to be collected2067 * via pipes or temporary files. In the former case, we are called2068 * whenever there is something to read on the pipe. We collect more2069 * output from the given job and store it in the job's outBuf. If2070 * this makes up a line, we print it tagged by the job's identifier,2071 * as necessary.2072 * If output has been collected in a temporary file, we open the2073 * file and read it line by line, transfering it to our own2074 * output channel until the file is empty. At which point we2075 * remove the temporary file.2076 * In both cases, however, we keep our figurative eye out for the2077 * 'noPrint' line for the shell from which the output came. If2078 * we recognize a line, we don't print it. If the command is not2079 * alone on the line (the character after it is not \0 or \n), we2080 * do print whatever follows it.2469 * This function is called at different times depending on 2470 * whether the user has specified that output is to be collected 2471 * via pipes or temporary files. In the former case, we are called 2472 * whenever there is something to read on the pipe. We collect more 2473 * output from the given job and store it in the job's outBuf. If 2474 * this makes up a line, we print it tagged by the job's identifier, 2475 * as necessary. 2476 * If output has been collected in a temporary file, we open the 2477 * file and read it line by line, transfering it to our own 2478 * output channel until the file is empty. At which point we 2479 * remove the temporary file. 2480 * In both cases, however, we keep our figurative eye out for the 2481 * 'noPrint' line for the shell from which the output came. If 2482 * we recognize a line, we don't print it. If the command is not 2483 * alone on the line (the character after it is not \0 or \n), we 2484 * do print whatever follows it. 2081 2485 * 2082 2486 * Results: 2083 * None2487 * None 2084 2488 * 2085 2489 * Side Effects: 2086 * curPos may be shifted as may the contents of outBuf.2490 * curPos may be shifted as may the contents of outBuf. 2087 2491 *----------------------------------------------------------------------- 2088 2492 */ 2089 2493 STATIC void 2090 2494 JobDoOutput(job, finish) 2091 register Job *job; /* the job whose output needs printing */2092 Boolean finish;/* TRUE if this is the last time we'll be2093 * called for this job */2495 register Job *job; /* the job whose output needs printing */ 2496 Boolean finish; /* TRUE if this is the last time we'll be 2497 * called for this job */ 2094 2498 { 2095 2499 Boolean gotNL = FALSE; /* true if got a newline */ 2096 Boolean fbuf; /* true if our buffer filled up */2097 register int nr; /* number of bytes read */2098 register int i; /* auxiliary index into outBuf */2099 register int max; /* limit for i (end of current data) */2100 int nRead;/* (Temporary) number of bytes read */2101 2102 FILE *oFILE;/* Stream pointer to shell's output file */2500 Boolean fbuf; /* true if our buffer filled up */ 2501 register int nr; /* number of bytes read */ 2502 register int i; /* auxiliary index into outBuf */ 2503 register int max; /* limit for i (end of current data) */ 2504 int nRead; /* (Temporary) number of bytes read */ 2505 2506 FILE *oFILE; /* Stream pointer to shell's output file */ 2103 2507 char inLine[132]; 2104 2508 2105 2509 2510 #ifdef USE_PIPES 2106 2511 if (usePipes) { 2107 /*2108 * Read as many bytes as will fit in the buffer.2109 */2512 /* 2513 * Read as many bytes as will fit in the buffer. 2514 */ 2110 2515 end_loop: 2111 gotNL = FALSE; 2112 fbuf = FALSE; 2113 2114 nRead = read(job->inPipe, &job->outBuf[job->curPos], 2115 JOB_BUFSIZE - job->curPos); 2116 if (nRead < 0) { 2117 if (DEBUG(JOB)) { 2118 perror("JobDoOutput(piperead)"); 2119 } 2120 nr = 0; 2121 } else { 2122 nr = nRead; 2123 } 2124 2125 /* 2126 * If we hit the end-of-file (the job is dead), we must flush its 2127 * remaining output, so pretend we read a newline if there's any 2128 * output remaining in the buffer. 2129 * Also clear the 'finish' flag so we stop looping. 2130 */ 2131 if ((nr == 0) && (job->curPos != 0)) { 2132 job->outBuf[job->curPos] = '\n'; 2133 nr = 1; 2134 finish = FALSE; 2135 } else if (nr == 0) { 2136 finish = FALSE; 2137 } 2138 2139 /* 2140 * Look for the last newline in the bytes we just got. If there is 2141 * one, break out of the loop with 'i' as its index and gotNL set 2142 * TRUE. 2143 */ 2144 max = job->curPos + nr; 2145 for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 2146 if (job->outBuf[i] == '\n') { 2147 gotNL = TRUE; 2148 break; 2149 } else if (job->outBuf[i] == '\0') { 2150 /* 2151 * Why? 2152 */ 2153 job->outBuf[i] = ' '; 2154 } 2155 } 2156 2157 if (!gotNL) { 2158 job->curPos += nr; 2159 if (job->curPos == JOB_BUFSIZE) { 2160 /* 2161 * If we've run out of buffer space, we have no choice 2162 * but to print the stuff. sigh. 2163 */ 2164 fbuf = TRUE; 2165 i = job->curPos; 2166 } 2167 } 2168 if (gotNL || fbuf) { 2169 /* 2170 * Need to send the output to the screen. Null terminate it 2171 * first, overwriting the newline character if there was one. 2172 * So long as the line isn't one we should filter (according 2173 * to the shell description), we print the line, preceeded 2174 * by a target banner if this target isn't the same as the 2175 * one for which we last printed something. 2176 * The rest of the data in the buffer are then shifted down 2177 * to the start of the buffer and curPos is set accordingly. 2178 */ 2179 job->outBuf[i] = '\0'; 2180 if (i >= job->curPos) { 2181 char *cp; 2182 2183 cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 2184 2185 /* 2186 * There's still more in that thar buffer. This time, though, 2187 * we know there's no newline at the end, so we add one of 2188 * our own efree will. 2189 */ 2190 if (*cp != '\0') { 2191 if (job->node != lastNode) { 2192 MESSAGE(stdout, job->node); 2193 lastNode = job->node; 2194 } 2195 (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 2196 (void) fflush(stdout); 2197 } 2198 } 2199 if (i < max - 1) { 2200 /* shift the remaining characters down */ 2201 (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 2202 job->curPos = max - (i + 1); 2203 2204 } else { 2205 /* 2206 * We have written everything out, so we just start over 2207 * from the start of the buffer. No copying. No nothing. 2208 */ 2209 job->curPos = 0; 2210 } 2211 } 2212 if (finish) { 2213 /* 2214 * If the finish flag is true, we must loop until we hit 2215 * end-of-file on the pipe. This is guaranteed to happen 2216 * eventually since the other end of the pipe is now closed 2217 * (we closed it explicitly and the child has exited). When 2218 * we do get an EOF, finish will be set FALSE and we'll fall 2219 * through and out. 2220 */ 2221 goto end_loop; 2222 } 2223 } else { 2224 /* 2225 * We've been called to retrieve the output of the job from the 2226 * temporary file where it's been squirreled away. This consists of 2227 * opening the file, reading the output line by line, being sure not 2228 * to print the noPrint line for the shell we used, then close and 2229 * remove the temporary file. Very simple. 2230 * 2231 * Change to read in blocks and do FindSubString type things as for 2232 * pipes? That would allow for "@echo -n..." 2233 */ 2234 oFILE = fopen(job->outFile, "r"); 2235 if (oFILE != NULL) { 2236 (void) fprintf(stdout, "Results of making %s:\n", job->node->name); 2237 (void) fflush(stdout); 2238 while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 2239 register char *cp, *endp, *oendp; 2240 2241 cp = inLine; 2242 oendp = endp = inLine + strlen(inLine); 2243 if (endp[-1] == '\n') { 2244 *--endp = '\0'; 2245 } 2246 cp = JobOutput(job, inLine, endp, FALSE); 2247 2248 /* 2249 * There's still more in that thar buffer. This time, though, 2250 * we know there's no newline at the end, so we add one of 2251 * our own efree will. 2252 */ 2253 (void) fprintf(stdout, "%s", cp); 2254 (void) fflush(stdout); 2255 if (endp != oendp) { 2256 (void) fprintf(stdout, "\n"); 2257 (void) fflush(stdout); 2258 } 2259 } 2260 (void) fclose(oFILE); 2261 (void) eunlink(job->outFile); 2262 } 2516 gotNL = FALSE; 2517 fbuf = FALSE; 2518 2519 nRead = read(job->inPipe, &job->outBuf[job->curPos], 2520 JOB_BUFSIZE - job->curPos); 2521 if (nRead < 0) { 2522 if (DEBUG(JOB)) { 2523 perror("JobDoOutput(piperead)"); 2524 } 2525 nr = 0; 2526 } else { 2527 nr = nRead; 2528 } 2529 2530 /* 2531 * If we hit the end-of-file (the job is dead), we must flush its 2532 * remaining output, so pretend we read a newline if there's any 2533 * output remaining in the buffer. 2534 * Also clear the 'finish' flag so we stop looping. 2535 */ 2536 if ((nr == 0) && (job->curPos != 0)) { 2537 job->outBuf[job->curPos] = '\n'; 2538 nr = 1; 2539 finish = FALSE; 2540 } else if (nr == 0) { 2541 finish = FALSE; 2542 } 2543 2544 /* 2545 * Look for the last newline in the bytes we just got. If there is 2546 * one, break out of the loop with 'i' as its index and gotNL set 2547 * TRUE. 2548 */ 2549 max = job->curPos + nr; 2550 for (i = job->curPos + nr - 1; i >= job->curPos; i--) { 2551 if (job->outBuf[i] == '\n') { 2552 gotNL = TRUE; 2553 break; 2554 } else if (job->outBuf[i] == '\0') { 2555 /* 2556 * Why? 2557 */ 2558 job->outBuf[i] = ' '; 2559 } 2560 } 2561 2562 if (!gotNL) { 2563 job->curPos += nr; 2564 if (job->curPos == JOB_BUFSIZE) { 2565 /* 2566 * If we've run out of buffer space, we have no choice 2567 * but to print the stuff. sigh. 2568 */ 2569 fbuf = TRUE; 2570 i = job->curPos; 2571 } 2572 } 2573 if (gotNL || fbuf) { 2574 /* 2575 * Need to send the output to the screen. Null terminate it 2576 * first, overwriting the newline character if there was one. 2577 * So long as the line isn't one we should filter (according 2578 * to the shell description), we print the line, preceeded 2579 * by a target banner if this target isn't the same as the 2580 * one for which we last printed something. 2581 * The rest of the data in the buffer are then shifted down 2582 * to the start of the buffer and curPos is set accordingly. 2583 */ 2584 job->outBuf[i] = '\0'; 2585 if (i >= job->curPos) { 2586 char *cp; 2587 2588 cp = JobOutput(job, job->outBuf, &job->outBuf[i], FALSE); 2589 2590 /* 2591 * There's still more in that thar buffer. This time, though, 2592 * we know there's no newline at the end, so we add one of 2593 * our own efree will. 2594 */ 2595 if (*cp != '\0') { 2596 if (job->node != lastNode) { 2597 MESSAGE(stdout, job->node); 2598 lastNode = job->node; 2599 } 2600 (void) fprintf(stdout, "%s%s", cp, gotNL ? "\n" : ""); 2601 (void) fflush(stdout); 2602 } 2603 } 2604 if (i < max - 1) { 2605 /* shift the remaining characters down */ 2606 (void) memcpy(job->outBuf, &job->outBuf[i + 1], max - (i + 1)); 2607 job->curPos = max - (i + 1); 2608 2609 } else { 2610 /* 2611 * We have written everything out, so we just start over 2612 * from the start of the buffer. No copying. No nothing. 2613 */ 2614 job->curPos = 0; 2615 } 2616 } 2617 if (finish) { 2618 /* 2619 * If the finish flag is true, we must loop until we hit 2620 * end-of-file on the pipe. This is guaranteed to happen 2621 * eventually since the other end of the pipe is now closed 2622 * (we closed it explicitly and the child has exited). When 2623 * we do get an EOF, finish will be set FALSE and we'll fall 2624 * through and out. 2625 */ 2626 goto end_loop; 2627 } 2628 } 2629 else 2630 #endif /* USE_PIPES */ 2631 { 2632 /* 2633 * We've been called to retrieve the output of the job from the 2634 * temporary file where it's been squirreled away. This consists of 2635 * opening the file, reading the output line by line, being sure not 2636 * to print the noPrint line for the shell we used, then close and 2637 * remove the temporary file. Very simple. 2638 * 2639 * Change to read in blocks and do FindSubString type things as for 2640 * pipes? That would allow for "@echo -n..." 2641 */ 2642 oFILE = fopen(job->outFile, "r"); 2643 if (oFILE != NULL) { 2644 (void) fprintf(stdout, "Results of making %s:\n", job->node->name); 2645 (void) fflush(stdout); 2646 while (fgets(inLine, sizeof(inLine), oFILE) != NULL) { 2647 register char *cp, *endp, *oendp; 2648 2649 cp = inLine; 2650 oendp = endp = inLine + strlen(inLine); 2651 if (endp[-1] == '\n') { 2652 *--endp = '\0'; 2653 } 2654 cp = JobOutput(job, inLine, endp, FALSE); 2655 2656 /* 2657 * There's still more in that thar buffer. This time, though, 2658 * we know there's no newline at the end, so we add one of 2659 * our own efree will. 2660 */ 2661 (void) fprintf(stdout, "%s", cp); 2662 (void) fflush(stdout); 2663 if (endp != oendp) { 2664 (void) fprintf(stdout, "\n"); 2665 (void) fflush(stdout); 2666 } 2667 } 2668 (void) fclose(oFILE); 2669 (void) eunlink(job->outFile); 2670 } 2263 2671 } 2264 2672 } … … 2267 2675 *----------------------------------------------------------------------- 2268 2676 * Job_CatchChildren -- 2269 * Handle the exit of a child. Called from Make_Make.2677 * Handle the exit of a child. Called from Make_Make. 2270 2678 * 2271 2679 * Results: 2272 * none.2680 * none. 2273 2681 * 2274 2682 * Side Effects: 2275 * The job descriptor is removed from the list of children.2683 * The job descriptor is removed from the list of children. 2276 2684 * 2277 2685 * Notes: 2278 * We do waits, blocking or not, according to the wisdom of our2279 * caller, until there are no more children to report. For each2280 * job, call JobFinish to finish things off. This will take care of2281 * putting jobs on the stoppedJobs queue.2686 * We do waits, blocking or not, according to the wisdom of our 2687 * caller, until there are no more children to report. For each 2688 * job, call JobFinish to finish things off. This will take care of 2689 * putting jobs on the stoppedJobs queue. 2282 2690 * 2283 2691 *----------------------------------------------------------------------- … … 2285 2693 void 2286 2694 Job_CatchChildren(block) 2287 Boolean block;/* TRUE if should block on the wait. */2695 Boolean block; /* TRUE if should block on the wait. */ 2288 2696 { 2289 int pid; /* pid of dead child */ 2290 register Job *job; /* job descriptor for dead child */ 2291 LstNode jnode; /* list element for finding job */ 2292 int status; /* Exit/termination status */ 2697 #ifdef USE_KLIB 2698 int pid; /* pid of dead child */ 2699 register Job *job; /* job descriptor for dead child */ 2700 LstNode jnode; /* list element for finding job */ 2701 KPROCRES status; /* Exit/termination status */ 2293 2702 2294 2703 /* … … 2296 2705 */ 2297 2706 if (nLocal == 0) { 2298 return; 2707 return; 2708 } 2709 2710 while (!kProcWait(KPID_NULL, KPROCWAIT_FLAGS_NOWAIT, &status, &pid)) 2711 { 2712 if (DEBUG(JOB)) { 2713 (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); 2714 (void) fflush(stdout); 2715 } 2716 2717 jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); 2718 if (jnode == NILLNODE) { 2719 Error("Child (%d) not in table?", pid); 2720 continue; 2721 } else { 2722 job = (Job *) Lst_Datum(jnode); 2723 (void) Lst_Remove(jobs, jnode); 2724 nJobs -= 1; 2725 if (jobFull && DEBUG(JOB)) { 2726 (void) fprintf(stdout, "Job queue is no longer full.\n"); 2727 (void) fflush(stdout); 2728 } 2729 jobFull = FALSE; 2730 nLocal -= 1; 2731 } 2732 JobFinish(job, &status); 2733 } 2734 2735 #else /* Don't Use kLib */ 2736 int pid; /* pid of dead child */ 2737 register Job *job; /* job descriptor for dead child */ 2738 LstNode jnode; /* list element for finding job */ 2739 int status; /* Exit/termination status */ 2740 2741 /* 2742 * Don't even bother if we know there's no one around. 2743 */ 2744 if (nLocal == 0) { 2745 return; 2299 2746 } 2300 2747 2301 2748 while ((pid = waitpid((pid_t) -1, &status, 2302 (block?0:WNOHANG)|WUNTRACED)) > 0)2749 (block?0:WNOHANG)|WUNTRACED)) > 0) 2303 2750 { 2304 if (DEBUG(JOB)) {2305 (void) fprintf(stdout, "Process %d exited or stopped.\n", pid);2306 (void) fflush(stdout);2307 }2308 2309 2310 jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid);2311 2312 if (jnode == NILLNODE) {2313 if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) {2314 jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid);2315 if (jnode == NILLNODE) {2316 Error("Resumed child (%d) not in table", pid);2317 continue;2318 }2319 job = (Job *)Lst_Datum(jnode);2320 (void) Lst_Remove(stoppedJobs, jnode);2321 } else {2322 Error("Child (%d) not in table?", pid);2323 continue;2324 }2325 } else {2326 job = (Job *) Lst_Datum(jnode);2327 (void) Lst_Remove(jobs, jnode);2328 nJobs -= 1;2329 if (jobFull && DEBUG(JOB)) {2330 (void) fprintf(stdout, "Job queue is no longer full.\n");2331 (void) fflush(stdout);2332 }2333 jobFull = FALSE;2751 if (DEBUG(JOB)) { 2752 (void) fprintf(stdout, "Process %d exited or stopped.\n", pid); 2753 (void) fflush(stdout); 2754 } 2755 2756 2757 jnode = Lst_Find(jobs, (ClientData)&pid, JobCmpPid); 2758 2759 if (jnode == NILLNODE) { 2760 if (WIFSIGNALED(status) && (WTERMSIG(status) == SIGCONT)) { 2761 jnode = Lst_Find(stoppedJobs, (ClientData) &pid, JobCmpPid); 2762 if (jnode == NILLNODE) { 2763 Error("Resumed child (%d) not in table", pid); 2764 continue; 2765 } 2766 job = (Job *)Lst_Datum(jnode); 2767 (void) Lst_Remove(stoppedJobs, jnode); 2768 } else { 2769 Error("Child (%d) not in table?", pid); 2770 continue; 2771 } 2772 } else { 2773 job = (Job *) Lst_Datum(jnode); 2774 (void) Lst_Remove(jobs, jnode); 2775 nJobs -= 1; 2776 if (jobFull && DEBUG(JOB)) { 2777 (void) fprintf(stdout, "Job queue is no longer full.\n"); 2778 (void) fflush(stdout); 2779 } 2780 jobFull = FALSE; 2334 2781 #ifdef REMOTE 2335 if (!(job->flags & JOB_REMOTE)) {2336 if (DEBUG(JOB)) {2337 (void) fprintf(stdout,2338 "Job queue has one fewer local process.\n");2339 (void) fflush(stdout);2340 }2341 nLocal -= 1;2342 }2782 if (!(job->flags & JOB_REMOTE)) { 2783 if (DEBUG(JOB)) { 2784 (void) fprintf(stdout, 2785 "Job queue has one fewer local process.\n"); 2786 (void) fflush(stdout); 2787 } 2788 nLocal -= 1; 2789 } 2343 2790 #else 2344 nLocal -= 1; 2345 #endif 2346 } 2347 2348 JobFinish(job, &status); 2349 } 2791 nLocal -= 1; 2792 #endif 2793 } 2794 2795 JobFinish(job, &status); 2796 } 2797 #endif /* USE_KLIB */ 2350 2798 } 2351 2799 … … 2353 2801 *----------------------------------------------------------------------- 2354 2802 * Job_CatchOutput -- 2355 * Catch the output from our children, if we're using2356 * pipes do so. Otherwise just block time until we get a2357 * signal (most likely a SIGCHLD) since there's no point in2358 * just spinning when there's nothing to do and the reaping2359 * of a child can wait for a while.2803 * Catch the output from our children, if we're using 2804 * pipes do so. Otherwise just block time until we get a 2805 * signal (most likely a SIGCHLD) since there's no point in 2806 * just spinning when there's nothing to do and the reaping 2807 * of a child can wait for a while. 2360 2808 * 2361 2809 * Results: 2362 * None2810 * None 2363 2811 * 2364 2812 * Side Effects: 2365 * Output is read from pipes if we're piping.2813 * Output is read from pipes if we're piping. 2366 2814 * ----------------------------------------------------------------------- 2367 2815 */ … … 2369 2817 Job_CatchOutput() 2370 2818 { 2371 int nfds;2372 struct timeval timeout;2373 fd_set readfds;2374 register LstNode ln;2375 register Job *job;2819 int nfds; 2820 struct timeval timeout; 2821 fd_set readfds; 2822 register LstNode ln; 2823 register Job *job; 2376 2824 #ifdef RMT_WILL_WATCH 2377 int pnJobs;/* Previous nJobs */2825 int pnJobs; /* Previous nJobs */ 2378 2826 #endif 2379 2827 … … 2399 2847 */ 2400 2848 while (nJobs != 0 && pnJobs == nJobs) { 2401 Rmt_Wait();2849 Rmt_Wait(); 2402 2850 } 2403 2851 #else 2852 #ifdef USE_PIPES 2404 2853 if (usePipes) { 2405 readfds = outputs; 2406 timeout.tv_sec = SEL_SEC; 2407 timeout.tv_usec = SEL_USEC; 2408 2409 if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, 2410 (fd_set *) 0, &timeout)) <= 0) 2411 return; 2412 else { 2413 if (Lst_Open(jobs) == FAILURE) { 2414 Punt("Cannot open job table"); 2415 } 2416 while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) { 2417 job = (Job *) Lst_Datum(ln); 2418 if (FD_ISSET(job->inPipe, &readfds)) { 2419 JobDoOutput(job, FALSE); 2420 nfds -= 1; 2421 } 2422 } 2423 Lst_Close(jobs); 2424 } 2425 } 2854 readfds = outputs; 2855 timeout.tv_sec = SEL_SEC; 2856 timeout.tv_usec = SEL_USEC; 2857 2858 if ((nfds = select(FD_SETSIZE, &readfds, (fd_set *) 0, 2859 (fd_set *) 0, &timeout)) <= 0) 2860 return; 2861 else { 2862 if (Lst_Open(jobs) == FAILURE) { 2863 Punt("Cannot open job table"); 2864 } 2865 while (nfds && (ln = Lst_Next(jobs)) != NILLNODE) { 2866 job = (Job *) Lst_Datum(ln); 2867 if (FD_ISSET(job->inPipe, &readfds)) { 2868 JobDoOutput(job, FALSE); 2869 nfds -= 1; 2870 } 2871 } 2872 Lst_Close(jobs); 2873 } 2874 } 2875 #endif /* USE_PIPES */ 2426 2876 #endif /* RMT_WILL_WATCH */ 2427 2877 } … … 2430 2880 *----------------------------------------------------------------------- 2431 2881 * Job_Make -- 2432 * Start the creation of a target. Basically a front-end for2433 * JobStart used by the Make module.2882 * Start the creation of a target. Basically a front-end for 2883 * JobStart used by the Make module. 2434 2884 * 2435 2885 * Results: 2436 * None.2886 * None. 2437 2887 * 2438 2888 * Side Effects: 2439 * Another job is started.2889 * Another job is started. 2440 2890 * 2441 2891 *----------------------------------------------------------------------- … … 2451 2901 *----------------------------------------------------------------------- 2452 2902 * Job_Init -- 2453 * Initialize the process module2903 * Initialize the process module 2454 2904 * 2455 2905 * Results: 2456 * none2906 * none 2457 2907 * 2458 2908 * Side Effects: 2459 * lists and counters are initialized2909 * lists and counters are initialized 2460 2910 *----------------------------------------------------------------------- 2461 2911 */ … … 2463 2913 Job_Init(maxproc, maxlocal) 2464 2914 int maxproc; /* the greatest number of jobs which may be 2465 * running at one time */2466 int maxlocal; /* the greatest number of local jobs which may2467 * be running at once. */2915 * running at one time */ 2916 int maxlocal; /* the greatest number of local jobs which may 2917 * be running at once. */ 2468 2918 { 2469 2919 GNode *begin; /* node for commands to do at the very start */ 2470 2920 2471 jobs = Lst_Init(FALSE); 2921 jobs = Lst_Init(FALSE); 2922 #ifdef SIGCONT 2472 2923 stoppedJobs = Lst_Init(FALSE); 2473 maxJobs = maxproc; 2474 maxLocal = maxlocal; 2475 nJobs = 0; 2476 nLocal = 0; 2477 jobFull = FALSE; 2478 2479 aborting = 0; 2480 errors = 0; 2481 2482 lastNode = NILGNODE; 2924 #endif 2925 maxJobs = maxproc; 2926 maxLocal = maxlocal; 2927 nJobs = 0; 2928 nLocal = 0; 2929 jobFull = FALSE; 2930 2931 aborting = 0; 2932 errors = 0; 2933 2934 lastNode = NILGNODE; 2483 2935 2484 2936 if (maxJobs == 1 || beVerbose == 0 2485 2937 #ifdef REMOTE 2486 || noMessages2487 #endif 2488 ) {2489 /*2490 * If only one job can run at a time, there's no need for a banner,2491 * no is there?2492 */2493 targFmt = "";2938 || noMessages 2939 #endif 2940 ) { 2941 /* 2942 * If only one job can run at a time, there's no need for a banner, 2943 * no is there? 2944 */ 2945 targFmt = ""; 2494 2946 } else { 2495 targFmt = TARG_FMT;2947 targFmt = TARG_FMT; 2496 2948 } 2497 2949 2498 2950 #ifndef KMK 2499 2951 if (shellPath == NULL) { 2500 /*2501 * The user didn't specify a shell to use, so we are using the2502 * default one... Both the absolute path and the last component2503 * must be set. The last component is taken from the 'name' field2504 * of the default shell description pointed-to by commandShell.2505 * All default shells are located in _PATH_DEFSHELLDIR.2506 */2507 shellName = commandShell->name;2508 shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH);2952 /* 2953 * The user didn't specify a shell to use, so we are using the 2954 * default one... Both the absolute path and the last component 2955 * must be set. The last component is taken from the 'name' field 2956 * of the default shell description pointed-to by commandShell. 2957 * All default shells are located in _PATH_DEFSHELLDIR. 2958 */ 2959 shellName = commandShell->name; 2960 shellPath = str_concat(_PATH_DEFSHELLDIR, shellName, STR_ADDSLASH); 2509 2961 } 2510 2962 2511 2963 if (commandShell->exit == NULL) { 2512 commandShell->exit = "";2964 commandShell->exit = ""; 2513 2965 } 2514 2966 if (commandShell->echo == NULL) { 2515 commandShell->echo = "";2967 commandShell->echo = ""; 2516 2968 } 2517 2969 #endif … … 2522 2974 */ 2523 2975 if (signal(SIGINT, SIG_IGN) != SIG_IGN) { 2524 (void) signal(SIGINT, JobPassSig); 2525 } 2976 (void) signal(SIGINT, JobPassSig); 2977 } 2978 #ifdef SIGHUP /* not all systems supports this signal */ 2526 2979 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 2527 (void) signal(SIGHUP, JobPassSig); 2528 } 2980 (void) signal(SIGHUP, JobPassSig); 2981 } 2982 #endif 2983 #ifdef SIGQUIT /* not all systems supports this signal */ 2529 2984 if (signal(SIGQUIT, SIG_IGN) != SIG_IGN) { 2530 (void) signal(SIGQUIT, JobPassSig); 2531 } 2985 (void) signal(SIGQUIT, JobPassSig); 2986 } 2987 #endif 2532 2988 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 2533 (void) signal(SIGTERM, JobPassSig);2989 (void) signal(SIGTERM, JobPassSig); 2534 2990 } 2535 2991 /* … … 2541 2997 #if defined(RMT_WANTS_SIGNALS) || defined(USE_PGRP) 2542 2998 if (signal(SIGTSTP, SIG_IGN) != SIG_IGN) { 2543 (void) signal(SIGTSTP, JobPassSig);2999 (void) signal(SIGTSTP, JobPassSig); 2544 3000 } 2545 3001 if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 2546 (void) signal(SIGTTOU, JobPassSig);3002 (void) signal(SIGTTOU, JobPassSig); 2547 3003 } 2548 3004 if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 2549 (void) signal(SIGTTIN, JobPassSig);3005 (void) signal(SIGTTIN, JobPassSig); 2550 3006 } 2551 3007 if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 2552 (void) signal(SIGWINCH, JobPassSig);3008 (void) signal(SIGWINCH, JobPassSig); 2553 3009 } 2554 3010 #endif … … 2557 3013 2558 3014 if (begin != NILGNODE) { 2559 JobStart(begin, JOB_SPECIAL, (Job *)0);2560 while (nJobs) {2561 Job_CatchOutput();3015 JobStart(begin, JOB_SPECIAL, (Job *)0); 3016 while (nJobs) { 3017 Job_CatchOutput(); 2562 3018 #ifndef RMT_WILL_WATCH 2563 Job_CatchChildren(!usePipes);3019 Job_CatchChildren(!usePipes); 2564 3020 #endif /* RMT_WILL_WATCH */ 2565 }3021 } 2566 3022 } 2567 3023 postCommands = Targ_FindNode(".END", TARG_CREATE); … … 2571 3027 *----------------------------------------------------------------------- 2572 3028 * Job_Full -- 2573 * See if the job table is full. It is considered full if it is OR2574 * if we are in the process of aborting OR if we have2575 * reached/exceeded our local quota. This prevents any more jobs2576 * from starting up.3029 * See if the job table is full. It is considered full if it is OR 3030 * if we are in the process of aborting OR if we have 3031 * reached/exceeded our local quota. This prevents any more jobs 3032 * from starting up. 2577 3033 * 2578 3034 * Results: 2579 * TRUE if the job table is full, FALSE otherwise3035 * TRUE if the job table is full, FALSE otherwise 2580 3036 * Side Effects: 2581 * None.3037 * None. 2582 3038 *----------------------------------------------------------------------- 2583 3039 */ … … 2591 3047 *----------------------------------------------------------------------- 2592 3048 * Job_Empty -- 2593 * See if the job table is empty. Because the local concurrency may2594 * be set to 0, it is possible for the job table to become empty,2595 * while the list of stoppedJobs remains non-empty. In such a case,2596 * we want to restart as many jobs as we can.3049 * See if the job table is empty. Because the local concurrency may 3050 * be set to 0, it is possible for the job table to become empty, 3051 * while the list of stoppedJobs remains non-empty. In such a case, 3052 * we want to restart as many jobs as we can. 2597 3053 * 2598 3054 * Results: 2599 * TRUE if it is. FALSE if it ain't.3055 * TRUE if it is. FALSE if it ain't. 2600 3056 * 2601 3057 * Side Effects: 2602 * None.3058 * None. 2603 3059 * 2604 3060 * ----------------------------------------------------------------------- … … 2608 3064 { 2609 3065 if (nJobs == 0) { 2610 if (!Lst_IsEmpty(stoppedJobs) && !aborting) { 2611 /* 2612 * The job table is obviously not full if it has no jobs in 2613 * it...Try and restart the stopped jobs. 2614 */ 2615 jobFull = FALSE; 2616 JobRestartJobs(); 2617 return(FALSE); 2618 } else { 2619 return(TRUE); 2620 } 3066 #ifdef SIGCONT 3067 if (!Lst_IsEmpty(stoppedJobs) && !aborting) { 3068 /* 3069 * The job table is obviously not full if it has no jobs in 3070 * it...Try and restart the stopped jobs. 3071 */ 3072 jobFull = FALSE; 3073 JobRestartJobs(); 3074 return(FALSE); 3075 } 3076 #else 3077 return(TRUE); 3078 #endif 2621 3079 } else { 2622 return(FALSE);3080 return(FALSE); 2623 3081 } 2624 3082 } … … 2628 3086 *----------------------------------------------------------------------- 2629 3087 * JobMatchShell -- 2630 * Find a matching shell in 'shells' given its final component.3088 * Find a matching shell in 'shells' given its final component. 2631 3089 * 2632 3090 * Results: 2633 * A pointer to the Shell structure.3091 * A pointer to the Shell structure. 2634 3092 * 2635 3093 * Side Effects: 2636 * None.3094 * None. 2637 3095 * 2638 3096 *----------------------------------------------------------------------- … … 2640 3098 static Shell * 2641 3099 JobMatchShell(name) 2642 char *name; /* Final component of shell path */3100 char *name; /* Final component of shell path */ 2643 3101 { 2644 register Shell *sh; /* Pointer into shells table */2645 Shell *match; /* Longest-matching shell */3102 register Shell *sh; /* Pointer into shells table */ 3103 Shell *match; /* Longest-matching shell */ 2646 3104 register char *cp1, 2647 *cp2;2648 char *eoname;3105 *cp2; 3106 char *eoname; 2649 3107 2650 3108 eoname = name + strlen(name); … … 2653 3111 2654 3112 for (sh = shells; sh->name != NULL; sh++) { 2655 for (cp1 = eoname - strlen(sh->name), cp2 = sh->name;2656 *cp1 != '\0' && *cp1 == *cp2;2657 cp1++, cp2++) {2658 continue;2659 }2660 if (*cp1 != *cp2) {2661 continue;2662 } else if (match == NULL || strlen(match->name) < strlen(sh->name)) {2663 match = sh;2664 }3113 for (cp1 = eoname - strlen(sh->name), cp2 = sh->name; 3114 *cp1 != '\0' && *cp1 == *cp2; 3115 cp1++, cp2++) { 3116 continue; 3117 } 3118 if (*cp1 != *cp2) { 3119 continue; 3120 } else if (match == NULL || strlen(match->name) < strlen(sh->name)) { 3121 match = sh; 3122 } 2665 3123 } 2666 3124 return(match == NULL ? sh : match); … … 2672 3130 *----------------------------------------------------------------------- 2673 3131 * Job_ParseShell -- 2674 * Parse a shell specification and set up commandShell, shellPath2675 * and shellName appropriately.3132 * Parse a shell specification and set up commandShell, shellPath 3133 * and shellName appropriately. 2676 3134 * 2677 3135 * Results: 2678 * FAILURE if the specification was incorrect.3136 * FAILURE if the specification was incorrect. 2679 3137 * 2680 3138 * Side Effects: 2681 * commandShell points to a Shell structure (either predefined or2682 * created from the shell spec), shellPath is the full path of the2683 * shell described by commandShell, while shellName is just the2684 * final component of shellPath.3139 * commandShell points to a Shell structure (either predefined or 3140 * created from the shell spec), shellPath is the full path of the 3141 * shell described by commandShell, while shellName is just the 3142 * final component of shellPath. 2685 3143 * 2686 3144 * Notes: 2687 * A shell specification consists of a .SHELL target, with dependency2688 * operator, followed by a series of blank-separated words. Double2689 * quotes can be used to use blanks in words. A backslash escapes2690 * anything (most notably a double-quote and a space) and2691 * provides the functionality it does in C. Each word consists of2692 * keyword and value separated by an equal sign. There should be no2693 * unnecessary spaces in the word. The keywords are as follows:2694 * nameName of shell.2695 * pathLocation of shell. Overrides "name" if given2696 * quietCommand to turn off echoing.2697 * echoCommand to turn echoing on2698 * filterResult of turning off echoing that shouldn't be2699 * printed.2700 * echoFlagFlag to turn echoing on at the start2701 * errFlagFlag to turn error checking on at the start2702 * hasErrCtlTrue if shell has error checking control2703 * checkCommand to turn on error checking if hasErrCtl2704 * is TRUE or template of command to echo a command2705 * for which error checking is off if hasErrCtl is2706 * FALSE.2707 * ignoreCommand to turn off error checking if hasErrCtl2708 * is TRUE or template of command to execute a2709 * command so as to ignore any errors it returns if2710 * hasErrCtl is FALSE.3145 * A shell specification consists of a .SHELL target, with dependency 3146 * operator, followed by a series of blank-separated words. Double 3147 * quotes can be used to use blanks in words. A backslash escapes 3148 * anything (most notably a double-quote and a space) and 3149 * provides the functionality it does in C. Each word consists of 3150 * keyword and value separated by an equal sign. There should be no 3151 * unnecessary spaces in the word. The keywords are as follows: 3152 * name Name of shell. 3153 * path Location of shell. Overrides "name" if given 3154 * quiet Command to turn off echoing. 3155 * echo Command to turn echoing on 3156 * filter Result of turning off echoing that shouldn't be 3157 * printed. 3158 * echoFlag Flag to turn echoing on at the start 3159 * errFlag Flag to turn error checking on at the start 3160 * hasErrCtl True if shell has error checking control 3161 * check Command to turn on error checking if hasErrCtl 3162 * is TRUE or template of command to echo a command 3163 * for which error checking is off if hasErrCtl is 3164 * FALSE. 3165 * ignore Command to turn off error checking if hasErrCtl 3166 * is TRUE or template of command to execute a 3167 * command so as to ignore any errors it returns if 3168 * hasErrCtl is FALSE. 2711 3169 * 2712 3170 *----------------------------------------------------------------------- … … 2714 3172 ReturnStatus 2715 3173 Job_ParseShell(line) 2716 char *line; /* The shell spec */3174 char *line; /* The shell spec */ 2717 3175 { 2718 char **words;2719 int wordCount;3176 char **words; 3177 int wordCount; 2720 3178 register char **argv; 2721 3179 register int argc; 2722 char *path;2723 Shell newShell;2724 Boolean fullSpec = FALSE;3180 char *path; 3181 Shell newShell; 3182 Boolean fullSpec = FALSE; 2725 3183 2726 3184 while (isspace(*line)) { 2727 line++;3185 line++; 2728 3186 } 2729 3187 words = brk_string(line, &wordCount, TRUE); … … 2735 3193 */ 2736 3194 for (path = NULL, argc = wordCount - 1, argv = words + 1; 2737 argc != 0;2738 argc--, argv++) {2739 if (strncmp(*argv, "path=", 5) == 0) {2740 path = &argv[0][5];2741 } else if (strncmp(*argv, "name=", 5) == 0) {2742 newShell.name = &argv[0][5];2743 } else {2744 if (strncmp(*argv, "quiet=", 6) == 0) {2745 newShell.echoOff = &argv[0][6];2746 } else if (strncmp(*argv, "echo=", 5) == 0) {2747 newShell.echoOn = &argv[0][5];2748 } else if (strncmp(*argv, "filter=", 7) == 0) {2749 newShell.noPrint = &argv[0][7];2750 newShell.noPLen = strlen(newShell.noPrint);2751 } else if (strncmp(*argv, "echoFlag=", 9) == 0) {2752 newShell.echo = &argv[0][9];2753 } else if (strncmp(*argv, "errFlag=", 8) == 0) {2754 newShell.exit = &argv[0][8];2755 } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) {2756 char c = argv[0][10];2757 newShell.hasErrCtl = !((c != 'Y') && (c != 'y') &&2758 (c != 'T') && (c != 't'));2759 } else if (strncmp(*argv, "check=", 6) == 0) {2760 newShell.errCheck = &argv[0][6];2761 } else if (strncmp(*argv, "ignore=", 7) == 0) {2762 newShell.ignErr = &argv[0][7];2763 } else {2764 Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"",2765 *argv);2766 return(FAILURE);2767 }2768 fullSpec = TRUE;2769 }3195 argc != 0; 3196 argc--, argv++) { 3197 if (strncmp(*argv, "path=", 5) == 0) { 3198 path = &argv[0][5]; 3199 } else if (strncmp(*argv, "name=", 5) == 0) { 3200 newShell.name = &argv[0][5]; 3201 } else { 3202 if (strncmp(*argv, "quiet=", 6) == 0) { 3203 newShell.echoOff = &argv[0][6]; 3204 } else if (strncmp(*argv, "echo=", 5) == 0) { 3205 newShell.echoOn = &argv[0][5]; 3206 } else if (strncmp(*argv, "filter=", 7) == 0) { 3207 newShell.noPrint = &argv[0][7]; 3208 newShell.noPLen = strlen(newShell.noPrint); 3209 } else if (strncmp(*argv, "echoFlag=", 9) == 0) { 3210 newShell.echo = &argv[0][9]; 3211 } else if (strncmp(*argv, "errFlag=", 8) == 0) { 3212 newShell.exit = &argv[0][8]; 3213 } else if (strncmp(*argv, "hasErrCtl=", 10) == 0) { 3214 char c = argv[0][10]; 3215 newShell.hasErrCtl = !((c != 'Y') && (c != 'y') && 3216 (c != 'T') && (c != 't')); 3217 } else if (strncmp(*argv, "check=", 6) == 0) { 3218 newShell.errCheck = &argv[0][6]; 3219 } else if (strncmp(*argv, "ignore=", 7) == 0) { 3220 newShell.ignErr = &argv[0][7]; 3221 } else { 3222 Parse_Error(PARSE_FATAL, "Unknown keyword \"%s\"", 3223 *argv); 3224 return(FAILURE); 3225 } 3226 fullSpec = TRUE; 3227 } 2770 3228 } 2771 3229 2772 3230 if (path == NULL) { 2773 /*2774 * If no path was given, the user wants one of the pre-defined shells,2775 * yes? So we find the one s/he wants with the help of JobMatchShell2776 * and set things up the right way. shellPath will be set up by2777 * Job_Init.2778 */2779 if (newShell.name == NULL) {2780 Parse_Error(PARSE_FATAL, "Neither path nor name specified");2781 return(FAILURE);2782 } else {2783 commandShell = JobMatchShell(newShell.name);2784 shellName = newShell.name;2785 }3231 /* 3232 * If no path was given, the user wants one of the pre-defined shells, 3233 * yes? So we find the one s/he wants with the help of JobMatchShell 3234 * and set things up the right way. shellPath will be set up by 3235 * Job_Init. 3236 */ 3237 if (newShell.name == NULL) { 3238 Parse_Error(PARSE_FATAL, "Neither path nor name specified"); 3239 return(FAILURE); 3240 } else { 3241 commandShell = JobMatchShell(newShell.name); 3242 shellName = newShell.name; 3243 } 2786 3244 } else { 2787 /*2788 * The user provided a path. If s/he gave nothing else (fullSpec is2789 * FALSE), try and find a matching shell in the ones we know of.2790 * Else we just take the specification at its word and copy it2791 * to a new location. In either case, we need to record the2792 * path the user gave for the shell.2793 */2794 shellPath = path;2795 path = strrchr(path, '/');2796 if (path == NULL) {2797 path = shellPath;2798 } else {2799 path += 1;2800 }2801 if (newShell.name != NULL) {2802 shellName = newShell.name;2803 } else {2804 shellName = path;2805 }2806 if (!fullSpec) {2807 commandShell = JobMatchShell(shellName);2808 } else {2809 commandShell = (Shell *) emalloc(sizeof(Shell));2810 *commandShell = newShell;2811 }3245 /* 3246 * The user provided a path. If s/he gave nothing else (fullSpec is 3247 * FALSE), try and find a matching shell in the ones we know of. 3248 * Else we just take the specification at its word and copy it 3249 * to a new location. In either case, we need to record the 3250 * path the user gave for the shell. 3251 */ 3252 shellPath = path; 3253 path = strrchr(path, '/'); 3254 if (path == NULL) { 3255 path = shellPath; 3256 } else { 3257 path += 1; 3258 } 3259 if (newShell.name != NULL) { 3260 shellName = newShell.name; 3261 } else { 3262 shellName = path; 3263 } 3264 if (!fullSpec) { 3265 commandShell = JobMatchShell(shellName); 3266 } else { 3267 commandShell = (Shell *) emalloc(sizeof(Shell)); 3268 *commandShell = newShell; 3269 } 2812 3270 } 2813 3271 2814 3272 if (commandShell->echoOn && commandShell->echoOff) { 2815 commandShell->hasEchoCtl = TRUE;3273 commandShell->hasEchoCtl = TRUE; 2816 3274 } 2817 3275 2818 3276 if (!commandShell->hasErrCtl) { 2819 if (commandShell->errCheck == NULL) {2820 commandShell->errCheck = "";2821 }2822 if (commandShell->ignErr == NULL) {2823 commandShell->ignErr = "%s\n";2824 }3277 if (commandShell->errCheck == NULL) { 3278 commandShell->errCheck = ""; 3279 } 3280 if (commandShell->ignErr == NULL) { 3281 commandShell->ignErr = "%s\n"; 3282 } 2825 3283 } 2826 3284 … … 2837 3295 *----------------------------------------------------------------------- 2838 3296 * JobInterrupt -- 2839 * Handle the receipt of an interrupt.3297 * Handle the receipt of an interrupt. 2840 3298 * 2841 3299 * Results: 2842 * None3300 * None 2843 3301 * 2844 3302 * Side Effects: 2845 * All children are killed. Another job will be started if the2846 * .INTERRUPT target was given.3303 * All children are killed. Another job will be started if the 3304 * .INTERRUPT target was given. 2847 3305 *----------------------------------------------------------------------- 2848 3306 */ 2849 3307 static void 2850 3308 JobInterrupt(runINTERRUPT, signo) 2851 int runINTERRUPT;/* Non-zero if commands for the .INTERRUPT2852 * target should be executed */2853 int signo;/* signal received */3309 int runINTERRUPT; /* Non-zero if commands for the .INTERRUPT 3310 * target should be executed */ 3311 int signo; /* signal received */ 2854 3312 { 2855 LstNode ln;/* element in job table */2856 Job *job = NULL; /* job descriptor in that element */2857 GNode *interrupt; /* the node describing the .INTERRUPT target */3313 LstNode ln; /* element in job table */ 3314 Job *job = NULL; /* job descriptor in that element */ 3315 GNode *interrupt; /* the node describing the .INTERRUPT target */ 2858 3316 2859 3317 aborting = ABORT_INTERRUPT; … … 2861 3319 (void) Lst_Open(jobs); 2862 3320 while ((ln = Lst_Next(jobs)) != NILLNODE) { 2863 job = (Job *) Lst_Datum(ln);2864 2865 if (!Targ_Precious(job->node)) {2866 char*file = (job->node->path == NULL ?2867 job->node->name :2868 job->node->path);2869 if (!noExecute && eunlink(file) != -1) {2870 Error("*** %s removed", file);2871 }2872 }3321 job = (Job *) Lst_Datum(ln); 3322 3323 if (!Targ_Precious(job->node)) { 3324 char *file = (job->node->path == NULL ? 3325 job->node->name : 3326 job->node->path); 3327 if (!noExecute && eunlink(file) != -1) { 3328 Error("*** %s removed", file); 3329 } 3330 } 2873 3331 #ifdef RMT_WANTS_SIGNALS 2874 if (job->flags & JOB_REMOTE) {2875 /*2876 * If job is remote, let the Rmt module do the killing.2877 */2878 if (!Rmt_Signal(job, signo)) {2879 /*2880 * If couldn't kill the thing, finish it out now with an2881 * error code, since no exit report will come in likely.2882 */2883 int status;2884 2885 status.w_status = 0;2886 status.w_retcode = 1;2887 JobFinish(job, &status);2888 }2889 } else if (job->pid) {2890 KILL(job->pid, signo);2891 }3332 if (job->flags & JOB_REMOTE) { 3333 /* 3334 * If job is remote, let the Rmt module do the killing. 3335 */ 3336 if (!Rmt_Signal(job, signo)) { 3337 /* 3338 * If couldn't kill the thing, finish it out now with an 3339 * error code, since no exit report will come in likely. 3340 */ 3341 int status; 3342 3343 status.w_status = 0; 3344 status.w_retcode = 1; 3345 JobFinish(job, &status); 3346 } 3347 } else if (job->pid) { 3348 KILL(job->pid, signo); 3349 } 2892 3350 #else 2893 if (job->pid) {2894 if (DEBUG(JOB)) {2895 (void) fprintf(stdout,2896 "JobInterrupt passing signal to child %d.\n",2897 job->pid);2898 (void) fflush(stdout);2899 }2900 KILL(job->pid, signo);2901 }3351 if (job->pid) { 3352 if (DEBUG(JOB)) { 3353 (void) fprintf(stdout, 3354 "JobInterrupt passing signal to child %d.\n", 3355 job->pid); 3356 (void) fflush(stdout); 3357 } 3358 KILL(job->pid, signo); 3359 } 2902 3360 #endif /* RMT_WANTS_SIGNALS */ 2903 3361 } … … 2906 3364 (void)Lst_Open(stoppedJobs); 2907 3365 while ((ln = Lst_Next(stoppedJobs)) != NILLNODE) { 2908 job = (Job *) Lst_Datum(ln);2909 2910 if (job->flags & JOB_RESTART) {2911 if (DEBUG(JOB)) {2912 (void) fprintf(stdout, "%s%s",2913 "JobInterrupt skipping job on stopped queue",2914 "-- it was waiting to be restarted.\n");2915 (void) fflush(stdout);2916 }2917 continue;2918 }2919 if (!Targ_Precious(job->node)) {2920 char*file = (job->node->path == NULL ?2921 job->node->name :2922 job->node->path);2923 if (eunlink(file) == 0) {2924 Error("*** %s removed", file);2925 }2926 }2927 /*2928 * Resume the thing so it will take the signal.2929 */2930 if (DEBUG(JOB)) {2931 (void) fprintf(stdout,2932 "JobInterrupt passing CONT to stopped child %d.\n",2933 job->pid);2934 (void) fflush(stdout);2935 }2936 KILL(job->pid, SIGCONT);3366 job = (Job *) Lst_Datum(ln); 3367 3368 if (job->flags & JOB_RESTART) { 3369 if (DEBUG(JOB)) { 3370 (void) fprintf(stdout, "%s%s", 3371 "JobInterrupt skipping job on stopped queue", 3372 "-- it was waiting to be restarted.\n"); 3373 (void) fflush(stdout); 3374 } 3375 continue; 3376 } 3377 if (!Targ_Precious(job->node)) { 3378 char *file = (job->node->path == NULL ? 3379 job->node->name : 3380 job->node->path); 3381 if (eunlink(file) == 0) { 3382 Error("*** %s removed", file); 3383 } 3384 } 3385 /* 3386 * Resume the thing so it will take the signal. 3387 */ 3388 if (DEBUG(JOB)) { 3389 (void) fprintf(stdout, 3390 "JobInterrupt passing CONT to stopped child %d.\n", 3391 job->pid); 3392 (void) fflush(stdout); 3393 } 3394 KILL(job->pid, SIGCONT); 2937 3395 #ifdef RMT_WANTS_SIGNALS 2938 if (job->flags & JOB_REMOTE) {2939 /*2940 * If job is remote, let the Rmt module do the killing.2941 */2942 if (!Rmt_Signal(job, SIGINT)) {2943 /*2944 * If couldn't kill the thing, finish it out now with an2945 * error code, since no exit report will come in likely.2946 */2947 int status;2948 status.w_status = 0;2949 status.w_retcode = 1;2950 JobFinish(job, &status);2951 }2952 } else if (job->pid) {2953 if (DEBUG(JOB)) {2954 (void) fprintf(stdout,2955 "JobInterrupt passing interrupt to stopped child %d.\n",2956 job->pid);2957 (void) fflush(stdout);2958 }2959 KILL(job->pid, SIGINT);2960 }3396 if (job->flags & JOB_REMOTE) { 3397 /* 3398 * If job is remote, let the Rmt module do the killing. 3399 */ 3400 if (!Rmt_Signal(job, SIGINT)) { 3401 /* 3402 * If couldn't kill the thing, finish it out now with an 3403 * error code, since no exit report will come in likely. 3404 */ 3405 int status; 3406 status.w_status = 0; 3407 status.w_retcode = 1; 3408 JobFinish(job, &status); 3409 } 3410 } else if (job->pid) { 3411 if (DEBUG(JOB)) { 3412 (void) fprintf(stdout, 3413 "JobInterrupt passing interrupt to stopped child %d.\n", 3414 job->pid); 3415 (void) fflush(stdout); 3416 } 3417 KILL(job->pid, SIGINT); 3418 } 2961 3419 #endif /* RMT_WANTS_SIGNALS */ 2962 3420 } 2963 #endif2964 3421 Lst_Close(stoppedJobs); 3422 #endif 2965 3423 2966 3424 if (runINTERRUPT && !touchFlag) { 2967 interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE);2968 if (interrupt != NILGNODE) {2969 ignoreErrors = FALSE;2970 2971 JobStart(interrupt, JOB_IGNDOTS, (Job *)0);2972 while (nJobs) {2973 Job_CatchOutput();3425 interrupt = Targ_FindNode(".INTERRUPT", TARG_NOCREATE); 3426 if (interrupt != NILGNODE) { 3427 ignoreErrors = FALSE; 3428 3429 JobStart(interrupt, JOB_IGNDOTS, (Job *)0); 3430 while (nJobs) { 3431 Job_CatchOutput(); 2974 3432 #ifndef RMT_WILL_WATCH 2975 Job_CatchChildren(!usePipes);3433 Job_CatchChildren(!usePipes); 2976 3434 #endif /* RMT_WILL_WATCH */ 2977 }2978 }3435 } 3436 } 2979 3437 } 2980 3438 } … … 2983 3441 *----------------------------------------------------------------------- 2984 3442 * Job_End -- 2985 * Do final processing such as the running of the commands2986 * attached to the .END target.3443 * Do final processing such as the running of the commands 3444 * attached to the .END target. 2987 3445 * 2988 3446 * Results: 2989 * Number of errors reported.3447 * Number of errors reported. 2990 3448 *----------------------------------------------------------------------- 2991 3449 */ … … 2994 3452 { 2995 3453 if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) { 2996 if (errors) {2997 Error("Errors reported so .END ignored");2998 } else {2999 JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL);3000 3001 while (nJobs) {3002 Job_CatchOutput();3454 if (errors) { 3455 Error("Errors reported so .END ignored"); 3456 } else { 3457 JobStart(postCommands, JOB_SPECIAL | JOB_IGNDOTS, NULL); 3458 3459 while (nJobs) { 3460 Job_CatchOutput(); 3003 3461 #ifndef RMT_WILL_WATCH 3004 Job_CatchChildren(!usePipes);3462 Job_CatchChildren(!usePipes); 3005 3463 #endif /* RMT_WILL_WATCH */ 3006 }3007 }3464 } 3465 } 3008 3466 } 3009 3467 return(errors); … … 3013 3471 *----------------------------------------------------------------------- 3014 3472 * Job_Wait -- 3015 * Waits for all running jobs to finish and returns. Sets 'aborting'3016 * to ABORT_WAIT to prevent other jobs from starting.3473 * Waits for all running jobs to finish and returns. Sets 'aborting' 3474 * to ABORT_WAIT to prevent other jobs from starting. 3017 3475 * 3018 3476 * Results: 3019 * None.3477 * None. 3020 3478 * 3021 3479 * Side Effects: 3022 * Currently running jobs finish.3480 * Currently running jobs finish. 3023 3481 * 3024 3482 *----------------------------------------------------------------------- … … 3029 3487 aborting = ABORT_WAIT; 3030 3488 while (nJobs != 0) { 3031 Job_CatchOutput();3489 Job_CatchOutput(); 3032 3490 #ifndef RMT_WILL_WATCH 3033 Job_CatchChildren(!usePipes);3491 Job_CatchChildren(!usePipes); 3034 3492 #endif /* RMT_WILL_WATCH */ 3035 3493 } … … 3040 3498 *----------------------------------------------------------------------- 3041 3499 * Job_AbortAll -- 3042 * Abort all currently running jobs without handling output or anything.3043 * This function is to be called only in the event of a major3044 * error. Most definitely NOT to be called from JobInterrupt.3500 * Abort all currently running jobs without handling output or anything. 3501 * This function is to be called only in the event of a major 3502 * error. Most definitely NOT to be called from JobInterrupt. 3045 3503 * 3046 3504 * Results: 3047 * None3505 * None 3048 3506 * 3049 3507 * Side Effects: 3050 * All children are killed, not just the firstborn3508 * All children are killed, not just the firstborn 3051 3509 *----------------------------------------------------------------------- 3052 3510 */ … … 3054 3512 Job_AbortAll() 3055 3513 { 3056 LstNode ln; /* element in job table */ 3057 Job *job; /* the job descriptor in that element */ 3058 int foo; 3514 #ifdef USE_KLIB 3515 LstNode ln; /* element in job table */ 3516 Job *job; /* the job descriptor in that element */ 3517 KPROCRES res; 3059 3518 3060 3519 aborting = ABORT_ERROR; 3061 3520 3521 if (nJobs) 3522 { 3523 Lst_Open(jobs); 3524 while ((ln = Lst_Next(jobs)) != NILLNODE) 3525 { 3526 job = (Job *) Lst_Datum(ln); 3527 3528 /* 3529 * kill the child process with increasingly drastic signals to make 3530 * darn sure it's dead. 3531 */ 3532 kProcKill(job->pid, KPROCKILL_FLAGS_TREE | KPROCKILL_FLAGS_TYPE_INT); 3533 kProcKill(job->pid, KPROCKILL_FLAGS_TREE | KPROCKILL_FLAGS_TYPE_KILL); 3534 } 3535 } 3536 3537 /* 3538 * Catch as many children as want to report in at first, then give up 3539 */ 3540 do 3541 { 3542 kThrdYield(); 3543 } while (!kProcWait(KPID_NULL, KPROCWAIT_FLAGS_NOWAIT, &res, NULL)); /** @todo checkout this call */ 3544 3545 #else /* Don't use kLib */ 3546 LstNode ln; /* element in job table */ 3547 Job *job; /* the job descriptor in that element */ 3548 int foo; 3549 3550 aborting = ABORT_ERROR; 3551 3062 3552 if (nJobs) { 3063 3553 3064 (void) Lst_Open(jobs);3065 while ((ln = Lst_Next(jobs)) != NILLNODE) {3066 job = (Job *) Lst_Datum(ln);3067 3068 /*3069 * kill the child process with increasingly drastic signals to make3070 * darn sure it's dead.3071 */3554 (void) Lst_Open(jobs); 3555 while ((ln = Lst_Next(jobs)) != NILLNODE) { 3556 job = (Job *) Lst_Datum(ln); 3557 3558 /* 3559 * kill the child process with increasingly drastic signals to make 3560 * darn sure it's dead. 3561 */ 3072 3562 #ifdef RMT_WANTS_SIGNALS 3073 if (job->flags & JOB_REMOTE) {3074 Rmt_Signal(job, SIGINT);3075 Rmt_Signal(job, SIGKILL);3076 } else {3077 KILL(job->pid, SIGINT);3078 KILL(job->pid, SIGKILL);3079 }3563 if (job->flags & JOB_REMOTE) { 3564 Rmt_Signal(job, SIGINT); 3565 Rmt_Signal(job, SIGKILL); 3566 } else { 3567 KILL(job->pid, SIGINT); 3568 KILL(job->pid, SIGKILL); 3569 } 3080 3570 #else 3081 KILL(job->pid, SIGINT);3082 KILL(job->pid, SIGKILL);3571 KILL(job->pid, SIGINT); 3572 KILL(job->pid, SIGKILL); 3083 3573 #endif /* RMT_WANTS_SIGNALS */ 3084 }3574 } 3085 3575 } 3086 3576 … … 3089 3579 */ 3090 3580 while (waitpid((pid_t) -1, &foo, WNOHANG) > 0) 3091 continue; 3581 continue; 3582 #endif /* USE_KLIB */ 3092 3583 } 3093 3584 … … 3096 3587 *----------------------------------------------------------------------- 3097 3588 * JobFlagForMigration -- 3098 * Handle the eviction of a child. Called from RmtStatusChange.3099 * Flags the child as remigratable and then suspends it.3589 * Handle the eviction of a child. Called from RmtStatusChange. 3590 * Flags the child as remigratable and then suspends it. 3100 3591 * 3101 3592 * Results: 3102 * none.3593 * none. 3103 3594 * 3104 3595 * Side Effects: 3105 * The job descriptor is flagged for remigration.3596 * The job descriptor is flagged for remigration. 3106 3597 * 3107 3598 *----------------------------------------------------------------------- … … 3109 3600 void 3110 3601 JobFlagForMigration(hostID) 3111 int hostID;/* ID of host we used, for matching children. */3602 int hostID; /* ID of host we used, for matching children. */ 3112 3603 { 3113 register Job *job; /* job descriptor for dead child */3114 LstNode jnode; /* list element for finding job */3604 register Job *job; /* job descriptor for dead child */ 3605 LstNode jnode; /* list element for finding job */ 3115 3606 3116 3607 if (DEBUG(JOB)) { 3117 (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID);3118 (void) fflush(stdout);3608 (void) fprintf(stdout, "JobFlagForMigration(%d) called.\n", hostID); 3609 (void) fflush(stdout); 3119 3610 } 3120 3611 jnode = Lst_Find(jobs, (ClientData)hostID, JobCmpRmtID); 3121 3612 3122 3613 if (jnode == NILLNODE) { 3123 jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID);3124 if (jnode == NILLNODE) {3125 if (DEBUG(JOB)) {3126 Error("Evicting host(%d) not in table", hostID);3127 }3128 return;3129 }3614 jnode = Lst_Find(stoppedJobs, (ClientData)hostID, JobCmpRmtID); 3615 if (jnode == NILLNODE) { 3616 if (DEBUG(JOB)) { 3617 Error("Evicting host(%d) not in table", hostID); 3618 } 3619 return; 3620 } 3130 3621 } 3131 3622 job = (Job *) Lst_Datum(jnode); 3132 3623 3133 3624 if (DEBUG(JOB)) { 3134 (void) fprintf(stdout,3135 "JobFlagForMigration(%d) found job '%s'.\n", hostID,3136 job->node->name);3137 (void) fflush(stdout);3625 (void) fprintf(stdout, 3626 "JobFlagForMigration(%d) found job '%s'.\n", hostID, 3627 job->node->name); 3628 (void) fflush(stdout); 3138 3629 } 3139 3630 … … 3146 3637 3147 3638 3639 #ifdef SIGCONT 3148 3640 /*- 3149 3641 *----------------------------------------------------------------------- 3150 3642 * JobRestartJobs -- 3151 * Tries to restart stopped jobs if there are slots available.3152 * Note that this tries to restart them regardless of pending errors.3153 * It's not good to leave stopped jobs lying around!3643 * Tries to restart stopped jobs if there are slots available. 3644 * Note that this tries to restart them regardless of pending errors. 3645 * It's not good to leave stopped jobs lying around! 3154 3646 * 3155 3647 * Results: 3156 * None.3648 * None. 3157 3649 * 3158 3650 * Side Effects: 3159 * Resumes(and possibly migrates) jobs.3651 * Resumes(and possibly migrates) jobs. 3160 3652 * 3161 3653 *----------------------------------------------------------------------- … … 3165 3657 { 3166 3658 while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { 3167 if (DEBUG(JOB)) {3168 (void) fprintf(stdout,3169 "Job queue is not full. Restarting a stopped job.\n");3170 (void) fflush(stdout);3171 }3172 JobRestart((Job *)Lst_DeQueue(stoppedJobs));3659 if (DEBUG(JOB)) { 3660 (void) fprintf(stdout, 3661 "Job queue is not full. Restarting a stopped job.\n"); 3662 (void) fflush(stdout); 3663 } 3664 JobRestart((Job *)Lst_DeQueue(stoppedJobs)); 3173 3665 } 3174 3666 } 3667 #endif -
trunk/src/kmk/job.h
r25 r51 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 36 36 * SUCH DAMAGE. 37 37 * 38 * from: @(#)job.h8.1 (Berkeley) 6/6/9338 * from: @(#)job.h 8.1 (Berkeley) 6/6/93 39 39 * $FreeBSD: src/usr.bin/make/job.h,v 1.11 2000/01/17 06:43:41 kris Exp $ 40 40 */ … … 42 42 /*- 43 43 * job.h -- 44 * Definitions pertaining to the running of jobs in parallel mode.45 * Exported from job.c for the use of remote-execution modules.44 * Definitions pertaining to the running of jobs in parallel mode. 45 * Exported from job.c for the use of remote-execution modules. 46 46 */ 47 47 #ifndef _JOB_H_ 48 48 #define _JOB_H_ 49 49 50 #define TMPPAT "/tmp/makeXXXXXXXXXX"50 #define TMPPAT "/tmp/makeXXXXXXXXXX" 51 51 52 52 /* … … 55 55 * seconds and SEL_USEC is the number of micro-seconds 56 56 */ 57 #define SEL_SEC 058 #define SEL_USEC 10000057 #define SEL_SEC 0 58 #define SEL_USEC 100000 59 59 60 60 … … 64 64 * 65 65 * Each job has several things associated with it: 66 * 1) The process id of the child shell67 * 2) The graph node describing the target being made by this job68 * 3) A LstNode for the first command to be saved after the job69 * completes. This is NILLNODE if there was no "..." in the job's70 * commands.71 * 4) An FILE* for writing out the commands. This is only72 * used before the job is actually started.73 * 5) A union of things used for handling the shell's output. Different74 * parts of the union are used based on the value of the usePipes75 * flag. If it is true, the output is being caught via a pipe and76 * the descriptors of our pipe, an array in which output is line77 * buffered and the current position in that buffer are all78 * maintained for each job. If, on the other hand, usePipes is false,79 * the output is routed to a temporary file and all that is kept80 * is the name of the file and the descriptor open to the file.81 * 6) An identifier provided by and for the exclusive use of the82 * Rmt module.83 * 7) A word of flags which determine how the module handles errors,84 * echoing, etc. for the job66 * 1) The process id of the child shell 67 * 2) The graph node describing the target being made by this job 68 * 3) A LstNode for the first command to be saved after the job 69 * completes. This is NILLNODE if there was no "..." in the job's 70 * commands. 71 * 4) An FILE* for writing out the commands. This is only 72 * used before the job is actually started. 73 * 5) A union of things used for handling the shell's output. Different 74 * parts of the union are used based on the value of the usePipes 75 * flag. If it is true, the output is being caught via a pipe and 76 * the descriptors of our pipe, an array in which output is line 77 * buffered and the current position in that buffer are all 78 * maintained for each job. If, on the other hand, usePipes is false, 79 * the output is routed to a temporary file and all that is kept 80 * is the name of the file and the descriptor open to the file. 81 * 6) An identifier provided by and for the exclusive use of the 82 * Rmt module. 83 * 7) A word of flags which determine how the module handles errors, 84 * echoing, etc. for the job 85 85 * 86 86 * The job "table" is kept as a linked Lst in 'jobs', with the number of … … 92 92 * traversal of the dependency graph. 93 93 */ 94 #define JOB_BUFSIZE 1024 94 #define JOB_BUFSIZE 1024 95 #define JOB_TMPFILESIZE 128 95 96 typedef struct Job { 96 int pid;/* The child's process ID */97 char tfile[sizeof(TMPPAT)];98 /* Temporary file to use for job */99 GNode *node; /* The target the child is making */100 LstNode tailCmds; /* The node of the first command to be101 * saved when the job has been run */102 FILE *cmdFILE; /* When creating the shell script, this is103 * where the commands go */104 int rmtID; /* ID returned from Rmt module */105 short flags;/* Flags to control treatment of job */106 #define JOB_IGNERR 0x001/* Ignore non-zero exits */107 #define JOB_SILENT 0x002/* no output */108 #define JOB_SPECIAL 0x004/* Target is a special one. i.e. run it locally109 * if we can't export it and maxLocal is 0 */110 #define JOB_IGNDOTS 0x008/* Ignore "..." lines when processing111 * commands */112 #define JOB_REMOTE 0x010/* Job is running remotely */113 #define JOB_FIRST 0x020/* Job is first job for the node */114 #define JOB_REMIGRATE 0x040/* Job needs to be remigrated */115 #define JOB_RESTART 0x080/* Job needs to be completely restarted */116 #define JOB_RESUME 0x100/* Job needs to be resumed b/c it stopped,117 * for some reason */118 #define JOB_CONTINUING 0x200/* We are in the process of resuming this job.119 * Used to avoid infinite recursion between120 * JobFinish and JobRestart */97 int pid; /* The child's process ID */ 98 char tfile[JOB_TMPFILESIZE]; 99 /* Temporary file to use for job */ 100 GNode *node; /* The target the child is making */ 101 LstNode tailCmds; /* The node of the first command to be 102 * saved when the job has been run */ 103 FILE *cmdFILE; /* When creating the shell script, this is 104 * where the commands go */ 105 int rmtID; /* ID returned from Rmt module */ 106 short flags; /* Flags to control treatment of job */ 107 #define JOB_IGNERR 0x001 /* Ignore non-zero exits */ 108 #define JOB_SILENT 0x002 /* no output */ 109 #define JOB_SPECIAL 0x004 /* Target is a special one. i.e. run it locally 110 * if we can't export it and maxLocal is 0 */ 111 #define JOB_IGNDOTS 0x008 /* Ignore "..." lines when processing 112 * commands */ 113 #define JOB_REMOTE 0x010 /* Job is running remotely */ 114 #define JOB_FIRST 0x020 /* Job is first job for the node */ 115 #define JOB_REMIGRATE 0x040 /* Job needs to be remigrated */ 116 #define JOB_RESTART 0x080 /* Job needs to be completely restarted */ 117 #define JOB_RESUME 0x100 /* Job needs to be resumed b/c it stopped, 118 * for some reason */ 119 #define JOB_CONTINUING 0x200 /* We are in the process of resuming this job. 120 * Used to avoid infinite recursion between 121 * JobFinish and JobRestart */ 121 122 union { 122 struct {123 int op_inPipe;/* Input side of pipe associated124 * with job's output channel */125 int op_outPipe;/* Output side of pipe associated with126 * job's output channel */127 charop_outBuf[JOB_BUFSIZE + 1];128 /* Buffer for storing the output of the129 * job, line by line */130 int op_curPos;/* Current position in op_outBuf */131 } o_pipe;/* data used when catching the output via132 * a pipe */133 struct {134 char of_outFile[sizeof(TMPPAT)];135 /* Name of file to which shell output136 * was rerouted */137 int of_outFd;/* Stream open to the output138 * file. Used to funnel all139 * from a single job to one file140 * while still allowing141 * multiple shell invocations */142 } o_file;/* Data used when catching the output in143 * a temporary file */144 } output;/* Data for tracking a shell's output */123 struct { 124 int op_inPipe; /* Input side of pipe associated 125 * with job's output channel */ 126 int op_outPipe; /* Output side of pipe associated with 127 * job's output channel */ 128 char op_outBuf[JOB_BUFSIZE + 1]; 129 /* Buffer for storing the output of the 130 * job, line by line */ 131 int op_curPos; /* Current position in op_outBuf */ 132 } o_pipe; /* data used when catching the output via 133 * a pipe */ 134 struct { 135 char of_outFile[JOB_TMPFILESIZE]; 136 /* Name of file to which shell output 137 * was rerouted */ 138 int of_outFd; /* Stream open to the output 139 * file. Used to funnel all 140 * from a single job to one file 141 * while still allowing 142 * multiple shell invocations */ 143 } o_file; /* Data used when catching the output in 144 * a temporary file */ 145 } output; /* Data for tracking a shell's output */ 145 146 } Job; 146 147 147 #define outPipe output.o_pipe.op_outPipe148 #define inPipe output.o_pipe.op_inPipe149 #define outBuf output.o_pipe.op_outBuf150 #define curPos output.o_pipe.op_curPos151 #define outFile output.o_file.of_outFile152 #define outFd output.o_file.of_outFd148 #define outPipe output.o_pipe.op_outPipe 149 #define inPipe output.o_pipe.op_inPipe 150 #define outBuf output.o_pipe.op_outBuf 151 #define curPos output.o_pipe.op_curPos 152 #define outFile output.o_file.of_outFile 153 #define outFd output.o_file.of_outFd 153 154 154 155 … … 157 158 * Shell Specifications: 158 159 * Each shell type has associated with it the following information: 159 * 1) The string which must match the last character of the shell name160 * for the shell to be considered of this type. The longest match161 * wins.162 * 2) A command to issue to turn off echoing of command lines163 * 3) A command to issue to turn echoing back on again164 * 4) What the shell prints, and its length, when given the echo-off165 * command. This line will not be printed when received from the shell166 * 5) A boolean to tell if the shell has the ability to control167 * error checking for individual commands.168 * 6) The string to turn this checking on.169 * 7) The string to turn it off.170 * 8) The command-flag to give to cause the shell to start echoing171 * commands right away.172 * 9) The command-flag to cause the shell to Lib_Exit when an error is173 * detected in one of the commands.160 * 1) The string which must match the last character of the shell name 161 * for the shell to be considered of this type. The longest match 162 * wins. 163 * 2) A command to issue to turn off echoing of command lines 164 * 3) A command to issue to turn echoing back on again 165 * 4) What the shell prints, and its length, when given the echo-off 166 * command. This line will not be printed when received from the shell 167 * 5) A boolean to tell if the shell has the ability to control 168 * error checking for individual commands. 169 * 6) The string to turn this checking on. 170 * 7) The string to turn it off. 171 * 8) The command-flag to give to cause the shell to start echoing 172 * commands right away. 173 * 9) The command-flag to cause the shell to Lib_Exit when an error is 174 * detected in one of the commands. 174 175 * 175 176 * Some special stuff goes on if a shell doesn't have error control. In such … … 181 182 */ 182 183 typedef struct Shell { 183 char *name;/* the name of the shell. For Bourne and C184 * shells, this is used only to find the185 * shell description when used as the single186 * source of a .SHELL target. For user-defined187 * shells, this is the full path of the shell.188 */189 Boolean hasEchoCtl;/* True if both echoOff and echoOn defined */190 char *echoOff; /* command to turn off echo */191 char *echoOn; /* command to turn it back on again */192 char *noPrint; /* command to skip when printing output from193 * shell. This is usually the command which194 * was executed to turn off echoing */195 int noPLen; /* length of noPrint command */196 Boolean hasErrCtl;/* set if can control error checking for197 * individual commands */198 char *errCheck;/* string to turn error checking on */199 char *ignErr;/* string to turn off error checking */184 char *name; /* the name of the shell. For Bourne and C 185 * shells, this is used only to find the 186 * shell description when used as the single 187 * source of a .SHELL target. For user-defined 188 * shells, this is the full path of the shell. 189 */ 190 Boolean hasEchoCtl; /* True if both echoOff and echoOn defined */ 191 char *echoOff; /* command to turn off echo */ 192 char *echoOn; /* command to turn it back on again */ 193 char *noPrint; /* command to skip when printing output from 194 * shell. This is usually the command which 195 * was executed to turn off echoing */ 196 int noPLen; /* length of noPrint command */ 197 Boolean hasErrCtl; /* set if can control error checking for 198 * individual commands */ 199 char *errCheck; /* string to turn error checking on */ 200 char *ignErr; /* string to turn off error checking */ 200 201 /* 201 202 * command-line flags 202 203 */ 203 char *echo; /* echo commands */204 char *exit; /* exit on error */204 char *echo; /* echo commands */ 205 char *exit; /* exit on error */ 205 206 } Shell; 206 207 207 208 208 extern char *targFmt;/* Format string for banner that separates209 * output from multiple jobs. Contains a210 * single %s where the name of the node being211 * made should be put. */212 extern GNode *lastNode;/* Last node for which a banner was printed.213 * If Rmt module finds it necessary to print214 * a banner, it should set this to the node215 * for which the banner was printed */216 extern int nJobs;/* Number of jobs running (local and remote) */217 extern int nLocal;/* Number of jobs running locally */218 extern Lst jobs;/* List of active job descriptors */219 extern Lst stoppedJobs;/* List of jobs that are stopped or didn't220 * quite get started */221 extern Boolean jobFull;/* Non-zero if no more jobs should/will start*/209 extern char *targFmt; /* Format string for banner that separates 210 * output from multiple jobs. Contains a 211 * single %s where the name of the node being 212 * made should be put. */ 213 extern GNode *lastNode; /* Last node for which a banner was printed. 214 * If Rmt module finds it necessary to print 215 * a banner, it should set this to the node 216 * for which the banner was printed */ 217 extern int nJobs; /* Number of jobs running (local and remote) */ 218 extern int nLocal; /* Number of jobs running locally */ 219 extern Lst jobs; /* List of active job descriptors */ 220 extern Lst stoppedJobs; /* List of jobs that are stopped or didn't 221 * quite get started */ 222 extern Boolean jobFull; /* Non-zero if no more jobs should/will start*/ 222 223 223 224 -
trunk/src/kmk/main.c
r50 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 40 40 static const char copyright[] = 41 41 "@(#) Copyright (c) 1988, 1989, 1990, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n";42 The Regents of the University of California. All rights reserved.\n"; 43 43 #endif /* not lint */ 44 44 45 45 #ifndef lint 46 46 #if 0 47 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94";47 static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 3/19/94"; 48 48 #else 49 49 static const char rcsid[] = 50 50 "$FreeBSD: src/usr.bin/make/main.c,v 1.35.2.6 2002/07/24 16:50:18 ru Exp $"; 51 51 #endif 52 #define KLIBFILEDEF rcsid 52 53 #endif /* not lint */ 53 54 54 55 /*- 55 56 * main.c -- 56 * The main file for this entire program. Exit routines etc57 * reside here.57 * The main file for this entire program. Exit routines etc 58 * reside here. 58 59 * 59 60 * Utility functions defined in this file: 60 * Main_ParseArgLineTakes a line of arguments, breaks them and61 * treats them as if they were given when first62 * invoked. Used by the parse module to implement63 * the .MFLAGS target.64 * 65 * ErrorPrint a tagged error message. The global66 * MAKE variable must have been defined. This67 * takes a format string and two optional68 * arguments for it.69 * 70 * FatalPrint an error message and exit. Also takes71 * a format string and two arguments.72 * 73 * PuntAborts all jobs and exits with a message. Also74 * takes a format string and two arguments.75 * 76 * FinishFinish things up by printing the number of77 * errors which occured, as passed to it, and78 * exiting.79 */ 80 81 #if defined(USE_KLIB) //|| defined(KMK)61 * Main_ParseArgLine Takes a line of arguments, breaks them and 62 * treats them as if they were given when first 63 * invoked. Used by the parse module to implement 64 * the .MFLAGS target. 65 * 66 * Error Print a tagged error message. The global 67 * MAKE variable must have been defined. This 68 * takes a format string and two optional 69 * arguments for it. 70 * 71 * Fatal Print an error message and exit. Also takes 72 * a format string and two arguments. 73 * 74 * Punt Aborts all jobs and exits with a message. Also 75 * takes a format string and two arguments. 76 * 77 * Finish Finish things up by printing the number of 78 * errors which occured, as passed to it, and 79 * exiting. 80 */ 81 82 #if defined(USE_KLIB) 82 83 #define KLIB_INSTRICT 83 84 #include <kLib/kLib.h> … … 96 97 #endif 97 98 #ifndef MACHINE 98 # if !defined(__IBMC__)99 99 # include <sys/utsname.h> 100 # endif 101 #endif 102 #if !defined(__IBMC__) 100 #endif 101 #ifndef USE_KLIB 103 102 #include <sys/wait.h> 103 #endif 104 104 #include <err.h> 105 #endif106 105 #include <stdlib.h> 107 106 #include <errno.h> 108 107 #include <fcntl.h> 109 108 #include <stdio.h> 110 #if !defined(__IBMC__) && !defined(__EMX__)109 #if defined(__EMX__) 111 110 #include <sysexits.h> 112 111 #endif 113 #if defined(__STDC__) || defined(__IBMC__)112 #if defined(__STDC__) 114 113 #include <stdarg.h> 115 114 #else … … 129 128 #define S_ISDIR(mode) (((mode) & S_IFMT) == S_IFDIR) 130 129 #endif 131 #endif 130 char *realpath(const char *pszFileName, char *pszResolvedName); 131 #define snprintf kStrNFormat 132 #endif 133 #include <getopt.h> 132 134 #include "make.h" 133 135 #include "hash.h" … … 136 138 #include "pathnames.h" 137 139 138 #ifndef DEFMAXLOCAL139 #define DEFMAXLOCAL DEFMAXJOBS140 #endif /* DEFMAXLOCAL */141 142 #define MAKEFLAGS".MAKEFLAGS"143 144 Lst create;/* Targets to be made */145 time_t now;/* Time at start of make */146 GNode *DEFAULT;/* .DEFAULT node */147 Boolean allPrecious;/* .PRECIOUS given on line by itself */148 149 static Boolean noBuiltins;/* -r flag */150 static Lst makefiles;/* ordered list of makefiles to read */151 static Boolean printVars;/* print value of one or more vars */152 static Boolean expandVars;/* fully expand printed variables */153 static Lst variables;/* list of variables to print */154 int maxJobs;/* -j argument */140 #ifndef DEFMAXLOCAL 141 #define DEFMAXLOCAL DEFMAXJOBS 142 #endif /* DEFMAXLOCAL */ 143 144 #define MAKEFLAGS ".MAKEFLAGS" 145 146 Lst create; /* Targets to be made */ 147 time_t now; /* Time at start of make */ 148 GNode *DEFAULT; /* .DEFAULT node */ 149 Boolean allPrecious; /* .PRECIOUS given on line by itself */ 150 151 static Boolean noBuiltins; /* -r flag */ 152 static Lst makefiles; /* ordered list of makefiles to read */ 153 static Boolean printVars; /* print value of one or more vars */ 154 static Boolean expandVars; /* fully expand printed variables */ 155 static Lst variables; /* list of variables to print */ 156 int maxJobs; /* -j argument */ 155 157 static Boolean forceJobs; /* -j argument given */ 156 static int maxLocal;/* -L argument */157 Boolean compatMake;/* -B argument */158 Boolean debug;/* -d flag */159 Boolean noExecute;/* -n flag */160 Boolean keepgoing;/* -k flag */161 Boolean queryFlag;/* -q flag */162 Boolean touchFlag;/* -t flag */163 Boolean usePipes;/* !-P flag */164 Boolean ignoreErrors;/* -i flag */165 Boolean beSilent;/* -s flag */166 Boolean beVerbose;/* -v flag */167 Boolean oldVars;/* variable substitution style */168 Boolean checkEnvFirst;/* -e flag */169 Lst envFirstVars;/* (-E) vars to override from env */170 static Boolean jobsRunning;/* TRUE if the jobs might be running */158 static int maxLocal; /* -L argument */ 159 Boolean compatMake; /* -B argument */ 160 Boolean debug; /* -d flag */ 161 Boolean noExecute; /* -n flag */ 162 Boolean keepgoing; /* -k flag */ 163 Boolean queryFlag; /* -q flag */ 164 Boolean touchFlag; /* -t flag */ 165 Boolean usePipes; /* !-P flag */ 166 Boolean ignoreErrors; /* -i flag */ 167 Boolean beSilent; /* -s flag */ 168 Boolean beVerbose; /* -v flag */ 169 Boolean oldVars; /* variable substitution style */ 170 Boolean checkEnvFirst; /* -e flag */ 171 Lst envFirstVars; /* (-E) vars to override from env */ 172 static Boolean jobsRunning; /* TRUE if the jobs might be running */ 171 173 #ifdef NMAKE 172 174 static Boolean go_to_objdir; /* ! -o flag */ 173 175 #endif 174 static void MainParseArgs __P((int, char **)); 175 char * chdir_verify_path __P((char *, char *)); 176 static int ReadMakefile __P((ClientData, ClientData)); 177 static void usage __P((void)); 178 179 static char *curdir; /* startup directory */ 180 static char *objdir; /* where we chdir'ed to */ 176 static void MainParseArgs __P((int, char **)); 177 char * chdir_verify_path __P((char *, char *)); 178 static int ReadMakefile __P((ClientData, ClientData)); 179 static void usage __P((void)); 180 181 static char *curdir; /* startup directory */ 182 static char *objdir; /* where we chdir'ed to */ 183 #ifdef KMK 184 char * argv0 = NULL; 185 #endif 181 186 182 187 /*- 183 188 * MainParseArgs -- 184 * Parse a given argument vector. Called from main() and from185 * Main_ParseArgLine() when the .MAKEFLAGS target is used.186 * 187 * XXX: Deal with command line overriding .MAKEFLAGS in makefile189 * Parse a given argument vector. Called from main() and from 190 * Main_ParseArgLine() when the .MAKEFLAGS target is used. 191 * 192 * XXX: Deal with command line overriding .MAKEFLAGS in makefile 188 193 * 189 194 * Results: 190 * None195 * None 191 196 * 192 197 * Side Effects: 193 * Various global and local flags will be set depending on the flags194 * given198 * Various global and local flags will be set depending on the flags 199 * given 195 200 */ 196 201 static void 197 202 MainParseArgs(argc, argv) 198 int argc;199 char **argv;200 { 201 extern int optind;202 extern char *optarg;203 char *p;204 int c;205 206 optind = 1;/* since we're called more than once */203 int argc; 204 char **argv; 205 { 206 extern int optind; 207 extern char *optarg; 208 char *p; 209 int c; 210 211 optind = 1; /* since we're called more than once */ 207 212 #ifdef REMOTE 208 213 # ifdef NMAKE … … 218 223 # endif 219 224 #endif 220 rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) {221 switch(c) {222 case 'D':223 Var_Set(optarg, "1", VAR_GLOBAL);224 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL);225 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);226 break;227 case 'I':228 Parse_AddIncludeDir(optarg);229 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL);230 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);231 break;232 case 'V':233 printVars = TRUE;234 (void)Lst_AtEnd(variables, (ClientData)optarg);235 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL);236 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);237 break;238 case 'X':239 expandVars = FALSE;240 break;241 case 'B':242 compatMake = TRUE;243 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL);244 break;225 rearg: while((c = getopt(argc, argv, OPTFLAGS)) != -1) { 226 switch(c) { 227 case 'D': 228 Var_Set(optarg, "1", VAR_GLOBAL); 229 Var_Append(MAKEFLAGS, "-D", VAR_GLOBAL); 230 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 231 break; 232 case 'I': 233 Parse_AddIncludeDir(optarg); 234 Var_Append(MAKEFLAGS, "-I", VAR_GLOBAL); 235 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 236 break; 237 case 'V': 238 printVars = TRUE; 239 (void)Lst_AtEnd(variables, (ClientData)optarg); 240 Var_Append(MAKEFLAGS, "-V", VAR_GLOBAL); 241 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 242 break; 243 case 'X': 244 expandVars = FALSE; 245 break; 246 case 'B': 247 compatMake = TRUE; 248 Var_Append(MAKEFLAGS, "-B", VAR_GLOBAL); 249 break; 245 250 #ifdef REMOTE 246 case 'L': {247 char *endptr;248 249 maxLocal = strtol(optarg, &endptr, 10);250 if (maxLocal < 0 || *endptr != '\0') {251 warnx("illegal number, -L argument -- %s",252 optarg);253 usage();254 }255 Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL);256 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);257 break;258 }259 #endif 260 case 'P':261 usePipes = FALSE;262 Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL);263 break;264 case 'S':265 keepgoing = FALSE;266 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL);267 break;268 case 'd': {269 char *modules = optarg;270 271 for (; *modules; ++modules)272 switch (*modules) {273 case 'A':274 debug = ~0;275 break;276 case 'a':251 case 'L': { 252 char *endptr; 253 254 maxLocal = strtol(optarg, &endptr, 10); 255 if (maxLocal < 0 || *endptr != '\0') { 256 warnx("illegal number, -L argument -- %s", 257 optarg); 258 usage(); 259 } 260 Var_Append(MAKEFLAGS, "-L", VAR_GLOBAL); 261 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 262 break; 263 } 264 #endif 265 case 'P': 266 usePipes = FALSE; 267 Var_Append(MAKEFLAGS, "-P", VAR_GLOBAL); 268 break; 269 case 'S': 270 keepgoing = FALSE; 271 Var_Append(MAKEFLAGS, "-S", VAR_GLOBAL); 272 break; 273 case 'd': { 274 char *modules = optarg; 275 276 for (; *modules; ++modules) 277 switch (*modules) { 278 case 'A': 279 debug = ~0; 280 break; 281 case 'a': 277 282 #ifdef USE_ARCHIVES 278 debug |= DEBUG_ARCH;283 debug |= DEBUG_ARCH; 279 284 #endif /* else ignore */ 280 break;281 case 'c':282 debug |= DEBUG_COND;283 break;284 case 'd':285 debug |= DEBUG_DIR;286 break;287 case 'f':288 debug |= DEBUG_FOR;289 break;290 case 'g':291 if (modules[1] == '1') {292 debug |= DEBUG_GRAPH1;293 ++modules;294 }295 else if (modules[1] == '2') {296 debug |= DEBUG_GRAPH2;297 ++modules;298 }299 break;300 case 'j':301 debug |= DEBUG_JOB;302 break;303 case 'l':304 debug |= DEBUG_LOUD;305 break;306 case 'm':307 debug |= DEBUG_MAKE;308 break;285 break; 286 case 'c': 287 debug |= DEBUG_COND; 288 break; 289 case 'd': 290 debug |= DEBUG_DIR; 291 break; 292 case 'f': 293 debug |= DEBUG_FOR; 294 break; 295 case 'g': 296 if (modules[1] == '1') { 297 debug |= DEBUG_GRAPH1; 298 ++modules; 299 } 300 else if (modules[1] == '2') { 301 debug |= DEBUG_GRAPH2; 302 ++modules; 303 } 304 break; 305 case 'j': 306 debug |= DEBUG_JOB; 307 break; 308 case 'l': 309 debug |= DEBUG_LOUD; 310 break; 311 case 'm': 312 debug |= DEBUG_MAKE; 313 break; 309 314 case 'p': /*kso*/ 310 debug |= DEBUG_PARSE;315 debug |= DEBUG_PARSE; 311 316 break; 312 317 case 's': 313 debug |= DEBUG_SUFF;314 break;315 case 't':316 debug |= DEBUG_TARG;317 break;318 case 'v':319 debug |= DEBUG_VAR;320 break;321 default:322 warnx("illegal argument to d option -- %c", *modules);323 usage();324 }325 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL);326 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);327 break;328 }329 case 'E':330 p = emalloc(strlen(optarg) + 1);331 (void)strcpy(p, optarg);332 (void)Lst_AtEnd(envFirstVars, (ClientData)p);333 Var_Append(MAKEFLAGS, "-E", VAR_GLOBAL);334 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);335 break;336 case 'e':337 checkEnvFirst = TRUE;338 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL);339 break;340 case 'f':341 (void)Lst_AtEnd(makefiles, (ClientData)optarg);342 break;343 case 'i':344 ignoreErrors = TRUE;345 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL);346 break;347 case 'j': {348 char *endptr;349 350 forceJobs = TRUE;351 maxJobs = strtol(optarg, &endptr, 10);352 if (maxJobs <= 0 || *endptr != '\0') {353 warnx("illegal number, -j argument -- %s",354 optarg);355 usage();356 }318 debug |= DEBUG_SUFF; 319 break; 320 case 't': 321 debug |= DEBUG_TARG; 322 break; 323 case 'v': 324 debug |= DEBUG_VAR; 325 break; 326 default: 327 warnx("illegal argument to d option -- %c", *modules); 328 usage(); 329 } 330 Var_Append(MAKEFLAGS, "-d", VAR_GLOBAL); 331 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 332 break; 333 } 334 case 'E': 335 p = emalloc(strlen(optarg) + 1); 336 (void)strcpy(p, optarg); 337 (void)Lst_AtEnd(envFirstVars, (ClientData)p); 338 Var_Append(MAKEFLAGS, "-E", VAR_GLOBAL); 339 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 340 break; 341 case 'e': 342 checkEnvFirst = TRUE; 343 Var_Append(MAKEFLAGS, "-e", VAR_GLOBAL); 344 break; 345 case 'f': 346 (void)Lst_AtEnd(makefiles, (ClientData)optarg); 347 break; 348 case 'i': 349 ignoreErrors = TRUE; 350 Var_Append(MAKEFLAGS, "-i", VAR_GLOBAL); 351 break; 352 case 'j': { 353 char *endptr; 354 355 forceJobs = TRUE; 356 maxJobs = strtol(optarg, &endptr, 10); 357 if (maxJobs <= 0 || *endptr != '\0') { 358 warnx("illegal number, -j argument -- %s", 359 optarg); 360 usage(); 361 } 357 362 #ifndef REMOTE 358 maxLocal = maxJobs;359 #endif 360 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL);361 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);362 break;363 }364 case 'k':365 keepgoing = TRUE;366 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL);367 break;368 case 'm':369 Dir_AddDir(sysIncPath, optarg);370 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL);371 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL);372 break;373 case 'n':374 noExecute = TRUE;375 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL);376 break;363 maxLocal = maxJobs; 364 #endif 365 Var_Append(MAKEFLAGS, "-j", VAR_GLOBAL); 366 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 367 break; 368 } 369 case 'k': 370 keepgoing = TRUE; 371 Var_Append(MAKEFLAGS, "-k", VAR_GLOBAL); 372 break; 373 case 'm': 374 Dir_AddDir(sysIncPath, optarg); 375 Var_Append(MAKEFLAGS, "-m", VAR_GLOBAL); 376 Var_Append(MAKEFLAGS, optarg, VAR_GLOBAL); 377 break; 378 case 'n': 379 noExecute = TRUE; 380 Var_Append(MAKEFLAGS, "-n", VAR_GLOBAL); 381 break; 377 382 #ifdef NMAKE 378 383 case 'o': 379 384 go_to_objdir = TRUE; 380 Var_Append(MAKEFLAGS, "-o", VAR_GLOBAL);381 break; 382 #endif 383 case 'q':384 queryFlag = TRUE;385 /* Kind of nonsensical, wot? */386 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL);387 break;388 case 'r':389 noBuiltins = TRUE;390 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL);391 break;392 case 's':393 beSilent = TRUE;394 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL);395 break;396 case 't':397 touchFlag = TRUE;398 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL);399 break;400 case 'v':401 beVerbose = TRUE;402 Var_Append(MAKEFLAGS, "-v", VAR_GLOBAL);403 break;404 default:405 case '?':406 usage();407 }408 }409 410 oldVars = TRUE;411 412 /*413 * See if the rest of the arguments are variable assignments and414 * perform them if so. Else take them to be targets and stuff them415 * on the end of the "create" list.416 */417 for (argv += optind, argc -= optind; *argv; ++argv, --argc)418 if (Parse_IsVar(*argv))419 Parse_DoVar(*argv, VAR_CMD);420 else {421 if (!**argv)422 Punt("illegal (null) argument.");423 if (**argv == '-') {424 if ((*argv)[1])425 optind = 0; /* -flag... */426 else427 optind = 1; /* - */428 goto rearg;429 }430 (void)Lst_AtEnd(create, (ClientData)estrdup(*argv));431 }385 Var_Append(MAKEFLAGS, "-o", VAR_GLOBAL); 386 break; 387 #endif 388 case 'q': 389 queryFlag = TRUE; 390 /* Kind of nonsensical, wot? */ 391 Var_Append(MAKEFLAGS, "-q", VAR_GLOBAL); 392 break; 393 case 'r': 394 noBuiltins = TRUE; 395 Var_Append(MAKEFLAGS, "-r", VAR_GLOBAL); 396 break; 397 case 's': 398 beSilent = TRUE; 399 Var_Append(MAKEFLAGS, "-s", VAR_GLOBAL); 400 break; 401 case 't': 402 touchFlag = TRUE; 403 Var_Append(MAKEFLAGS, "-t", VAR_GLOBAL); 404 break; 405 case 'v': 406 beVerbose = TRUE; 407 Var_Append(MAKEFLAGS, "-v", VAR_GLOBAL); 408 break; 409 default: 410 case '?': 411 usage(); 412 } 413 } 414 415 oldVars = TRUE; 416 417 /* 418 * See if the rest of the arguments are variable assignments and 419 * perform them if so. Else take them to be targets and stuff them 420 * on the end of the "create" list. 421 */ 422 for (argv += optind, argc -= optind; *argv; ++argv, --argc) 423 if (Parse_IsVar(*argv)) 424 Parse_DoVar(*argv, VAR_CMD); 425 else { 426 if (!**argv) 427 Punt("illegal (null) argument."); 428 if (**argv == '-') { 429 if ((*argv)[1]) 430 optind = 0; /* -flag... */ 431 else 432 optind = 1; /* - */ 433 goto rearg; 434 } 435 (void)Lst_AtEnd(create, (ClientData)estrdup(*argv)); 436 } 432 437 } 433 438 434 439 /*- 435 440 * Main_ParseArgLine -- 436 * Used by the parse module when a .MFLAGS or .MAKEFLAGS target437 * is encountered and by main() when reading the .MAKEFLAGS envariable.438 * Takes a line of arguments and breaks it into its439 * component words and passes those words and the number of them to the440 * MainParseArgs function.441 * The line should have all its leading whitespace removed.441 * Used by the parse module when a .MFLAGS or .MAKEFLAGS target 442 * is encountered and by main() when reading the .MAKEFLAGS envariable. 443 * Takes a line of arguments and breaks it into its 444 * component words and passes those words and the number of them to the 445 * MainParseArgs function. 446 * The line should have all its leading whitespace removed. 442 447 * 443 448 * Results: 444 * None449 * None 445 450 * 446 451 * Side Effects: 447 * Only those that come from the various arguments.452 * Only those that come from the various arguments. 448 453 */ 449 454 void 450 455 Main_ParseArgLine(line) 451 char *line;/* Line to fracture */452 { 453 char **argv;/* Manufactured argument vector */454 int argc;/* Number of arguments in argv */455 456 if (line == NULL)457 return;458 for (; *line == ' '; ++line)459 continue;460 if (!*line)461 return;462 463 argv = brk_string(line, &argc, TRUE);464 MainParseArgs(argc, argv);456 char *line; /* Line to fracture */ 457 { 458 char **argv; /* Manufactured argument vector */ 459 int argc; /* Number of arguments in argv */ 460 461 if (line == NULL) 462 return; 463 for (; *line == ' '; ++line) 464 continue; 465 if (!*line) 466 return; 467 468 argv = brk_string(line, &argc, TRUE); 469 MainParseArgs(argc, argv); 465 470 } 466 471 467 472 char * 468 473 chdir_verify_path(path, obpath) 469 char *path;470 char *obpath;474 char *path; 475 char *obpath; 471 476 { 472 477 struct stat sb; … … 476 481 #endif 477 482 478 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) {479 if (chdir(path)) {480 warn("warning: %s", path);481 return 0;482 }483 else {484 if (path[0] != '/') {485 (void) snprintf(obpath, MAXPATHLEN, "%s/%s",486 curdir, path);487 return obpath;488 }489 else490 return path;491 }492 }493 494 return 0;483 if (stat(path, &sb) == 0 && S_ISDIR(sb.st_mode)) { 484 if (chdir(path)) { 485 warn("warning: %s", path); 486 return 0; 487 } 488 else { 489 if (path[0] != '/') { 490 (void) snprintf(obpath, MAXPATHLEN, "%s/%s", 491 curdir, path); 492 return obpath; 493 } 494 else 495 return path; 496 } 497 } 498 499 return 0; 495 500 } 496 501 … … 498 503 /*- 499 504 * main -- 500 * The main function, for obvious reasons. Initializes variables501 * and a few modules, then parses the arguments give it in the502 * environment and on the command line. Reads the system makefile503 * followed by either Makefile, makefile or the file given by the504 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the505 * flags it has received by then uses either the Make or the Compat506 * module to create the initial list of targets.505 * The main function, for obvious reasons. Initializes variables 506 * and a few modules, then parses the arguments give it in the 507 * environment and on the command line. Reads the system makefile 508 * followed by either Makefile, makefile or the file given by the 509 * -f argument. Sets the .MAKEFLAGS PMake variable based on all the 510 * flags it has received by then uses either the Make or the Compat 511 * module to create the initial list of targets. 507 512 * 508 513 * Results: 509 * If -q was given, exits -1 if anything was out-of-date. Else it exits510 * 0.514 * If -q was given, exits -1 if anything was out-of-date. Else it exits 515 * 0. 511 516 * 512 517 * Side Effects: 513 * The program exits when done. Targets are created. etc. etc. etc.518 * The program exits when done. Targets are created. etc. etc. etc. 514 519 */ 515 520 int … … 519 524 main(argc, argv) 520 525 #endif 521 int argc;522 char **argv;523 { 524 Lst targs;/* target nodes to create -- passed to Make_Init */525 Boolean outOfDate = TRUE;/* FALSE if all targets up to date */526 struct stat sa;527 char *p, *p1, *path, *pathp;526 int argc; 527 char **argv; 528 { 529 Lst targs; /* target nodes to create -- passed to Make_Init */ 530 Boolean outOfDate = TRUE; /* FALSE if all targets up to date */ 531 struct stat sa; 532 char *p, *p1, *path, *pathp; 528 533 #ifdef WANT_ENV_PWD 529 struct stat sb;530 char *pwd;531 #endif 532 char mdpath[MAXPATHLEN + 1];533 char obpath[MAXPATHLEN + 1];534 char cdpath[MAXPATHLEN + 1];535 char *machine = getenv("MACHINE");536 char *machine_arch = getenv("MACHINE_ARCH");537 char *machine_cpu = getenv("MACHINE_CPU");538 Lst sysMkPath;/* Path of sys.mk */539 char *cp = NULL, *start;540 /* avoid faults on read-only strings */534 struct stat sb; 535 char *pwd; 536 #endif 537 char mdpath[MAXPATHLEN + 1]; 538 char obpath[MAXPATHLEN + 1]; 539 char cdpath[MAXPATHLEN + 1]; 540 char *machine = getenv("MACHINE"); 541 char *machine_arch = getenv("MACHINE_ARCH"); 542 char *machine_cpu = getenv("MACHINE_CPU"); 543 Lst sysMkPath; /* Path of sys.mk */ 544 char *cp = NULL, *start; 545 /* avoid faults on read-only strings */ 541 546 #ifndef KMK 542 static char syspath[] = _PATH_DEFSYSPATH;547 static char syspath[] = _PATH_DEFSYSPATH; 543 548 #endif 544 549 550 #ifdef KMK 551 /* 552 * Save ourselfs. 553 */ 554 argv0 = argv[0]; 555 #endif 556 545 557 #ifdef RLIMIT_NOFILE 546 /*547 * get rid of resource limit on file descriptors548 */549 {550 struct rlimit rl;551 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 &&552 rl.rlim_cur != rl.rlim_max) {553 rl.rlim_cur = rl.rlim_max;554 (void) setrlimit(RLIMIT_NOFILE, &rl);555 }556 }557 #endif 558 /*559 * Find where we are and take care of PWD for the automounter...560 * All this code is so that we know where we are when we start up561 * on a different machine with pmake.562 */563 curdir = cdpath;564 if (getcwd(curdir, MAXPATHLEN) == NULL)565 err(2, NULL);566 567 if (stat(curdir, &sa) == -1)568 err(2, "%s", curdir);558 /* 559 * get rid of resource limit on file descriptors 560 */ 561 { 562 struct rlimit rl; 563 if (getrlimit(RLIMIT_NOFILE, &rl) != -1 && 564 rl.rlim_cur != rl.rlim_max) { 565 rl.rlim_cur = rl.rlim_max; 566 (void) setrlimit(RLIMIT_NOFILE, &rl); 567 } 568 } 569 #endif 570 /* 571 * Find where we are and take care of PWD for the automounter... 572 * All this code is so that we know where we are when we start up 573 * on a different machine with pmake. 574 */ 575 curdir = cdpath; 576 if (getcwd(curdir, MAXPATHLEN) == NULL) 577 err(2, NULL); 578 579 if (stat(curdir, &sa) == -1) 580 err(2, "%s", curdir); 569 581 570 582 #ifdef WANT_ENV_PWD 571 if ((pwd = getenv("PWD")) != NULL) {572 if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino &&573 sa.st_dev == sb.st_dev)574 (void) strcpy(curdir, pwd);575 }583 if ((pwd = getenv("PWD")) != NULL) { 584 if (stat(pwd, &sb) == 0 && sa.st_ino == sb.st_ino && 585 sa.st_dev == sb.st_dev) 586 (void) strcpy(curdir, pwd); 587 } 576 588 #endif 577 589 578 590 #if defined(__i386__) && defined(__FreeBSD_version) && \ 579 591 __FreeBSD_version > 300003 580 /*581 * PC-98 kernel sets the `i386' string to the utsname.machine and582 * it cannot be distinguished from IBM-PC by uname(3). Therefore,583 * we check machine.ispc98 and adjust the machine variable before584 * using usname(3) below.585 * NOTE: machdep.ispc98 was defined on 1998/8/31. At that time,586 * __FreeBSD_version was defined as 300003. So, this check can587 * safely be done with any kernel with version > 300003.588 */589 if (!machine) {590 intispc98;591 size_tlen;592 593 len = sizeof(ispc98);594 if (!sysctlbyname("machdep.ispc98", &ispc98, &len, NULL, 0)) {595 if (ispc98)596 machine = "pc98";597 }598 }599 #endif 600 601 /*602 * Get the name of this type of MACHINE from utsname603 * so we can share an executable for similar machines.604 * (i.e. m68k: amiga hp300, mac68k, sun3, ...)605 *606 * Note that while MACHINE is decided at run-time,607 * MACHINE_ARCH is always known at compile time.608 */609 if (!machine) {592 /* 593 * PC-98 kernel sets the `i386' string to the utsname.machine and 594 * it cannot be distinguished from IBM-PC by uname(3). Therefore, 595 * we check machine.ispc98 and adjust the machine variable before 596 * using usname(3) below. 597 * NOTE: machdep.ispc98 was defined on 1998/8/31. At that time, 598 * __FreeBSD_version was defined as 300003. So, this check can 599 * safely be done with any kernel with version > 300003. 600 */ 601 if (!machine) { 602 int ispc98; 603 size_t len; 604 605 len = sizeof(ispc98); 606 if (!sysctlbyname("machdep.ispc98", &ispc98, &len, NULL, 0)) { 607 if (ispc98) 608 machine = "pc98"; 609 } 610 } 611 #endif 612 613 /* 614 * Get the name of this type of MACHINE from utsname 615 * so we can share an executable for similar machines. 616 * (i.e. m68k: amiga hp300, mac68k, sun3, ...) 617 * 618 * Note that while MACHINE is decided at run-time, 619 * MACHINE_ARCH is always known at compile time. 620 */ 621 if (!machine) { 610 622 #ifndef MACHINE 611 struct utsname utsname;612 613 if (uname(&utsname) == -1) {614 perror(MAKE_NAME ": uname");615 exit(2);616 }617 machine = utsname.machine;618 #else 619 machine = MACHINE;620 #endif 621 }622 623 if (!machine_arch) {623 struct utsname utsname; 624 625 if (uname(&utsname) == -1) { 626 perror(MAKE_NAME ": uname"); 627 exit(2); 628 } 629 machine = utsname.machine; 630 #else 631 machine = MACHINE; 632 #endif 633 } 634 635 if (!machine_arch) { 624 636 #ifndef MACHINE_ARCH 625 machine_arch = "unknown";626 #else 627 machine_arch = MACHINE_ARCH;628 #endif 629 }630 631 /*632 * Set machine_cpu to the minumum supported CPU revision based633 * on the target architecture, if not already set.634 */635 if (!machine_cpu) {636 if (!strcmp(machine_arch, "i386"))637 machine_cpu = "i386";638 else if (!strcmp(machine_arch, "alpha"))639 machine_cpu = "ev4";640 else641 machine_cpu = "unknown";642 }643 637 machine_arch = "unknown"; 638 #else 639 machine_arch = MACHINE_ARCH; 640 #endif 641 } 642 643 /* 644 * Set machine_cpu to the minumum supported CPU revision based 645 * on the target architecture, if not already set. 646 */ 647 if (!machine_cpu) { 648 if (!strcmp(machine_arch, "i386")) 649 machine_cpu = "i386"; 650 else if (!strcmp(machine_arch, "alpha")) 651 machine_cpu = "ev4"; 652 else 653 machine_cpu = "unknown"; 654 } 655 644 656 #ifdef KMK 645 657 /* @todo figure out how to set object directory! */ 646 658 #else 647 /*648 * The object directory location is determined using the649 * following order of preference:650 *651 *1. MAKEOBJDIRPREFIX`cwd`652 *2. MAKEOBJDIR653 *3. _PATH_OBJDIR.${MACHINE}654 *4. _PATH_OBJDIR655 *5. _PATH_OBJDIRPREFIX`cwd`656 *657 * If one of the first two fails, use the current directory.658 * If the remaining three all fail, use the current directory.659 *660 * Once things are initted,661 * have to add the original directory to the search path,662 * and modify the paths for the Makefiles apropriately. The663 * current directory is also placed as a variable for make scripts.664 */665 if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) {666 if (!(path = getenv("MAKEOBJDIR"))) {667 path = _PATH_OBJDIR;668 pathp = _PATH_OBJDIRPREFIX;669 (void) snprintf(mdpath, MAXPATHLEN, "%s.%s",670 path, machine);671 if (!(objdir = chdir_verify_path(mdpath, obpath)))672 if (!(objdir=chdir_verify_path(path, obpath))) {673 (void) snprintf(mdpath, MAXPATHLEN,674 "%s%s", pathp, curdir);675 if (!(objdir=chdir_verify_path(mdpath,676 obpath)))677 objdir = curdir;678 }679 }680 else if (!(objdir = chdir_verify_path(path, obpath)))681 objdir = curdir;682 }683 else {684 (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir);685 if (!(objdir = chdir_verify_path(mdpath, obpath)))686 objdir = curdir;687 }659 /* 660 * The object directory location is determined using the 661 * following order of preference: 662 * 663 * 1. MAKEOBJDIRPREFIX`cwd` 664 * 2. MAKEOBJDIR 665 * 3. _PATH_OBJDIR.${MACHINE} 666 * 4. _PATH_OBJDIR 667 * 5. _PATH_OBJDIRPREFIX`cwd` 668 * 669 * If one of the first two fails, use the current directory. 670 * If the remaining three all fail, use the current directory. 671 * 672 * Once things are initted, 673 * have to add the original directory to the search path, 674 * and modify the paths for the Makefiles apropriately. The 675 * current directory is also placed as a variable for make scripts. 676 */ 677 if (!(pathp = getenv("MAKEOBJDIRPREFIX"))) { 678 if (!(path = getenv("MAKEOBJDIR"))) { 679 path = _PATH_OBJDIR; 680 pathp = _PATH_OBJDIRPREFIX; 681 (void) snprintf(mdpath, MAXPATHLEN, "%s.%s", 682 path, machine); 683 if (!(objdir = chdir_verify_path(mdpath, obpath))) 684 if (!(objdir=chdir_verify_path(path, obpath))) { 685 (void) snprintf(mdpath, MAXPATHLEN, 686 "%s%s", pathp, curdir); 687 if (!(objdir=chdir_verify_path(mdpath, 688 obpath))) 689 objdir = curdir; 690 } 691 } 692 else if (!(objdir = chdir_verify_path(path, obpath))) 693 objdir = curdir; 694 } 695 else { 696 (void) snprintf(mdpath, MAXPATHLEN, "%s%s", pathp, curdir); 697 if (!(objdir = chdir_verify_path(mdpath, obpath))) 698 objdir = curdir; 699 } 688 700 #endif 689 701 690 702 #ifdef WANT_ENV_PWD 691 703 #ifdef USE_KLIB 692 kEnvSet("PWD", objdir);704 kEnvSet("PWD", objdir); 693 705 #else 694 setenv("PWD", objdir, 1);706 setenv("PWD", objdir, 1); 695 707 #endif 696 708 #endif 697 709 698 create = Lst_Init(FALSE); 699 makefiles = Lst_Init(FALSE); 700 envFirstVars = Lst_Init(FALSE); 701 printVars = FALSE; 702 expandVars = TRUE; 703 variables = Lst_Init(FALSE); 704 beSilent = FALSE; /* Print commands as executed */ 705 ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 706 noExecute = FALSE; /* Execute all commands */ 707 keepgoing = FALSE; /* Stop on error */ 708 allPrecious = FALSE; /* Remove targets when interrupted */ 709 queryFlag = FALSE; /* This is not just a check-run */ 710 noBuiltins = FALSE; /* Read the built-in rules */ 711 touchFlag = FALSE; /* Actually update targets */ 712 usePipes = TRUE; /* Catch child output in pipes */ 713 debug = 0; /* No debug verbosity, please. */ 714 jobsRunning = FALSE; 710 create = Lst_Init(FALSE); 711 makefiles = Lst_Init(FALSE); 712 envFirstVars = Lst_Init(FALSE); 713 printVars = FALSE; 714 expandVars = TRUE; 715 variables = Lst_Init(FALSE); 716 beSilent = FALSE; /* Print commands as executed */ 717 ignoreErrors = FALSE; /* Pay attention to non-zero returns */ 718 noExecute = FALSE; /* Execute all commands */ 719 keepgoing = FALSE; /* Stop on error */ 720 allPrecious = FALSE; /* Remove targets when interrupted */ 721 queryFlag = FALSE; /* This is not just a check-run */ 722 noBuiltins = FALSE; /* Read the built-in rules */ 723 touchFlag = FALSE; /* Actually update targets */ 724 #ifdef USE_PIPES 725 usePipes = TRUE; /* Catch child output in pipes */ 726 #else 727 usePipes = FALSE; /* Don't catch child output in pipes if multiple wait isn't supported */ 728 #endif 729 debug = 0; /* No debug verbosity, please. */ 730 jobsRunning = FALSE; 715 731 #ifdef NMAKE 716 go_to_objdir = FALSE;717 #endif 718 719 maxLocal = DEFMAXLOCAL;/* Set default local max concurrency */732 go_to_objdir = FALSE; 733 #endif 734 735 maxLocal = DEFMAXLOCAL; /* Set default local max concurrency */ 720 736 #ifdef REMOTE 721 maxJobs = DEFMAXJOBS;/* Set default max concurrency */722 #else 723 maxJobs = maxLocal;724 #endif 725 forceJobs = FALSE; /* No -j flag */726 compatMake = FALSE;/* No compat mode */727 728 729 /*730 * Initialize the parsing, directory and variable modules to prepare731 * for the reading of inclusion paths and variable settings on the732 * command line733 */734 Dir_Init();/* Initialize directory structures so -I flags735 * can be processed correctly */736 Parse_Init();/* Need to initialize the paths of #include737 * directories */738 Var_Init();/* As well as the lists of variables for739 * parsing arguments */737 maxJobs = DEFMAXJOBS; /* Set default max concurrency */ 738 #else 739 maxJobs = maxLocal; 740 #endif 741 forceJobs = FALSE; /* No -j flag */ 742 compatMake = FALSE; /* No compat mode */ 743 744 745 /* 746 * Initialize the parsing, directory and variable modules to prepare 747 * for the reading of inclusion paths and variable settings on the 748 * command line 749 */ 750 Dir_Init(); /* Initialize directory structures so -I flags 751 * can be processed correctly */ 752 Parse_Init(); /* Need to initialize the paths of #include 753 * directories */ 754 Var_Init(); /* As well as the lists of variables for 755 * parsing arguments */ 740 756 str_init(); 741 if (objdir != curdir)742 Dir_AddDir(dirSearchPath, curdir);743 Var_Set(".CURDIR", curdir, VAR_GLOBAL);744 Var_Set(".OBJDIR", objdir, VAR_GLOBAL);745 746 /*747 * Initialize various variables.748 *MAKE also gets this name, for compatibility749 *.MAKEFLAGS gets set to the empty string just in case.750 *MFLAGS also gets initialized empty, for compatibility.751 */752 Var_Set("MAKE", argv[0], VAR_GLOBAL);753 Var_Set(MAKEFLAGS, "", VAR_GLOBAL);754 Var_Set("MFLAGS", "", VAR_GLOBAL);755 Var_Set("MACHINE", machine, VAR_GLOBAL);756 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL);757 Var_Set("MACHINE_CPU", machine_cpu, VAR_GLOBAL);758 759 /*760 * First snag any flags out of the MAKE environment variable.761 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's762 * in a different format).763 */757 if (objdir != curdir) 758 Dir_AddDir(dirSearchPath, curdir); 759 Var_Set(".CURDIR", curdir, VAR_GLOBAL); 760 Var_Set(".OBJDIR", objdir, VAR_GLOBAL); 761 762 /* 763 * Initialize various variables. 764 * MAKE also gets this name, for compatibility 765 * .MAKEFLAGS gets set to the empty string just in case. 766 * MFLAGS also gets initialized empty, for compatibility. 767 */ 768 Var_Set("MAKE", argv[0], VAR_GLOBAL); 769 Var_Set(MAKEFLAGS, "", VAR_GLOBAL); 770 Var_Set("MFLAGS", "", VAR_GLOBAL); 771 Var_Set("MACHINE", machine, VAR_GLOBAL); 772 Var_Set("MACHINE_ARCH", machine_arch, VAR_GLOBAL); 773 Var_Set("MACHINE_CPU", machine_cpu, VAR_GLOBAL); 774 775 /* 776 * First snag any flags out of the MAKE environment variable. 777 * (Note this is *not* MAKEFLAGS since /bin/make uses that and it's 778 * in a different format). 779 */ 764 780 #ifdef POSIX 765 Main_ParseArgLine(getenv("MAKEFLAGS")); 766 #else 767 Main_ParseArgLine(getenv("MAKE")); 768 #endif 769 770 MainParseArgs(argc, argv); 771 772 /* 773 * Be compatible if user did not specify -j and did not explicitly 774 * turned compatibility on 775 */ 776 if (!compatMake && !forceJobs) 777 compatMake = TRUE; 778 779 /* 780 * Initialize archive, target and suffix modules in preparation for 781 * parsing the makefile(s) 782 */ 781 Main_ParseArgLine(getenv("MAKEFLAGS")); 782 #else 783 Main_ParseArgLine(getenv("MAKE")); 784 #endif 785 786 #ifdef KMK 787 /* 788 * Completely ignore the tool argument. 789 */ 790 if (argc > 1 && !kStrCmp(argv[1], "--kMk")) 791 { 792 argc--; 793 argv++; 794 } 795 #endif 796 MainParseArgs(argc, argv); 797 798 /* 799 * Be compatible if user did not specify -j and did not explicitly 800 * turned compatibility on 801 */ 802 if (!compatMake && !forceJobs) 803 compatMake = TRUE; 804 805 /* 806 * Initialize archive, target and suffix modules in preparation for 807 * parsing the makefile(s) 808 */ 783 809 #ifdef USE_ARCHIVES 784 Arch_Init();785 #endif 786 Targ_Init();787 Suff_Init();788 789 DEFAULT = NILGNODE;790 (void)time(&now);791 792 /*793 * Set up the .TARGETS variable to contain the list of targets to be794 * created. If none specified, make the variable empty -- the parser795 * will fill the thing in with the default or .MAIN target.796 */797 if (!Lst_IsEmpty(create)) {798 LstNode ln;799 800 for (ln = Lst_First(create); ln != NILLNODE;801 ln = Lst_Succ(ln)) {802 char *name = (char *)Lst_Datum(ln);803 804 Var_Append(".TARGETS", name, VAR_GLOBAL);805 }806 } else807 Var_Set(".TARGETS", "", VAR_GLOBAL);810 Arch_Init(); 811 #endif 812 Targ_Init(); 813 Suff_Init(); 814 815 DEFAULT = NILGNODE; 816 (void)time(&now); 817 818 /* 819 * Set up the .TARGETS variable to contain the list of targets to be 820 * created. If none specified, make the variable empty -- the parser 821 * will fill the thing in with the default or .MAIN target. 822 */ 823 if (!Lst_IsEmpty(create)) { 824 LstNode ln; 825 826 for (ln = Lst_First(create); ln != NILLNODE; 827 ln = Lst_Succ(ln)) { 828 char *name = (char *)Lst_Datum(ln); 829 830 Var_Append(".TARGETS", name, VAR_GLOBAL); 831 } 832 } else 833 Var_Set(".TARGETS", "", VAR_GLOBAL); 808 834 809 835 810 836 #ifdef KMK 811 /*812 * Add current directory tree to system include path all levels up to the root.837 /* 838 * Add current directory tree to system include path all levels up to the root. 813 839 * ASSUMES that curdir is absolute. 814 */840 */ 815 841 { 816 842 char * psz = estrdup(curdir); … … 834 860 835 861 #else 836 /*837 * If no user-supplied system path was given (through the -m option)838 * add the directories from the DEFSYSPATH (more than one may be given839 * as dir1:...:dirn) to the system include path.840 */841 if (Lst_IsEmpty(sysIncPath)) {842 for (start = syspath; *start != '\0'; start = cp) {843 for (cp = start; *cp != '\0' && *cp != ':'; cp++)844 continue;845 if (*cp == '\0') {846 Dir_AddDir(sysIncPath, start);847 } else {848 *cp++ = '\0';849 Dir_AddDir(sysIncPath, start);850 }851 }852 }862 /* 863 * If no user-supplied system path was given (through the -m option) 864 * add the directories from the DEFSYSPATH (more than one may be given 865 * as dir1:...:dirn) to the system include path. 866 */ 867 if (Lst_IsEmpty(sysIncPath)) { 868 for (start = syspath; *start != '\0'; start = cp) { 869 for (cp = start; *cp != '\0' && *cp != ':'; cp++) 870 continue; 871 if (*cp == '\0') { 872 Dir_AddDir(sysIncPath, start); 873 } else { 874 *cp++ = '\0'; 875 Dir_AddDir(sysIncPath, start); 876 } 877 } 878 } 853 879 #endif 854 880 855 /*856 * Read in the built-in rules first, followed by the specified857 * makefile, if it was (makefile != (char *) NULL), or the default858 * Makefile and makefile, in that order, if it wasn't.859 */860 if (!noBuiltins) {861 LstNode ln;862 863 sysMkPath = Lst_Init (FALSE);864 Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath);881 /* 882 * Read in the built-in rules first, followed by the specified 883 * makefile, if it was (makefile != (char *) NULL), or the default 884 * Makefile and makefile, in that order, if it wasn't. 885 */ 886 if (!noBuiltins) { 887 LstNode ln; 888 889 sysMkPath = Lst_Init (FALSE); 890 Dir_Expand (_PATH_DEFSYSMK, sysIncPath, sysMkPath); 865 891 #ifdef NMAKE 866 if (!Lst_IsEmpty(sysMkPath))892 if (!Lst_IsEmpty(sysMkPath)) 867 893 { 868 894 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); … … 872 898 873 899 #elif defined(KMK) 874 if (!Lst_IsEmpty(sysMkPath))900 if (!Lst_IsEmpty(sysMkPath)) 875 901 { 876 902 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); … … 879 905 880 906 } 881 Error(MAKE_NAME ": no config rules (%s).", _PATH_DEFSYSMK);882 #else 883 if (Lst_IsEmpty(sysMkPath))884 Fatal(MAKE_NAME ": no system rules (%s).", _PATH_DEFSYSMK);885 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile);886 if (ln != NILLNODE)887 Fatal(MAKE_NAME ": cannot open %s.", (char *)Lst_Datum(ln));888 #endif 889 }890 891 if (!Lst_IsEmpty(makefiles)) {892 LstNode ln;893 894 ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile);895 if (ln != NILLNODE)896 Fatal(MAKE_NAME ": cannot open %s.", (char *)Lst_Datum(ln));897 } else907 Error(MAKE_NAME ": no config rules (%s).", _PATH_DEFSYSMK); 908 #else 909 if (Lst_IsEmpty(sysMkPath)) 910 Fatal(MAKE_NAME ": no system rules (%s).", _PATH_DEFSYSMK); 911 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); 912 if (ln != NILLNODE) 913 Fatal(MAKE_NAME ": cannot open %s.", (char *)Lst_Datum(ln)); 914 #endif 915 } 916 917 if (!Lst_IsEmpty(makefiles)) { 918 LstNode ln; 919 920 ln = Lst_Find(makefiles, (ClientData)NULL, ReadMakefile); 921 if (ln != NILLNODE) 922 Fatal(MAKE_NAME ": cannot open %s.", (char *)Lst_Datum(ln)); 923 } else 898 924 #ifdef KMK 899 925 if ( !ReadMakefile("Makefile.kMk", NULL) … … 911 937 #endif 912 938 913 (void)ReadMakefile(".depend", NULL);914 915 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL);916 efree(p1);917 918 /* Install all the flags into the MAKE envariable. */919 if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p)939 (void)ReadMakefile(".depend", NULL); 940 941 Var_Append("MFLAGS", Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1), VAR_GLOBAL); 942 efree(p1); 943 944 /* Install all the flags into the MAKE envariable. */ 945 if (((p = Var_Value(MAKEFLAGS, VAR_GLOBAL, &p1)) != NULL) && *p) 920 946 #ifdef POSIX 921 947 #ifdef USE_KLIB 922 948 kEnvSet("MAKEFLAGS", p, TRUE); 923 949 #else 924 setenv("MAKEFLAGS", p, 1);950 setenv("MAKEFLAGS", p, 1); 925 951 #endif 926 952 #else 927 953 #ifdef USE_KLIB 928 kEnvSet("MAKE", p, TRUE);954 kEnvSet("MAKE", p, TRUE); 929 955 #else 930 setenv("MAKE", p, 1);956 setenv("MAKE", p, 1); 931 957 #endif 932 958 #endif 933 efree(p1);934 935 /*936 * For compatibility, look at the directories in the VPATH variable937 * and add them to the search path, if the variable is defined. The938 * variable's value is in the same format as the PATH envariable, i.e.939 * <directory>:<directory>:<directory>...940 */941 if (Var_Exists("VPATH", VAR_CMD)) {942 char *vpath, *path, *cp, savec;943 /*944 * GCC stores string constants in read-only memory, but945 * Var_Subst will want to write this thing, so store it946 * in an array947 */948 static char VPATH[] = "${VPATH}";949 950 vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE);951 path = vpath;952 do {953 /* skip to end of directory */954 for (cp = path; *cp != ':' && *cp != '\0'; cp++)955 continue;956 /* Save terminator character so know when to stop */957 savec = *cp;958 *cp = '\0';959 /* Add directory to search path */960 Dir_AddDir(dirSearchPath, path);961 *cp = savec;962 path = cp + 1;963 } while (savec == ':');964 (void)efree((Address)vpath);965 }966 967 /*968 * Now that all search paths have been read for suffixes et al, it's969 * time to add the default search path to their lists...970 */971 Suff_DoPaths();972 973 /* print the initial graph, if the user requested it */974 if (DEBUG(GRAPH1))975 Targ_PrintGraph(1);976 977 /* print the values of any variables requested by the user */978 if (printVars) {979 LstNode ln;980 981 for (ln = Lst_First(variables); ln != NILLNODE;982 ln = Lst_Succ(ln)) {983 char *value;984 if (expandVars) {985 p1 = emalloc(strlen((char *)Lst_Datum(ln)) + 1 + 3);986 /* This sprintf is safe, because of the malloc above */987 (void)sprintf(p1, "${%s}", (char *)Lst_Datum(ln));988 value = Var_Subst(NULL, p1, VAR_GLOBAL, FALSE);989 } else {990 value = Var_Value((char *)Lst_Datum(ln),991 VAR_GLOBAL, &p1);992 }993 printf("%s\n", value ? value : "");994 if (p1)995 efree(p1);996 }997 }998 999 /*1000 * Have now read the entire graph and need to make a list of targets1001 * to create. If none was given on the command line, we consult the1002 * parsing module to find the main target(s) to create.1003 */1004 if (Lst_IsEmpty(create))1005 targs = Parse_MainName();1006 else1007 targs = Targ_FindList(create, TARG_CREATE);1008 1009 if (!compatMake && !printVars) {1010 /*1011 * Initialize job module before traversing the graph, now that1012 * any .BEGIN and .END targets have been read. This is done1013 * only if the -q flag wasn't given (to prevent the .BEGIN from1014 * being executed should it exist).1015 */1016 if (!queryFlag) {1017 if (maxLocal == -1)1018 maxLocal = maxJobs;1019 Job_Init(maxJobs, maxLocal);1020 jobsRunning = TRUE;1021 }1022 1023 /* Traverse the graph, checking on all the targets */1024 outOfDate = Make_Run(targs);1025 } else if (!printVars) {1026 /*1027 * Compat_Init will take care of creating all the targets as1028 * well as initializing the module.1029 */1030 Compat_Run(targs);1031 }1032 1033 Lst_Destroy(targs, NOFREE);1034 Lst_Destroy(variables, NOFREE);1035 Lst_Destroy(makefiles, NOFREE);1036 Lst_Destroy(create, (void (*) __P((ClientData))) efree);1037 1038 /* print the graph now it's been processed if the user requested it */1039 if (DEBUG(GRAPH2))1040 Targ_PrintGraph(2);1041 1042 Suff_End();959 efree(p1); 960 961 /* 962 * For compatibility, look at the directories in the VPATH variable 963 * and add them to the search path, if the variable is defined. The 964 * variable's value is in the same format as the PATH envariable, i.e. 965 * <directory>:<directory>:<directory>... 966 */ 967 if (Var_Exists("VPATH", VAR_CMD)) { 968 char *vpath, *path, *cp, savec; 969 /* 970 * GCC stores string constants in read-only memory, but 971 * Var_Subst will want to write this thing, so store it 972 * in an array 973 */ 974 static char VPATH[] = "${VPATH}"; 975 976 vpath = Var_Subst(NULL, VPATH, VAR_CMD, FALSE); 977 path = vpath; 978 do { 979 /* skip to end of directory */ 980 for (cp = path; *cp != ':' && *cp != '\0'; cp++) 981 continue; 982 /* Save terminator character so know when to stop */ 983 savec = *cp; 984 *cp = '\0'; 985 /* Add directory to search path */ 986 Dir_AddDir(dirSearchPath, path); 987 *cp = savec; 988 path = cp + 1; 989 } while (savec == ':'); 990 (void)efree((Address)vpath); 991 } 992 993 /* 994 * Now that all search paths have been read for suffixes et al, it's 995 * time to add the default search path to their lists... 996 */ 997 Suff_DoPaths(); 998 999 /* print the initial graph, if the user requested it */ 1000 if (DEBUG(GRAPH1)) 1001 Targ_PrintGraph(1); 1002 1003 /* print the values of any variables requested by the user */ 1004 if (printVars) { 1005 LstNode ln; 1006 1007 for (ln = Lst_First(variables); ln != NILLNODE; 1008 ln = Lst_Succ(ln)) { 1009 char *value; 1010 if (expandVars) { 1011 p1 = emalloc(strlen((char *)Lst_Datum(ln)) + 1 + 3); 1012 /* This sprintf is safe, because of the malloc above */ 1013 (void)sprintf(p1, "${%s}", (char *)Lst_Datum(ln)); 1014 value = Var_Subst(NULL, p1, VAR_GLOBAL, FALSE); 1015 } else { 1016 value = Var_Value((char *)Lst_Datum(ln), 1017 VAR_GLOBAL, &p1); 1018 } 1019 printf("%s\n", value ? value : ""); 1020 if (p1) 1021 efree(p1); 1022 } 1023 } 1024 1025 /* 1026 * Have now read the entire graph and need to make a list of targets 1027 * to create. If none was given on the command line, we consult the 1028 * parsing module to find the main target(s) to create. 1029 */ 1030 if (Lst_IsEmpty(create)) 1031 targs = Parse_MainName(); 1032 else 1033 targs = Targ_FindList(create, TARG_CREATE); 1034 1035 if (!compatMake && !printVars) { 1036 /* 1037 * Initialize job module before traversing the graph, now that 1038 * any .BEGIN and .END targets have been read. This is done 1039 * only if the -q flag wasn't given (to prevent the .BEGIN from 1040 * being executed should it exist). 1041 */ 1042 if (!queryFlag) { 1043 if (maxLocal == -1) 1044 maxLocal = maxJobs; 1045 Job_Init(maxJobs, maxLocal); 1046 jobsRunning = TRUE; 1047 } 1048 1049 /* Traverse the graph, checking on all the targets */ 1050 outOfDate = Make_Run(targs); 1051 } else if (!printVars) { 1052 /* 1053 * Compat_Init will take care of creating all the targets as 1054 * well as initializing the module. 1055 */ 1056 Compat_Run(targs); 1057 } 1058 1059 Lst_Destroy(targs, NOFREE); 1060 Lst_Destroy(variables, NOFREE); 1061 Lst_Destroy(makefiles, NOFREE); 1062 Lst_Destroy(create, (void (*) __P((ClientData))) efree); 1063 1064 /* print the graph now it's been processed if the user requested it */ 1065 if (DEBUG(GRAPH2)) 1066 Targ_PrintGraph(2); 1067 1068 Suff_End(); 1043 1069 Targ_End(); 1044 1070 #ifdef USE_ARCHIVES 1045 Arch_End();1046 #endif 1047 str_end();1048 Var_End();1049 Parse_End();1050 Dir_End();1051 1052 if (queryFlag && outOfDate)1053 return(1);1054 else1055 return(0);1071 Arch_End(); 1072 #endif 1073 str_end(); 1074 Var_End(); 1075 Parse_End(); 1076 Dir_End(); 1077 1078 if (queryFlag && outOfDate) 1079 return(1); 1080 else 1081 return(0); 1056 1082 } 1057 1083 1058 1084 /*- 1059 1085 * ReadMakefile -- 1060 * Open and parse the given makefile.1086 * Open and parse the given makefile. 1061 1087 * 1062 1088 * Results: 1063 * TRUE if ok. FALSE if couldn't open file.1089 * TRUE if ok. FALSE if couldn't open file. 1064 1090 * 1065 1091 * Side Effects: 1066 * lots1092 * lots 1067 1093 */ 1068 1094 static Boolean 1069 1095 ReadMakefile(p, q) 1070 ClientData p, q;1071 { 1072 char *fname = p;/* makefile to read */1073 extern Lst parseIncPath;1074 FILE *stream;1075 char *name, path[MAXPATHLEN + 1];1076 char *MAKEFILE;1077 int setMAKEFILE;1078 1079 if (!strcmp(fname, "-")) {1080 Parse_File("(stdin)", stdin);1081 Var_Set("MAKEFILE", "", VAR_GLOBAL);1082 } else {1083 setMAKEFILE = strcmp(fname, ".depend");1084 1085 /* if we've chdir'd, rebuild the path name */1086 if (curdir != objdir && *fname != '/') {1087 (void)snprintf(path, MAXPATHLEN, "%s/%s", curdir, fname);1088 if (realpath(path, path) != NULL &&1089 (stream = fopen(path, "r")) != NULL) {1090 MAKEFILE = fname;1091 fname = path;1092 goto found;1093 }1094 } else if (realpath(fname, path) != NULL) {1095 MAKEFILE = fname;1096 fname = path;1097 if ((stream = fopen(fname, "r")) != NULL)1098 goto found;1099 }1100 /* look in -I and system include directories. */1101 name = Dir_FindFile(fname, parseIncPath);1102 if (!name)1103 name = Dir_FindFile(fname, sysIncPath);1104 if (!name || !(stream = fopen(name, "r")))1105 return(FALSE);1106 MAKEFILE = fname = name;1107 /*1108 * set the MAKEFILE variable desired by System V fans -- the1109 * placement of the setting here means it gets set to the last1110 * makefile specified, as it is set by SysV make.1111 */1096 ClientData p, q; 1097 { 1098 char *fname = p; /* makefile to read */ 1099 extern Lst parseIncPath; 1100 FILE *stream; 1101 char *name, path[MAXPATHLEN + 1]; 1102 char *MAKEFILE; 1103 int setMAKEFILE; 1104 1105 if (!strcmp(fname, "-")) { 1106 Parse_File("(stdin)", stdin); 1107 Var_Set("MAKEFILE", "", VAR_GLOBAL); 1108 } else { 1109 setMAKEFILE = strcmp(fname, ".depend"); 1110 1111 /* if we've chdir'd, rebuild the path name */ 1112 if (curdir != objdir && *fname != '/') { 1113 (void)snprintf(path, MAXPATHLEN, "%s/%s", curdir, fname); 1114 if (realpath(path, path) != NULL && 1115 (stream = fopen(path, "r")) != NULL) { 1116 MAKEFILE = fname; 1117 fname = path; 1118 goto found; 1119 } 1120 } else if (realpath(fname, path) != NULL) { 1121 MAKEFILE = fname; 1122 fname = path; 1123 if ((stream = fopen(fname, "r")) != NULL) 1124 goto found; 1125 } 1126 /* look in -I and system include directories. */ 1127 name = Dir_FindFile(fname, parseIncPath); 1128 if (!name) 1129 name = Dir_FindFile(fname, sysIncPath); 1130 if (!name || !(stream = fopen(name, "r"))) 1131 return(FALSE); 1132 MAKEFILE = fname = name; 1133 /* 1134 * set the MAKEFILE variable desired by System V fans -- the 1135 * placement of the setting here means it gets set to the last 1136 * makefile specified, as it is set by SysV make. 1137 */ 1112 1138 found: 1113 if (setMAKEFILE)1114 Var_Set("MAKEFILE", MAKEFILE, VAR_GLOBAL);1115 Parse_File(fname, stream);1116 (void)fclose(stream);1117 }1118 return(TRUE);1139 if (setMAKEFILE) 1140 Var_Set("MAKEFILE", MAKEFILE, VAR_GLOBAL); 1141 Parse_File(fname, stream); 1142 (void)fclose(stream); 1143 } 1144 return(TRUE); 1119 1145 } 1120 1146 1121 1147 /*- 1122 1148 * Cmd_Exec -- 1123 * Execute the command in cmd, and return the output of that command1124 * in a string.1149 * Execute the command in cmd, and return the output of that command 1150 * in a string. 1125 1151 * 1126 1152 * Results: 1127 * A string containing the output of the command, or the empty string1128 * If err is not NULL, it contains the reason for the command failure1153 * A string containing the output of the command, or the empty string 1154 * If err is not NULL, it contains the reason for the command failure 1129 1155 * 1130 1156 * Side Effects: 1131 * The string must be freed by the caller.1157 * The string must be freed by the caller. 1132 1158 */ 1133 1159 char * … … 1136 1162 char **err; 1137 1163 { 1138 char *args[4]; /* Args for invoking the shell */ 1139 int fds[2]; /* Pipe streams */ 1140 int cpid; /* Child PID */ 1141 int pid; /* PID from wait() */ 1142 char *res; /* result */ 1143 int status; /* command exit status */ 1144 Buffer buf; /* buffer to store the result */ 1145 char *cp; 1146 int cc; 1164 #ifdef KMK 1165 /** @todo this can be executed directly in the shell!!! 1166 */ 1167 int rc; 1168 char * args[4]; /* Args for invoking the shell */ 1169 KFILE fhPipe; /* Pipe handle. */ 1170 KPID cpid; /* Child PID */ 1171 KPROCRES status; /* Child exit status. */ 1172 char * res; /* result */ 1173 Buffer buf; /* buffer to store the result */ 1174 char * cp; 1175 int cc; 1176 1177 1178 *err = NULL; 1179 1180 /* 1181 * Set up arguments for shell 1182 */ 1183 args[0] = argv0; 1184 args[1] = "--kShell"; 1185 args[2] = cmd; 1186 args[3] = NULL; 1187 1188 1189 /* 1190 * Execute command in pipe. 1191 */ 1192 rc = kProcPiped(&args[0], 1193 KPROCPIPED_FLAGS_STDOUT, 1194 &cpid, 1195 &fhPipe); 1196 if (!rc) 1197 { 1198 FILE *phPipe; 1199 buf = Buf_Init (MAKE_BSIZE); 1200 1201 /* 1202 * Read the output using a file stream for automatic '\n' newline conv. 1203 */ 1204 phPipe = fdopen(fhPipe, "r"); 1205 cc = -1; 1206 if (phPipe) 1207 { 1208 do { 1209 char result[BUFSIZ]; 1210 cc = fread(result, 1, sizeof(result), phPipe); 1211 if (cc > 0) 1212 Buf_AddBytes(buf, cc, (Byte *) result); 1213 } 1214 while (cc > 0 || (cc == -1 && errno == EINTR)); 1215 fclose(phPipe); 1216 } 1217 1218 /* 1219 * Close the input side of the pipe and wait for the child to exit. 1220 */ 1221 kFileClose(fhPipe); 1222 rc = kProcWait(cpid, KPROCWAIT_FLAGS_WAIT, &status, NULL); 1223 1224 /* 1225 * Check for errors, get buffered bits. 1226 */ 1227 if (cc == -1) 1228 *err = "Error reading shell's output for \"%s\""; 1229 1230 res = (char *)Buf_GetAll (buf, &cc); 1231 Buf_Destroy (buf, FALSE); 1232 1233 if (status.uExitCode || status.fFlags != KPROCRES_FLAGS_NORMAL) 1234 *err = "\"%s\" returned non-zero status"; 1235 1236 /* 1237 * Null-terminate the result, convert newlines to spaces and 1238 * install it in the variable. Final newline is removed. 1239 */ 1240 res[cc] = '\0'; 1241 cp = &res[cc] - 1; 1242 if (*cp == '\n') 1243 *cp-- = '\0'; 1244 1245 while (cp >= res) 1246 { 1247 if (*cp == '\n') 1248 *cp = ' '; 1249 cp--; 1250 } 1251 1252 return res; 1253 } 1254 else 1255 *err = "Couldn't exec \"%s\""; 1256 1257 res = emalloc(1); 1258 *res = '\0'; 1259 return res; 1260 1261 #else /* not KMK */ 1262 1263 char *args[4]; /* Args for invoking the shell */ 1264 int fds[2]; /* Pipe streams */ 1265 int cpid; /* Child PID */ 1266 int pid; /* PID from wait() */ 1267 char *res; /* result */ 1268 int status; /* command exit status */ 1269 Buffer buf; /* buffer to store the result */ 1270 char *cp; 1271 int cc; 1147 1272 1148 1273 … … 1161 1286 */ 1162 1287 if (pipe(fds) == -1) { 1163 *err = "Couldn't create pipe for \"%s\"";1164 goto bad;1288 *err = "Couldn't create pipe for \"%s\""; 1289 goto bad; 1165 1290 } 1166 1291 … … 1169 1294 */ 1170 1295 #ifdef __EMX__ 1171 switch (cpid = fork()) { 1172 #else 1173 switch (cpid = vfork()) { 1174 #endif 1296 switch (cpid = fork()) 1297 #else 1298 switch (cpid = vfork()) 1299 #endif 1300 { 1175 1301 case 0: 1176 /*1177 * Close input side of pipe1178 */1179 (void) close(fds[0]);1180 1181 /*1182 * Duplicate the output stream to the shell's output, then1183 * shut the extra thing down. Note we don't fetch the error1184 * stream...why not? Why?1185 */1186 (void) dup2(fds[1], 1);1187 (void) close(fds[1]);1302 /* 1303 * Close input side of pipe 1304 */ 1305 (void) close(fds[0]); 1306 1307 /* 1308 * Duplicate the output stream to the shell's output, then 1309 * shut the extra thing down. Note we don't fetch the error 1310 * stream...why not? Why? 1311 */ 1312 (void) dup2(fds[1], 1); 1313 (void) close(fds[1]); 1188 1314 1189 1315 #ifdef OS2 … … 1194 1320 if (!psz) 1195 1321 psz = "c:\\os2\\cmd.exe"; 1196 (void) execv(psz, args);1322 (void) execv(psz, args); 1197 1323 } 1198 1324 #else 1199 (void) execv("/bin/sh", args);1325 (void) execv("/bin/sh", args); 1200 1326 #endif 1201 _exit(1);1202 /*NOTREACHED*/1327 _exit(1); 1328 /*NOTREACHED*/ 1203 1329 1204 1330 case -1: 1205 *err = "Couldn't exec \"%s\"";1206 goto bad;1331 *err = "Couldn't exec \"%s\""; 1332 goto bad; 1207 1333 1208 1334 default: 1209 /*1210 * No need for the writing half1211 */1212 (void) close(fds[1]);1213 1214 buf = Buf_Init (MAKE_BSIZE);1215 1216 do {1217 char result[BUFSIZ];1218 cc = read(fds[0], result, sizeof(result));1219 if (cc > 0)1220 Buf_AddBytes(buf, cc, (Byte *) result);1221 }1222 while (cc > 0 || (cc == -1 && errno == EINTR));1223 1224 /*1225 * Close the input side of the pipe.1226 */1227 (void) close(fds[0]);1228 1229 /*1230 * Wait for the process to exit.1231 */1232 while(((pid = wait(&status)) != cpid) && (pid >= 0))1233 continue;1234 1235 if (cc == -1)1236 *err = "Error reading shell's output for \"%s\"";1237 1238 res = (char *)Buf_GetAll (buf, &cc);1239 Buf_Destroy (buf, FALSE);1240 1241 if (status)1242 *err = "\"%s\" returned non-zero status";1243 1244 /*1245 * Null-terminate the result, convert newlines to spaces and1246 * install it in the variable.1247 */1248 res[cc] = '\0';1249 cp = &res[cc] - 1;1250 1251 if (*cp == '\n') {1252 /*1253 * A final newline is just stripped1254 */1255 *cp-- = '\0';1256 }1257 while (cp >= res) {1258 if (*cp == '\n') {1259 *cp = ' ';1260 }1261 cp--;1262 }1263 break;1335 /* 1336 * No need for the writing half 1337 */ 1338 (void) close(fds[1]); 1339 1340 buf = Buf_Init (MAKE_BSIZE); 1341 1342 do { 1343 char result[BUFSIZ]; 1344 cc = read(fds[0], result, sizeof(result)); 1345 if (cc > 0) 1346 Buf_AddBytes(buf, cc, (Byte *) result); 1347 } 1348 while (cc > 0 || (cc == -1 && errno == EINTR)); 1349 1350 /* 1351 * Close the input side of the pipe. 1352 */ 1353 (void) close(fds[0]); 1354 1355 /* 1356 * Wait for the process to exit. 1357 */ 1358 while(((pid = wait(&status)) != cpid) && (pid >= 0)) 1359 continue; 1360 1361 if (cc == -1) 1362 *err = "Error reading shell's output for \"%s\""; 1363 1364 res = (char *)Buf_GetAll (buf, &cc); 1365 Buf_Destroy (buf, FALSE); 1366 1367 if (status) 1368 *err = "\"%s\" returned non-zero status"; 1369 1370 /* 1371 * Null-terminate the result, convert newlines to spaces and 1372 * install it in the variable. 1373 */ 1374 res[cc] = '\0'; 1375 cp = &res[cc] - 1; 1376 1377 if (*cp == '\n') { 1378 /* 1379 * A final newline is just stripped 1380 */ 1381 *cp-- = '\0'; 1382 } 1383 while (cp >= res) { 1384 if (*cp == '\n') { 1385 *cp = ' '; 1386 } 1387 cp--; 1388 } 1389 break; 1264 1390 } 1265 1391 return res; … … 1268 1394 *res = '\0'; 1269 1395 return res; 1396 #endif /* KMK */ 1270 1397 } 1271 1398 1272 1399 /*- 1273 1400 * Error -- 1274 * Print an error message given its format.1401 * Print an error message given its format. 1275 1402 * 1276 1403 * Results: 1277 * None.1404 * None. 1278 1405 * 1279 1406 * Side Effects: 1280 * The message is printed.1407 * The message is printed. 1281 1408 */ 1282 1409 /* VARARGS */ … … 1286 1413 #else 1287 1414 Error(va_alist) 1288 va_dcl1289 #endif 1290 { 1291 va_list ap;1415 va_dcl 1416 #endif 1417 { 1418 va_list ap; 1292 1419 #if defined(__STDC__) || defined(__IBMC__) 1293 va_start(ap, fmt);1294 #else 1295 char *fmt;1296 1297 va_start(ap);1298 fmt = va_arg(ap, char *);1299 #endif 1300 (void)vfprintf(stderr, fmt, ap);1301 va_end(ap);1302 (void)fprintf(stderr, "\n");1303 (void)fflush(stderr);1420 va_start(ap, fmt); 1421 #else 1422 char *fmt; 1423 1424 va_start(ap); 1425 fmt = va_arg(ap, char *); 1426 #endif 1427 (void)vfprintf(stderr, fmt, ap); 1428 va_end(ap); 1429 (void)fprintf(stderr, "\n"); 1430 (void)fflush(stderr); 1304 1431 } 1305 1432 1306 1433 /*- 1307 1434 * Fatal -- 1308 * Produce a Fatal error message. If jobs are running, waits for them1309 * to finish.1435 * Produce a Fatal error message. If jobs are running, waits for them 1436 * to finish. 1310 1437 * 1311 1438 * Results: 1312 * None1439 * None 1313 1440 * 1314 1441 * Side Effects: 1315 * The program exits1442 * The program exits 1316 1443 */ 1317 1444 /* VARARGS */ … … 1321 1448 #else 1322 1449 Fatal(va_alist) 1323 va_dcl1324 #endif 1325 { 1326 va_list ap;1450 va_dcl 1451 #endif 1452 { 1453 va_list ap; 1327 1454 #if defined(__STDC__) || defined(__IBMC__) 1328 va_start(ap, fmt);1329 #else 1330 char *fmt;1331 1332 va_start(ap);1333 fmt = va_arg(ap, char *);1334 #endif 1335 if (jobsRunning)1336 Job_Wait();1337 1338 (void)vfprintf(stderr, fmt, ap);1339 va_end(ap);1340 (void)fprintf(stderr, "\n");1341 (void)fflush(stderr);1342 1343 if (DEBUG(GRAPH2))1344 Targ_PrintGraph(2);1345 exit(2);/* Not 1 so -q can distinguish error */1455 va_start(ap, fmt); 1456 #else 1457 char *fmt; 1458 1459 va_start(ap); 1460 fmt = va_arg(ap, char *); 1461 #endif 1462 if (jobsRunning) 1463 Job_Wait(); 1464 1465 (void)vfprintf(stderr, fmt, ap); 1466 va_end(ap); 1467 (void)fprintf(stderr, "\n"); 1468 (void)fflush(stderr); 1469 1470 if (DEBUG(GRAPH2)) 1471 Targ_PrintGraph(2); 1472 exit(2); /* Not 1 so -q can distinguish error */ 1346 1473 } 1347 1474 1348 1475 /* 1349 1476 * Punt -- 1350 * Major exception once jobs are being created. Kills all jobs, prints1351 * a message and exits.1477 * Major exception once jobs are being created. Kills all jobs, prints 1478 * a message and exits. 1352 1479 * 1353 1480 * Results: 1354 * None1481 * None 1355 1482 * 1356 1483 * Side Effects: 1357 * All children are killed indiscriminately and the program Lib_Exits1484 * All children are killed indiscriminately and the program Lib_Exits 1358 1485 */ 1359 1486 /* VARARGS */ … … 1363 1490 #else 1364 1491 Punt(va_alist) 1365 va_dcl1366 #endif 1367 { 1368 va_list ap;1492 va_dcl 1493 #endif 1494 { 1495 va_list ap; 1369 1496 #if defined(__STDC__) || defined(__IBMC__) 1370 va_start(ap, fmt);1371 #else 1372 char *fmt;1373 1374 va_start(ap);1375 fmt = va_arg(ap, char *);1376 #endif 1377 1378 (void)fprintf(stderr, MAKE_NAME ": ");1379 (void)vfprintf(stderr, fmt, ap);1380 va_end(ap);1381 (void)fprintf(stderr, "\n");1382 (void)fflush(stderr);1383 1384 DieHorribly();1497 va_start(ap, fmt); 1498 #else 1499 char *fmt; 1500 1501 va_start(ap); 1502 fmt = va_arg(ap, char *); 1503 #endif 1504 1505 (void)fprintf(stderr, MAKE_NAME ": "); 1506 (void)vfprintf(stderr, fmt, ap); 1507 va_end(ap); 1508 (void)fprintf(stderr, "\n"); 1509 (void)fflush(stderr); 1510 1511 DieHorribly(); 1385 1512 } 1386 1513 1387 1514 /*- 1388 1515 * DieHorribly -- 1389 * Exit without giving a message.1516 * Exit without giving a message. 1390 1517 * 1391 1518 * Results: 1392 * None1519 * None 1393 1520 * 1394 1521 * Side Effects: 1395 * A big one...1522 * A big one... 1396 1523 */ 1397 1524 void 1398 1525 DieHorribly() 1399 1526 { 1400 if (jobsRunning)1401 Job_AbortAll();1402 if (DEBUG(GRAPH2))1403 Targ_PrintGraph(2);1404 exit(2);/* Not 1, so -q can distinguish error */1527 if (jobsRunning) 1528 Job_AbortAll(); 1529 if (DEBUG(GRAPH2)) 1530 Targ_PrintGraph(2); 1531 exit(2); /* Not 1, so -q can distinguish error */ 1405 1532 } 1406 1533 1407 1534 /* 1408 1535 * Finish -- 1409 * Called when aborting due to errors in child shell to signal1410 * abnormal exit.1536 * Called when aborting due to errors in child shell to signal 1537 * abnormal exit. 1411 1538 * 1412 1539 * Results: 1413 * None1540 * None 1414 1541 * 1415 1542 * Side Effects: 1416 * The program exits1543 * The program exits 1417 1544 */ 1418 1545 void 1419 1546 Finish(errors) 1420 int errors;/* number of errors encountered in Make_Make */1421 { 1422 Fatal("%d error%s", errors, errors == 1 ? "" : "s");1547 int errors; /* number of errors encountered in Make_Make */ 1548 { 1549 Fatal("%d error%s", errors, errors == 1 ? "" : "s"); 1423 1550 } 1424 1551 1425 1552 /* 1426 1553 * emalloc -- 1427 * malloc, but die on error.1554 * malloc, but die on error. 1428 1555 */ 1429 1556 void * 1430 1557 emalloc(len) 1431 size_t len;1432 { 1433 void *p;1434 1435 if ((p = malloc(len)) == NULL)1436 enomem();1437 return(p);1558 size_t len; 1559 { 1560 void *p; 1561 1562 if ((p = malloc(len)) == NULL) 1563 enomem(); 1564 return(p); 1438 1565 } 1439 1566 1440 1567 /* 1441 1568 * estrdup -- 1442 * strdup, but die on error.1569 * strdup, but die on error. 1443 1570 */ 1444 1571 char * 1445 1572 estrdup(str) 1446 const char *str;1447 { 1448 char *p;1449 1450 if ((p = strdup(str)) == NULL)1451 enomem();1452 return(p);1573 const char *str; 1574 { 1575 char *p; 1576 1577 if ((p = strdup(str)) == NULL) 1578 enomem(); 1579 return(p); 1453 1580 } 1454 1581 1455 1582 /* 1456 1583 * erealloc -- 1457 * realloc, but die on error.1584 * realloc, but die on error. 1458 1585 */ 1459 1586 void * 1460 1587 erealloc(ptr, size) 1461 void *ptr;1462 size_t size;1463 { 1464 if ((ptr = realloc(ptr, size)) == NULL)1465 enomem();1466 return(ptr);1588 void *ptr; 1589 size_t size; 1590 { 1591 if ((ptr = realloc(ptr, size)) == NULL) 1592 enomem(); 1593 return(ptr); 1467 1594 } 1468 1595 … … 1481 1608 /* 1482 1609 * enomem -- 1483 * die when out of memory.1610 * die when out of memory. 1484 1611 */ 1485 1612 void 1486 1613 enomem() 1487 1614 { 1488 err(2, NULL);1615 err(2, NULL); 1489 1616 } 1490 1617 1491 1618 /* 1492 1619 * enunlink -- 1493 * Remove a file carefully, avoiding directories.1620 * Remove a file carefully, avoiding directories. 1494 1621 */ 1495 1622 int 1496 1623 eunlink(file) 1497 const char *file;1498 { 1499 struct stat st;1500 1501 #if def __EMX__1502 if (stat(file, &st) == -1)1503 #else 1504 if (lstat(file, &st) == -1)1505 #endif 1506 return -1;1507 1508 if (S_ISDIR(st.st_mode)) {1509 errno = EISDIR;1510 return -1;1511 }1512 return unlink(file);1624 const char *file; 1625 { 1626 struct stat st; 1627 1628 #if defined(OS2) 1629 if (stat(file, &st) == -1) 1630 #else 1631 if (lstat(file, &st) == -1) 1632 #endif 1633 return -1; 1634 1635 if (S_ISDIR(st.st_mode)) { 1636 errno = EISDIR; 1637 return -1; 1638 } 1639 return unlink(file); 1513 1640 } 1514 1641 1515 1642 /* 1516 1643 * usage -- 1517 * exit with usage message1644 * exit with usage message 1518 1645 */ 1519 1646 static void 1520 1647 usage() 1521 1648 { 1522 (void)fprintf(stderr, "%s\n%s\n%s\n"1649 (void)fprintf(stderr, "%s\n%s\n%s\n" 1523 1650 #ifdef NMAKE 1524 1651 "%s\n" … … 1538 1665 #endif 1539 1666 ); 1540 exit(2);1667 exit(2); 1541 1668 } 1542 1669 -
trunk/src/kmk/make.c
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93";41 static char sccsid[] = "@(#)make.c 8.1 (Berkeley) 6/6/93"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/make.c,v 1.11 1999/09/11 13:08:01 hoek Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * make.c -- 50 * The functions which perform the examination of targets and51 * their suitability for creation51 * The functions which perform the examination of targets and 52 * their suitability for creation 52 53 * 53 54 * Interface: 54 * Make_RunInitialize things for the module and recreate55 * whatever needs recreating. Returns TRUE if56 * work was (or would have been) done and FALSE57 * otherwise.58 * 59 * Make_UpdateUpdate all parents of a given child. Performs60 * various bookkeeping chores like the updating61 * of the cmtime field of the parent, filling62 * of the IMPSRC context variable, etc. It will63 * place the parent on the toBeMade queue if it64 * should be.65 * 66 * Make_TimeStampFunction to set the parent's cmtime field67 * based on a child's modification time.68 * 69 * Make_DoAllVarSet up the various local variables for a70 * target, including the .ALLSRC variable, making71 * sure that any variable that needs to exist72 * at the very least has the empty value.73 * 74 * Make_OODateDetermine if a target is out-of-date.75 * 76 * Make_HandleUseSee if a child is a .USE node for a parent77 * and perform the .USE actions if so.55 * Make_Run Initialize things for the module and recreate 56 * whatever needs recreating. Returns TRUE if 57 * work was (or would have been) done and FALSE 58 * otherwise. 59 * 60 * Make_Update Update all parents of a given child. Performs 61 * various bookkeeping chores like the updating 62 * of the cmtime field of the parent, filling 63 * of the IMPSRC context variable, etc. It will 64 * place the parent on the toBeMade queue if it 65 * should be. 66 * 67 * Make_TimeStamp Function to set the parent's cmtime field 68 * based on a child's modification time. 69 * 70 * Make_DoAllVar Set up the various local variables for a 71 * target, including the .ALLSRC variable, making 72 * sure that any variable that needs to exist 73 * at the very least has the empty value. 74 * 75 * Make_OODate Determine if a target is out-of-date. 76 * 77 * Make_HandleUse See if a child is a .USE node for a parent 78 * and perform the .USE actions if so. 78 79 */ 79 80 … … 83 84 #include "job.h" 84 85 85 static Lst toBeMade;/* The current fringe of the graph. These86 * are nodes which await examination by87 * MakeOODate. It is added to by88 * Make_Update and subtracted from by89 * MakeStartJobs */90 static int numNodes;/* Number of nodes to be processed. If this91 * is non-zero when Job_Empty() returns92 * TRUE, there's a cycle in the graph */86 static Lst toBeMade; /* The current fringe of the graph. These 87 * are nodes which await examination by 88 * MakeOODate. It is added to by 89 * Make_Update and subtracted from by 90 * MakeStartJobs */ 91 static int numNodes; /* Number of nodes to be processed. If this 92 * is non-zero when Job_Empty() returns 93 * TRUE, there's a cycle in the graph */ 93 94 94 95 static int MakeAddChild __P((ClientData, ClientData)); … … 101 102 *----------------------------------------------------------------------- 102 103 * Make_TimeStamp -- 103 * Set the cmtime field of a parent node based on the mtime stamp in its104 * child. Called from MakeOODate via Lst_ForEach.105 * 106 * Results: 107 * Always returns 0.108 * 109 * Side Effects: 110 * The cmtime of the parent node will be changed if the mtime111 * field of the child is greater than it.104 * Set the cmtime field of a parent node based on the mtime stamp in its 105 * child. Called from MakeOODate via Lst_ForEach. 106 * 107 * Results: 108 * Always returns 0. 109 * 110 * Side Effects: 111 * The cmtime of the parent node will be changed if the mtime 112 * field of the child is greater than it. 112 113 *----------------------------------------------------------------------- 113 114 */ 114 115 int 115 116 Make_TimeStamp (pgn, cgn) 116 GNode *pgn; /* the current parent */117 GNode *cgn; /* the child we've just examined */117 GNode *pgn; /* the current parent */ 118 GNode *cgn; /* the child we've just examined */ 118 119 { 119 120 if (cgn->mtime > pgn->cmtime) { 120 pgn->cmtime = cgn->mtime;121 pgn->cmtime = cgn->mtime; 121 122 } 122 123 return (0); … … 125 126 static int 126 127 MakeTimeStamp (pgn, cgn) 127 ClientData pgn; /* the current parent */128 ClientData cgn; /* the child we've just examined */128 ClientData pgn; /* the current parent */ 129 ClientData cgn; /* the child we've just examined */ 129 130 { 130 131 return Make_TimeStamp((GNode *) pgn, (GNode *) cgn); … … 135 136 *----------------------------------------------------------------------- 136 137 * Make_OODate -- 137 * See if a given node is out of date with respect to its sources.138 * Used by Make_Run when deciding which nodes to place on the139 * toBeMade queue initially and by Make_Update to screen out USE and140 * EXEC nodes. In the latter case, however, any other sort of node141 * must be considered out-of-date since at least one of its children142 * will have been recreated.143 * 144 * Results: 145 * TRUE if the node is out of date. FALSE otherwise.146 * 147 * Side Effects: 148 * The mtime field of the node and the cmtime field of its parents149 * will/may be changed.138 * See if a given node is out of date with respect to its sources. 139 * Used by Make_Run when deciding which nodes to place on the 140 * toBeMade queue initially and by Make_Update to screen out USE and 141 * EXEC nodes. In the latter case, however, any other sort of node 142 * must be considered out-of-date since at least one of its children 143 * will have been recreated. 144 * 145 * Results: 146 * TRUE if the node is out of date. FALSE otherwise. 147 * 148 * Side Effects: 149 * The mtime field of the node and the cmtime field of its parents 150 * will/may be changed. 150 151 *----------------------------------------------------------------------- 151 152 */ 152 153 Boolean 153 154 Make_OODate (gn) 154 register GNode *gn; /* the node to check */155 register GNode *gn; /* the node to check */ 155 156 { 156 157 Boolean oodate; … … 161 162 */ 162 163 if ((gn->type & (OP_JOIN|OP_USE|OP_EXEC)) == 0) { 163 (void) Dir_MTime (gn);164 if (DEBUG(MAKE)) {165 if (gn->mtime != 0) {166 printf ("modified %s...", Targ_FmtTime(gn->mtime));167 } else {168 printf ("non-existent...");169 }170 }164 (void) Dir_MTime (gn); 165 if (DEBUG(MAKE)) { 166 if (gn->mtime != 0) { 167 printf ("modified %s...", Targ_FmtTime(gn->mtime)); 168 } else { 169 printf ("non-existent..."); 170 } 171 } 171 172 } 172 173 173 174 /* 174 175 * A target is remade in one of the following circumstances: 175 * its modification time is smaller than that of its youngest child176 * and it would actually be run (has commands or type OP_NOP)177 * it's the object of a force operator178 * it has no children, was on the lhs of an operator and doesn't exist179 * already.176 * its modification time is smaller than that of its youngest child 177 * and it would actually be run (has commands or type OP_NOP) 178 * it's the object of a force operator 179 * it has no children, was on the lhs of an operator and doesn't exist 180 * already. 180 181 * 181 182 * Libraries are only considered out-of-date if the archive module says … … 186 187 */ 187 188 if (gn->type & OP_USE) { 188 /*189 * If the node is a USE node it is *never* out of date190 * no matter *what*.191 */192 if (DEBUG(MAKE)) {193 printf(".USE node...");194 }195 oodate = FALSE;189 /* 190 * If the node is a USE node it is *never* out of date 191 * no matter *what*. 192 */ 193 if (DEBUG(MAKE)) { 194 printf(".USE node..."); 195 } 196 oodate = FALSE; 196 197 #ifdef USE_ARCHIVES 197 198 } else if (gn->type & OP_LIB) { 198 if (DEBUG(MAKE)) {199 printf("library...");200 }201 202 /*203 * always out of date if no children and :: target204 */205 206 oodate = Arch_LibOODate (gn) ||207 ((gn->cmtime == 0) && (gn->type & OP_DOUBLEDEP));199 if (DEBUG(MAKE)) { 200 printf("library..."); 201 } 202 203 /* 204 * always out of date if no children and :: target 205 */ 206 207 oodate = Arch_LibOODate (gn) || 208 ((gn->cmtime == 0) && (gn->type & OP_DOUBLEDEP)); 208 209 #endif 209 210 } else if (gn->type & OP_JOIN) { 210 /*211 * A target with the .JOIN attribute is only considered212 * out-of-date if any of its children was out-of-date.213 */214 if (DEBUG(MAKE)) {215 printf(".JOIN node...");216 }217 oodate = gn->childMade;211 /* 212 * A target with the .JOIN attribute is only considered 213 * out-of-date if any of its children was out-of-date. 214 */ 215 if (DEBUG(MAKE)) { 216 printf(".JOIN node..."); 217 } 218 oodate = gn->childMade; 218 219 } else if (gn->type & (OP_FORCE|OP_EXEC|OP_PHONY)) { 219 /*220 * A node which is the object of the force (!) operator or which has221 * the .EXEC attribute is always considered out-of-date.222 */223 if (DEBUG(MAKE)) {224 if (gn->type & OP_FORCE) {225 printf("! operator...");226 } else if (gn->type & OP_PHONY) {227 printf(".PHONY node...");228 } else {229 printf(".EXEC node...");230 }231 }232 oodate = TRUE;220 /* 221 * A node which is the object of the force (!) operator or which has 222 * the .EXEC attribute is always considered out-of-date. 223 */ 224 if (DEBUG(MAKE)) { 225 if (gn->type & OP_FORCE) { 226 printf("! operator..."); 227 } else if (gn->type & OP_PHONY) { 228 printf(".PHONY node..."); 229 } else { 230 printf(".EXEC node..."); 231 } 232 } 233 oodate = TRUE; 233 234 } else if ((gn->mtime < gn->cmtime) || 234 ((gn->cmtime == 0) &&235 ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP))))235 ((gn->cmtime == 0) && 236 ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP)))) 236 237 { 237 /*238 * A node whose modification time is less than that of its239 * youngest child or that has no children (cmtime == 0) and240 * either doesn't exist (mtime == 0) or was the object of a241 * :: operator is out-of-date. Why? Because that's the way Make does242 * it.243 */244 if (DEBUG(MAKE)) {245 if (gn->mtime < gn->cmtime) {246 printf("modified before source...");247 } else if (gn->mtime == 0) {248 printf("non-existent and no sources...");249 } else {250 printf(":: operator and no sources...");251 }252 }253 oodate = TRUE;238 /* 239 * A node whose modification time is less than that of its 240 * youngest child or that has no children (cmtime == 0) and 241 * either doesn't exist (mtime == 0) or was the object of a 242 * :: operator is out-of-date. Why? Because that's the way Make does 243 * it. 244 */ 245 if (DEBUG(MAKE)) { 246 if (gn->mtime < gn->cmtime) { 247 printf("modified before source..."); 248 } else if (gn->mtime == 0) { 249 printf("non-existent and no sources..."); 250 } else { 251 printf(":: operator and no sources..."); 252 } 253 } 254 oodate = TRUE; 254 255 } else { 255 256 #if 0 256 /* WHY? */257 if (DEBUG(MAKE)) {258 printf("source %smade...", gn->childMade ? "" : "not ");259 }260 oodate = gn->childMade;257 /* WHY? */ 258 if (DEBUG(MAKE)) { 259 printf("source %smade...", gn->childMade ? "" : "not "); 260 } 261 oodate = gn->childMade; 261 262 #else 262 oodate = FALSE;263 oodate = FALSE; 263 264 #endif /* 0 */ 264 265 } … … 272 273 */ 273 274 if (!oodate) { 274 Lst_ForEach (gn->parents, MakeTimeStamp, (ClientData)gn);275 Lst_ForEach (gn->parents, MakeTimeStamp, (ClientData)gn); 275 276 } 276 277 … … 282 283 *----------------------------------------------------------------------- 283 284 * MakeAddChild -- 284 * Function used by Make_Run to add a child to the list l.285 * It will only add the child if its make field is FALSE.286 * 287 * Results: 288 * Always returns 0289 * 290 * Side Effects: 291 * The given list is extended285 * Function used by Make_Run to add a child to the list l. 286 * It will only add the child if its make field is FALSE. 287 * 288 * Results: 289 * Always returns 0 290 * 291 * Side Effects: 292 * The given list is extended 292 293 *----------------------------------------------------------------------- 293 294 */ 294 295 static int 295 296 MakeAddChild (gnp, lp) 296 ClientData gnp; /* the node to add */297 ClientData lp; /* the list to which to add it */297 ClientData gnp; /* the node to add */ 298 ClientData lp; /* the list to which to add it */ 298 299 { 299 300 GNode *gn = (GNode *) gnp; … … 301 302 302 303 if (!gn->make && !(gn->type & OP_USE)) { 303 (void)Lst_EnQueue (l, (ClientData)gn);304 (void)Lst_EnQueue (l, (ClientData)gn); 304 305 } 305 306 return (0); … … 310 311 *----------------------------------------------------------------------- 311 312 * Make_HandleUse -- 312 * Function called by Make_Run and SuffApplyTransform on the downward313 * pass to handle .USE and transformation nodes. A callback function314 * for Lst_ForEach, it implements the .USE and transformation315 * functionality by copying the node's commands, type flags316 * and children to the parent node. Should be called before the317 * children are enqueued to be looked at by MakeAddChild.318 * 319 * A .USE node is much like an explicit transformation rule, except320 * its commands are always added to the target node, even if the321 * target already has commands.322 * 323 * Results: 324 * returns 0.325 * 326 * Side Effects: 327 * Children and commands may be added to the parent and the parent's328 * type may be changed.313 * Function called by Make_Run and SuffApplyTransform on the downward 314 * pass to handle .USE and transformation nodes. A callback function 315 * for Lst_ForEach, it implements the .USE and transformation 316 * functionality by copying the node's commands, type flags 317 * and children to the parent node. Should be called before the 318 * children are enqueued to be looked at by MakeAddChild. 319 * 320 * A .USE node is much like an explicit transformation rule, except 321 * its commands are always added to the target node, even if the 322 * target already has commands. 323 * 324 * Results: 325 * returns 0. 326 * 327 * Side Effects: 328 * Children and commands may be added to the parent and the parent's 329 * type may be changed. 329 330 * 330 331 *----------------------------------------------------------------------- … … 332 333 int 333 334 Make_HandleUse (cgn, pgn) 334 register GNode *cgn;/* The .USE node */335 register GNode *pgn;/* The target of the .USE node */336 { 337 register GNode *gn;/* A child of the .USE node */338 register LstNode ln;/* An element in the children list */335 register GNode *cgn; /* The .USE node */ 336 register GNode *pgn; /* The target of the .USE node */ 337 { 338 register GNode *gn; /* A child of the .USE node */ 339 register LstNode ln; /* An element in the children list */ 339 340 340 341 if (cgn->type & (OP_USE|OP_TRANSFORM)) { 341 if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) {342 /*343 * .USE or transformation and target has no commands -- append344 * the child's commands to the parent.345 */346 (void) Lst_Concat (pgn->commands, cgn->commands, LST_CONCNEW);347 }348 349 if (Lst_Open (cgn->children) == SUCCESS) {350 while ((ln = Lst_Next (cgn->children)) != NILLNODE) {351 gn = (GNode *)Lst_Datum (ln);352 353 if (Lst_Member (pgn->children, gn) == NILLNODE) {354 (void) Lst_AtEnd (pgn->children, gn);355 (void) Lst_AtEnd (gn->parents, pgn);356 pgn->unmade += 1;357 }358 }359 Lst_Close (cgn->children);360 }361 362 pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM);363 364 /*365 * This child node is now "made", so we decrement the count of366 * unmade children in the parent... We also remove the child367 * from the parent's list to accurately reflect the number of decent368 * children the parent has. This is used by Make_Run to decide369 * whether to queue the parent or examine its children...370 */371 if (cgn->type & OP_USE) {372 pgn->unmade--;373 }342 if ((cgn->type & OP_USE) || Lst_IsEmpty(pgn->commands)) { 343 /* 344 * .USE or transformation and target has no commands -- append 345 * the child's commands to the parent. 346 */ 347 (void) Lst_Concat (pgn->commands, cgn->commands, LST_CONCNEW); 348 } 349 350 if (Lst_Open (cgn->children) == SUCCESS) { 351 while ((ln = Lst_Next (cgn->children)) != NILLNODE) { 352 gn = (GNode *)Lst_Datum (ln); 353 354 if (Lst_Member (pgn->children, gn) == NILLNODE) { 355 (void) Lst_AtEnd (pgn->children, gn); 356 (void) Lst_AtEnd (gn->parents, pgn); 357 pgn->unmade += 1; 358 } 359 } 360 Lst_Close (cgn->children); 361 } 362 363 pgn->type |= cgn->type & ~(OP_OPMASK|OP_USE|OP_TRANSFORM); 364 365 /* 366 * This child node is now "made", so we decrement the count of 367 * unmade children in the parent... We also remove the child 368 * from the parent's list to accurately reflect the number of decent 369 * children the parent has. This is used by Make_Run to decide 370 * whether to queue the parent or examine its children... 371 */ 372 if (cgn->type & OP_USE) { 373 pgn->unmade--; 374 } 374 375 } 375 376 return (0); … … 377 378 static int 378 379 MakeHandleUse (pgn, cgn) 379 ClientData pgn; /* the current parent */380 ClientData cgn; /* the child we've just examined */380 ClientData pgn; /* the current parent */ 381 ClientData cgn; /* the child we've just examined */ 381 382 { 382 383 return Make_HandleUse((GNode *) pgn, (GNode *) cgn); … … 387 388 *----------------------------------------------------------------------- 388 389 * Make_Update -- 389 * Perform update on the parents of a node. Used by JobFinish once390 * a node has been dealt with and by MakeStartJobs if it finds an391 * up-to-date node.392 * 393 * Results: 394 * Always returns 0395 * 396 * Side Effects: 397 * The unmade field of pgn is decremented and pgn may be placed on398 * the toBeMade queue if this field becomes 0.399 * 400 * If the child was made, the parent's childMade field will be set true401 * and its cmtime set to now.402 * 403 * If the child wasn't made, the cmtime field of the parent will be404 * altered if the child's mtime is big enough.405 * 406 * Finally, if the child is the implied source for the parent, the407 * parent's IMPSRC variable is set appropriately.390 * Perform update on the parents of a node. Used by JobFinish once 391 * a node has been dealt with and by MakeStartJobs if it finds an 392 * up-to-date node. 393 * 394 * Results: 395 * Always returns 0 396 * 397 * Side Effects: 398 * The unmade field of pgn is decremented and pgn may be placed on 399 * the toBeMade queue if this field becomes 0. 400 * 401 * If the child was made, the parent's childMade field will be set true 402 * and its cmtime set to now. 403 * 404 * If the child wasn't made, the cmtime field of the parent will be 405 * altered if the child's mtime is big enough. 406 * 407 * Finally, if the child is the implied source for the parent, the 408 * parent's IMPSRC variable is set appropriately. 408 409 * 409 410 *----------------------------------------------------------------------- … … 411 412 void 412 413 Make_Update (cgn) 413 register GNode *cgn; /* the child node */414 { 415 register GNode *pgn;/* the parent node */416 register char *cname;/* the child's name */417 register LstNode ln;/* Element in parents and iParents lists */414 register GNode *cgn; /* the child node */ 415 { 416 register GNode *pgn; /* the parent node */ 417 register char *cname; /* the child's name */ 418 register LstNode ln; /* Element in parents and iParents lists */ 418 419 char *p1; 419 420 … … 428 429 if (cgn->made != UPTODATE) { 429 430 #ifndef RECHECK 430 /*431 * We can't re-stat the thing, but we can at least take care of rules432 * where a target depends on a source that actually creates the433 * target, but only if it has changed, e.g.434 *435 * parse.h : parse.o436 *437 * parse.o : parse.y438 *yacc -d parse.y439 *cc -c y.tab.c440 *mv y.tab.o parse.o441 *cmp -s y.tab.h parse.h || mv y.tab.h parse.h442 *443 * In this case, if the definitions produced by yacc haven't changed444 * from before, parse.h won't have been updated and cgn->mtime will445 * reflect the current modification time for parse.h. This is446 * something of a kludge, I admit, but it's a useful one..447 * XXX: People like to use a rule like448 *449 * FRC:450 *451 * To force things that depend on FRC to be made, so we have to452 * check for gn->children being empty as well...453 */454 if (!Lst_IsEmpty(cgn->commands) || Lst_IsEmpty(cgn->children)) {455 cgn->mtime = now;456 }431 /* 432 * We can't re-stat the thing, but we can at least take care of rules 433 * where a target depends on a source that actually creates the 434 * target, but only if it has changed, e.g. 435 * 436 * parse.h : parse.o 437 * 438 * parse.o : parse.y 439 * yacc -d parse.y 440 * cc -c y.tab.c 441 * mv y.tab.o parse.o 442 * cmp -s y.tab.h parse.h || mv y.tab.h parse.h 443 * 444 * In this case, if the definitions produced by yacc haven't changed 445 * from before, parse.h won't have been updated and cgn->mtime will 446 * reflect the current modification time for parse.h. This is 447 * something of a kludge, I admit, but it's a useful one.. 448 * XXX: People like to use a rule like 449 * 450 * FRC: 451 * 452 * To force things that depend on FRC to be made, so we have to 453 * check for gn->children being empty as well... 454 */ 455 if (!Lst_IsEmpty(cgn->commands) || Lst_IsEmpty(cgn->children)) { 456 cgn->mtime = now; 457 } 457 458 #else 458 /*459 * This is what Make does and it's actually a good thing, as it460 * allows rules like461 *462 *cmp -s y.tab.h parse.h || cp y.tab.h parse.h463 *464 * to function as intended. Unfortunately, thanks to the stateless465 * nature of NFS (by which I mean the loose coupling of two clients466 * using the same file from a common server), there are times467 * when the modification time of a file created on a remote468 * machine will not be modified before the local stat() implied by469 * the Dir_MTime occurs, thus leading us to believe that the file470 * is unchanged, wreaking havoc with files that depend on this one.471 *472 * I have decided it is better to make too much than to make too473 * little, so this stuff is commented out unless you're sure it's ok.474 * -- ardeb 1/12/88475 */476 /*477 * Christos, 4/9/92: If we are saving commands pretend that478 * the target is made now. Otherwise archives with ... rules479 * don't work!480 */481 if (noExecute || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) {482 cgn->mtime = now;483 }484 if (DEBUG(MAKE)) {485 printf("update time: %s\n", Targ_FmtTime(cgn->mtime));486 }459 /* 460 * This is what Make does and it's actually a good thing, as it 461 * allows rules like 462 * 463 * cmp -s y.tab.h parse.h || cp y.tab.h parse.h 464 * 465 * to function as intended. Unfortunately, thanks to the stateless 466 * nature of NFS (by which I mean the loose coupling of two clients 467 * using the same file from a common server), there are times 468 * when the modification time of a file created on a remote 469 * machine will not be modified before the local stat() implied by 470 * the Dir_MTime occurs, thus leading us to believe that the file 471 * is unchanged, wreaking havoc with files that depend on this one. 472 * 473 * I have decided it is better to make too much than to make too 474 * little, so this stuff is commented out unless you're sure it's ok. 475 * -- ardeb 1/12/88 476 */ 477 /* 478 * Christos, 4/9/92: If we are saving commands pretend that 479 * the target is made now. Otherwise archives with ... rules 480 * don't work! 481 */ 482 if (noExecute || (cgn->type & OP_SAVE_CMDS) || Dir_MTime(cgn) == 0) { 483 cgn->mtime = now; 484 } 485 if (DEBUG(MAKE)) { 486 printf("update time: %s\n", Targ_FmtTime(cgn->mtime)); 487 } 487 488 #endif 488 489 } 489 490 490 491 if (Lst_Open (cgn->parents) == SUCCESS) { 491 while ((ln = Lst_Next (cgn->parents)) != NILLNODE) {492 pgn = (GNode *)Lst_Datum (ln);493 if (pgn->make) {494 pgn->unmade -= 1;495 496 if ( ! (cgn->type & (OP_EXEC|OP_USE))) {497 if (cgn->made == MADE) {498 pgn->childMade = TRUE;499 if (pgn->cmtime < cgn->mtime) {500 pgn->cmtime = cgn->mtime;501 }502 } else {503 (void)Make_TimeStamp (pgn, cgn);504 }505 }506 if (pgn->unmade == 0) {507 /*508 * Queue the node up -- any unmade predecessors will509 * be dealt with in MakeStartJobs.510 */511 (void)Lst_EnQueue (toBeMade, (ClientData)pgn);512 } else if (pgn->unmade < 0) {513 Error ("Graph cycles through %s", pgn->name);514 }515 }516 }517 Lst_Close (cgn->parents);492 while ((ln = Lst_Next (cgn->parents)) != NILLNODE) { 493 pgn = (GNode *)Lst_Datum (ln); 494 if (pgn->make) { 495 pgn->unmade -= 1; 496 497 if ( ! (cgn->type & (OP_EXEC|OP_USE))) { 498 if (cgn->made == MADE) { 499 pgn->childMade = TRUE; 500 if (pgn->cmtime < cgn->mtime) { 501 pgn->cmtime = cgn->mtime; 502 } 503 } else { 504 (void)Make_TimeStamp (pgn, cgn); 505 } 506 } 507 if (pgn->unmade == 0) { 508 /* 509 * Queue the node up -- any unmade predecessors will 510 * be dealt with in MakeStartJobs. 511 */ 512 (void)Lst_EnQueue (toBeMade, (ClientData)pgn); 513 } else if (pgn->unmade < 0) { 514 Error ("Graph cycles through %s", pgn->name); 515 } 516 } 517 } 518 Lst_Close (cgn->parents); 518 519 } 519 520 /* … … 524 525 */ 525 526 for (ln = Lst_First(cgn->successors); ln != NILLNODE; ln = Lst_Succ(ln)) { 526 GNode*succ = (GNode *)Lst_Datum(ln);527 528 if (succ->make && succ->unmade == 0 && succ->made == UNMADE &&529 Lst_Member(toBeMade, (ClientData)succ) == NILLNODE)530 {531 (void)Lst_EnQueue(toBeMade, (ClientData)succ);532 }527 GNode *succ = (GNode *)Lst_Datum(ln); 528 529 if (succ->make && succ->unmade == 0 && succ->made == UNMADE && 530 Lst_Member(toBeMade, (ClientData)succ) == NILLNODE) 531 { 532 (void)Lst_EnQueue(toBeMade, (ClientData)succ); 533 } 533 534 } 534 535 … … 538 539 */ 539 540 if (Lst_Open (cgn->iParents) == SUCCESS) { 540 char *p1;541 char*cpref = Var_Value(PREFIX, cgn, &p1);542 543 while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) {544 pgn = (GNode *)Lst_Datum (ln);545 if (pgn->make) {546 Var_Set (IMPSRC, cname, pgn);547 Var_Set (PREFIX, cpref, pgn);548 }549 }550 efree(p1);551 Lst_Close (cgn->iParents);541 char *p1; 542 char *cpref = Var_Value(PREFIX, cgn, &p1); 543 544 while ((ln = Lst_Next (cgn->iParents)) != NILLNODE) { 545 pgn = (GNode *)Lst_Datum (ln); 546 if (pgn->make) { 547 Var_Set (IMPSRC, cname, pgn); 548 Var_Set (PREFIX, cpref, pgn); 549 } 550 } 551 efree(p1); 552 Lst_Close (cgn->iParents); 552 553 } 553 554 } … … 557 558 *----------------------------------------------------------------------- 558 559 * MakeAddAllSrc -- 559 * Add a child's name to the ALLSRC and OODATE variables of the given560 * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only561 * if it has not been given the .EXEC, .USE or .INVISIBLE attributes.562 * .EXEC and .USE children are very rarely going to be files, so...563 * A child is added to the OODATE variable if its modification time is564 * later than that of its parent, as defined by Make, except if the565 * parent is a .JOIN node. In that case, it is only added to the OODATE566 * variable if it was actually made (since .JOIN nodes don't have567 * modification times, the comparison is rather unfair...)..568 * 569 * Results: 570 * Always returns 0571 * 572 * Side Effects: 573 * The ALLSRC variable for the given node is extended.560 * Add a child's name to the ALLSRC and OODATE variables of the given 561 * node. Called from Make_DoAllVar via Lst_ForEach. A child is added only 562 * if it has not been given the .EXEC, .USE or .INVISIBLE attributes. 563 * .EXEC and .USE children are very rarely going to be files, so... 564 * A child is added to the OODATE variable if its modification time is 565 * later than that of its parent, as defined by Make, except if the 566 * parent is a .JOIN node. In that case, it is only added to the OODATE 567 * variable if it was actually made (since .JOIN nodes don't have 568 * modification times, the comparison is rather unfair...).. 569 * 570 * Results: 571 * Always returns 0 572 * 573 * Side Effects: 574 * The ALLSRC variable for the given node is extended. 574 575 *----------------------------------------------------------------------- 575 576 */ 576 577 static int 577 578 MakeAddAllSrc (cgnp, pgnp) 578 ClientData cgnp;/* The child to add */579 ClientData pgnp;/* The parent to whose ALLSRC variable it should be */580 /* added */581 { 582 GNode *cgn = (GNode *) cgnp;583 GNode *pgn = (GNode *) pgnp;579 ClientData cgnp; /* The child to add */ 580 ClientData pgnp; /* The parent to whose ALLSRC variable it should be */ 581 /* added */ 582 { 583 GNode *cgn = (GNode *) cgnp; 584 GNode *pgn = (GNode *) pgnp; 584 585 if ((cgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { 585 char *child;586 char *p1 = NULL;587 588 if (OP_NOP(cgn->type)) {589 /*590 * this node is only source; use the specific pathname for it591 */592 child = cgn->path ? cgn->path : cgn->name;593 }594 else595 child = Var_Value(TARGET, cgn, &p1);596 Var_Append (ALLSRC, child, pgn);597 if (pgn->type & OP_JOIN) {598 if (cgn->made == MADE) {599 Var_Append(OODATE, child, pgn);600 }601 } else if ((pgn->mtime < cgn->mtime) ||602 (cgn->mtime >= now && cgn->made == MADE))603 {604 /*605 * It goes in the OODATE variable if the parent is younger than the606 * child or if the child has been modified more recently than607 * the start of the make. This is to keep pmake from getting608 * confused if something else updates the parent after the609 * make starts (shouldn't happen, I know, but sometimes it610 * does). In such a case, if we've updated the kid, the parent611 * is likely to have a modification time later than that of612 * the kid and anything that relies on the OODATE variable will613 * be hosed.614 *615 * XXX: This will cause all made children to go in the OODATE616 * variable, even if they're not touched, if RECHECK isn't defined,617 * since cgn->mtime is set to now in Make_Update. According to618 * some people, this is good...619 */620 Var_Append(OODATE, child, pgn);621 }622 efree(p1);586 char *child; 587 char *p1 = NULL; 588 589 if (OP_NOP(cgn->type)) { 590 /* 591 * this node is only source; use the specific pathname for it 592 */ 593 child = cgn->path ? cgn->path : cgn->name; 594 } 595 else 596 child = Var_Value(TARGET, cgn, &p1); 597 Var_Append (ALLSRC, child, pgn); 598 if (pgn->type & OP_JOIN) { 599 if (cgn->made == MADE) { 600 Var_Append(OODATE, child, pgn); 601 } 602 } else if ((pgn->mtime < cgn->mtime) || 603 (cgn->mtime >= now && cgn->made == MADE)) 604 { 605 /* 606 * It goes in the OODATE variable if the parent is younger than the 607 * child or if the child has been modified more recently than 608 * the start of the make. This is to keep pmake from getting 609 * confused if something else updates the parent after the 610 * make starts (shouldn't happen, I know, but sometimes it 611 * does). In such a case, if we've updated the kid, the parent 612 * is likely to have a modification time later than that of 613 * the kid and anything that relies on the OODATE variable will 614 * be hosed. 615 * 616 * XXX: This will cause all made children to go in the OODATE 617 * variable, even if they're not touched, if RECHECK isn't defined, 618 * since cgn->mtime is set to now in Make_Update. According to 619 * some people, this is good... 620 */ 621 Var_Append(OODATE, child, pgn); 622 } 623 efree(p1); 623 624 } 624 625 return (0); … … 632 633 * 633 634 * Results: 634 * Always returns 0635 * 636 * Side Effects: 637 * The PARENTS variable for the given node is extended.635 * Always returns 0 636 * 637 * Side Effects: 638 * The PARENTS variable for the given node is extended. 638 639 *----------------------------------------------------------------------- 639 640 */ 640 641 static int 641 642 MakeAddParents (pgnp, cgnp) 642 ClientData pgnp;/* The parent to add to add */643 ClientData cgnp;/* The child to whose PARENTS variable it should be */644 { 645 GNode *pgn = (GNode *) pgnp;646 GNode *cgn = (GNode *) cgnp;643 ClientData pgnp; /* The parent to add to add */ 644 ClientData cgnp; /* The child to whose PARENTS variable it should be */ 645 { 646 GNode *pgn = (GNode *) pgnp; 647 GNode *cgn = (GNode *) cgnp; 647 648 if ((pgn->type & (OP_EXEC|OP_USE|OP_INVISIBLE)) == 0) { 648 char *parent;649 char *p1 = NULL;650 651 652 if (OP_NOP(pgn->type) || !(parent = Var_Value(TARGET, pgn, &p1))) {653 /* this node is only source; use the specific pathname for it */654 parent = pgn->path ? pgn->path : pgn->name;655 } 656 Var_Append(PARENTS, parent, cgn);657 efree(p1);649 char *parent; 650 char *p1 = NULL; 651 652 653 if (OP_NOP(pgn->type) || !(parent = Var_Value(TARGET, pgn, &p1))) { 654 /* this node is only source; use the specific pathname for it */ 655 parent = pgn->path ? pgn->path : pgn->name; 656 } 657 Var_Append(PARENTS, parent, cgn); 658 efree(p1); 658 659 } 659 660 return (0); … … 665 666 *----------------------------------------------------------------------- 666 667 * Make_DoAllVar -- 667 * Set up the ALLSRC and OODATE variables. Sad to say, it must be668 * done separately, rather than while traversing the graph. This is669 * because Make defined OODATE to contain all sources whose modification670 * times were later than that of the target, *not* those sources that671 * were out-of-date. Since in both compatibility and native modes,672 * the modification time of the parent isn't found until the child673 * has been dealt with, we have to wait until now to fill in the674 * variable. As for ALLSRC, the ordering is important and not675 * guaranteed when in native mode, so it must be set here, too.676 * 677 * Results: 678 * None679 * 680 * Side Effects: 681 * The ALLSRC and OODATE variables of the given node is filled in.682 * If the node is a .JOIN node, its TARGET variable will be set to683 * match its ALLSRC variable.668 * Set up the ALLSRC and OODATE variables. Sad to say, it must be 669 * done separately, rather than while traversing the graph. This is 670 * because Make defined OODATE to contain all sources whose modification 671 * times were later than that of the target, *not* those sources that 672 * were out-of-date. Since in both compatibility and native modes, 673 * the modification time of the parent isn't found until the child 674 * has been dealt with, we have to wait until now to fill in the 675 * variable. As for ALLSRC, the ordering is important and not 676 * guaranteed when in native mode, so it must be set here, too. 677 * 678 * Results: 679 * None 680 * 681 * Side Effects: 682 * The ALLSRC and OODATE variables of the given node is filled in. 683 * If the node is a .JOIN node, its TARGET variable will be set to 684 * match its ALLSRC variable. 684 685 *----------------------------------------------------------------------- 685 686 */ 686 687 void 687 688 Make_DoAllVar (gn) 688 GNode *gn;689 GNode *gn; 689 690 { 690 691 Lst_ForEach (gn->children, MakeAddAllSrc, (ClientData) gn); … … 694 695 695 696 if (!Var_Exists (OODATE, gn)) { 696 Var_Set (OODATE, "", gn);697 Var_Set (OODATE, "", gn); 697 698 } 698 699 if (!Var_Exists (ALLSRC, gn)) { 699 Var_Set (ALLSRC, "", gn);700 Var_Set (ALLSRC, "", gn); 700 701 } 701 702 702 703 if (gn->type & OP_JOIN) { 703 char *p1;704 Var_Set (TARGET, Var_Value (ALLSRC, gn, &p1), gn);705 efree(p1);704 char *p1; 705 Var_Set (TARGET, Var_Value (ALLSRC, gn, &p1), gn); 706 efree(p1); 706 707 } 707 708 } … … 711 712 *----------------------------------------------------------------------- 712 713 * MakeStartJobs -- 713 * Start as many jobs as possible.714 * 715 * Results: 716 * If the query flag was given to pmake, no job will be started,717 * but as soon as an out-of-date target is found, this function718 * returns TRUE. At all other times, this function returns FALSE.719 * 720 * Side Effects: 721 * Nodes are removed from the toBeMade queue and job table slots722 * are filled.714 * Start as many jobs as possible. 715 * 716 * Results: 717 * If the query flag was given to pmake, no job will be started, 718 * but as soon as an out-of-date target is found, this function 719 * returns TRUE. At all other times, this function returns FALSE. 720 * 721 * Side Effects: 722 * Nodes are removed from the toBeMade queue and job table slots 723 * are filled. 723 724 * 724 725 *----------------------------------------------------------------------- … … 727 728 MakeStartJobs () 728 729 { 729 register GNode *gn;730 register GNode *gn; 730 731 731 732 while (!Job_Full() && !Lst_IsEmpty (toBeMade)) { 732 gn = (GNode *) Lst_DeQueue (toBeMade);733 if (DEBUG(MAKE)) {734 printf ("Examining %s...", gn->name);735 }736 /*737 * Make sure any and all predecessors that are going to be made,738 * have been.739 */740 if (!Lst_IsEmpty(gn->preds)) {741 LstNode ln;742 743 for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){744 GNode*pgn = (GNode *)Lst_Datum(ln);745 746 if (pgn->make && pgn->made == UNMADE) {747 if (DEBUG(MAKE)) {748 printf("predecessor %s not made yet.\n", pgn->name);749 }750 break;751 }752 }753 /*754 * If ln isn't nil, there's a predecessor as yet unmade, so we755 * just drop this node on the floor. When the node in question756 * has been made, it will notice this node as being ready to757 * make but as yet unmade and will place the node on the queue.758 */759 if (ln != NILLNODE) {760 continue;761 }762 }763 764 numNodes--;765 if (Make_OODate (gn)) {766 if (DEBUG(MAKE)) {767 printf ("out-of-date\n");768 }769 if (queryFlag) {770 return (TRUE);771 }772 Make_DoAllVar (gn);773 Job_Make (gn);774 } else {775 if (DEBUG(MAKE)) {776 printf ("up-to-date\n");777 }778 gn->made = UPTODATE;779 if (gn->type & OP_JOIN) {780 /*781 * Even for an up-to-date .JOIN node, we need it to have its782 * context variables so references to it get the correct783 * value for .TARGET when building up the context variables784 * of its parent(s)...785 */786 Make_DoAllVar (gn);787 }788 789 Make_Update (gn);790 }733 gn = (GNode *) Lst_DeQueue (toBeMade); 734 if (DEBUG(MAKE)) { 735 printf ("Examining %s...", gn->name); 736 } 737 /* 738 * Make sure any and all predecessors that are going to be made, 739 * have been. 740 */ 741 if (!Lst_IsEmpty(gn->preds)) { 742 LstNode ln; 743 744 for (ln = Lst_First(gn->preds); ln != NILLNODE; ln = Lst_Succ(ln)){ 745 GNode *pgn = (GNode *)Lst_Datum(ln); 746 747 if (pgn->make && pgn->made == UNMADE) { 748 if (DEBUG(MAKE)) { 749 printf("predecessor %s not made yet.\n", pgn->name); 750 } 751 break; 752 } 753 } 754 /* 755 * If ln isn't nil, there's a predecessor as yet unmade, so we 756 * just drop this node on the floor. When the node in question 757 * has been made, it will notice this node as being ready to 758 * make but as yet unmade and will place the node on the queue. 759 */ 760 if (ln != NILLNODE) { 761 continue; 762 } 763 } 764 765 numNodes--; 766 if (Make_OODate (gn)) { 767 if (DEBUG(MAKE)) { 768 printf ("out-of-date\n"); 769 } 770 if (queryFlag) { 771 return (TRUE); 772 } 773 Make_DoAllVar (gn); 774 Job_Make (gn); 775 } else { 776 if (DEBUG(MAKE)) { 777 printf ("up-to-date\n"); 778 } 779 gn->made = UPTODATE; 780 if (gn->type & OP_JOIN) { 781 /* 782 * Even for an up-to-date .JOIN node, we need it to have its 783 * context variables so references to it get the correct 784 * value for .TARGET when building up the context variables 785 * of its parent(s)... 786 */ 787 Make_DoAllVar (gn); 788 } 789 790 Make_Update (gn); 791 } 791 792 } 792 793 return (FALSE); … … 797 798 *----------------------------------------------------------------------- 798 799 * MakePrintStatus -- 799 * Print the status of a top-level node, viz. it being up-to-date800 * already or not created due to an error in a lower level.801 * Callback function for Make_Run via Lst_ForEach.802 * 803 * Results: 804 * Always returns 0.805 * 806 * Side Effects: 807 * A message may be printed.800 * Print the status of a top-level node, viz. it being up-to-date 801 * already or not created due to an error in a lower level. 802 * Callback function for Make_Run via Lst_ForEach. 803 * 804 * Results: 805 * Always returns 0. 806 * 807 * Side Effects: 808 * A message may be printed. 808 809 * 809 810 *----------------------------------------------------------------------- … … 811 812 static int 812 813 MakePrintStatus(gnp, cyclep) 813 ClientData gnp; /* Node to examine */814 ClientData cyclep;/* True if gn->unmade being non-zero implies815 * a cycle in the graph, not an error in an816 * inferior */817 { 818 GNode *gn = (GNode *) gnp;819 Boolean cycle = *(Boolean *) cyclep;814 ClientData gnp; /* Node to examine */ 815 ClientData cyclep; /* True if gn->unmade being non-zero implies 816 * a cycle in the graph, not an error in an 817 * inferior */ 818 { 819 GNode *gn = (GNode *) gnp; 820 Boolean cycle = *(Boolean *) cyclep; 820 821 if (gn->made == UPTODATE) { 821 printf ("`%s' is up to date.\n", gn->name);822 printf ("`%s' is up to date.\n", gn->name); 822 823 } else if (gn->unmade != 0) { 823 if (cycle) {824 Boolean t = TRUE;825 /*826 * If printing cycles and came to one that has unmade children,827 * print out the cycle by recursing on its children. Note a828 * cycle like:829 *a : b830 *b : c831 *c : b832 * will cause this to erroneously complain about a being in833 * the cycle, but this is a good approximation.834 */835 if (gn->made == CYCLE) {836 Error("Graph cycles through `%s'", gn->name);837 gn->made = ENDCYCLE;838 Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);839 gn->made = UNMADE;840 } else if (gn->made != ENDCYCLE) {841 gn->made = CYCLE;842 Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t);843 }844 } else {845 printf ("`%s' not remade because of errors.\n", gn->name);846 }824 if (cycle) { 825 Boolean t = TRUE; 826 /* 827 * If printing cycles and came to one that has unmade children, 828 * print out the cycle by recursing on its children. Note a 829 * cycle like: 830 * a : b 831 * b : c 832 * c : b 833 * will cause this to erroneously complain about a being in 834 * the cycle, but this is a good approximation. 835 */ 836 if (gn->made == CYCLE) { 837 Error("Graph cycles through `%s'", gn->name); 838 gn->made = ENDCYCLE; 839 Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t); 840 gn->made = UNMADE; 841 } else if (gn->made != ENDCYCLE) { 842 gn->made = CYCLE; 843 Lst_ForEach(gn->children, MakePrintStatus, (ClientData) &t); 844 } 845 } else { 846 printf ("`%s' not remade because of errors.\n", gn->name); 847 } 847 848 } 848 849 return (0); … … 853 854 *----------------------------------------------------------------------- 854 855 * Make_Run -- 855 * Initialize the nodes to remake and the list of nodes which are856 * ready to be made by doing a breadth-first traversal of the graph857 * starting from the nodes in the given list. Once this traversal858 * is finished, all the 'leaves' of the graph are in the toBeMade859 * queue.860 * Using this queue and the Job module, work back up the graph,861 * calling on MakeStartJobs to keep the job table as full as862 * possible.863 * 864 * Results: 865 * TRUE if work was done. FALSE otherwise.866 * 867 * Side Effects: 868 * The make field of all nodes involved in the creation of the given869 * targets is set to 1. The toBeMade list is set to contain all the870 * 'leaves' of these subgraphs.856 * Initialize the nodes to remake and the list of nodes which are 857 * ready to be made by doing a breadth-first traversal of the graph 858 * starting from the nodes in the given list. Once this traversal 859 * is finished, all the 'leaves' of the graph are in the toBeMade 860 * queue. 861 * Using this queue and the Job module, work back up the graph, 862 * calling on MakeStartJobs to keep the job table as full as 863 * possible. 864 * 865 * Results: 866 * TRUE if work was done. FALSE otherwise. 867 * 868 * Side Effects: 869 * The make field of all nodes involved in the creation of the given 870 * targets is set to 1. The toBeMade list is set to contain all the 871 * 'leaves' of these subgraphs. 871 872 *----------------------------------------------------------------------- 872 873 */ 873 874 Boolean 874 875 Make_Run (targs) 875 Lst targs; /* the initial list of targets */876 { 877 register GNode *gn; /* a temporary pointer */878 register Lst examine; /* List of targets to examine */879 int errors;/* Number of errors the Job module reports */876 Lst targs; /* the initial list of targets */ 877 { 878 register GNode *gn; /* a temporary pointer */ 879 register Lst examine; /* List of targets to examine */ 880 int errors; /* Number of errors the Job module reports */ 880 881 881 882 toBeMade = Lst_Init (FALSE); … … 893 894 */ 894 895 while (!Lst_IsEmpty (examine)) { 895 gn = (GNode *) Lst_DeQueue (examine);896 897 if (!gn->make) {898 gn->make = TRUE;899 numNodes++;900 901 /*902 * Apply any .USE rules before looking for implicit dependencies903 * to make sure everything has commands that should...904 */905 Lst_ForEach (gn->children, MakeHandleUse, (ClientData)gn);906 Suff_FindDeps (gn);907 908 if (gn->unmade != 0) {909 Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine);910 } else {911 (void)Lst_EnQueue (toBeMade, (ClientData)gn);912 }913 }896 gn = (GNode *) Lst_DeQueue (examine); 897 898 if (!gn->make) { 899 gn->make = TRUE; 900 numNodes++; 901 902 /* 903 * Apply any .USE rules before looking for implicit dependencies 904 * to make sure everything has commands that should... 905 */ 906 Lst_ForEach (gn->children, MakeHandleUse, (ClientData)gn); 907 Suff_FindDeps (gn); 908 909 if (gn->unmade != 0) { 910 Lst_ForEach (gn->children, MakeAddChild, (ClientData)examine); 911 } else { 912 (void)Lst_EnQueue (toBeMade, (ClientData)gn); 913 } 914 } 914 915 } 915 916 … … 917 918 918 919 if (queryFlag) { 919 /*920 * We wouldn't do any work unless we could start some jobs in the921 * next loop... (we won't actually start any, of course, this is just922 * to see if any of the targets was out of date)923 */924 return (MakeStartJobs());920 /* 921 * We wouldn't do any work unless we could start some jobs in the 922 * next loop... (we won't actually start any, of course, this is just 923 * to see if any of the targets was out of date) 924 */ 925 return (MakeStartJobs()); 925 926 } else { 926 /*927 * Initialization. At the moment, no jobs are running and until some928 * get started, nothing will happen since the remaining upward929 * traversal of the graph is performed by the routines in job.c upon930 * the finishing of a job. So we fill the Job table as much as we can931 * before going into our loop.932 */933 (void) MakeStartJobs();927 /* 928 * Initialization. At the moment, no jobs are running and until some 929 * get started, nothing will happen since the remaining upward 930 * traversal of the graph is performed by the routines in job.c upon 931 * the finishing of a job. So we fill the Job table as much as we can 932 * before going into our loop. 933 */ 934 (void) MakeStartJobs(); 934 935 } 935 936 … … 945 946 */ 946 947 while (!Job_Empty ()) { 947 Job_CatchOutput ();948 Job_CatchChildren (!usePipes);949 (void)MakeStartJobs();948 Job_CatchOutput (); 949 Job_CatchChildren (!usePipes); 950 (void)MakeStartJobs(); 950 951 } 951 952 -
trunk/src/kmk/make.h
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 36 36 * SUCH DAMAGE. 37 37 * 38 * from: @(#)make.h8.3 (Berkeley) 6/13/9538 * from: @(#)make.h 8.3 (Berkeley) 6/13/95 39 39 * $FreeBSD: src/usr.bin/make/make.h,v 1.12.2.2 2001/02/13 03:13:58 will Exp $ 40 40 */ … … 42 42 /*- 43 43 * make.h -- 44 * The global definitions for pmake44 * The global definitions for pmake 45 45 */ 46 46 … … 60 60 /*kso: # if defined(__STDC__) || defined(__cplusplus) */ 61 61 # if defined(__STDC__) || defined(__cplusplus) || defined(__IBMC__) 62 # define __P(protos) protos/* full-blown ANSI C */62 # define __P(protos) protos /* full-blown ANSI C */ 63 63 # else 64 # define __P(protos) ()/* traditional C preprocessor */64 # define __P(protos) () /* traditional C preprocessor */ 65 65 # endif 66 66 # endif … … 76 76 #endif 77 77 78 #if defined(__IBMC__) 79 #include <stdlib.h> 80 #include <time.h> 81 /*#ifdef __STDC__*/ 82 #elif defined(__STDC__) 78 #if defined(__STDC__) || defined(__IBMC__) 83 79 #include <stdlib.h> 84 80 #include <unistd.h> … … 93 89 * The structure for an individual graph node. Each node has several 94 90 * pieces of data associated with it. 95 * 1) the name of the target it describes96 * 2) the location of the target file in the file system.97 * 3) the type of operator used to define its sources (qv. parse.c)98 * 4) whether it is involved in this invocation of make99 * 5) whether the target has been remade100 * 6) whether any of its children has been remade101 * 7) the number of its children that are, as yet, unmade102 * 8) its modification time103 * 9) the modification time of its youngest child (qv. make.c)104 * 10) a list of nodes for which this is a source105 * 11) a list of nodes on which this depends106 * 12) a list of nodes that depend on this, as gleaned from the107 * transformation rules.108 * 13) a list of nodes of the same name created by the :: operator109 * 14) a list of nodes that must be made (if they're made) before110 * this node can be, but that do no enter into the datedness of111 * this node.112 * 15) a list of nodes that must be made (if they're made) after113 * this node is, but that do not depend on this node, in the114 * normal sense.115 * 16) a Lst of ``local'' variables that are specific to this target116 * and this target only (qv. var.c [$@ $< $?, etc.])117 * 17) a Lst of strings that are commands to be given to a shell118 * to create this target.91 * 1) the name of the target it describes 92 * 2) the location of the target file in the file system. 93 * 3) the type of operator used to define its sources (qv. parse.c) 94 * 4) whether it is involved in this invocation of make 95 * 5) whether the target has been remade 96 * 6) whether any of its children has been remade 97 * 7) the number of its children that are, as yet, unmade 98 * 8) its modification time 99 * 9) the modification time of its youngest child (qv. make.c) 100 * 10) a list of nodes for which this is a source 101 * 11) a list of nodes on which this depends 102 * 12) a list of nodes that depend on this, as gleaned from the 103 * transformation rules. 104 * 13) a list of nodes of the same name created by the :: operator 105 * 14) a list of nodes that must be made (if they're made) before 106 * this node can be, but that do no enter into the datedness of 107 * this node. 108 * 15) a list of nodes that must be made (if they're made) after 109 * this node is, but that do not depend on this node, in the 110 * normal sense. 111 * 16) a Lst of ``local'' variables that are specific to this target 112 * and this target only (qv. var.c [$@ $< $?, etc.]) 113 * 17) a Lst of strings that are commands to be given to a shell 114 * to create this target. 119 115 */ 120 116 typedef struct GNode { 121 char *name; /* The target's name */122 char *path;/* The full pathname of the file */123 int type; /* Its type (see the OP flags, below) */124 int order;/* Its wait weight */125 126 Boolean make; /* TRUE if this target needs to be remade */117 char *name; /* The target's name */ 118 char *path; /* The full pathname of the file */ 119 int type; /* Its type (see the OP flags, below) */ 120 int order; /* Its wait weight */ 121 122 Boolean make; /* TRUE if this target needs to be remade */ 127 123 enum { 128 UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED,129 CYCLE, ENDCYCLE130 } made;/* Set to reflect the state of processing131 * on this node:132 * UNMADE - Not examined yet133 * BEINGMADE - Target is already being made.134 *Indicates a cycle in the graph. (compat135 *mode only)136 * MADE - Was out-of-date and has been made137 * UPTODATE - Was already up-to-date138 * ERROR - An error occured while it was being139 *made (used only in compat mode)140 * ABORTED - The target was aborted due to141 *an error making an inferior (compat).142 * CYCLE - Marked as potentially being part of143 *a graph cycle. If we come back to a144 *node marked this way, it is printed145 *and 'made' is changed to ENDCYCLE.146 * ENDCYCLE - the cycle has been completely147 *printed. Go back and unmark all its148 *members.149 */150 Boolean childMade;/* TRUE if one of this target's children was151 * made */152 int unmade; /* The number of unmade children */153 154 int mtime; /* Its modification time */155 int cmtime;/* The modification time of its youngest156 * child */157 158 Lst iParents;/* Links to parents for which this is an159 * implied source, if any */160 Lst cohorts;/* Other nodes for the :: operator */161 Lst parents; /* Nodes that depend on this one */162 Lst children; /* Nodes on which this one depends */163 Lst successors;/* Nodes that must be made after this one */164 Lst preds;/* Nodes that must be made before this one */165 166 Lst context; /* The local variables */167 Lst commands; /* Creation commands */168 169 struct _Suff *suffix; /* Suffix for the node (determined by170 * Suff_FindDeps and opaque to everyone171 * but the Suff module) */124 UNMADE, BEINGMADE, MADE, UPTODATE, ERROR, ABORTED, 125 CYCLE, ENDCYCLE 126 } made; /* Set to reflect the state of processing 127 * on this node: 128 * UNMADE - Not examined yet 129 * BEINGMADE - Target is already being made. 130 * Indicates a cycle in the graph. (compat 131 * mode only) 132 * MADE - Was out-of-date and has been made 133 * UPTODATE - Was already up-to-date 134 * ERROR - An error occured while it was being 135 * made (used only in compat mode) 136 * ABORTED - The target was aborted due to 137 * an error making an inferior (compat). 138 * CYCLE - Marked as potentially being part of 139 * a graph cycle. If we come back to a 140 * node marked this way, it is printed 141 * and 'made' is changed to ENDCYCLE. 142 * ENDCYCLE - the cycle has been completely 143 * printed. Go back and unmark all its 144 * members. 145 */ 146 Boolean childMade; /* TRUE if one of this target's children was 147 * made */ 148 int unmade; /* The number of unmade children */ 149 150 int mtime; /* Its modification time */ 151 int cmtime; /* The modification time of its youngest 152 * child */ 153 154 Lst iParents; /* Links to parents for which this is an 155 * implied source, if any */ 156 Lst cohorts; /* Other nodes for the :: operator */ 157 Lst parents; /* Nodes that depend on this one */ 158 Lst children; /* Nodes on which this one depends */ 159 Lst successors; /* Nodes that must be made after this one */ 160 Lst preds; /* Nodes that must be made before this one */ 161 162 Lst context; /* The local variables */ 163 Lst commands; /* Creation commands */ 164 165 struct _Suff *suffix; /* Suffix for the node (determined by 166 * Suff_FindDeps and opaque to everyone 167 * but the Suff module) */ 172 168 } GNode; 173 169 … … 175 171 * Manifest constants 176 172 */ 177 #define NILGNODE ((GNode *) NIL)173 #define NILGNODE ((GNode *) NIL) 178 174 179 175 /* … … 186 182 * righthand side... 187 183 */ 188 #define OP_DEPENDS 0x00000001 /* Execution of commands depends on189 * kids (:) */190 #define OP_FORCE 0x00000002 /* Always execute commands (!) */191 #define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids192 * per line (::) */193 #define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP)194 195 #define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't196 * exist and can't be created */197 #define OP_USE 0x00000010 /* Use associated commands for parents */198 #define OP_EXEC 0x00000020 /* Target is never out of date, but always199 * execute commands anyway. Its time200 * doesn't matter, so it has none...sort201 * of */202 #define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */203 #define OP_PRECIOUS 0x00000080 /* Don't remove the target when204 * interrupted */205 #define OP_SILENT 0x00000100 /* Don't echo commands when executed */206 #define OP_MAKE 0x00000200 /* Target is a recurrsive make so its207 * commands should always be executed when208 * it is out of date, regardless of the209 * state of the -n or -t flags */210 #define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its211 * children was out-of-date */212 #define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents.213 * I.e. it doesn't show up in the parents's214 * local variables. */215 #define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main216 * target' processing in parse.c */217 #define OP_PHONY 0x00010000 /* Not a file target; run always */184 #define OP_DEPENDS 0x00000001 /* Execution of commands depends on 185 * kids (:) */ 186 #define OP_FORCE 0x00000002 /* Always execute commands (!) */ 187 #define OP_DOUBLEDEP 0x00000004 /* Execution of commands depends on kids 188 * per line (::) */ 189 #define OP_OPMASK (OP_DEPENDS|OP_FORCE|OP_DOUBLEDEP) 190 191 #define OP_OPTIONAL 0x00000008 /* Don't care if the target doesn't 192 * exist and can't be created */ 193 #define OP_USE 0x00000010 /* Use associated commands for parents */ 194 #define OP_EXEC 0x00000020 /* Target is never out of date, but always 195 * execute commands anyway. Its time 196 * doesn't matter, so it has none...sort 197 * of */ 198 #define OP_IGNORE 0x00000040 /* Ignore errors when creating the node */ 199 #define OP_PRECIOUS 0x00000080 /* Don't remove the target when 200 * interrupted */ 201 #define OP_SILENT 0x00000100 /* Don't echo commands when executed */ 202 #define OP_MAKE 0x00000200 /* Target is a recurrsive make so its 203 * commands should always be executed when 204 * it is out of date, regardless of the 205 * state of the -n or -t flags */ 206 #define OP_JOIN 0x00000400 /* Target is out-of-date only if any of its 207 * children was out-of-date */ 208 #define OP_INVISIBLE 0x00004000 /* The node is invisible to its parents. 209 * I.e. it doesn't show up in the parents's 210 * local variables. */ 211 #define OP_NOTMAIN 0x00008000 /* The node is exempt from normal 'main 212 * target' processing in parse.c */ 213 #define OP_PHONY 0x00010000 /* Not a file target; run always */ 218 214 /* Attributes applied by PMake */ 219 #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */215 #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ 220 216 #ifdef USE_ARCHIVES 221 #define OP_MEMBER 0x40000000 /* Target is a member of an archive */222 #define OP_LIB 0x20000000 /* Target is a library */223 #define OP_ARCHV 0x10000000 /* Target is an archive construct */224 #endif 225 #define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should.226 * Used when parsing to catch multiple227 * commands for a target */228 #define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */229 #define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */217 #define OP_MEMBER 0x40000000 /* Target is a member of an archive */ 218 #define OP_LIB 0x20000000 /* Target is a library */ 219 #define OP_ARCHV 0x10000000 /* Target is an archive construct */ 220 #endif 221 #define OP_HAS_COMMANDS 0x08000000 /* Target has all the commands it should. 222 * Used when parsing to catch multiple 223 * commands for a target */ 224 #define OP_SAVE_CMDS 0x04000000 /* Saving commands on .END (Compat) */ 225 #define OP_DEPS_FOUND 0x02000000 /* Already processed by Suff_FindDeps */ 230 226 231 227 /* … … 233 229 * object of a dependency operator 234 230 */ 235 #define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000)231 #define OP_NOP(t) (((t) & OP_OPMASK) == 0x00000000) 236 232 237 233 /* … … 243 239 * a NIL pointer will be returned. 244 240 */ 245 #define TARG_CREATE 0x01/* create node if not found */246 #define TARG_NOCREATE 0x00/* don't create it */241 #define TARG_CREATE 0x01 /* create node if not found */ 242 #define TARG_NOCREATE 0x00 /* don't create it */ 247 243 248 244 /* … … 255 251 * schemes allocate in powers of two. 256 252 */ 257 #define MAKE_BSIZE 256/* starting size for expandable buffers */253 #define MAKE_BSIZE 256 /* starting size for expandable buffers */ 258 254 259 255 /* … … 266 262 * Str_Concat returns. 267 263 */ 268 #define STR_ADDSPACE 0x01/* add a space when Str_Concat'ing */269 #define STR_DOFREE 0x02/* free source strings after concatenation */270 #define STR_ADDSLASH 0x04/* add a slash when Str_Concat'ing */264 #define STR_ADDSPACE 0x01 /* add a space when Str_Concat'ing */ 265 #define STR_DOFREE 0x02 /* free source strings after concatenation */ 266 #define STR_ADDSLASH 0x04 /* add a slash when Str_Concat'ing */ 271 267 272 268 /* … … 275 271 * as the first argument to Parse_Error. 276 272 */ 277 #define PARSE_WARNING 2278 #define PARSE_FATAL 1273 #define PARSE_WARNING 2 274 #define PARSE_FATAL 1 279 275 280 276 /* 281 277 * Values returned by Cond_Eval. 282 278 */ 283 #define COND_PARSE 0/* Parse the next lines */284 #define COND_SKIP 1/* Skip the next lines */285 #define COND_INVALID 2/* Not a conditional statement */279 #define COND_PARSE 0 /* Parse the next lines */ 280 #define COND_SKIP 1 /* Skip the next lines */ 281 #define COND_INVALID 2 /* Not a conditional statement */ 286 282 287 283 /* 288 284 * Definitions for the "local" variables. Used only for clarity. 289 285 */ 290 #define TARGET "@"/* Target of dependency */291 #define OODATE "?"/* All out-of-date sources */292 #define ALLSRC ">"/* All sources */293 #define IMPSRC "<"/* Source implied by transformation */294 #define PREFIX "*"/* Common prefix */286 #define TARGET "@" /* Target of dependency */ 287 #define OODATE "?" /* All out-of-date sources */ 288 #define ALLSRC ">" /* All sources */ 289 #define IMPSRC "<" /* Source implied by transformation */ 290 #define PREFIX "*" /* Common prefix */ 295 291 #ifdef KMK 296 292 #define PARENTS "^" /* Parent of this target (if any) (long name .PARENTS) */ 297 293 #endif 298 294 #ifdef USE_ARCHIVES 299 #define ARCHIVE "!"/* Archive in "archive(member)" syntax */300 #define MEMBER "%"/* Member in "archive(member)" syntax */295 #define ARCHIVE "!" /* Archive in "archive(member)" syntax */ 296 #define MEMBER "%" /* Member in "archive(member)" syntax */ 301 297 #endif 302 298 … … 311 307 * Global Variables 312 308 */ 313 extern Lst create;/* The list of target names specified on the314 * command line. used to resolve #if315 * make(...) statements */316 extern Lst dirSearchPath;/* The list of directories to search when317 * looking for targets */318 319 extern Boolean compatMake;/* True if we are make compatible */320 extern Boolean ignoreErrors;/* True if should ignore all errors */321 extern Boolean beSilent; /* True if should print no commands */322 extern Boolean beVerbose;/* True if should print extra cruft */323 extern Boolean noExecute; /* True if should execute nothing */324 extern Boolean allPrecious; /* True if every target is precious */325 extern Boolean keepgoing; /* True if should continue on unaffected326 * portions of the graph when have an error327 * in one portion */328 extern Boolean touchFlag;/* TRUE if targets should just be 'touched'329 * if out of date. Set by the -t flag */330 extern Boolean usePipes; /* TRUE if should capture the output of331 * subshells by means of pipes. Otherwise it332 * is routed to temporary files from which it333 * is retrieved when the shell exits */334 extern Boolean queryFlag;/* TRUE if we aren't supposed to really make335 * anything, just see if the targets are out-336 * of-date */337 338 extern Boolean checkEnvFirst;/* TRUE if environment should be searched for339 * all variables before the global context */340 extern Lst envFirstVars;/* List of specific variables for which the341 * environment should be searched before the342 * global context */343 344 extern GNode *DEFAULT; /* .DEFAULT rule */345 346 extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g347 * in the Makefile itself */348 extern GNode *VAR_CMD; /* Variables defined on the command line */349 extern char var_Error[];/* Value returned by Var_Parse when an error350 * is encountered. It actually points to351 * an empty string, so naive callers needn't352 * worry about it. */353 354 extern time_t now;/* The time at the start of this whole355 * process */356 357 extern Boolean oldVars;/* Do old-style variable substitution */358 359 extern Lst sysIncPath;/* The system include path. */309 extern Lst create; /* The list of target names specified on the 310 * command line. used to resolve #if 311 * make(...) statements */ 312 extern Lst dirSearchPath; /* The list of directories to search when 313 * looking for targets */ 314 315 extern Boolean compatMake; /* True if we are make compatible */ 316 extern Boolean ignoreErrors; /* True if should ignore all errors */ 317 extern Boolean beSilent; /* True if should print no commands */ 318 extern Boolean beVerbose; /* True if should print extra cruft */ 319 extern Boolean noExecute; /* True if should execute nothing */ 320 extern Boolean allPrecious; /* True if every target is precious */ 321 extern Boolean keepgoing; /* True if should continue on unaffected 322 * portions of the graph when have an error 323 * in one portion */ 324 extern Boolean touchFlag; /* TRUE if targets should just be 'touched' 325 * if out of date. Set by the -t flag */ 326 extern Boolean usePipes; /* TRUE if should capture the output of 327 * subshells by means of pipes. Otherwise it 328 * is routed to temporary files from which it 329 * is retrieved when the shell exits */ 330 extern Boolean queryFlag; /* TRUE if we aren't supposed to really make 331 * anything, just see if the targets are out- 332 * of-date */ 333 334 extern Boolean checkEnvFirst; /* TRUE if environment should be searched for 335 * all variables before the global context */ 336 extern Lst envFirstVars; /* List of specific variables for which the 337 * environment should be searched before the 338 * global context */ 339 340 extern GNode *DEFAULT; /* .DEFAULT rule */ 341 342 extern GNode *VAR_GLOBAL; /* Variables defined in a global context, e.g 343 * in the Makefile itself */ 344 extern GNode *VAR_CMD; /* Variables defined on the command line */ 345 extern char var_Error[]; /* Value returned by Var_Parse when an error 346 * is encountered. It actually points to 347 * an empty string, so naive callers needn't 348 * worry about it. */ 349 350 extern time_t now; /* The time at the start of this whole 351 * process */ 352 353 extern Boolean oldVars; /* Do old-style variable substitution */ 354 355 extern Lst sysIncPath; /* The system include path. */ 360 356 361 357 /* 362 358 * debug control: 363 * There is one bit per module. It is up to the module what debug364 * information to print.359 * There is one bit per module. It is up to the module what debug 360 * information to print. 365 361 */ 366 362 extern int debug; 367 363 #ifdef USE_ARCHIVES 368 #define DEBUG_ARCH0x0001369 #endif 370 #define DEBUG_COND0x0002371 #define DEBUG_DIR0x0004372 #define DEBUG_GRAPH10x0008373 #define DEBUG_GRAPH20x0010374 #define DEBUG_JOB0x0020375 #define DEBUG_MAKE0x0040376 #define DEBUG_SUFF0x0080377 #define DEBUG_TARG0x0100378 #define DEBUG_VAR0x0200379 #define DEBUG_FOR 0x0400380 #define DEBUG_LOUD 0x0800364 #define DEBUG_ARCH 0x0001 365 #endif 366 #define DEBUG_COND 0x0002 367 #define DEBUG_DIR 0x0004 368 #define DEBUG_GRAPH1 0x0008 369 #define DEBUG_GRAPH2 0x0010 370 #define DEBUG_JOB 0x0020 371 #define DEBUG_MAKE 0x0040 372 #define DEBUG_SUFF 0x0080 373 #define DEBUG_TARG 0x0100 374 #define DEBUG_VAR 0x0200 375 #define DEBUG_FOR 0x0400 376 #define DEBUG_LOUD 0x0800 381 377 #define DEBUG_PARSE 0x8000 /*kso*/ 382 378 383 379 /*#ifdef __STDC__*/ 384 380 #if defined(__STDC__) || defined(__IBMC__) 385 #define CONCAT(a,b) a##b381 #define CONCAT(a,b) a##b 386 382 #else 387 #define I(a) a388 #define CONCAT(a,b) I(a)b383 #define I(a) a 384 #define CONCAT(a,b) I(a)b 389 385 #endif /* __STDC__ */ 390 386 391 387 392 388 393 #define DEBUG(module)(debug & CONCAT(DEBUG_,module))389 #define DEBUG(module) (debug & CONCAT(DEBUG_,module)) 394 390 #define ISDOT(c) ((c)[0] == '.' && (((c)[1] == '\0') || ((c)[1] == '/'))) 395 391 #define ISDOTDOT(c) ((c)[0] == '.' && ISDOT(&((c)[1]))) -
trunk/src/kmk/nonints.h
r46 r51 1 1 /*- 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 36 36 * SUCH DAMAGE. 37 37 * 38 * from: @(#)nonints.h8.3 (Berkeley) 3/19/9438 * from: @(#)nonints.h 8.3 (Berkeley) 3/19/94 39 39 * $FreeBSD: src/usr.bin/make/nonints.h,v 1.8 1999/08/28 01:03:35 peter Exp $ 40 40 */ 41 42 #ifndef __nonints_h__ 43 #define __nonints_h__ 41 44 42 45 /* arch.c */ … … 149 152 void Var_End __P((void)); 150 153 void Var_Dump __P((GNode *)); 154 155 #endif -
trunk/src/kmk/parse.c
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94";41 static char sccsid[] = "@(#)parse.c 8.3 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/parse.c,v 1.22 1999/08/28 01:03:35 peter Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * parse.c -- 50 * Functions to parse a makefile.51 * 52 * One function, Parse_Init, must be called before any functions53 * in this module are used. After that, the function Parse_File is the54 * main entry point and controls most of the other functions in this55 * module.56 * 57 * Most important structures are kept in Lsts. Directories for58 * the #include "..." function are kept in the 'parseIncPath' Lst, while59 * those for the #include <...> are kept in the 'sysIncPath' Lst. The60 * targets currently being defined are kept in the 'targets' Lst.61 * 62 * The variables 'fname' and 'lineno' are used to track the name63 * of the current file and the line number in that file so that error64 * messages can be more meaningful.51 * Functions to parse a makefile. 52 * 53 * One function, Parse_Init, must be called before any functions 54 * in this module are used. After that, the function Parse_File is the 55 * main entry point and controls most of the other functions in this 56 * module. 57 * 58 * Most important structures are kept in Lsts. Directories for 59 * the #include "..." function are kept in the 'parseIncPath' Lst, while 60 * those for the #include <...> are kept in the 'sysIncPath' Lst. The 61 * targets currently being defined are kept in the 'targets' Lst. 62 * 63 * The variables 'fname' and 'lineno' are used to track the name 64 * of the current file and the line number in that file so that error 65 * messages can be more meaningful. 65 66 * 66 67 * Interface: 67 * Parse_InitInitialization function which must be68 * called before anything else in this module69 * is used.70 * 71 * Parse_EndCleanup the module72 * 73 * Parse_FileFunction used to parse a makefile. It must74 * be given the name of the file, which should75 * already have been opened, and a function76 * to call to read a character from the file.77 * 78 * Parse_IsVarReturns TRUE if the given line is a79 * variable assignment. Used by MainParseArgs80 * to determine if an argument is a target81 * or a variable assignment. Used internally82 * for pretty much the same thing...83 * 84 * Parse_ErrorFunction called when an error occurs in85 * parsing. Used by the variable and86 * conditional modules.87 * Parse_MainNameReturns a Lst of the main target to create.88 */ 89 90 #if defined(__STDC__) || defined(__IBMC__)68 * Parse_Init Initialization function which must be 69 * called before anything else in this module 70 * is used. 71 * 72 * Parse_End Cleanup the module 73 * 74 * Parse_File Function used to parse a makefile. It must 75 * be given the name of the file, which should 76 * already have been opened, and a function 77 * to call to read a character from the file. 78 * 79 * Parse_IsVar Returns TRUE if the given line is a 80 * variable assignment. Used by MainParseArgs 81 * to determine if an argument is a target 82 * or a variable assignment. Used internally 83 * for pretty much the same thing... 84 * 85 * Parse_Error Function called when an error occurs in 86 * parsing. Used by the variable and 87 * conditional modules. 88 * Parse_MainName Returns a Lst of the main target to create. 89 */ 90 91 #ifdef __STDC__ 91 92 #include <stdarg.h> 92 93 #else … … 109 110 * or if it's DONE. 110 111 */ 111 #define CONTINUE1112 #define DONE0113 static Lst targets;/* targets we're working on */114 /*static Lst targCmds; *//* command lines for targets */115 static Boolean inLine;/* true if currently in a dependency116 * line or its commands */112 #define CONTINUE 1 113 #define DONE 0 114 static Lst targets; /* targets we're working on */ 115 /*static Lst targCmds; */ /* command lines for targets */ 116 static Boolean inLine; /* true if currently in a dependency 117 * line or its commands */ 117 118 #if defined(USE_INLINEFILES) 118 119 static Boolean inInlineFile; /* true if currently in a inline file.*/ … … 123 124 } PTR; 124 125 125 static char *fname;/* name of current file (for errors) */126 static int lineno; /* line number in current file */127 static FILE *curFILE = NULL;/* current makefile */128 129 static PTR *curPTR = NULL;/* current makefile */130 131 static int fatals = 0;132 133 static GNode *mainNode;/* The main target to create. This is the134 * first target on the first dependency135 * line in the first makefile */126 static char *fname; /* name of current file (for errors) */ 127 static int lineno; /* line number in current file */ 128 static FILE *curFILE = NULL; /* current makefile */ 129 130 static PTR *curPTR = NULL; /* current makefile */ 131 132 static int fatals = 0; 133 134 static GNode *mainNode; /* The main target to create. This is the 135 * first target on the first dependency 136 * line in the first makefile */ 136 137 /* 137 138 * Definitions for handling #include specifications 138 139 */ 139 140 typedef struct IFile { 140 char *fname; /* name of previous file */141 int lineno; /* saved line number */142 FILE * F; /* the open stream */143 PTR * p;/* the char pointer */141 char *fname; /* name of previous file */ 142 int lineno; /* saved line number */ 143 FILE * F; /* the open stream */ 144 PTR * p; /* the char pointer */ 144 145 } IFile; 145 146 146 static Lst includes; /* stack of IFiles generated by147 * #includes */148 Lst parseIncPath;/* list of directories for "..." includes */149 Lst sysIncPath;/* list of directories for <...> includes */147 static Lst includes; /* stack of IFiles generated by 148 * #includes */ 149 Lst parseIncPath; /* list of directories for "..." includes */ 150 Lst sysIncPath; /* list of directories for <...> includes */ 150 151 151 152 /*- … … 156 157 */ 157 158 typedef enum { 158 Begin, /* .BEGIN */159 Default, /* .DEFAULT */160 End, /* .END */161 Ignore, /* .IGNORE */162 Includes, /* .INCLUDES */163 Interrupt, /* .INTERRUPT */159 Begin, /* .BEGIN */ 160 Default, /* .DEFAULT */ 161 End, /* .END */ 162 Ignore, /* .IGNORE */ 163 Includes, /* .INCLUDES */ 164 Interrupt, /* .INTERRUPT */ 164 165 #ifdef USE_ARCHIVES 165 Libs, /* .LIBS */166 #endif 167 MFlags, /* .MFLAGS or .MAKEFLAGS */168 Main, /* .MAIN and we don't have anything user-specified to169 * make */170 NoExport, /* .NOEXPORT */171 Not, /* Not special */166 Libs, /* .LIBS */ 167 #endif 168 MFlags, /* .MFLAGS or .MAKEFLAGS */ 169 Main, /* .MAIN and we don't have anything user-specified to 170 * make */ 171 NoExport, /* .NOEXPORT */ 172 Not, /* Not special */ 172 173 NotParallel, /* .NOTPARALELL */ 173 Null, /* .NULL */174 Order, /* .ORDER */175 Parallel, /* .PARALLEL */176 ExPath, /* .PATH */177 Phony, /* .PHONY */174 Null, /* .NULL */ 175 Order, /* .ORDER */ 176 Parallel, /* .PARALLEL */ 177 ExPath, /* .PATH */ 178 Phony, /* .PHONY */ 178 179 #ifdef POSIX 179 Posix, /* .POSIX */180 #endif 181 Precious, /* .PRECIOUS */182 ExShell, /* .SHELL */183 Silent, /* .SILENT */180 Posix, /* .POSIX */ 181 #endif 182 Precious, /* .PRECIOUS */ 183 ExShell, /* .SHELL */ 184 Silent, /* .SILENT */ 184 185 SingleShell, /* .SINGLESHELL */ 185 Suffixes, /* .SUFFIXES */186 Wait, /* .WAIT */187 Attribute /* Generic attribute */186 Suffixes, /* .SUFFIXES */ 187 Wait, /* .WAIT */ 188 Attribute /* Generic attribute */ 188 189 } ParseSpecial; 189 190 … … 195 196 * seen, then set to each successive source on the line. 196 197 */ 197 static GNode *predecessor;198 static GNode *predecessor; 198 199 199 200 /* … … 205 206 */ 206 207 static struct { 207 char *name;/* Name of keyword */208 ParseSpecial spec; /* Type when used as a target */209 int op;/* Operator when used as a source */208 char *name; /* Name of keyword */ 209 ParseSpecial spec; /* Type when used as a target */ 210 int op; /* Operator when used as a source */ 210 211 } parseKeywords[] = { 211 { ".BEGIN", Begin,0 },212 { ".DEFAULT", Default,0 },213 { ".END", End,0 },214 { ".EXEC", Attribute,OP_EXEC },215 { ".IGNORE", Ignore,OP_IGNORE },216 { ".INCLUDES", Includes,0 },217 { ".INTERRUPT", Interrupt,0 },218 { ".INVISIBLE", Attribute,OP_INVISIBLE },219 { ".JOIN", Attribute,OP_JOIN },212 { ".BEGIN", Begin, 0 }, 213 { ".DEFAULT", Default, 0 }, 214 { ".END", End, 0 }, 215 { ".EXEC", Attribute, OP_EXEC }, 216 { ".IGNORE", Ignore, OP_IGNORE }, 217 { ".INCLUDES", Includes, 0 }, 218 { ".INTERRUPT", Interrupt, 0 }, 219 { ".INVISIBLE", Attribute, OP_INVISIBLE }, 220 { ".JOIN", Attribute, OP_JOIN }, 220 221 #ifdef USE_ARCHIVES 221 { ".LIBS", Libs,0 },222 #endif 223 { ".MAIN", Main,0 },224 { ".MAKE", Attribute,OP_MAKE },225 { ".MAKEFLAGS", MFlags,0 },226 { ".MFLAGS", MFlags,0 },227 { ".NOTMAIN", Attribute,OP_NOTMAIN },228 { ".NOTPARALLEL", NotParallel, 0 },229 { ".NO_PARALLEL", NotParallel, 0 },230 { ".NULL", Null,0 },231 { ".OPTIONAL", Attribute,OP_OPTIONAL },232 { ".ORDER", Order,0 },233 { ".PARALLEL", Parallel,0 },234 { ".PATH", ExPath,0 },235 { ".PHONY", Phony,OP_PHONY },222 { ".LIBS", Libs, 0 }, 223 #endif 224 { ".MAIN", Main, 0 }, 225 { ".MAKE", Attribute, OP_MAKE }, 226 { ".MAKEFLAGS", MFlags, 0 }, 227 { ".MFLAGS", MFlags, 0 }, 228 { ".NOTMAIN", Attribute, OP_NOTMAIN }, 229 { ".NOTPARALLEL", NotParallel, 0 }, 230 { ".NO_PARALLEL", NotParallel, 0 }, 231 { ".NULL", Null, 0 }, 232 { ".OPTIONAL", Attribute, OP_OPTIONAL }, 233 { ".ORDER", Order, 0 }, 234 { ".PARALLEL", Parallel, 0 }, 235 { ".PATH", ExPath, 0 }, 236 { ".PHONY", Phony, OP_PHONY }, 236 237 #ifdef POSIX 237 { ".POSIX", Posix,0 },238 #endif 239 { ".PRECIOUS", Precious,OP_PRECIOUS },240 { ".RECURSIVE", Attribute,OP_MAKE },241 { ".SHELL", ExShell,0 },242 { ".SILENT", Silent,OP_SILENT },243 { ".SINGLESHELL", SingleShell, 0 },244 { ".SUFFIXES", Suffixes,0 },245 { ".USE", Attribute,OP_USE },246 { ".WAIT", Wait,0 },238 { ".POSIX", Posix, 0 }, 239 #endif 240 { ".PRECIOUS", Precious, OP_PRECIOUS }, 241 { ".RECURSIVE", Attribute, OP_MAKE }, 242 { ".SHELL", ExShell, 0 }, 243 { ".SILENT", Silent, OP_SILENT }, 244 { ".SINGLESHELL", SingleShell, 0 }, 245 { ".SUFFIXES", Suffixes, 0 }, 246 { ".USE", Attribute, OP_USE }, 247 { ".WAIT", Wait, 0 }, 247 248 }; 248 249 … … 277 278 *---------------------------------------------------------------------- 278 279 * ParseFindKeyword -- 279 * Look in the table of keywords for one matching the given string.280 * Look in the table of keywords for one matching the given string. 280 281 * 281 282 * Results: 282 * The index of the keyword, or -1 if it isn't there.283 * The index of the keyword, or -1 if it isn't there. 283 284 * 284 285 * Side Effects: 285 * None286 * None 286 287 *---------------------------------------------------------------------- 287 288 */ 288 289 static int 289 290 ParseFindKeyword (str) 290 char *str;/* String to find */291 char *str; /* String to find */ 291 292 { 292 293 register int start, 293 end,294 cur;294 end, 295 cur; 295 296 register int diff; 296 297 … … 299 300 300 301 do { 301 cur = start + ((end - start) / 2);302 diff = strcmp (str, parseKeywords[cur].name);303 304 if (diff == 0) {305 return (cur);306 } else if (diff < 0) {307 end = cur - 1;308 } else {309 start = cur + 1;310 }302 cur = start + ((end - start) / 2); 303 diff = strcmp (str, parseKeywords[cur].name); 304 305 if (diff == 0) { 306 return (cur); 307 } else if (diff < 0) { 308 end = cur - 1; 309 } else { 310 start = cur + 1; 311 } 311 312 } while (start <= end); 312 313 return (-1); … … 315 316 /*- 316 317 * Parse_Error -- 317 * Error message abort function for parsing. Prints out the context318 * of the error (line number and file) as well as the message with319 * two optional arguments.318 * Error message abort function for parsing. Prints out the context 319 * of the error (line number and file) as well as the message with 320 * two optional arguments. 320 321 * 321 322 * Results: 322 * None323 * None 323 324 * 324 325 * Side Effects: 325 * "fatals" is incremented if the level is PARSE_FATAL.326 * "fatals" is incremented if the level is PARSE_FATAL. 326 327 */ 327 328 /* VARARGS */ … … 331 332 #else 332 333 Parse_Error(va_alist) 333 va_dcl334 #endif 335 { 336 va_list ap;334 va_dcl 335 #endif 336 { 337 va_list ap; 337 338 #if defined(__STDC__) || defined(__IBMC__) 338 va_start(ap, fmt);339 va_start(ap, fmt); 339 340 #else 340 int type;/* Error type (PARSE_WARNING, PARSE_FATAL) */341 char *fmt;342 343 va_start(ap);344 type = va_arg(ap, int);345 fmt = va_arg(ap, char *);346 #endif 347 348 (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno);349 if (type == PARSE_WARNING)350 (void)fprintf(stderr, "warning: ");351 (void)vfprintf(stderr, fmt, ap);352 va_end(ap);353 (void)fprintf(stderr, "\n");354 (void)fflush(stderr);355 if (type == PARSE_FATAL)356 fatals += 1;341 int type; /* Error type (PARSE_WARNING, PARSE_FATAL) */ 342 char *fmt; 343 344 va_start(ap); 345 type = va_arg(ap, int); 346 fmt = va_arg(ap, char *); 347 #endif 348 349 (void)fprintf(stderr, "\"%s\", line %d: ", fname, lineno); 350 if (type == PARSE_WARNING) 351 (void)fprintf(stderr, "warning: "); 352 (void)vfprintf(stderr, fmt, ap); 353 va_end(ap); 354 (void)fprintf(stderr, "\n"); 355 (void)fflush(stderr); 356 if (type == PARSE_FATAL) 357 fatals += 1; 357 358 } 358 359 … … 360 361 *--------------------------------------------------------------------- 361 362 * ParseLinkSrc -- 362 * Link the parent node to its new child. Used in a Lst_ForEach by363 * ParseDoDependency. If the specType isn't 'Not', the parent364 * isn't linked as a parent of the child.363 * Link the parent node to its new child. Used in a Lst_ForEach by 364 * ParseDoDependency. If the specType isn't 'Not', the parent 365 * isn't linked as a parent of the child. 365 366 * 366 367 * Results: 367 * Always = 0368 * Always = 0 368 369 * 369 370 * Side Effects: 370 * New elements are added to the parents list of cgn and the371 * children list of cgn. the unmade field of pgn is updated372 * to reflect the additional child.371 * New elements are added to the parents list of cgn and the 372 * children list of cgn. the unmade field of pgn is updated 373 * to reflect the additional child. 373 374 *--------------------------------------------------------------------- 374 375 */ 375 376 static int 376 377 ParseLinkSrc (pgnp, cgnp) 377 ClientData pgnp; /* The parent node */378 ClientData cgnp; /* The child node */378 ClientData pgnp; /* The parent node */ 379 ClientData cgnp; /* The child node */ 379 380 { 380 381 GNode *pgn = (GNode *) pgnp; 381 382 GNode *cgn = (GNode *) cgnp; 382 383 if (Lst_Member (pgn->children, (ClientData)cgn) == NILLNODE) { 383 (void)Lst_AtEnd (pgn->children, (ClientData)cgn);384 if (specType == Not) {385 (void)Lst_AtEnd (cgn->parents, (ClientData)pgn);386 }387 pgn->unmade += 1;384 (void)Lst_AtEnd (pgn->children, (ClientData)cgn); 385 if (specType == Not) { 386 (void)Lst_AtEnd (cgn->parents, (ClientData)pgn); 387 } 388 pgn->unmade += 1; 388 389 } 389 390 return (0); … … 393 394 *--------------------------------------------------------------------- 394 395 * ParseDoOp -- 395 * Apply the parsed operator to the given target node. Used in a396 * Lst_ForEach call by ParseDoDependency once all targets have397 * been found and their operator parsed. If the previous and new398 * operators are incompatible, a major error is taken.396 * Apply the parsed operator to the given target node. Used in a 397 * Lst_ForEach call by ParseDoDependency once all targets have 398 * been found and their operator parsed. If the previous and new 399 * operators are incompatible, a major error is taken. 399 400 * 400 401 * Results: 401 * Always 0402 * Always 0 402 403 * 403 404 * Side Effects: 404 * The type field of the node is altered to reflect any new bits in405 * the op.405 * The type field of the node is altered to reflect any new bits in 406 * the op. 406 407 *--------------------------------------------------------------------- 407 408 */ 408 409 static int 409 410 ParseDoOp (gnp, opp) 410 ClientData gnp; /* The node to which the operator is to be411 * applied */412 ClientData opp; /* The operator to apply */411 ClientData gnp; /* The node to which the operator is to be 412 * applied */ 413 ClientData opp; /* The operator to apply */ 413 414 { 414 415 GNode *gn = (GNode *) gnp; … … 420 421 */ 421 422 if (((op & OP_OPMASK) != (gn->type & OP_OPMASK)) && 422 !OP_NOP(gn->type) && !OP_NOP(op))423 !OP_NOP(gn->type) && !OP_NOP(op)) 423 424 { 424 Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name);425 return (1);425 Parse_Error (PARSE_FATAL, "Inconsistent operator for %s", gn->name); 426 return (1); 426 427 } 427 428 428 429 if ((op == OP_DOUBLEDEP) && ((gn->type & OP_OPMASK) == OP_DOUBLEDEP)) { 429 /*430 * If the node was the object of a :: operator, we need to create a431 * new instance of it for the children and commands on this dependency432 * line. The new instance is placed on the 'cohorts' list of the433 * initial one (note the initial one is not on its own cohorts list)434 * and the new instance is linked to all parents of the initial435 * instance.436 */437 register GNode*cohort;438 LstNodeln;439 440 cohort = Targ_NewGN(gn->name);441 /*442 * Duplicate links to parents so graph traversal is simple. Perhaps443 * some type bits should be duplicated?444 *445 * Make the cohort invisible as well to avoid duplicating it into446 * other variables. True, parents of this target won't tend to do447 * anything with their local variables, but better safe than448 * sorry.449 */450 Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort);451 cohort->type = OP_DOUBLEDEP|OP_INVISIBLE;452 (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort);453 454 /*455 * Replace the node in the targets list with the new copy456 */457 ln = Lst_Member(targets, (ClientData)gn);458 Lst_Replace(ln, (ClientData)cohort);459 gn = cohort;430 /* 431 * If the node was the object of a :: operator, we need to create a 432 * new instance of it for the children and commands on this dependency 433 * line. The new instance is placed on the 'cohorts' list of the 434 * initial one (note the initial one is not on its own cohorts list) 435 * and the new instance is linked to all parents of the initial 436 * instance. 437 */ 438 register GNode *cohort; 439 LstNode ln; 440 441 cohort = Targ_NewGN(gn->name); 442 /* 443 * Duplicate links to parents so graph traversal is simple. Perhaps 444 * some type bits should be duplicated? 445 * 446 * Make the cohort invisible as well to avoid duplicating it into 447 * other variables. True, parents of this target won't tend to do 448 * anything with their local variables, but better safe than 449 * sorry. 450 */ 451 Lst_ForEach(gn->parents, ParseLinkSrc, (ClientData)cohort); 452 cohort->type = OP_DOUBLEDEP|OP_INVISIBLE; 453 (void)Lst_AtEnd(gn->cohorts, (ClientData)cohort); 454 455 /* 456 * Replace the node in the targets list with the new copy 457 */ 458 ln = Lst_Member(targets, (ClientData)gn); 459 Lst_Replace(ln, (ClientData)cohort); 460 gn = cohort; 460 461 } 461 462 /* … … 471 472 *--------------------------------------------------------------------- 472 473 * ParseAddDep -- 473 * Check if the pair of GNodes given needs to be synchronized.474 * This has to be when two nodes are on different sides of a475 * .WAIT directive.474 * Check if the pair of GNodes given needs to be synchronized. 475 * This has to be when two nodes are on different sides of a 476 * .WAIT directive. 476 477 * 477 478 * Results: 478 * Returns 1 if the two targets need to be ordered, 0 otherwise.479 * If it returns 1, the search can stop479 * Returns 1 if the two targets need to be ordered, 0 otherwise. 480 * If it returns 1, the search can stop 480 481 * 481 482 * Side Effects: 482 * A dependency can be added between the two nodes.483 * A dependency can be added between the two nodes. 483 484 * 484 485 *--------------------------------------------------------------------- … … 493 494 494 495 if (p->order < s->order) { 495 /*496 * XXX: This can cause loops, and loops can cause unmade targets,497 * but checking is tedious, and the debugging output can show the498 * problem499 */500 (void)Lst_AtEnd(p->successors, (ClientData)s);501 (void)Lst_AtEnd(s->preds, (ClientData)p);502 return 0;496 /* 497 * XXX: This can cause loops, and loops can cause unmade targets, 498 * but checking is tedious, and the debugging output can show the 499 * problem 500 */ 501 (void)Lst_AtEnd(p->successors, (ClientData)s); 502 (void)Lst_AtEnd(s->preds, (ClientData)p); 503 return 0; 503 504 } 504 505 else 505 return 1;506 return 1; 506 507 } 507 508 … … 510 511 *--------------------------------------------------------------------- 511 512 * ParseDoSrc -- 512 * Given the name of a source, figure out if it is an attribute513 * and apply it to the targets if it is. Else decide if there is514 * some attribute which should be applied *to* the source because515 * of some special target and apply it if so. Otherwise, make the516 * source be a child of the targets in the list 'targets'513 * Given the name of a source, figure out if it is an attribute 514 * and apply it to the targets if it is. Else decide if there is 515 * some attribute which should be applied *to* the source because 516 * of some special target and apply it if so. Otherwise, make the 517 * source be a child of the targets in the list 'targets' 517 518 * 518 519 * Results: 519 * None520 * None 520 521 * 521 522 * Side Effects: 522 * Operator bits may be added to the list of targets or to the source.523 * The targets may have a new source added to their lists of children.523 * Operator bits may be added to the list of targets or to the source. 524 * The targets may have a new source added to their lists of children. 524 525 *--------------------------------------------------------------------- 525 526 */ 526 527 static void 527 528 ParseDoSrc (tOp, src, allsrc) 528 int tOp;/* operator (if any) from special targets */529 char *src;/* name of the source to handle */530 Lst allsrc;/* List of all sources to wait for */531 { 532 GNode *gn = NULL;529 int tOp; /* operator (if any) from special targets */ 530 char *src; /* name of the source to handle */ 531 Lst allsrc; /* List of all sources to wait for */ 532 { 533 GNode *gn = NULL; 533 534 534 535 if (*src == '.' && isupper (src[1])) { 535 int keywd = ParseFindKeyword(src);536 if (keywd != -1) {537 int op = parseKeywords[keywd].op;538 if (op != 0) {539 Lst_ForEach (targets, ParseDoOp, (ClientData)&op);540 return;541 }542 if (parseKeywords[keywd].spec == Wait) {543 waiting++;544 return;545 }546 }536 int keywd = ParseFindKeyword(src); 537 if (keywd != -1) { 538 int op = parseKeywords[keywd].op; 539 if (op != 0) { 540 Lst_ForEach (targets, ParseDoOp, (ClientData)&op); 541 return; 542 } 543 if (parseKeywords[keywd].spec == Wait) { 544 waiting++; 545 return; 546 } 547 } 547 548 } 548 549 549 550 switch (specType) { 550 551 case Main: 551 /*552 * If we have noted the existence of a .MAIN, it means we need553 * to add the sources of said target to the list of things554 * to create. The string 'src' is likely to be efree, so we555 * must make a new copy of it. Note that this will only be556 * invoked if the user didn't specify a target on the command557 * line. This is to allow #ifmake's to succeed, or something...558 */559 (void) Lst_AtEnd (create, (ClientData)estrdup(src));560 /*561 * Add the name to the .TARGETS variable as well, so the user cna562 * employ that, if desired.563 */564 Var_Append(".TARGETS", src, VAR_GLOBAL);565 return;552 /* 553 * If we have noted the existence of a .MAIN, it means we need 554 * to add the sources of said target to the list of things 555 * to create. The string 'src' is likely to be efree, so we 556 * must make a new copy of it. Note that this will only be 557 * invoked if the user didn't specify a target on the command 558 * line. This is to allow #ifmake's to succeed, or something... 559 */ 560 (void) Lst_AtEnd (create, (ClientData)estrdup(src)); 561 /* 562 * Add the name to the .TARGETS variable as well, so the user cna 563 * employ that, if desired. 564 */ 565 Var_Append(".TARGETS", src, VAR_GLOBAL); 566 return; 566 567 567 568 case Order: 568 /*569 * Create proper predecessor/successor links between the previous570 * source and the current one.571 */572 gn = Targ_FindNode(src, TARG_CREATE);573 if (predecessor != NILGNODE) {574 (void)Lst_AtEnd(predecessor->successors, (ClientData)gn);575 (void)Lst_AtEnd(gn->preds, (ClientData)predecessor);576 }577 /*578 * The current source now becomes the predecessor for the next one.579 */580 predecessor = gn;581 break;569 /* 570 * Create proper predecessor/successor links between the previous 571 * source and the current one. 572 */ 573 gn = Targ_FindNode(src, TARG_CREATE); 574 if (predecessor != NILGNODE) { 575 (void)Lst_AtEnd(predecessor->successors, (ClientData)gn); 576 (void)Lst_AtEnd(gn->preds, (ClientData)predecessor); 577 } 578 /* 579 * The current source now becomes the predecessor for the next one. 580 */ 581 predecessor = gn; 582 break; 582 583 583 584 default: 584 /*585 * If the source is not an attribute, we need to find/create586 * a node for it. After that we can apply any operator to it587 * from a special target or link it to its parents, as588 * appropriate.589 *590 * In the case of a source that was the object of a :: operator,591 * the attribute is applied to all of its instances (as kept in592 * the 'cohorts' list of the node) or all the cohorts are linked593 * to all the targets.594 */595 gn = Targ_FindNode (src, TARG_CREATE);596 if (tOp) {597 gn->type |= tOp;598 } else {599 Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn);600 }601 if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) {602 register GNode*cohort;603 register LstNodeln;604 605 for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){606 cohort = (GNode *)Lst_Datum(ln);607 if (tOp) {608 cohort->type |= tOp;609 } else {610 Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort);611 }612 }613 }614 break;585 /* 586 * If the source is not an attribute, we need to find/create 587 * a node for it. After that we can apply any operator to it 588 * from a special target or link it to its parents, as 589 * appropriate. 590 * 591 * In the case of a source that was the object of a :: operator, 592 * the attribute is applied to all of its instances (as kept in 593 * the 'cohorts' list of the node) or all the cohorts are linked 594 * to all the targets. 595 */ 596 gn = Targ_FindNode (src, TARG_CREATE); 597 if (tOp) { 598 gn->type |= tOp; 599 } else { 600 Lst_ForEach (targets, ParseLinkSrc, (ClientData)gn); 601 } 602 if ((gn->type & OP_OPMASK) == OP_DOUBLEDEP) { 603 register GNode *cohort; 604 register LstNode ln; 605 606 for (ln=Lst_First(gn->cohorts); ln != NILLNODE; ln = Lst_Succ(ln)){ 607 cohort = (GNode *)Lst_Datum(ln); 608 if (tOp) { 609 cohort->type |= tOp; 610 } else { 611 Lst_ForEach(targets, ParseLinkSrc, (ClientData)cohort); 612 } 613 } 614 } 615 break; 615 616 } 616 617 … … 618 619 (void)Lst_AtEnd(allsrc, (ClientData)gn); 619 620 if (waiting) { 620 Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn);621 Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn); 621 622 } 622 623 } … … 625 626 *----------------------------------------------------------------------- 626 627 * ParseFindMain -- 627 * Find a real target in the list and set it to be the main one.628 * Called by ParseDoDependency when a main target hasn't been found629 * yet.628 * Find a real target in the list and set it to be the main one. 629 * Called by ParseDoDependency when a main target hasn't been found 630 * yet. 630 631 * 631 632 * Results: 632 * 0 if main not found yet, 1 if it is.633 * 0 if main not found yet, 1 if it is. 633 634 * 634 635 * Side Effects: 635 * mainNode is changed and Targ_SetMain is called.636 * mainNode is changed and Targ_SetMain is called. 636 637 * 637 638 *----------------------------------------------------------------------- … … 639 640 static int 640 641 ParseFindMain(gnp, dummy) 641 ClientData gnp;/* Node to examine */642 ClientData gnp; /* Node to examine */ 642 643 ClientData dummy; 643 644 { 644 GNode *gn = (GNode *) gnp;645 GNode *gn = (GNode *) gnp; 645 646 if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 646 mainNode = gn;647 Targ_SetMain(gn);648 return (dummy ? 1 : 1);647 mainNode = gn; 648 Targ_SetMain(gn); 649 return (dummy ? 1 : 1); 649 650 } else { 650 return (dummy ? 0 : 0);651 return (dummy ? 0 : 0); 651 652 } 652 653 } … … 655 656 *----------------------------------------------------------------------- 656 657 * ParseAddDir -- 657 * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going658 * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 658 659 * 659 660 * Results: 660 * === 0661 * === 0 661 662 * 662 663 * Side Effects: 663 * See Dir_AddDir.664 * See Dir_AddDir. 664 665 * 665 666 *----------------------------------------------------------------------- … … 667 668 static int 668 669 ParseAddDir(path, name) 669 ClientData path;670 ClientData path; 670 671 ClientData name; 671 672 { … … 677 678 *----------------------------------------------------------------------- 678 679 * ParseClearPath -- 679 * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going680 * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 680 681 * 681 682 * Results: 682 * === 0683 * === 0 683 684 * 684 685 * Side Effects: 685 * See Dir_ClearPath686 * See Dir_ClearPath 686 687 * 687 688 *----------------------------------------------------------------------- … … 699 700 *--------------------------------------------------------------------- 700 701 * ParseDoDependency -- 701 * Parse the dependency line in line.702 * Parse the dependency line in line. 702 703 * 703 704 * Results: 704 * None705 * None 705 706 * 706 707 * Side Effects: 707 * The nodes of the sources are linked as children to the nodes of the708 * targets. Some nodes may be created.709 * 710 * We parse a dependency line by first extracting words from the line and708 * The nodes of the sources are linked as children to the nodes of the 709 * targets. Some nodes may be created. 710 * 711 * We parse a dependency line by first extracting words from the line and 711 712 * finding nodes in the list of all targets with that name. This is done 712 713 * until a character is encountered which is an operator character. Currently 713 714 * these are only ! and :. At this point the operator is parsed and the 714 715 * pointer into the line advanced until the first source is encountered. 715 * The parsed operator is applied to each node in the 'targets' list,716 * The parsed operator is applied to each node in the 'targets' list, 716 717 * which is where the nodes found for the targets are kept, by means of 717 718 * the ParseDoOp function. 718 * The sources are read in much the same way as the targets were except719 * The sources are read in much the same way as the targets were except 719 720 * that now they are expanded using the wildcarding scheme of the C-Shell 720 721 * and all instances of the resulting words in the list of all targets 721 722 * are found. Each of the resulting nodes is then linked to each of the 722 723 * targets as one of its children. 723 * Certain targets are handled specially. These are the ones detailed724 * Certain targets are handled specially. These are the ones detailed 724 725 * by the specType variable. 725 * The storing of transformation rules is also taken care of here.726 * The storing of transformation rules is also taken care of here. 726 727 * A target is recognized as a transformation rule by calling 727 728 * Suff_IsTransform. If it is a transformation rule, its node is gotten … … 732 733 static void 733 734 ParseDoDependency (line) 734 char *line; /* the line to parse */735 { 736 char *cp;/* our current position */737 GNode *gn;/* a general purpose temporary node */738 int op; /* the operator on the line */739 char savec; /* a place to save a character */740 Lst paths;/* List of search paths to alter when parsing741 * a list of .PATH targets */742 int tOp;/* operator from special target */735 char *line; /* the line to parse */ 736 { 737 char *cp; /* our current position */ 738 GNode *gn; /* a general purpose temporary node */ 739 int op; /* the operator on the line */ 740 char savec; /* a place to save a character */ 741 Lst paths; /* List of search paths to alter when parsing 742 * a list of .PATH targets */ 743 int tOp; /* operator from special target */ 743 744 #ifdef USE_ARCHIVES 744 Lst sources;/* list of archive source names after745 * expansion */746 #endif 747 Lst curTargs;/* list of target names to be found and added748 * to the targets list */749 Lst curSrcs;/* list of sources in order */745 Lst sources; /* list of archive source names after 746 * expansion */ 747 #endif 748 Lst curTargs; /* list of target names to be found and added 749 * to the targets list */ 750 Lst curSrcs; /* list of sources in order */ 750 751 751 752 tOp = 0; … … 759 760 760 761 do { 761 for (cp = line;762 *cp && !isspace (*cp) &&763 (*cp != '!') && (*cp != ':') && (*cp != '(');764 cp++)765 {766 if (*cp == '$') {767 /*768 * Must be a dynamic source (would have been expanded769 * otherwise), so call the Var module to parse the puppy770 * so we can safely advance beyond it...There should be771 * no errors in this, as they would have been discovered772 * in the initial Var_Subst and we wouldn't be here.773 */774 intlength;775 BooleanfreeIt;776 char*result;777 778 result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt);779 780 if (freeIt) {781 efree(result);782 }783 cp += length-1;784 }785 continue;786 }787 if (*cp == '(') {762 for (cp = line; 763 *cp && !isspace (*cp) && 764 (*cp != '!') && (*cp != ':') && (*cp != '('); 765 cp++) 766 { 767 if (*cp == '$') { 768 /* 769 * Must be a dynamic source (would have been expanded 770 * otherwise), so call the Var module to parse the puppy 771 * so we can safely advance beyond it...There should be 772 * no errors in this, as they would have been discovered 773 * in the initial Var_Subst and we wouldn't be here. 774 */ 775 int length; 776 Boolean freeIt; 777 char *result; 778 779 result=Var_Parse(cp, VAR_CMD, TRUE, &length, &freeIt); 780 781 if (freeIt) { 782 efree(result); 783 } 784 cp += length-1; 785 } 786 continue; 787 } 788 if (*cp == '(') { 788 789 #ifdef USE_ARCHIVES 789 /*790 * Archives must be handled specially to make sure the OP_ARCHV791 * flag is set in their 'type' field, for one thing, and because792 * things like "archive(file1.o file2.o file3.o)" are permissible.793 * Arch_ParseArchive will set 'line' to be the first non-blank794 * after the archive-spec. It creates/finds nodes for the members795 * and places them on the given list, returning SUCCESS if all796 * went well and FAILURE if there was an error in the797 * specification. On error, line should remain untouched.798 */799 if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) {800 Parse_Error (PARSE_FATAL,801 "Error in archive specification: \"%s\"", line);802 return;803 } else804 continue;790 /* 791 * Archives must be handled specially to make sure the OP_ARCHV 792 * flag is set in their 'type' field, for one thing, and because 793 * things like "archive(file1.o file2.o file3.o)" are permissible. 794 * Arch_ParseArchive will set 'line' to be the first non-blank 795 * after the archive-spec. It creates/finds nodes for the members 796 * and places them on the given list, returning SUCCESS if all 797 * went well and FAILURE if there was an error in the 798 * specification. On error, line should remain untouched. 799 */ 800 if (Arch_ParseArchive (&line, targets, VAR_CMD) != SUCCESS) { 801 Parse_Error (PARSE_FATAL, 802 "Error in archive specification: \"%s\"", line); 803 return; 804 } else 805 continue; 805 806 #else 806 807 Parse_Error(PARSE_FATAL, "Archives are not supported!", line); 807 808 return; 808 809 #endif /* USE_ARCHIVES */ 809 }810 savec = *cp;811 812 if (!*cp) {813 /*814 * Ending a dependency line without an operator is a Bozo815 * no-no816 */817 Parse_Error (PARSE_FATAL, "Need an operator");818 return;819 }820 *cp = '\0';821 /*822 * Have a word in line. See if it's a special target and set823 * specType to match it.824 */825 if (*line == '.' && isupper (line[1])) {826 /*827 * See if the target is a special target that must have it828 * or its sources handled specially.829 */830 int keywd = ParseFindKeyword(line);831 if (keywd != -1) {832 if (specType == ExPath && parseKeywords[keywd].spec != ExPath) {833 Parse_Error(PARSE_FATAL, "Mismatched special targets");834 return;835 }836 837 specType = parseKeywords[keywd].spec;838 tOp = parseKeywords[keywd].op;839 840 /*841 * Certain special targets have special semantics:842 * .PATHHave to set the dirSearchPath843 *variable too844 * .MAINIts sources are only used if845 *nothing has been specified to846 *create.847 * .DEFAULTNeed to create a node to hang848 *commands on, but we don't want849 *it in the graph, nor do we want850 *it to be the Main Target, so we851 *create it, set OP_NOTMAIN and852 *add it to the list, setting853 *DEFAULT to the new node for854 *later use. We claim the node is855 *A transformation rule to make856 *life easier later, when we'll857 *use Make_HandleUse to actually858 *apply the .DEFAULT commands.859 * .PHONYThe list of targets860 *.BEGIN861 *.END862 * .INTERRUPTAre not to be considered the863 *main target.864 * .NOTPARALLELMake only one target at a time.865 * .SINGLESHELLCreate a shell for each command.866 * .ORDERMust set initial predecessor to NIL867 */868 switch (specType) {869 case ExPath:870 if (paths == NULL) {871 paths = Lst_Init(FALSE);872 }873 (void)Lst_AtEnd(paths, (ClientData)dirSearchPath);874 break;875 case Main:876 if (!Lst_IsEmpty(create)) {877 specType = Not;878 }879 break;880 case Begin:881 case End:882 case Interrupt:883 gn = Targ_FindNode(line, TARG_CREATE);884 gn->type |= OP_NOTMAIN;885 (void)Lst_AtEnd(targets, (ClientData)gn);886 break;887 case Default:888 gn = Targ_NewGN(".DEFAULT");889 gn->type |= (OP_NOTMAIN|OP_TRANSFORM);890 (void)Lst_AtEnd(targets, (ClientData)gn);891 DEFAULT = gn;892 break;893 case NotParallel:894 {895 extern int maxJobs;896 897 maxJobs = 1;898 break;899 }900 case SingleShell:901 compatMake = 1;902 break;903 case Order:904 predecessor = NILGNODE;905 break;906 default:907 break;908 }909 } else if (strncmp (line, ".PATH", 5) == 0) {910 /*911 * .PATH<suffix> has to be handled specially.912 * Call on the suffix module to give us a path to913 * modify.914 */915 Lstpath;916 917 specType = ExPath;918 path = Suff_GetPath (&line[5]);919 if (path == NILLST) {920 Parse_Error (PARSE_FATAL,921 "Suffix '%s' not defined (yet)",922 &line[5]);923 return;924 } else {925 if (paths == (Lst)NULL) {926 paths = Lst_Init(FALSE);927 }928 (void)Lst_AtEnd(paths, (ClientData)path);929 }930 }931 }932 933 /*934 * Have word in line. Get or create its node and stick it at935 * the end of the targets list936 */937 if ((specType == Not) && (*line != '\0')) {938 if (Dir_HasWildcards(line)) {939 /*940 * Targets are to be sought only in the current directory,941 * so create an empty path for the thing. Note we need to942 * use Dir_Destroy in the destruction of the path as the943 * Dir module could have added a directory to the path...944 */945 LstemptyPath = Lst_Init(FALSE);946 947 Dir_Expand(line, emptyPath, curTargs);948 949 Lst_Destroy(emptyPath, Dir_Destroy);950 } else {951 /*952 * No wildcards, but we want to avoid code duplication,953 * so create a list with the word on it.954 */955 (void)Lst_AtEnd(curTargs, (ClientData)line);956 }957 958 while(!Lst_IsEmpty(curTargs)) {959 char*targName = (char *)Lst_DeQueue(curTargs);960 961 if (!Suff_IsTransform (targName)) {962 gn = Targ_FindNode (targName, TARG_CREATE);963 } else {964 gn = Suff_AddTransform (targName);965 }966 967 (void)Lst_AtEnd (targets, (ClientData)gn);968 }969 } else if (specType == ExPath && *line != '.' && *line != '\0') {970 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line);971 }972 973 *cp = savec;974 /*975 * If it is a special type and not .PATH, it's the only target we976 * allow on this line...977 */978 if (specType != Not && specType != ExPath) {979 Boolean warn = FALSE;980 981 while ((*cp != '!') && (*cp != ':') && *cp) {982 if (*cp != ' ' && *cp != '\t') {983 warn = TRUE;984 }985 cp++;986 }987 if (warn) {988 Parse_Error(PARSE_WARNING, "Extra target ignored");989 }990 } else {991 while (*cp && isspace (*cp)) {992 cp++;993 }994 }995 line = cp;810 } 811 savec = *cp; 812 813 if (!*cp) { 814 /* 815 * Ending a dependency line without an operator is a Bozo 816 * no-no 817 */ 818 Parse_Error (PARSE_FATAL, "Need an operator"); 819 return; 820 } 821 *cp = '\0'; 822 /* 823 * Have a word in line. See if it's a special target and set 824 * specType to match it. 825 */ 826 if (*line == '.' && isupper (line[1])) { 827 /* 828 * See if the target is a special target that must have it 829 * or its sources handled specially. 830 */ 831 int keywd = ParseFindKeyword(line); 832 if (keywd != -1) { 833 if (specType == ExPath && parseKeywords[keywd].spec != ExPath) { 834 Parse_Error(PARSE_FATAL, "Mismatched special targets"); 835 return; 836 } 837 838 specType = parseKeywords[keywd].spec; 839 tOp = parseKeywords[keywd].op; 840 841 /* 842 * Certain special targets have special semantics: 843 * .PATH Have to set the dirSearchPath 844 * variable too 845 * .MAIN Its sources are only used if 846 * nothing has been specified to 847 * create. 848 * .DEFAULT Need to create a node to hang 849 * commands on, but we don't want 850 * it in the graph, nor do we want 851 * it to be the Main Target, so we 852 * create it, set OP_NOTMAIN and 853 * add it to the list, setting 854 * DEFAULT to the new node for 855 * later use. We claim the node is 856 * A transformation rule to make 857 * life easier later, when we'll 858 * use Make_HandleUse to actually 859 * apply the .DEFAULT commands. 860 * .PHONY The list of targets 861 * .BEGIN 862 * .END 863 * .INTERRUPT Are not to be considered the 864 * main target. 865 * .NOTPARALLEL Make only one target at a time. 866 * .SINGLESHELL Create a shell for each command. 867 * .ORDER Must set initial predecessor to NIL 868 */ 869 switch (specType) { 870 case ExPath: 871 if (paths == NULL) { 872 paths = Lst_Init(FALSE); 873 } 874 (void)Lst_AtEnd(paths, (ClientData)dirSearchPath); 875 break; 876 case Main: 877 if (!Lst_IsEmpty(create)) { 878 specType = Not; 879 } 880 break; 881 case Begin: 882 case End: 883 case Interrupt: 884 gn = Targ_FindNode(line, TARG_CREATE); 885 gn->type |= OP_NOTMAIN; 886 (void)Lst_AtEnd(targets, (ClientData)gn); 887 break; 888 case Default: 889 gn = Targ_NewGN(".DEFAULT"); 890 gn->type |= (OP_NOTMAIN|OP_TRANSFORM); 891 (void)Lst_AtEnd(targets, (ClientData)gn); 892 DEFAULT = gn; 893 break; 894 case NotParallel: 895 { 896 extern int maxJobs; 897 898 maxJobs = 1; 899 break; 900 } 901 case SingleShell: 902 compatMake = 1; 903 break; 904 case Order: 905 predecessor = NILGNODE; 906 break; 907 default: 908 break; 909 } 910 } else if (strncmp (line, ".PATH", 5) == 0) { 911 /* 912 * .PATH<suffix> has to be handled specially. 913 * Call on the suffix module to give us a path to 914 * modify. 915 */ 916 Lst path; 917 918 specType = ExPath; 919 path = Suff_GetPath (&line[5]); 920 if (path == NILLST) { 921 Parse_Error (PARSE_FATAL, 922 "Suffix '%s' not defined (yet)", 923 &line[5]); 924 return; 925 } else { 926 if (paths == (Lst)NULL) { 927 paths = Lst_Init(FALSE); 928 } 929 (void)Lst_AtEnd(paths, (ClientData)path); 930 } 931 } 932 } 933 934 /* 935 * Have word in line. Get or create its node and stick it at 936 * the end of the targets list 937 */ 938 if ((specType == Not) && (*line != '\0')) { 939 if (Dir_HasWildcards(line)) { 940 /* 941 * Targets are to be sought only in the current directory, 942 * so create an empty path for the thing. Note we need to 943 * use Dir_Destroy in the destruction of the path as the 944 * Dir module could have added a directory to the path... 945 */ 946 Lst emptyPath = Lst_Init(FALSE); 947 948 Dir_Expand(line, emptyPath, curTargs); 949 950 Lst_Destroy(emptyPath, Dir_Destroy); 951 } else { 952 /* 953 * No wildcards, but we want to avoid code duplication, 954 * so create a list with the word on it. 955 */ 956 (void)Lst_AtEnd(curTargs, (ClientData)line); 957 } 958 959 while(!Lst_IsEmpty(curTargs)) { 960 char *targName = (char *)Lst_DeQueue(curTargs); 961 962 if (!Suff_IsTransform (targName)) { 963 gn = Targ_FindNode (targName, TARG_CREATE); 964 } else { 965 gn = Suff_AddTransform (targName); 966 } 967 968 (void)Lst_AtEnd (targets, (ClientData)gn); 969 } 970 } else if (specType == ExPath && *line != '.' && *line != '\0') { 971 Parse_Error(PARSE_WARNING, "Extra target (%s) ignored", line); 972 } 973 974 *cp = savec; 975 /* 976 * If it is a special type and not .PATH, it's the only target we 977 * allow on this line... 978 */ 979 if (specType != Not && specType != ExPath) { 980 Boolean warn = FALSE; 981 982 while ((*cp != '!') && (*cp != ':') && *cp) { 983 if (*cp != ' ' && *cp != '\t') { 984 warn = TRUE; 985 } 986 cp++; 987 } 988 if (warn) { 989 Parse_Error(PARSE_WARNING, "Extra target ignored"); 990 } 991 } else { 992 while (*cp && isspace (*cp)) { 993 cp++; 994 } 995 } 996 line = cp; 996 997 } while ((*line != '!') && (*line != ':') && *line); 997 998 … … 1002 1003 1003 1004 if (!Lst_IsEmpty(targets)) { 1004 switch(specType) {1005 default:1006 Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored");1007 break;1008 case Default:1009 case Begin:1010 case End:1011 case Interrupt:1012 /*1013 * These four create nodes on which to hang commands, so1014 * targets shouldn't be empty...1015 */1016 case Not:1017 /*1018 * Nothing special here -- targets can be empty if it wants.1019 */1020 break;1021 }1005 switch(specType) { 1006 default: 1007 Parse_Error(PARSE_WARNING, "Special and mundane targets don't mix. Mundane ones ignored"); 1008 break; 1009 case Default: 1010 case Begin: 1011 case End: 1012 case Interrupt: 1013 /* 1014 * These four create nodes on which to hang commands, so 1015 * targets shouldn't be empty... 1016 */ 1017 case Not: 1018 /* 1019 * Nothing special here -- targets can be empty if it wants. 1020 */ 1021 break; 1022 } 1022 1023 } 1023 1024 … … 1027 1028 */ 1028 1029 if (*cp == '!') { 1029 op = OP_FORCE;1030 op = OP_FORCE; 1030 1031 } else if (*cp == ':') { 1031 if (cp[1] == ':') {1032 op = OP_DOUBLEDEP;1033 cp++;1034 } else {1035 op = OP_DEPENDS;1036 }1032 if (cp[1] == ':') { 1033 op = OP_DOUBLEDEP; 1034 cp++; 1035 } else { 1036 op = OP_DEPENDS; 1037 } 1037 1038 } else { 1038 Parse_Error (PARSE_FATAL, "Missing dependency operator");1039 return;1040 } 1041 1042 cp++; /* Advance beyond operator */1039 Parse_Error (PARSE_FATAL, "Missing dependency operator"); 1040 return; 1041 } 1042 1043 cp++; /* Advance beyond operator */ 1043 1044 1044 1045 Lst_ForEach (targets, ParseDoOp, (ClientData)&op); … … 1048 1049 */ 1049 1050 while (*cp && isspace (*cp)) { 1050 cp++;1051 cp++; 1051 1052 } 1052 1053 line = cp; … … 1055 1056 * Several special targets take different actions if present with no 1056 1057 * sources: 1057 * a .SUFFIXES line with no sources clears out all old suffixes1058 * a .PRECIOUS line makes all targets precious1059 * a .IGNORE line ignores errors for all targets1060 * a .SILENT line creates silence when making all targets1061 * a .PATH removes all directories from the search path(s).1058 * a .SUFFIXES line with no sources clears out all old suffixes 1059 * a .PRECIOUS line makes all targets precious 1060 * a .IGNORE line ignores errors for all targets 1061 * a .SILENT line creates silence when making all targets 1062 * a .PATH removes all directories from the search path(s). 1062 1063 */ 1063 1064 if (!*line) { 1064 switch (specType) {1065 case Suffixes:1066 Suff_ClearSuffixes ();1067 break;1068 case Precious:1069 allPrecious = TRUE;1070 break;1071 case Ignore:1072 ignoreErrors = TRUE;1073 break;1074 case Silent:1075 beSilent = TRUE;1076 break;1077 case ExPath:1078 Lst_ForEach(paths, ParseClearPath, (ClientData)NULL);1079 break;1065 switch (specType) { 1066 case Suffixes: 1067 Suff_ClearSuffixes (); 1068 break; 1069 case Precious: 1070 allPrecious = TRUE; 1071 break; 1072 case Ignore: 1073 ignoreErrors = TRUE; 1074 break; 1075 case Silent: 1076 beSilent = TRUE; 1077 break; 1078 case ExPath: 1079 Lst_ForEach(paths, ParseClearPath, (ClientData)NULL); 1080 break; 1080 1081 #ifdef POSIX 1081 case Posix:1082 Var_Set("%POSIX", "1003.2", VAR_GLOBAL);1083 break;1084 #endif 1085 default:1086 break;1087 }1082 case Posix: 1083 Var_Set("%POSIX", "1003.2", VAR_GLOBAL); 1084 break; 1085 #endif 1086 default: 1087 break; 1088 } 1088 1089 } else if (specType == MFlags) { 1089 /*1090 * Call on functions in main.c to deal with these arguments and1091 * set the initial character to a null-character so the loop to1092 * get sources won't get anything1093 */1094 Main_ParseArgLine (line);1095 *line = '\0';1090 /* 1091 * Call on functions in main.c to deal with these arguments and 1092 * set the initial character to a null-character so the loop to 1093 * get sources won't get anything 1094 */ 1095 Main_ParseArgLine (line); 1096 *line = '\0'; 1096 1097 } else if (specType == ExShell) { 1097 1098 #ifdef KMK … … 1099 1100 return; 1100 1101 #else 1101 if (Job_ParseShell (line) != SUCCESS) {1102 Parse_Error (PARSE_FATAL, "improper shell specification");1103 return;1104 }1102 if (Job_ParseShell (line) != SUCCESS) { 1103 Parse_Error (PARSE_FATAL, "improper shell specification"); 1104 return; 1105 } 1105 1106 #endif 1106 *line = '\0';1107 *line = '\0'; 1107 1108 } else if ((specType == NotParallel) || (specType == SingleShell)) { 1108 *line = '\0';1109 *line = '\0'; 1109 1110 } 1110 1111 … … 1113 1114 */ 1114 1115 if ((specType == Suffixes) || (specType == ExPath) || 1115 (specType == Includes) ||1116 (specType == Includes) || 1116 1117 #ifdef USE_ARCHIVES 1117 1118 (specType == Libs) || 1118 1119 #endif 1119 (specType == Null))1120 (specType == Null)) 1120 1121 { 1121 while (*line) {1122 /*1123 * If the target was one that doesn't take files as its sources1124 * but takes something like suffixes, we take each1125 * space-separated word on the line as a something and deal1126 * with it accordingly.1127 *1128 * If the target was .SUFFIXES, we take each source as a1129 * suffix and add it to the list of suffixes maintained by the1130 * Suff module.1131 *1132 * If the target was a .PATH, we add the source as a directory1133 * to search on the search path.1134 *1135 * If it was .INCLUDES, the source is taken to be the suffix of1136 * files which will be #included and whose search path should1137 * be present in the .INCLUDES variable.1138 *1139 * If it was .LIBS, the source is taken to be the suffix of1140 * files which are considered libraries and whose search path1141 * should be present in the .LIBS variable.1142 *1143 * If it was .NULL, the source is the suffix to use when a file1144 * has no valid suffix.1145 */1146 char savec;1147 while (*cp && !isspace (*cp)) {1148 cp++;1149 }1150 savec = *cp;1151 *cp = '\0';1152 switch (specType) {1153 case Suffixes:1154 Suff_AddSuffix (line);1155 break;1156 case ExPath:1157 Lst_ForEach(paths, ParseAddDir, (ClientData)line);1158 break;1159 case Includes:1160 Suff_AddInclude (line);1161 break;1122 while (*line) { 1123 /* 1124 * If the target was one that doesn't take files as its sources 1125 * but takes something like suffixes, we take each 1126 * space-separated word on the line as a something and deal 1127 * with it accordingly. 1128 * 1129 * If the target was .SUFFIXES, we take each source as a 1130 * suffix and add it to the list of suffixes maintained by the 1131 * Suff module. 1132 * 1133 * If the target was a .PATH, we add the source as a directory 1134 * to search on the search path. 1135 * 1136 * If it was .INCLUDES, the source is taken to be the suffix of 1137 * files which will be #included and whose search path should 1138 * be present in the .INCLUDES variable. 1139 * 1140 * If it was .LIBS, the source is taken to be the suffix of 1141 * files which are considered libraries and whose search path 1142 * should be present in the .LIBS variable. 1143 * 1144 * If it was .NULL, the source is the suffix to use when a file 1145 * has no valid suffix. 1146 */ 1147 char savec; 1148 while (*cp && !isspace (*cp)) { 1149 cp++; 1150 } 1151 savec = *cp; 1152 *cp = '\0'; 1153 switch (specType) { 1154 case Suffixes: 1155 Suff_AddSuffix (line); 1156 break; 1157 case ExPath: 1158 Lst_ForEach(paths, ParseAddDir, (ClientData)line); 1159 break; 1160 case Includes: 1161 Suff_AddInclude (line); 1162 break; 1162 1163 #ifdef USE_ARCHIVES 1163 case Libs:1164 Suff_AddLib (line);1165 break;1166 #endif 1167 case Null:1168 Suff_SetNull (line);1169 break;1170 default:1171 break;1172 }1173 *cp = savec;1174 if (savec != '\0') {1175 cp++;1176 }1177 while (*cp && isspace (*cp)) {1178 cp++;1179 }1180 line = cp;1181 }1182 if (paths) {1183 Lst_Destroy(paths, NOFREE);1184 }1164 case Libs: 1165 Suff_AddLib (line); 1166 break; 1167 #endif 1168 case Null: 1169 Suff_SetNull (line); 1170 break; 1171 default: 1172 break; 1173 } 1174 *cp = savec; 1175 if (savec != '\0') { 1176 cp++; 1177 } 1178 while (*cp && isspace (*cp)) { 1179 cp++; 1180 } 1181 line = cp; 1182 } 1183 if (paths) { 1184 Lst_Destroy(paths, NOFREE); 1185 } 1185 1186 } else { 1186 while (*line) {1187 /*1188 * The targets take real sources, so we must beware of archive1189 * specifications (i.e. things with left parentheses in them)1190 * and handle them accordingly.1191 */1192 while (*cp && !isspace (*cp)) {1193 if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) {1194 /*1195 * Only stop for a left parenthesis if it isn't at the1196 * start of a word (that'll be for variable changes1197 * later) and isn't preceded by a dollar sign (a dynamic1198 * source).1199 */1200 break;1201 } else {1202 cp++;1203 }1204 }1205 1206 if (*cp == '(') {1187 while (*line) { 1188 /* 1189 * The targets take real sources, so we must beware of archive 1190 * specifications (i.e. things with left parentheses in them) 1191 * and handle them accordingly. 1192 */ 1193 while (*cp && !isspace (*cp)) { 1194 if ((*cp == '(') && (cp > line) && (cp[-1] != '$')) { 1195 /* 1196 * Only stop for a left parenthesis if it isn't at the 1197 * start of a word (that'll be for variable changes 1198 * later) and isn't preceded by a dollar sign (a dynamic 1199 * source). 1200 */ 1201 break; 1202 } else { 1203 cp++; 1204 } 1205 } 1206 1207 if (*cp == '(') { 1207 1208 #ifdef USE_ARCHIVES 1208 GNode*gn;1209 1210 sources = Lst_Init (FALSE);1211 if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) {1212 Parse_Error (PARSE_FATAL,1213 "Error in source archive spec \"%s\"", line);1214 return;1215 }1216 1217 while (!Lst_IsEmpty (sources)) {1218 gn = (GNode *) Lst_DeQueue (sources);1219 ParseDoSrc (tOp, gn->name, curSrcs);1220 }1221 Lst_Destroy (sources, NOFREE);1222 cp = line;1209 GNode *gn; 1210 1211 sources = Lst_Init (FALSE); 1212 if (Arch_ParseArchive (&line, sources, VAR_CMD) != SUCCESS) { 1213 Parse_Error (PARSE_FATAL, 1214 "Error in source archive spec \"%s\"", line); 1215 return; 1216 } 1217 1218 while (!Lst_IsEmpty (sources)) { 1219 gn = (GNode *) Lst_DeQueue (sources); 1220 ParseDoSrc (tOp, gn->name, curSrcs); 1221 } 1222 Lst_Destroy (sources, NOFREE); 1223 cp = line; 1223 1224 #else 1224 1225 Parse_Error(PARSE_FATAL, "Archives are not supported!", line); 1225 1226 return; 1226 1227 #endif /* USE_ARCHIVES */ 1227 } else {1228 if (*cp) {1229 *cp = '\0';1230 cp += 1;1231 }1232 1233 ParseDoSrc (tOp, line, curSrcs);1234 }1235 while (*cp && isspace (*cp)) {1236 cp++;1237 }1238 line = cp;1239 }1228 } else { 1229 if (*cp) { 1230 *cp = '\0'; 1231 cp += 1; 1232 } 1233 1234 ParseDoSrc (tOp, line, curSrcs); 1235 } 1236 while (*cp && isspace (*cp)) { 1237 cp++; 1238 } 1239 line = cp; 1240 } 1240 1241 } 1241 1242 1242 1243 if (mainNode == NILGNODE) { 1243 /*1244 * If we have yet to decide on a main target to make, in the1245 * absence of any user input, we want the first target on1246 * the first dependency line that is actually a real target1247 * (i.e. isn't a .USE or .EXEC rule) to be made.1248 */1249 Lst_ForEach (targets, ParseFindMain, (ClientData)0);1244 /* 1245 * If we have yet to decide on a main target to make, in the 1246 * absence of any user input, we want the first target on 1247 * the first dependency line that is actually a real target 1248 * (i.e. isn't a .USE or .EXEC rule) to be made. 1249 */ 1250 Lst_ForEach (targets, ParseFindMain, (ClientData)0); 1250 1251 } 1251 1252 … … 1259 1260 *--------------------------------------------------------------------- 1260 1261 * Parse_IsVar -- 1261 * Return TRUE if the passed line is a variable assignment. A variable1262 * assignment consists of a single word followed by optional whitespace1263 * followed by either a += or an = operator.1264 * This function is used both by the Parse_File function and main when1265 * parsing the command-line arguments.1262 * Return TRUE if the passed line is a variable assignment. A variable 1263 * assignment consists of a single word followed by optional whitespace 1264 * followed by either a += or an = operator. 1265 * This function is used both by the Parse_File function and main when 1266 * parsing the command-line arguments. 1266 1267 * 1267 1268 * Results: 1268 * TRUE if it is. FALSE if it ain't1269 * TRUE if it is. FALSE if it ain't 1269 1270 * 1270 1271 * Side Effects: 1271 * none1272 * none 1272 1273 *--------------------------------------------------------------------- 1273 1274 */ 1274 1275 Boolean 1275 1276 Parse_IsVar (line) 1276 register char *line; /* the line to check */1277 { 1278 register Boolean wasSpace = FALSE; /* set TRUE if found a space */1279 register Boolean haveName = FALSE; /* Set TRUE if have a variable name */1277 register char *line; /* the line to check */ 1278 { 1279 register Boolean wasSpace = FALSE; /* set TRUE if found a space */ 1280 register Boolean haveName = FALSE; /* Set TRUE if have a variable name */ 1280 1281 int level = 0; 1281 1282 #define ISEQOPERATOR(c) \ 1282 (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!'))1283 (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 1283 1284 1284 1285 /* … … 1286 1287 */ 1287 1288 for (;(*line == ' ') || (*line == '\t'); line++) 1288 continue;1289 continue; 1289 1290 1290 1291 for (; *line != '=' || level != 0; line++) 1291 switch (*line) {1292 case '\0':1293 /*1294 * end-of-line -- can't be a variable assignment.1295 */1296 return FALSE;1297 1298 case ' ':1299 case '\t':1300 /*1301 * there can be as much white space as desired so long as there is1302 * only one word before the operator1303 */1304 wasSpace = TRUE;1305 break;1306 1307 case '(':1308 case '{':1309 level++;1310 break;1311 1312 case '}':1313 case ')':1314 level--;1315 break;1316 1317 default:1318 if (wasSpace && haveName) {1319 if (ISEQOPERATOR(*line)) {1320 /*1321 * We must have a finished word1322 */1323 if (level != 0)1324 return FALSE;1325 1326 /*1327 * When an = operator [+?!:] is found, the next1328 * character must be an = or it ain't a valid1329 * assignment.1330 */1331 if (line[1] == '=')1332 return haveName;1292 switch (*line) { 1293 case '\0': 1294 /* 1295 * end-of-line -- can't be a variable assignment. 1296 */ 1297 return FALSE; 1298 1299 case ' ': 1300 case '\t': 1301 /* 1302 * there can be as much white space as desired so long as there is 1303 * only one word before the operator 1304 */ 1305 wasSpace = TRUE; 1306 break; 1307 1308 case '(': 1309 case '{': 1310 level++; 1311 break; 1312 1313 case '}': 1314 case ')': 1315 level--; 1316 break; 1317 1318 default: 1319 if (wasSpace && haveName) { 1320 if (ISEQOPERATOR(*line)) { 1321 /* 1322 * We must have a finished word 1323 */ 1324 if (level != 0) 1325 return FALSE; 1326 1327 /* 1328 * When an = operator [+?!:] is found, the next 1329 * character must be an = or it ain't a valid 1330 * assignment. 1331 */ 1332 if (line[1] == '=') 1333 return haveName; 1333 1334 #ifdef SUNSHCMD 1334 /*1335 * This is a shell command1336 */1337 if (strncmp(line, ":sh", 3) == 0)1338 return haveName;1339 #endif 1340 }1341 /*1342 * This is the start of another word, so not assignment.1343 */1344 return FALSE;1345 }1346 else {1347 haveName = TRUE;1348 wasSpace = FALSE;1349 }1350 break;1351 }1335 /* 1336 * This is a shell command 1337 */ 1338 if (strncmp(line, ":sh", 3) == 0) 1339 return haveName; 1340 #endif 1341 } 1342 /* 1343 * This is the start of another word, so not assignment. 1344 */ 1345 return FALSE; 1346 } 1347 else { 1348 haveName = TRUE; 1349 wasSpace = FALSE; 1350 } 1351 break; 1352 } 1352 1353 1353 1354 return haveName; … … 1357 1358 *--------------------------------------------------------------------- 1358 1359 * Parse_DoVar -- 1359 * Take the variable assignment in the passed line and do it in the1360 * global context.1361 * 1362 * Note: There is a lexical ambiguity with assignment modifier characters1363 * in variable names. This routine interprets the character before the =1364 * as a modifier. Therefore, an assignment like1365 * C++=/usr/bin/CC1366 * is interpreted as "C+ +=" instead of "C++ =".1360 * Take the variable assignment in the passed line and do it in the 1361 * global context. 1362 * 1363 * Note: There is a lexical ambiguity with assignment modifier characters 1364 * in variable names. This routine interprets the character before the = 1365 * as a modifier. Therefore, an assignment like 1366 * C++=/usr/bin/CC 1367 * is interpreted as "C+ +=" instead of "C++ =". 1367 1368 * 1368 1369 * Results: 1369 * none1370 * none 1370 1371 * 1371 1372 * Side Effects: 1372 * the variable structure of the given variable name is altered in the1373 * global context.1373 * the variable structure of the given variable name is altered in the 1374 * global context. 1374 1375 *--------------------------------------------------------------------- 1375 1376 */ 1376 1377 void 1377 1378 Parse_DoVar (line, ctxt) 1378 char *line; /* a line guaranteed to be a variable1379 * assignment. This reduces error checks */1380 GNode *ctxt;/* Context in which to do the assignment */1381 { 1382 char *cp;/* pointer into line */1379 char *line; /* a line guaranteed to be a variable 1380 * assignment. This reduces error checks */ 1381 GNode *ctxt; /* Context in which to do the assignment */ 1382 { 1383 char *cp; /* pointer into line */ 1383 1384 enum { 1384 VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL1385 } type;/* Type of assignment */1386 char *opc; /* ptr to operator character to1387 * null-terminate the variable name */1385 VAR_SUBST, VAR_APPEND, VAR_SHELL, VAR_NORMAL 1386 } type; /* Type of assignment */ 1387 char *opc; /* ptr to operator character to 1388 * null-terminate the variable name */ 1388 1389 /* 1389 1390 * Avoid clobbered variable warnings by forcing the compiler … … 1399 1400 */ 1400 1401 while ((*line == ' ') || (*line == '\t')) { 1401 line++;1402 line++; 1402 1403 } 1403 1404 … … 1406 1407 */ 1407 1408 for (cp = line + 1; *cp != '='; cp++) { 1408 if (isspace (*cp)) {1409 *cp = '\0';1410 }1411 } 1412 opc = cp-1; /* operator is the previous character */1413 *cp++ = '\0'; /* nuke the = */1409 if (isspace (*cp)) { 1410 *cp = '\0'; 1411 } 1412 } 1413 opc = cp-1; /* operator is the previous character */ 1414 *cp++ = '\0'; /* nuke the = */ 1414 1415 1415 1416 /* … … 1417 1418 */ 1418 1419 switch (*opc) { 1419 case '+':1420 type = VAR_APPEND;1421 *opc = '\0';1422 break;1423 1424 case '?':1425 /*1426 * If the variable already has a value, we don't do anything.1427 */1428 *opc = '\0';1429 if (Var_Exists(line, ctxt)) {1430 return;1431 } else {1432 type = VAR_NORMAL;1433 }1434 break;1435 1436 case ':':1437 type = VAR_SUBST;1438 *opc = '\0';1439 break;1440 1441 case '!':1442 type = VAR_SHELL;1443 *opc = '\0';1444 break;1445 1446 default:1420 case '+': 1421 type = VAR_APPEND; 1422 *opc = '\0'; 1423 break; 1424 1425 case '?': 1426 /* 1427 * If the variable already has a value, we don't do anything. 1428 */ 1429 *opc = '\0'; 1430 if (Var_Exists(line, ctxt)) { 1431 return; 1432 } else { 1433 type = VAR_NORMAL; 1434 } 1435 break; 1436 1437 case ':': 1438 type = VAR_SUBST; 1439 *opc = '\0'; 1440 break; 1441 1442 case '!': 1443 type = VAR_SHELL; 1444 *opc = '\0'; 1445 break; 1446 1447 default: 1447 1448 #ifdef SUNSHCMD 1448 while (*opc != ':')1449 if (opc == line)1450 break;1451 else1452 --opc;1453 1454 if (strncmp(opc, ":sh", 3) == 0) {1455 type = VAR_SHELL;1456 *opc = '\0';1457 break;1458 }1459 #endif 1460 type = VAR_NORMAL;1461 break;1449 while (*opc != ':') 1450 if (opc == line) 1451 break; 1452 else 1453 --opc; 1454 1455 if (strncmp(opc, ":sh", 3) == 0) { 1456 type = VAR_SHELL; 1457 *opc = '\0'; 1458 break; 1459 } 1460 #endif 1461 type = VAR_NORMAL; 1462 break; 1462 1463 } 1463 1464 1464 1465 while (isspace (*cp)) { 1465 cp++;1466 cp++; 1466 1467 } 1467 1468 1468 1469 if (type == VAR_APPEND) { 1469 Var_Append (line, cp, ctxt);1470 Var_Append (line, cp, ctxt); 1470 1471 } else if (type == VAR_SUBST) { 1471 /*1472 * Allow variables in the old value to be undefined, but leave their1473 * invocation alone -- this is done by forcing oldVars to be false.1474 * XXX: This can cause recursive variables, but that's not hard to do,1475 * and this allows someone to do something like1476 *1477 * CFLAGS = $(.INCLUDES)1478 * CFLAGS := -I.. $(CFLAGS)1479 *1480 * And not get an error.1481 */1482 BooleanoldOldVars = oldVars;1483 1484 oldVars = FALSE;1485 cp = Var_Subst(NULL, cp, ctxt, FALSE);1486 oldVars = oldOldVars;1487 1488 Var_Set(line, cp, ctxt);1489 efree(cp);1472 /* 1473 * Allow variables in the old value to be undefined, but leave their 1474 * invocation alone -- this is done by forcing oldVars to be false. 1475 * XXX: This can cause recursive variables, but that's not hard to do, 1476 * and this allows someone to do something like 1477 * 1478 * CFLAGS = $(.INCLUDES) 1479 * CFLAGS := -I.. $(CFLAGS) 1480 * 1481 * And not get an error. 1482 */ 1483 Boolean oldOldVars = oldVars; 1484 1485 oldVars = FALSE; 1486 cp = Var_Subst(NULL, cp, ctxt, FALSE); 1487 oldVars = oldOldVars; 1488 1489 Var_Set(line, cp, ctxt); 1490 efree(cp); 1490 1491 } else if (type == VAR_SHELL) { 1491 BooleanfreeCmd = FALSE; /* TRUE if the command needs to be freed, i.e.1492 * if any variable expansion was performed */1493 char *res, *err;1494 1495 if (strchr(cp, '$') != NULL) {1496 /*1497 * There's a dollar sign in the command, so perform variable1498 * expansion on the whole thing. The resulting string will need1499 * freeing when we're done, so set freeCmd to TRUE.1500 */1501 cp = Var_Subst(NULL, cp, VAR_CMD, TRUE);1502 freeCmd = TRUE;1503 }1504 1505 res = Cmd_Exec(cp, &err);1506 Var_Set(line, res, ctxt);1507 efree(res);1508 1509 if (err)1510 Parse_Error(PARSE_WARNING, err, cp);1511 1512 if (freeCmd)1513 efree(cp);1492 Boolean freeCmd = FALSE; /* TRUE if the command needs to be freed, i.e. 1493 * if any variable expansion was performed */ 1494 char *res, *err; 1495 1496 if (strchr(cp, '$') != NULL) { 1497 /* 1498 * There's a dollar sign in the command, so perform variable 1499 * expansion on the whole thing. The resulting string will need 1500 * freeing when we're done, so set freeCmd to TRUE. 1501 */ 1502 cp = Var_Subst(NULL, cp, VAR_CMD, TRUE); 1503 freeCmd = TRUE; 1504 } 1505 1506 res = Cmd_Exec(cp, &err); 1507 Var_Set(line, res, ctxt); 1508 efree(res); 1509 1510 if (err) 1511 Parse_Error(PARSE_WARNING, err, cp); 1512 1513 if (freeCmd) 1514 efree(cp); 1514 1515 } else { 1515 /*1516 * Normal assignment -- just do it.1517 */1518 Var_Set(line, cp, ctxt);1516 /* 1517 * Normal assignment -- just do it. 1518 */ 1519 Var_Set(line, cp, ctxt); 1519 1520 } 1520 1521 } … … 1523 1524 /*- 1524 1525 * ParseAddCmd -- 1525 * Lst_ForEach function to add a command line to all targets1526 * Lst_ForEach function to add a command line to all targets 1526 1527 * 1527 1528 * Results: 1528 * Always 01529 * Always 0 1529 1530 * 1530 1531 * Side Effects: 1531 * A new element is added to the commands list of the node.1532 * A new element is added to the commands list of the node. 1532 1533 */ 1533 1534 static int 1534 1535 ParseAddCmd(gnp, cmd) 1535 ClientData gnp; /* the node to which the command is to be added */1536 ClientData cmd; /* the command to add */1536 ClientData gnp; /* the node to which the command is to be added */ 1537 ClientData cmd; /* the command to add */ 1537 1538 { 1538 1539 GNode *gn = (GNode *) gnp; 1539 1540 /* if target already supplied, ignore commands */ 1540 1541 if (!(gn->type & OP_HAS_COMMANDS)) 1541 (void)Lst_AtEnd(gn->commands, cmd);1542 (void)Lst_AtEnd(gn->commands, cmd); 1542 1543 return(0); 1543 1544 } … … 1548 1549 /*- 1549 1550 * ParseAppendInline -- 1550 * Lst_ForEach function to append the line to the last command1551 * Lst_ForEach function to append the line to the last command 1551 1552 * 1552 1553 * Results: 1553 * Always 01554 * Always 0 1554 1555 * 1555 1556 * Side Effects: 1556 * A new element is added to the last commands list of the node.1557 * A new element is added to the last commands list of the node. 1557 1558 */ 1558 1559 static int 1559 1560 ParseAppendInline(gnp, line) 1560 ClientData gnp; /* the node to which the command is to be added */1561 ClientData line; /* the command to add */1561 ClientData gnp; /* the node to which the command is to be added */ 1562 ClientData line; /* the command to add */ 1562 1563 { 1563 1564 GNode *gn = (GNode *)gnp; … … 1585 1586 * 1586 1587 * Results: 1587 * returns TRUE if it is, FALSE if not.1588 * returns TRUE if it is, FALSE if not. 1588 1589 * 1589 1590 * Side Effects: 1590 * OP_HAS_COMMANDS may be set for the target.1591 * OP_HAS_COMMANDS may be set for the target. 1591 1592 * 1592 1593 *----------------------------------------------------------------------- … … 1641 1642 *----------------------------------------------------------------------- 1642 1643 * ParseHasCommands -- 1643 * Callback procedure for Parse_File when destroying the list of1644 * targets on the last dependency line. Marks a target as already1645 * having commands if it does, to keep from having shell commands1646 * on multiple dependency lines.1644 * Callback procedure for Parse_File when destroying the list of 1645 * targets on the last dependency line. Marks a target as already 1646 * having commands if it does, to keep from having shell commands 1647 * on multiple dependency lines. 1647 1648 * 1648 1649 * Results: 1649 * None1650 * None 1650 1651 * 1651 1652 * Side Effects: 1652 * OP_HAS_COMMANDS may be set for the target.1653 * OP_HAS_COMMANDS may be set for the target. 1653 1654 * 1654 1655 *----------------------------------------------------------------------- … … 1656 1657 static void 1657 1658 ParseHasCommands(gnp) 1658 ClientData gnp;/* Node to examine */1659 ClientData gnp; /* Node to examine */ 1659 1660 { 1660 1661 GNode *gn = (GNode *) gnp; 1661 1662 if (!Lst_IsEmpty(gn->commands)) { 1662 gn->type |= OP_HAS_COMMANDS;1663 gn->type |= OP_HAS_COMMANDS; 1663 1664 } 1664 1665 } … … 1667 1668 *----------------------------------------------------------------------- 1668 1669 * Parse_AddIncludeDir -- 1669 * Add a directory to the path searched for included makefiles1670 * bracketed by double-quotes. Used by functions in main.c1670 * Add a directory to the path searched for included makefiles 1671 * bracketed by double-quotes. Used by functions in main.c 1671 1672 * 1672 1673 * Results: 1673 * None.1674 * None. 1674 1675 * 1675 1676 * Side Effects: 1676 * The directory is appended to the list.1677 * The directory is appended to the list. 1677 1678 * 1678 1679 *----------------------------------------------------------------------- … … 1680 1681 void 1681 1682 Parse_AddIncludeDir (dir) 1682 char *dir;/* The name of the directory to add */1683 char *dir; /* The name of the directory to add */ 1683 1684 { 1684 1685 Dir_AddDir (parseIncPath, dir); … … 1687 1688 /*--------------------------------------------------------------------- 1688 1689 * ParseDoError -- 1689 * Handle error directive1690 * 1691 * The input is the line minus the ".error". We substitute variables,1692 * print the message and exit(1) or just print a warning if the ".error"1693 * directive is malformed.1690 * Handle error directive 1691 * 1692 * The input is the line minus the ".error". We substitute variables, 1693 * print the message and exit(1) or just print a warning if the ".error" 1694 * directive is malformed. 1694 1695 * 1695 1696 *--------------------------------------------------------------------- … … 1697 1698 static void 1698 1699 ParseDoError(errmsg) 1699 char *errmsg; /* error message */1700 { 1701 if (!isspace(*errmsg)) {1702 Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg);1703 return;1704 }1705 1706 while (isspace(*errmsg))1707 errmsg++;1708 1709 errmsg = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE);1710 1711 /* use fprintf/exit instead of Parse_Error to terminate immediately */1712 fprintf(stderr, "\"%s\", line %d: %s\n", fname, lineno, errmsg);1713 exit(1);1700 char *errmsg; /* error message */ 1701 { 1702 if (!isspace(*errmsg)) { 1703 Parse_Error(PARSE_WARNING, "invalid syntax: .error%s", errmsg); 1704 return; 1705 } 1706 1707 while (isspace(*errmsg)) 1708 errmsg++; 1709 1710 errmsg = Var_Subst(NULL, errmsg, VAR_GLOBAL, FALSE); 1711 1712 /* use fprintf/exit instead of Parse_Error to terminate immediately */ 1713 fprintf(stderr, "\"%s\", line %d: %s\n", fname, lineno, errmsg); 1714 exit(1); 1714 1715 } 1715 1716 … … 1717 1718 *--------------------------------------------------------------------- 1718 1719 * ParseDoInclude -- 1719 * Push to another file.1720 * 1721 * The input is the line minus the #include. A file spec is a string1722 * enclosed in <> or "". The former is looked for only in sysIncPath.1723 * The latter in . and the directories specified by -I command line1724 * options1720 * Push to another file. 1721 * 1722 * The input is the line minus the #include. A file spec is a string 1723 * enclosed in <> or "". The former is looked for only in sysIncPath. 1724 * The latter in . and the directories specified by -I command line 1725 * options 1725 1726 * 1726 1727 * Results: 1727 * None1728 * None 1728 1729 * 1729 1730 * Side Effects: 1730 * A structure is added to the includes Lst and readProc, lineno,1731 * fname and curFILE are altered for the new file1731 * A structure is added to the includes Lst and readProc, lineno, 1732 * fname and curFILE are altered for the new file 1732 1733 *--------------------------------------------------------------------- 1733 1734 */ 1734 1735 static void 1735 1736 ParseDoInclude (file, chPre) 1736 char *file; /* file specification */1737 char *file; /* file specification */ 1737 1738 char chPre; /* Preprocessor char */ 1738 1739 { 1739 char *fullname; /* full pathname of file */1740 IFile *oldFile; /* state associated with current file */1741 char endc; /* the character which ends the file spec */1742 char *cp; /* current position in file spec */1743 Boolean isSystem;/* TRUE if makefile is a system makefile */1740 char *fullname; /* full pathname of file */ 1741 IFile *oldFile; /* state associated with current file */ 1742 char endc; /* the character which ends the file spec */ 1743 char *cp; /* current position in file spec */ 1744 Boolean isSystem; /* TRUE if makefile is a system makefile */ 1744 1745 1745 1746 /* … … 1747 1748 */ 1748 1749 while ((*file == ' ') || (*file == '\t')) { 1749 file++;1750 file++; 1750 1751 } 1751 1752 1752 1753 #ifndef NMAKE 1753 1754 if ((*file != '"') && (*file != '<')) { 1754 Parse_Error (PARSE_FATAL,1755 "%cinclude filename must be delimited by '\"' or '<'", chPre);1756 return;1755 Parse_Error (PARSE_FATAL, 1756 "%cinclude filename must be delimited by '\"' or '<'", chPre); 1757 return; 1757 1758 } 1758 1759 #endif … … 1764 1765 */ 1765 1766 if (*file == '<') { 1766 isSystem = TRUE;1767 endc = '>';1767 isSystem = TRUE; 1768 endc = '>'; 1768 1769 } else { 1769 isSystem = FALSE;1770 isSystem = FALSE; 1770 1771 #ifdef NMAKE 1771 1772 if (*file == '"') 1772 endc = '"';1773 endc = '"'; 1773 1774 else 1774 1775 { … … 1777 1778 } 1778 1779 #else 1779 endc = '"';1780 endc = '"'; 1780 1781 #endif 1781 1782 } … … 1785 1786 */ 1786 1787 for (cp = ++file; *cp && *cp != endc; cp++) { 1787 continue;1788 continue; 1788 1789 } 1789 1790 … … 1793 1794 if (*cp != endc) { 1794 1795 #endif 1795 Parse_Error (PARSE_FATAL,1796 "Unclosed %cinclude filename. '%c' expected",1797 chPre, endc);1798 return;1796 Parse_Error (PARSE_FATAL, 1797 "Unclosed %cinclude filename. '%c' expected", 1798 chPre, endc); 1799 return; 1799 1800 } 1800 1801 *cp = '\0'; … … 1812 1813 */ 1813 1814 if (!isSystem) { 1814 /*1815 * Include files contained in double-quotes are first searched for1816 * relative to the including file's location. We don't want to1817 * cd there, of course, so we just tack on the old file's1818 * leading path components and call Dir_FindFile to see if1819 * we can locate the beast.1820 */1821 char*prefEnd, *Fname;1822 1823 /* Make a temporary copy of this, to be safe. */1824 Fname = estrdup(fname);1825 1826 prefEnd = strrchr (Fname, '/');1827 if (prefEnd != (char *)NULL) {1828 char*newName;1829 1830 *prefEnd = '\0';1831 if (file[0] == '/')1832 newName = estrdup(file);1833 else1834 newName = str_concat (Fname, file, STR_ADDSLASH);1835 fullname = Dir_FindFile (newName, parseIncPath);1836 if (fullname == (char *)NULL) {1837 fullname = Dir_FindFile(newName, dirSearchPath);1838 }1839 efree (newName);1840 *prefEnd = '/';1841 } else {1842 fullname = (char *)NULL;1843 }1844 efree (Fname);1815 /* 1816 * Include files contained in double-quotes are first searched for 1817 * relative to the including file's location. We don't want to 1818 * cd there, of course, so we just tack on the old file's 1819 * leading path components and call Dir_FindFile to see if 1820 * we can locate the beast. 1821 */ 1822 char *prefEnd, *Fname; 1823 1824 /* Make a temporary copy of this, to be safe. */ 1825 Fname = estrdup(fname); 1826 1827 prefEnd = strrchr (Fname, '/'); 1828 if (prefEnd != (char *)NULL) { 1829 char *newName; 1830 1831 *prefEnd = '\0'; 1832 if (file[0] == '/') 1833 newName = estrdup(file); 1834 else 1835 newName = str_concat (Fname, file, STR_ADDSLASH); 1836 fullname = Dir_FindFile (newName, parseIncPath); 1837 if (fullname == (char *)NULL) { 1838 fullname = Dir_FindFile(newName, dirSearchPath); 1839 } 1840 efree (newName); 1841 *prefEnd = '/'; 1842 } else { 1843 fullname = (char *)NULL; 1844 } 1845 efree (Fname); 1845 1846 } else { 1846 fullname = (char *)NULL;1847 fullname = (char *)NULL; 1847 1848 } 1848 1849 1849 1850 if (fullname == (char *)NULL) { 1850 /*1851 * System makefile or makefile wasn't found in same directory as1852 * included makefile. Search for it first on the -I search path,1853 * then on the .PATH search path, if not found in a -I directory.1854 * XXX: Suffix specific?1855 */1856 fullname = Dir_FindFile (file, parseIncPath);1857 if (fullname == (char *)NULL) {1858 fullname = Dir_FindFile(file, dirSearchPath);1859 }1851 /* 1852 * System makefile or makefile wasn't found in same directory as 1853 * included makefile. Search for it first on the -I search path, 1854 * then on the .PATH search path, if not found in a -I directory. 1855 * XXX: Suffix specific? 1856 */ 1857 fullname = Dir_FindFile (file, parseIncPath); 1858 if (fullname == (char *)NULL) { 1859 fullname = Dir_FindFile(file, dirSearchPath); 1860 } 1860 1861 } 1861 1862 1862 1863 if (fullname == (char *)NULL) { 1863 /*1864 * Still haven't found the makefile. Look for it on the system1865 * path as a last resort.1866 */1867 fullname = Dir_FindFile(file, sysIncPath);1864 /* 1865 * Still haven't found the makefile. Look for it on the system 1866 * path as a last resort. 1867 */ 1868 fullname = Dir_FindFile(file, sysIncPath); 1868 1869 } 1869 1870 1870 1871 if (fullname == (char *) NULL) { 1871 *cp = endc;1872 Parse_Error (PARSE_FATAL, "Could not find '%s'", file);1873 return;1872 *cp = endc; 1873 Parse_Error (PARSE_FATAL, "Could not find '%s'", file); 1874 return; 1874 1875 } 1875 1876 … … 1904 1905 curPTR = NULL; 1905 1906 if (curFILE == (FILE * ) NULL) { 1906 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);1907 /*1908 * Pop to previous file1909 */1910 (void) ParseEOF(0);1907 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 1908 /* 1909 * Pop to previous file 1910 */ 1911 (void) ParseEOF(0); 1911 1912 } 1912 1913 } … … 1917 1918 *--------------------------------------------------------------------- 1918 1919 * Parse_FromString -- 1919 * Start Parsing from the given string1920 * Start Parsing from the given string 1920 1921 * 1921 1922 * Results: 1922 * None1923 * None 1923 1924 * 1924 1925 * Side Effects: 1925 * A structure is added to the includes Lst and readProc, lineno,1926 * fname and curFILE are altered for the new file1926 * A structure is added to the includes Lst and readProc, lineno, 1927 * fname and curFILE are altered for the new file 1927 1928 *--------------------------------------------------------------------- 1928 1929 */ … … 1931 1932 char *str; 1932 1933 { 1933 IFile *oldFile; /* state associated with this file */1934 IFile *oldFile; /* state associated with this file */ 1934 1935 1935 1936 if (DEBUG(FOR)) 1936 (void) fprintf(stderr, "%s\n----\n", str);1937 (void) fprintf(stderr, "%s\n----\n", str); 1937 1938 1938 1939 oldFile = (IFile *) emalloc (sizeof (IFile)); … … 1956 1957 *--------------------------------------------------------------------- 1957 1958 * ParseTraditionalInclude -- 1958 * Push to another file.1959 * 1960 * The input is the line minus the "include". The file name is1961 * the string following the "include".1959 * Push to another file. 1960 * 1961 * The input is the line minus the "include". The file name is 1962 * the string following the "include". 1962 1963 * 1963 1964 * Results: 1964 * None1965 * None 1965 1966 * 1966 1967 * Side Effects: 1967 * A structure is added to the includes Lst and readProc, lineno,1968 * fname and curFILE are altered for the new file1968 * A structure is added to the includes Lst and readProc, lineno, 1969 * fname and curFILE are altered for the new file 1969 1970 *--------------------------------------------------------------------- 1970 1971 */ 1971 1972 static void 1972 1973 ParseTraditionalInclude (file) 1973 char *file; /* file specification */1974 { 1975 char *fullname; /* full pathname of file */1976 IFile *oldFile; /* state associated with current file */1977 char *cp; /* current position in file spec */1978 char *prefEnd;1974 char *file; /* file specification */ 1975 { 1976 char *fullname; /* full pathname of file */ 1977 IFile *oldFile; /* state associated with current file */ 1978 char *cp; /* current position in file spec */ 1979 char *prefEnd; 1979 1980 1980 1981 /* … … 1982 1983 */ 1983 1984 while ((*file == ' ') || (*file == '\t')) { 1984 file++;1985 file++; 1985 1986 } 1986 1987 1987 1988 if (*file == '\0') { 1988 Parse_Error (PARSE_FATAL,1989 "Filename missing from \"include\"");1990 return;1989 Parse_Error (PARSE_FATAL, 1990 "Filename missing from \"include\""); 1991 return; 1991 1992 } 1992 1993 … … 1995 1996 */ 1996 1997 for (cp = file; *cp && *cp != '\n' && *cp != '\t' && *cp != ' '; cp++) { 1997 continue;1998 continue; 1998 1999 } 1999 2000 … … 2019 2020 prefEnd = strrchr (fname, '/'); 2020 2021 if (prefEnd != (char *)NULL) { 2021 char*newName;2022 2023 *prefEnd = '\0';2024 newName = str_concat (fname, file, STR_ADDSLASH);2025 fullname = Dir_FindFile (newName, parseIncPath);2026 if (fullname == (char *)NULL) {2027 fullname = Dir_FindFile(newName, dirSearchPath);2028 }2029 efree (newName);2030 *prefEnd = '/';2022 char *newName; 2023 2024 *prefEnd = '\0'; 2025 newName = str_concat (fname, file, STR_ADDSLASH); 2026 fullname = Dir_FindFile (newName, parseIncPath); 2027 if (fullname == (char *)NULL) { 2028 fullname = Dir_FindFile(newName, dirSearchPath); 2029 } 2030 efree (newName); 2031 *prefEnd = '/'; 2031 2032 } else { 2032 fullname = (char *)NULL;2033 fullname = (char *)NULL; 2033 2034 } 2034 2035 2035 2036 if (fullname == (char *)NULL) { 2036 /*2037 * System makefile or makefile wasn't found in same directory as2038 * included makefile. Search for it first on the -I search path,2039 * then on the .PATH search path, if not found in a -I directory.2040 * XXX: Suffix specific?2041 */2042 fullname = Dir_FindFile (file, parseIncPath);2043 if (fullname == (char *)NULL) {2044 fullname = Dir_FindFile(file, dirSearchPath);2045 }2037 /* 2038 * System makefile or makefile wasn't found in same directory as 2039 * included makefile. Search for it first on the -I search path, 2040 * then on the .PATH search path, if not found in a -I directory. 2041 * XXX: Suffix specific? 2042 */ 2043 fullname = Dir_FindFile (file, parseIncPath); 2044 if (fullname == (char *)NULL) { 2045 fullname = Dir_FindFile(file, dirSearchPath); 2046 } 2046 2047 } 2047 2048 2048 2049 if (fullname == (char *)NULL) { 2049 /*2050 * Still haven't found the makefile. Look for it on the system2051 * path as a last resort.2052 */2053 fullname = Dir_FindFile(file, sysIncPath);2050 /* 2051 * Still haven't found the makefile. Look for it on the system 2052 * path as a last resort. 2053 */ 2054 fullname = Dir_FindFile(file, sysIncPath); 2054 2055 } 2055 2056 2056 2057 if (fullname == (char *) NULL) { 2057 Parse_Error (PARSE_FATAL, "Could not find %s", file);2058 return;2058 Parse_Error (PARSE_FATAL, "Could not find %s", file); 2059 return; 2059 2060 } 2060 2061 … … 2087 2088 curPTR = NULL; 2088 2089 if (curFILE == (FILE * ) NULL) { 2089 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname);2090 /*2091 * Pop to previous file2092 */2093 (void) ParseEOF(1);2090 Parse_Error (PARSE_FATAL, "Cannot open %s", fullname); 2091 /* 2092 * Pop to previous file 2093 */ 2094 (void) ParseEOF(1); 2094 2095 } 2095 2096 } … … 2099 2100 *--------------------------------------------------------------------- 2100 2101 * ParseEOF -- 2101 * Called when EOF is reached in the current file. If we were reading2102 * an include file, the includes stack is popped and things set up2103 * to go back to reading the previous file at the previous location.2102 * Called when EOF is reached in the current file. If we were reading 2103 * an include file, the includes stack is popped and things set up 2104 * to go back to reading the previous file at the previous location. 2104 2105 * 2105 2106 * Results: 2106 * CONTINUE if there's more to do. DONE if not.2107 * CONTINUE if there's more to do. DONE if not. 2107 2108 * 2108 2109 * Side Effects: 2109 * The old curFILE, is closed. The includes list is shortened.2110 * lineno, curFILE, and fname are changed if CONTINUE is returned.2110 * The old curFILE, is closed. The includes list is shortened. 2111 * lineno, curFILE, and fname are changed if CONTINUE is returned. 2111 2112 *--------------------------------------------------------------------- 2112 2113 */ … … 2115 2116 int opened; 2116 2117 { 2117 IFile *ifile; /* the state on the top of the includes stack */2118 IFile *ifile; /* the state on the top of the includes stack */ 2118 2119 2119 2120 if (Lst_IsEmpty (includes)) { 2120 return (DONE);2121 return (DONE); 2121 2122 } 2122 2123 … … 2126 2127 lineno = ifile->lineno; 2127 2128 if (opened && curFILE) 2128 (void) fclose (curFILE);2129 (void) fclose (curFILE); 2129 2130 if (curPTR) { 2130 efree((Address) curPTR->str);2131 efree((Address) curPTR);2131 efree((Address) curPTR->str); 2132 efree((Address) curPTR); 2132 2133 } 2133 2134 curFILE = ifile->F; … … 2140 2141 *--------------------------------------------------------------------- 2141 2142 * ParseReadc -- 2142 * Read a character from the current file2143 * Read a character from the current file 2143 2144 * 2144 2145 * Results: 2145 * The character that was read2146 * The character that was read 2146 2147 * 2147 2148 * Side Effects: … … 2152 2153 { 2153 2154 if (curFILE) 2154 return fgetc(curFILE);2155 return fgetc(curFILE); 2155 2156 2156 2157 if (curPTR && *curPTR->ptr) 2157 return *curPTR->ptr++;2158 return *curPTR->ptr++; 2158 2159 return EOF; 2159 2160 } … … 2163 2164 *--------------------------------------------------------------------- 2164 2165 * ParseUnreadc -- 2165 * Put back a character to the current file2166 * Put back a character to the current file 2166 2167 * 2167 2168 * Results: 2168 * None.2169 * None. 2169 2170 * 2170 2171 * Side Effects: … … 2176 2177 { 2177 2178 if (curFILE) { 2178 ungetc(c, curFILE);2179 return;2179 ungetc(c, curFILE); 2180 return; 2180 2181 } 2181 2182 if (curPTR) { 2182 *--(curPTR->ptr) = c;2183 return;2183 *--(curPTR->ptr) = c; 2184 return; 2184 2185 } 2185 2186 } … … 2187 2188 2188 2189 /* ParseSkipLine(): 2189 * Grab the next line2190 * Grab the next line 2190 2191 */ 2191 2192 static char * 2192 2193 ParseSkipLine(skip) 2193 int skip; /* Skip lines that don't start with . */2194 int skip; /* Skip lines that don't start with . */ 2194 2195 { 2195 2196 char *line; … … 2242 2243 *--------------------------------------------------------------------- 2243 2244 * ParseReadLine -- 2244 * Read an entire line from the input file. Called only by Parse_File.2245 * To facilitate escaped newlines and what have you, a character is2246 * buffered in 'lastc', which is '\0' when no characters have been2247 * read. When we break out of the loop, c holds the terminating2248 * character and lastc holds a character that should be added to2249 * the line (unless we don't read anything but a terminator).2245 * Read an entire line from the input file. Called only by Parse_File. 2246 * To facilitate escaped newlines and what have you, a character is 2247 * buffered in 'lastc', which is '\0' when no characters have been 2248 * read. When we break out of the loop, c holds the terminating 2249 * character and lastc holds a character that should be added to 2250 * the line (unless we don't read anything but a terminator). 2250 2251 * 2251 2252 * Results: 2252 * A line w/o its newline2253 * A line w/o its newline 2253 2254 * 2254 2255 * Side Effects: 2255 * Only those associated with reading a character2256 * Only those associated with reading a character 2256 2257 *--------------------------------------------------------------------- 2257 2258 */ … … 2259 2260 ParseReadLine () 2260 2261 { 2261 Buffer buf;/* Buffer for current line */2262 register int c; /* the current character */2263 register int lastc; /* The most-recent character */2264 Boolean semiNL;/* treat semi-colons as newlines */2265 Boolean ignDepOp;/* TRUE if should ignore dependency operators2266 * for the purposes of setting semiNL */2267 Boolean ignComment;/* TRUE if should ignore comments (in a2268 * shell command */2269 char *line;/* Result */2270 char *ep; /* to strip trailing blanks */2271 int lineLength;/* Length of result */2262 Buffer buf; /* Buffer for current line */ 2263 register int c; /* the current character */ 2264 register int lastc; /* The most-recent character */ 2265 Boolean semiNL; /* treat semi-colons as newlines */ 2266 Boolean ignDepOp; /* TRUE if should ignore dependency operators 2267 * for the purposes of setting semiNL */ 2268 Boolean ignComment; /* TRUE if should ignore comments (in a 2269 * shell command */ 2270 char *line; /* Result */ 2271 char *ep; /* to strip trailing blanks */ 2272 int lineLength; /* Length of result */ 2272 2273 2273 2274 semiNL = FALSE; … … 2287 2288 */ 2288 2289 for (;;) { 2289 c = ParseReadc();2290 c = ParseReadc(); 2290 2291 #ifdef USE_INLINEFILES 2291 2292 if (inInlineFile) … … 2293 2294 #endif 2294 2295 2295 if (c == '\t') {2296 ignComment = ignDepOp = TRUE;2297 break;2298 } else if (c == '\n') {2299 lineno++;2300 } else if (c == '#') {2301 ParseUnreadc(c);2302 break;2303 } else {2304 /*2305 * Anything else breaks out without doing anything2306 */2307 break;2308 }2296 if (c == '\t') { 2297 ignComment = ignDepOp = TRUE; 2298 break; 2299 } else if (c == '\n') { 2300 lineno++; 2301 } else if (c == '#') { 2302 ParseUnreadc(c); 2303 break; 2304 } else { 2305 /* 2306 * Anything else breaks out without doing anything 2307 */ 2308 break; 2309 } 2309 2310 } 2310 2311 2311 2312 if (c != EOF) { 2312 lastc = c;2313 buf = Buf_Init(MAKE_BSIZE);2313 lastc = c; 2314 buf = Buf_Init(MAKE_BSIZE); 2314 2315 2315 2316 /* @todo any inline changes here? */ 2316 2317 #ifdef NMAKE 2317 while (((c = ParseReadc ()) != '\n' || (lastc == '\\') || (lastc == '^')) && (c != EOF))2318 while (((c = ParseReadc ()) != '\n' || (lastc == '\\') || (lastc == '^')) && (c != EOF)) 2318 2319 #else 2319 while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF))2320 while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF)) 2320 2321 #endif 2321 {2322 { 2322 2323 test_char: 2323 switch(c) {2324 case '\n':2324 switch(c) { 2325 case '\n': 2325 2326 #ifdef USE_INLINEFILES 2326 2327 /* No newline escaping in inline files, unless it's a directive. */ … … 2336 2337 } 2337 2338 #endif 2338 2339 2339 2340 /* 2340 * Escaped newline: read characters until a non-space or an2341 * unescaped newline and replace them all by a single space.2342 * This is done by storing the space over the backslash and2343 * dropping through with the next nonspace. If it is a2344 * semi-colon and semiNL is TRUE, it will be recognized as a2345 * newline in the code below this...2346 */2347 lineno++;2348 lastc = ' ';2341 * Escaped newline: read characters until a non-space or an 2342 * unescaped newline and replace them all by a single space. 2343 * This is done by storing the space over the backslash and 2344 * dropping through with the next nonspace. If it is a 2345 * semi-colon and semiNL is TRUE, it will be recognized as a 2346 * newline in the code below this... 2347 */ 2348 lineno++; 2349 lastc = ' '; 2349 2350 #ifdef NMAKE 2350 2351 if (lastc == '^') 2351 lastc = '\n';2352 lastc = '\n'; 2352 2353 2353 2354 do { 2354 2355 while ((c = ParseReadc ()) == ' ' || c == '\t') { 2355 continue;2356 }2356 continue; 2357 } 2357 2358 if (c != '#') 2358 2359 break; 2359 2360 /* comment - skip line */ 2360 2361 while ((c = ParseReadc ()) != '\n' && c != EOF) { 2361 continue;2362 }2362 continue; 2363 } 2363 2364 if (c == EOF) 2364 2365 break; 2365 2366 } while (1); 2366 2367 #else 2367 while ((c = ParseReadc ()) == ' ' || c == '\t') {2368 continue;2369 }2370 #endif 2371 if (c == EOF || c == '\n') {2372 goto line_read;2373 } else {2374 /*2375 * Check for comments, semiNL's, etc. -- easier than2376 * ParseUnreadc(c); continue;2377 */2378 goto test_char;2379 }2380 /*NOTREACHED*/2381 break;2368 while ((c = ParseReadc ()) == ' ' || c == '\t') { 2369 continue; 2370 } 2371 #endif 2372 if (c == EOF || c == '\n') { 2373 goto line_read; 2374 } else { 2375 /* 2376 * Check for comments, semiNL's, etc. -- easier than 2377 * ParseUnreadc(c); continue; 2378 */ 2379 goto test_char; 2380 } 2381 /*NOTREACHED*/ 2382 break; 2382 2383 2383 2384 /* We don't need this, and don't want it! */ 2384 2385 #ifndef KMK 2385 case ';':2386 case ';': 2386 2387 #ifdef USE_INLINEFILES 2387 2388 if (inInlineFile) 2388 2389 break; 2389 2390 #endif 2390 /*2391 * Semi-colon: Need to see if it should be interpreted as a2392 * newline2393 */2394 if (semiNL) {2395 /*2396 * To make sure the command that may be following this2397 * semi-colon begins with a tab, we push one back into the2398 * input stream. This will overwrite the semi-colon in the2399 * buffer. If there is no command following, this does no2400 * harm, since the newline remains in the buffer and the2401 * whole line is ignored.2402 */2403 ParseUnreadc('\t');2404 goto line_read;2405 }2406 break;2407 case '=':2391 /* 2392 * Semi-colon: Need to see if it should be interpreted as a 2393 * newline 2394 */ 2395 if (semiNL) { 2396 /* 2397 * To make sure the command that may be following this 2398 * semi-colon begins with a tab, we push one back into the 2399 * input stream. This will overwrite the semi-colon in the 2400 * buffer. If there is no command following, this does no 2401 * harm, since the newline remains in the buffer and the 2402 * whole line is ignored. 2403 */ 2404 ParseUnreadc('\t'); 2405 goto line_read; 2406 } 2407 break; 2408 case '=': 2408 2409 #ifdef USE_INLINEFILES 2409 2410 if (inInlineFile) … … 2411 2412 #endif 2412 2413 if (!semiNL) { 2413 /*2414 * Haven't seen a dependency operator before this, so this2415 * must be a variable assignment -- don't pay attention to2416 * dependency operators after this.2417 */2418 ignDepOp = TRUE;2419 } else if (lastc == ':' || lastc == '!') {2420 /*2421 * Well, we've seen a dependency operator already, but it2422 * was the previous character, so this is really just an2423 * expanded variable assignment. Revert semi-colons to2424 * being just semi-colons again and ignore any more2425 * dependency operators.2426 *2427 * XXX: Note that a line like "foo : a:=b" will blow up,2428 * but who'd write a line like that anyway?2429 */2430 ignDepOp = TRUE; semiNL = FALSE;2431 }2432 break;2433 case '#':2434 if (!ignComment) {2435 if (2414 /* 2415 * Haven't seen a dependency operator before this, so this 2416 * must be a variable assignment -- don't pay attention to 2417 * dependency operators after this. 2418 */ 2419 ignDepOp = TRUE; 2420 } else if (lastc == ':' || lastc == '!') { 2421 /* 2422 * Well, we've seen a dependency operator already, but it 2423 * was the previous character, so this is really just an 2424 * expanded variable assignment. Revert semi-colons to 2425 * being just semi-colons again and ignore any more 2426 * dependency operators. 2427 * 2428 * XXX: Note that a line like "foo : a:=b" will blow up, 2429 * but who'd write a line like that anyway? 2430 */ 2431 ignDepOp = TRUE; semiNL = FALSE; 2432 } 2433 break; 2434 case '#': 2435 if (!ignComment) { 2436 if ( 2436 2437 #if 0 2437 compatMake &&2438 #endif 2439 (lastc != '\\')) {2440 /*2441 * If the character is a hash mark and it isn't escaped2442 * (or we're being compatible), the thing is a comment.2443 * Skip to the end of the line.2444 */2445 do {2446 c = ParseReadc();2447 } while ((c != '\n') && (c != EOF));2448 goto line_read;2449 } else {2450 /*2451 * Don't add the backslash. Just let the # get copied2452 * over.2453 */2454 lastc = c;2455 continue;2456 }2457 }2458 break;2459 case ':':2460 case '!':2438 compatMake && 2439 #endif 2440 (lastc != '\\')) { 2441 /* 2442 * If the character is a hash mark and it isn't escaped 2443 * (or we're being compatible), the thing is a comment. 2444 * Skip to the end of the line. 2445 */ 2446 do { 2447 c = ParseReadc(); 2448 } while ((c != '\n') && (c != EOF)); 2449 goto line_read; 2450 } else { 2451 /* 2452 * Don't add the backslash. Just let the # get copied 2453 * over. 2454 */ 2455 lastc = c; 2456 continue; 2457 } 2458 } 2459 break; 2460 case ':': 2461 case '!': 2461 2462 #ifdef USE_INLINEFILES 2462 2463 if (inInlineFile) 2463 2464 break; 2464 2465 #endif 2465 if (!ignDepOp && (c == ':' || c == '!')) {2466 /*2467 * A semi-colon is recognized as a newline only on2468 * dependency lines. Dependency lines are lines with a2469 * colon or an exclamation point. Ergo...2470 */2471 semiNL = TRUE;2472 }2473 break;2466 if (!ignDepOp && (c == ':' || c == '!')) { 2467 /* 2468 * A semi-colon is recognized as a newline only on 2469 * dependency lines. Dependency lines are lines with a 2470 * colon or an exclamation point. Ergo... 2471 */ 2472 semiNL = TRUE; 2473 } 2474 break; 2474 2475 #endif /* !KMK */ 2475 }2476 /*2477 * Copy in the previous character and save this one in lastc.2478 */2479 Buf_AddByte (buf, (Byte)lastc);2480 lastc = c;2481 2482 }2476 } 2477 /* 2478 * Copy in the previous character and save this one in lastc. 2479 */ 2480 Buf_AddByte (buf, (Byte)lastc); 2481 lastc = c; 2482 2483 } 2483 2484 line_read: 2484 lineno++;2485 2486 if (lastc != '\0') {2487 Buf_AddByte (buf, (Byte)lastc);2488 }2489 Buf_AddByte (buf, (Byte)'\0');2490 line = (char *)Buf_GetAll (buf, &lineLength);2491 Buf_Destroy (buf, FALSE);2492 2493 /*2494 * Strip trailing blanks and tabs from the line.2495 * Do not strip a blank or tab that is preceeded by2496 * a '\'2497 */2485 lineno++; 2486 2487 if (lastc != '\0') { 2488 Buf_AddByte (buf, (Byte)lastc); 2489 } 2490 Buf_AddByte (buf, (Byte)'\0'); 2491 line = (char *)Buf_GetAll (buf, &lineLength); 2492 Buf_Destroy (buf, FALSE); 2493 2494 /* 2495 * Strip trailing blanks and tabs from the line. 2496 * Do not strip a blank or tab that is preceeded by 2497 * a '\' 2498 */ 2498 2499 #ifdef USE_INLINEFILES 2499 2500 if (!inInlineFile) { 2500 2501 #endif 2501 ep = line;2502 while (*ep)2503 ++ep;2504 while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) {2505 if (ep > line + 1 && ep[-2] == '\\')2506 break;2507 --ep;2508 }2509 *ep = 0;2502 ep = line; 2503 while (*ep) 2504 ++ep; 2505 while (ep > line + 1 && (ep[-1] == ' ' || ep[-1] == '\t')) { 2506 if (ep > line + 1 && ep[-2] == '\\') 2507 break; 2508 --ep; 2509 } 2510 *ep = 0; 2510 2511 #ifdef USE_INLINEFILES 2511 2512 } … … 2513 2514 2514 2515 #ifdef NMAKE 2515 if (line[0] == '.' || line[0] == '!') {2516 if (line[0] == '.' || line[0] == '!') { 2516 2517 #else 2517 if (line[0] == '.') {2518 #endif 2519 /*2520 * The line might be a conditional. Ask the conditional module2521 * about it and act accordingly2522 */2523 switch (Cond_Eval (line)) {2524 case COND_SKIP:2525 /*2526 * Skip to next conditional that evaluates to COND_PARSE.2527 */2528 do {2529 efree (line);2530 line = ParseSkipLine(1);2531 } while (line && Cond_Eval(line) != COND_PARSE);2532 if (line == NULL)2533 break;2534 /*FALLTHRU*/2535 case COND_PARSE:2536 efree ((Address) line);2537 line = ParseReadLine();2538 break;2539 case COND_INVALID:2540 if (For_Eval(line)) {2541 int ok;2542 efree(line);2543 do {2544 /*2545 * Skip after the matching end2546 */2547 line = ParseSkipLine(0);2548 if (line == NULL) {2549 Parse_Error (PARSE_FATAL,2550 "Unexpected end of file in for loop.\n");2551 break;2552 }2553 ok = For_Eval(line);2554 efree(line);2555 }2556 while (ok);2557 if (line != NULL)2558 For_Run();2559 line = ParseReadLine();2560 }2561 break;2562 }2563 }2564 return (line);2518 if (line[0] == '.') { 2519 #endif 2520 /* 2521 * The line might be a conditional. Ask the conditional module 2522 * about it and act accordingly 2523 */ 2524 switch (Cond_Eval (line)) { 2525 case COND_SKIP: 2526 /* 2527 * Skip to next conditional that evaluates to COND_PARSE. 2528 */ 2529 do { 2530 efree (line); 2531 line = ParseSkipLine(1); 2532 } while (line && Cond_Eval(line) != COND_PARSE); 2533 if (line == NULL) 2534 break; 2535 /*FALLTHRU*/ 2536 case COND_PARSE: 2537 efree ((Address) line); 2538 line = ParseReadLine(); 2539 break; 2540 case COND_INVALID: 2541 if (For_Eval(line)) { 2542 int ok; 2543 efree(line); 2544 do { 2545 /* 2546 * Skip after the matching end 2547 */ 2548 line = ParseSkipLine(0); 2549 if (line == NULL) { 2550 Parse_Error (PARSE_FATAL, 2551 "Unexpected end of file in for loop.\n"); 2552 break; 2553 } 2554 ok = For_Eval(line); 2555 efree(line); 2556 } 2557 while (ok); 2558 if (line != NULL) 2559 For_Run(); 2560 line = ParseReadLine(); 2561 } 2562 break; 2563 } 2564 } 2565 return (line); 2565 2566 2566 2567 } else { 2567 /*2568 * Hit end-of-file, so return a NULL line to indicate this.2569 */2570 return((char *)NULL);2568 /* 2569 * Hit end-of-file, so return a NULL line to indicate this. 2570 */ 2571 return((char *)NULL); 2571 2572 } 2572 2573 } … … 2575 2576 *----------------------------------------------------------------------- 2576 2577 * ParseFinishLine -- 2577 * Handle the end of a dependency group.2578 * Handle the end of a dependency group. 2578 2579 * 2579 2580 * Results: 2580 * Nothing.2581 * Nothing. 2581 2582 * 2582 2583 * Side Effects: 2583 * inLine set FALSE. 'targets' list destroyed.2584 * inLine set FALSE. 'targets' list destroyed. 2584 2585 * 2585 2586 *----------------------------------------------------------------------- … … 2589 2590 { 2590 2591 if (inLine) { 2591 Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL);2592 Lst_Destroy (targets, ParseHasCommands);2593 targets = NULL;2594 inLine = FALSE;2592 Lst_ForEach(targets, Suff_EndTransform, (ClientData)NULL); 2593 Lst_Destroy (targets, ParseHasCommands); 2594 targets = NULL; 2595 inLine = FALSE; 2595 2596 } 2596 2597 } … … 2600 2601 *--------------------------------------------------------------------- 2601 2602 * Parse_File -- 2602 * Parse a file into its component parts, incorporating it into the2603 * current dependency graph. This is the main function and controls2604 * almost every other function in this module2603 * Parse a file into its component parts, incorporating it into the 2604 * current dependency graph. This is the main function and controls 2605 * almost every other function in this module 2605 2606 * 2606 2607 * Results: 2607 * None2608 * None 2608 2609 * 2609 2610 * Side Effects: 2610 * Loads. Nodes are added to the list of all targets, nodes and links2611 * are added to the dependency graph. etc. etc. etc.2611 * Loads. Nodes are added to the list of all targets, nodes and links 2612 * are added to the dependency graph. etc. etc. etc. 2612 2613 *--------------------------------------------------------------------- 2613 2614 */ 2614 2615 void 2615 2616 Parse_File(name, stream) 2616 char *name; /* the name of the file being read */2617 FILE * stream;/* Stream open to makefile to parse */2618 { 2619 register char *cp, /* pointer into the line */2620 *line; /* the line we're working on */2617 char *name; /* the name of the file being read */ 2618 FILE * stream; /* Stream open to makefile to parse */ 2619 { 2620 register char *cp, /* pointer into the line */ 2621 *line; /* the line we're working on */ 2621 2622 2622 2623 inLine = FALSE; … … 2630 2631 2631 2632 do { 2632 while ((line = ParseReadLine ()) != NULL) {2633 while ((line = ParseReadLine ()) != NULL) { 2633 2634 if (DEBUG(PARSE)) 2634 2635 printf("%s(%d): inLine=%d inInlineFile=%d\n%s\n", fname, lineno, inLine, inInlineFile, line); 2635 2636 #ifdef NMAKE 2636 if (*line == '.' || *line == '!') {2637 if (*line == '.' || *line == '!') { 2637 2638 #else 2638 if (*line == '.') {2639 if (*line == '.') { 2639 2640 #endif 2640 /*2641 * Lines that begin with the special character are either2642 * include or undef directives.2643 */2644 for (cp = line + 1; isspace (*cp); cp++) {2645 continue;2646 }2647 if (strncmp (cp, "include", 7) == 0) {2648 ParseDoInclude (cp + 7, *line);2649 goto nextLine;2650 } else if (strncmp (cp, "error", 5) == 0) {2651 ParseDoError(cp + 5);2652 goto nextLine; 2653 } else if (strncmp(cp, "undef", 5) == 0) {2654 char *cp2;2655 for (cp += 5; isspace((unsigned char) *cp); cp++) {2656 continue;2657 }2658 2659 for (cp2 = cp; !isspace((unsigned char) *cp2) &&2660 (*cp2 != '\0'); cp2++) {2661 continue;2662 }2663 2664 *cp2 = '\0';2665 2666 Var_Delete(cp, VAR_GLOBAL);2667 goto nextLine;2668 }2669 }2641 /* 2642 * Lines that begin with the special character are either 2643 * include or undef directives. 2644 */ 2645 for (cp = line + 1; isspace (*cp); cp++) { 2646 continue; 2647 } 2648 if (strncmp (cp, "include", 7) == 0) { 2649 ParseDoInclude (cp + 7, *line); 2650 goto nextLine; 2651 } else if (strncmp (cp, "error", 5) == 0) { 2652 ParseDoError(cp + 5); 2653 goto nextLine; 2654 } else if (strncmp(cp, "undef", 5) == 0) { 2655 char *cp2; 2656 for (cp += 5; isspace((unsigned char) *cp); cp++) { 2657 continue; 2658 } 2659 2660 for (cp2 = cp; !isspace((unsigned char) *cp2) && 2661 (*cp2 != '\0'); cp2++) { 2662 continue; 2663 } 2664 2665 *cp2 = '\0'; 2666 2667 Var_Delete(cp, VAR_GLOBAL); 2668 goto nextLine; 2669 } 2670 } 2670 2671 2671 2672 #ifdef USE_INLINEFILES … … 2705 2706 /*Lst_AtEnd(targCmds, (ClientData) line); */ 2706 2707 } 2707 goto nextLine;2708 goto nextLine; 2708 2709 } 2709 2710 #endif 2710 2711 2711 if (*line == '#') {2712 /* If we're this far, the line must be a comment. */2713 goto nextLine;2714 }2715 2716 if (*line == '\t') {2717 /*2718 * If a line starts with a tab, it can only hope to be2719 * a creation command.2720 */2712 if (*line == '#') { 2713 /* If we're this far, the line must be a comment. */ 2714 goto nextLine; 2715 } 2716 2717 if (*line == '\t') { 2718 /* 2719 * If a line starts with a tab, it can only hope to be 2720 * a creation command. 2721 */ 2721 2722 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2722 shellCommand:2723 #endif 2724 for (cp = line + 1; isspace (*cp); cp++) {2725 continue;2726 }2727 if (*cp) {2728 if (inLine) {2723 shellCommand: 2724 #endif 2725 for (cp = line + 1; isspace (*cp); cp++) { 2726 continue; 2727 } 2728 if (*cp) { 2729 if (inLine) { 2729 2730 #ifdef USE_INLINEFILES 2730 2731 if (ParseCmdIsComponent(cp, "<<")) … … 2736 2737 } 2737 2738 #endif 2738 /*2739 * So long as it's not a blank line and we're actually2740 * in a dependency spec, add the command to the list of2741 * commands of all targets in the dependency spec2742 */2743 Lst_ForEach (targets, ParseAddCmd, cp);2744 /*Lst_AtEnd(targCmds, (ClientData) line);*/2745 continue;2746 } else {2747 Parse_Error (PARSE_FATAL,2748 "Unassociated shell command \"%s\"",2749 cp);2750 }2751 }2739 /* 2740 * So long as it's not a blank line and we're actually 2741 * in a dependency spec, add the command to the list of 2742 * commands of all targets in the dependency spec 2743 */ 2744 Lst_ForEach (targets, ParseAddCmd, cp); 2745 /*Lst_AtEnd(targCmds, (ClientData) line);*/ 2746 continue; 2747 } else { 2748 Parse_Error (PARSE_FATAL, 2749 "Unassociated shell command \"%s\"", 2750 cp); 2751 } 2752 } 2752 2753 #ifdef SYSVINCLUDE 2753 } else if (strncmp (line, "include", 7) == 0 &&2754 isspace((unsigned char) line[7]) &&2755 strchr(line, ':') == NULL) {2756 /*2757 * It's an S3/S5-style "include".2758 */2759 ParseTraditionalInclude (line + 7);2760 goto nextLine;2761 #endif 2762 } else if (Parse_IsVar (line)) {2763 ParseFinishLine();2764 Parse_DoVar (line, VAR_GLOBAL);2765 } else {2766 /*2767 * We now know it's a dependency line so it needs to have all2768 * variables expanded before being parsed. Tell the variable2769 * module to complain if some variable is undefined...2770 * To make life easier on novices, if the line is indented we2771 * first make sure the line has a dependency operator in it.2772 * If it doesn't have an operator and we're in a dependency2773 * line's script, we assume it's actually a shell command2774 * and add it to the current list of targets.2775 */2754 } else if (strncmp (line, "include", 7) == 0 && 2755 isspace((unsigned char) line[7]) && 2756 strchr(line, ':') == NULL) { 2757 /* 2758 * It's an S3/S5-style "include". 2759 */ 2760 ParseTraditionalInclude (line + 7); 2761 goto nextLine; 2762 #endif 2763 } else if (Parse_IsVar (line)) { 2764 ParseFinishLine(); 2765 Parse_DoVar (line, VAR_GLOBAL); 2766 } else { 2767 /* 2768 * We now know it's a dependency line so it needs to have all 2769 * variables expanded before being parsed. Tell the variable 2770 * module to complain if some variable is undefined... 2771 * To make life easier on novices, if the line is indented we 2772 * first make sure the line has a dependency operator in it. 2773 * If it doesn't have an operator and we're in a dependency 2774 * line's script, we assume it's actually a shell command 2775 * and add it to the current list of targets. 2776 */ 2776 2777 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2777 BooleannonSpace = FALSE;2778 #endif 2779 2780 cp = line;2781 if (isspace((unsigned char) line[0])) {2782 while ((*cp != '\0') && isspace((unsigned char) *cp)) {2783 cp++;2784 }2785 if (*cp == '\0') {2786 goto nextLine;2787 }2778 Boolean nonSpace = FALSE; 2779 #endif 2780 2781 cp = line; 2782 if (isspace((unsigned char) line[0])) { 2783 while ((*cp != '\0') && isspace((unsigned char) *cp)) { 2784 cp++; 2785 } 2786 if (*cp == '\0') { 2787 goto nextLine; 2788 } 2788 2789 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2789 while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) {2790 nonSpace = TRUE;2791 cp++;2792 }2793 #endif 2794 }2790 while ((*cp != ':') && (*cp != '!') && (*cp != '\0')) { 2791 nonSpace = TRUE; 2792 cp++; 2793 } 2794 #endif 2795 } 2795 2796 2796 2797 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2797 if (*cp == '\0') {2798 if (inLine) {2798 if (*cp == '\0') { 2799 if (inLine) { 2799 2800 #if !defined(USE_NO_STUPID_TABS) 2800 Parse_Error (PARSE_WARNING,2801 "Shell command needs a leading tab");2802 #endif 2803 goto shellCommand;2804 } else if (nonSpace) {2805 Parse_Error (PARSE_FATAL, "Missing operator");2806 }2807 } else {2808 #endif 2809 ParseFinishLine();2810 2811 cp = Var_Subst (NULL, line, VAR_CMD, TRUE);2812 efree (line);2813 line = cp;2814 2815 /*2816 * Need a non-circular list for the target nodes2817 */2818 if (targets)2819 Lst_Destroy(targets, NOFREE);2820 2821 targets = Lst_Init (FALSE);2822 inLine = TRUE;2823 2824 ParseDoDependency (line);2801 Parse_Error (PARSE_WARNING, 2802 "Shell command needs a leading tab"); 2803 #endif 2804 goto shellCommand; 2805 } else if (nonSpace) { 2806 Parse_Error (PARSE_FATAL, "Missing operator"); 2807 } 2808 } else { 2809 #endif 2810 ParseFinishLine(); 2811 2812 cp = Var_Subst (NULL, line, VAR_CMD, TRUE); 2813 efree (line); 2814 line = cp; 2815 2816 /* 2817 * Need a non-circular list for the target nodes 2818 */ 2819 if (targets) 2820 Lst_Destroy(targets, NOFREE); 2821 2822 targets = Lst_Init (FALSE); 2823 inLine = TRUE; 2824 2825 ParseDoDependency (line); 2825 2826 #if !defined(POSIX) || defined(USE_NO_STUPID_TABS) 2826 }2827 #endif 2828 }2829 2830 nextLine:2831 2832 efree (line);2833 }2834 /*2835 * Reached EOF, but it may be just EOF of an include file...2836 */2827 } 2828 #endif 2829 } 2830 2831 nextLine: 2832 2833 efree (line); 2834 } 2835 /* 2836 * Reached EOF, but it may be just EOF of an include file... 2837 */ 2837 2838 } while (ParseEOF(1) == CONTINUE); 2838 2839 … … 2843 2844 2844 2845 if (fatals) 2845 errx(1, "fatal errors encountered -- cannot continue");2846 errx(1, "fatal errors encountered -- cannot continue"); 2846 2847 } 2847 2848 … … 2849 2850 *--------------------------------------------------------------------- 2850 2851 * Parse_Init -- 2851 * initialize the parsing module2852 * initialize the parsing module 2852 2853 * 2853 2854 * Results: 2854 * none2855 * none 2855 2856 * 2856 2857 * Side Effects: 2857 * the parseIncPath list is initialized...2858 * the parseIncPath list is initialized... 2858 2859 *--------------------------------------------------------------------- 2859 2860 */ … … 2873 2874 /*Lst_Destroy(targCmds, (void (*) __P((ClientData))) efree);*/ 2874 2875 if (targets) 2875 Lst_Destroy(targets, NOFREE);2876 Lst_Destroy(targets, NOFREE); 2876 2877 Lst_Destroy(sysIncPath, Dir_Destroy); 2877 2878 Lst_Destroy(parseIncPath, Dir_Destroy); 2878 Lst_Destroy(includes, NOFREE); /* Should be empty now */2879 Lst_Destroy(includes, NOFREE); /* Should be empty now */ 2879 2880 } 2880 2881 … … 2883 2884 *----------------------------------------------------------------------- 2884 2885 * Parse_MainName -- 2885 * Return a Lst of the main target to create for main()'s sake. If2886 * no such target exists, we Punt with an obnoxious error message.2886 * Return a Lst of the main target to create for main()'s sake. If 2887 * no such target exists, we Punt with an obnoxious error message. 2887 2888 * 2888 2889 * Results: 2889 * A Lst of the single node to create.2890 * A Lst of the single node to create. 2890 2891 * 2891 2892 * Side Effects: 2892 * None.2893 * None. 2893 2894 * 2894 2895 *----------------------------------------------------------------------- … … 2897 2898 Parse_MainName() 2898 2899 { 2899 Lst listmain; /* result list */2900 Lst listmain; /* result list */ 2900 2901 2901 2902 listmain = Lst_Init (FALSE); 2902 2903 2903 2904 if (mainNode == NILGNODE) { 2904 Punt ("no target to make.");2905 /*NOTREACHED*/2905 Punt ("no target to make."); 2906 /*NOTREACHED*/ 2906 2907 } else if (mainNode->type & OP_DOUBLEDEP) { 2907 (void) Lst_AtEnd (listmain, (ClientData)mainNode);2908 Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW);2908 (void) Lst_AtEnd (listmain, (ClientData)mainNode); 2909 Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW); 2909 2910 } 2910 2911 else 2911 (void) Lst_AtEnd (listmain, (ClientData)mainNode);2912 (void) Lst_AtEnd (listmain, (ClientData)mainNode); 2912 2913 return (listmain); 2913 2914 } -
trunk/src/kmk/str.c
r35 r51 1 1 /*- 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90";41 static char sccsid[] = "@(#)str.c 5.8 (Berkeley) 6/1/90"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/str.c,v 1.12.2.1 2002/06/17 04:30:48 jmallett Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 … … 53 54 /* 54 55 * str_init -- 55 * Initialize the strings package56 * Initialize the strings package 56 57 * 57 58 */ … … 67 68 /* 68 69 * str_end -- 69 * Cleanup the strings package70 * Cleanup the strings package 70 71 * 71 72 */ … … 74 75 { 75 76 if (argv) { 76 if (argv[0])77 efree(argv[0]);78 efree((Address) argv);77 if (argv[0]) 78 efree(argv[0]); 79 efree((Address) argv); 79 80 } 80 81 if (buffer) 81 efree(buffer);82 efree(buffer); 82 83 } 83 84 84 85 /*- 85 86 * str_concat -- 86 * concatenate the two strings, inserting a space or slash between them,87 * freeing them if requested.87 * concatenate the two strings, inserting a space or slash between them, 88 * freeing them if requested. 88 89 * 89 90 * returns -- 90 * the resulting string in allocated space.91 * the resulting string in allocated space. 91 92 */ 92 93 char * 93 94 str_concat(s1, s2, flags) 94 char *s1, *s2;95 int flags;96 { 97 register int len1, len2;98 register char *result;99 100 /* get the length of both strings */101 len1 = strlen(s1);102 len2 = strlen(s2);103 104 /* allocate length plus separator plus EOS */105 result = emalloc((u_int)(len1 + len2 + 2));106 107 /* copy first string into place */108 memcpy(result, s1, len1);109 110 /* add separator character */111 if (flags & STR_ADDSPACE) {112 result[len1] = ' ';113 ++len1;114 } else if (flags & STR_ADDSLASH) {115 result[len1] = '/';116 ++len1;117 }118 119 /* copy second string plus EOS into place */120 memcpy(result + len1, s2, len2 + 1);121 122 /* efree original strings */123 if (flags & STR_DOFREE) {124 (void)efree(s1);125 (void)efree(s2);126 }127 return(result);95 char *s1, *s2; 96 int flags; 97 { 98 register int len1, len2; 99 register char *result; 100 101 /* get the length of both strings */ 102 len1 = strlen(s1); 103 len2 = strlen(s2); 104 105 /* allocate length plus separator plus EOS */ 106 result = emalloc((u_int)(len1 + len2 + 2)); 107 108 /* copy first string into place */ 109 memcpy(result, s1, len1); 110 111 /* add separator character */ 112 if (flags & STR_ADDSPACE) { 113 result[len1] = ' '; 114 ++len1; 115 } else if (flags & STR_ADDSLASH) { 116 result[len1] = '/'; 117 ++len1; 118 } 119 120 /* copy second string plus EOS into place */ 121 memcpy(result + len1, s2, len2 + 1); 122 123 /* efree original strings */ 124 if (flags & STR_DOFREE) { 125 (void)efree(s1); 126 (void)efree(s2); 127 } 128 return(result); 128 129 } 129 130 130 131 /*- 131 132 * brk_string -- 132 * Fracture a string into an array of words (as delineated by tabs or133 * spaces) taking quotation marks into account. Leading tabs/spaces134 * are ignored.133 * Fracture a string into an array of words (as delineated by tabs or 134 * spaces) taking quotation marks into account. Leading tabs/spaces 135 * are ignored. 135 136 * 136 137 * returns -- 137 * Pointer to the array of pointers to the words. To make life easier,138 * the first word is always the value of the .MAKE variable.138 * Pointer to the array of pointers to the words. To make life easier, 139 * the first word is always the value of the .MAKE variable. 139 140 */ 140 141 char ** 141 142 brk_string(str, store_argc, expand) 142 register char *str;143 int *store_argc;144 Boolean expand;145 { 146 register int argc, ch;147 register char inquote, *p, *start, *t;148 int len;149 150 /* skip leading space chars. */151 for (; *str == ' ' || *str == '\t'; ++str)152 continue;153 154 /* allocate room for a copy of the string */155 if ((len = strlen(str) + 1) > curlen) {156 if (buffer)157 efree(buffer);158 buffer = emalloc(curlen = len);159 }160 161 /*162 * copy the string; at the same time, parse backslashes,163 * quotes and build the argument list.164 */165 argc = 1;166 inquote = '\0';167 for (p = str, start = t = buffer;; ++p) {168 switch(ch = *p) {169 case '"':170 case '\'':171 if (inquote) {172 if (inquote == ch)173 inquote = '\0';174 else175 break;176 } else {177 inquote = (char) ch;178 /* Don't miss "" or '' */179 if (start == NULL && p[1] == inquote) {180 start = t + 1;181 break;182 }183 }184 if (!expand) {185 if (!start)186 start = t;187 *t++ = ch;188 }189 continue;190 case ' ':191 case '\t':192 case '\n':193 if (inquote)194 break;195 if (!start)196 continue;197 /* FALLTHROUGH */198 case '\0':199 /*200 * end of a token -- make sure there's enough argv201 * space and save off a pointer.202 */203 if (!start)204 goto done;205 206 *t++ = '\0';207 if (argc == argmax) {208 argmax *= 2;/* ramp up fast */209 argv = (char **)erealloc(argv,210 (argmax + 1) * sizeof(char *));211 }212 argv[argc++] = start;213 start = (char *)NULL;214 if (ch == '\n' || ch == '\0')215 goto done;216 continue;217 case '\\':218 if (!expand) {219 if (!start)220 start = t;221 *t++ = '\\';222 ch = *++p;223 break;224 }225 226 switch (ch = *++p) {227 case '\0':228 case '\n':229 /* hmmm; fix it up as best we can */230 ch = '\\';231 --p;232 break;233 case 'b':234 ch = '\b';235 break;236 case 'f':237 ch = '\f';238 break;239 case 'n':240 ch = '\n';241 break;242 case 'r':243 ch = '\r';244 break;245 case 't':246 ch = '\t';247 break;248 }249 break;250 }251 if (!start)252 start = t;253 *t++ = (char) ch;254 }255 done: argv[argc] = (char *)NULL;256 *store_argc = argc;257 return(argv);143 register char *str; 144 int *store_argc; 145 Boolean expand; 146 { 147 register int argc, ch; 148 register char inquote, *p, *start, *t; 149 int len; 150 151 /* skip leading space chars. */ 152 for (; *str == ' ' || *str == '\t'; ++str) 153 continue; 154 155 /* allocate room for a copy of the string */ 156 if ((len = strlen(str) + 1) > curlen) { 157 if (buffer) 158 efree(buffer); 159 buffer = emalloc(curlen = len); 160 } 161 162 /* 163 * copy the string; at the same time, parse backslashes, 164 * quotes and build the argument list. 165 */ 166 argc = 1; 167 inquote = '\0'; 168 for (p = str, start = t = buffer;; ++p) { 169 switch(ch = *p) { 170 case '"': 171 case '\'': 172 if (inquote) { 173 if (inquote == ch) 174 inquote = '\0'; 175 else 176 break; 177 } else { 178 inquote = (char) ch; 179 /* Don't miss "" or '' */ 180 if (start == NULL && p[1] == inquote) { 181 start = t + 1; 182 break; 183 } 184 } 185 if (!expand) { 186 if (!start) 187 start = t; 188 *t++ = ch; 189 } 190 continue; 191 case ' ': 192 case '\t': 193 case '\n': 194 if (inquote) 195 break; 196 if (!start) 197 continue; 198 /* FALLTHROUGH */ 199 case '\0': 200 /* 201 * end of a token -- make sure there's enough argv 202 * space and save off a pointer. 203 */ 204 if (!start) 205 goto done; 206 207 *t++ = '\0'; 208 if (argc == argmax) { 209 argmax *= 2; /* ramp up fast */ 210 argv = (char **)erealloc(argv, 211 (argmax + 1) * sizeof(char *)); 212 } 213 argv[argc++] = start; 214 start = (char *)NULL; 215 if (ch == '\n' || ch == '\0') 216 goto done; 217 continue; 218 case '\\': 219 if (!expand) { 220 if (!start) 221 start = t; 222 *t++ = '\\'; 223 ch = *++p; 224 break; 225 } 226 227 switch (ch = *++p) { 228 case '\0': 229 case '\n': 230 /* hmmm; fix it up as best we can */ 231 ch = '\\'; 232 --p; 233 break; 234 case 'b': 235 ch = '\b'; 236 break; 237 case 'f': 238 ch = '\f'; 239 break; 240 case 'n': 241 ch = '\n'; 242 break; 243 case 'r': 244 ch = '\r'; 245 break; 246 case 't': 247 ch = '\t'; 248 break; 249 } 250 break; 251 } 252 if (!start) 253 start = t; 254 *t++ = (char) ch; 255 } 256 done: argv[argc] = (char *)NULL; 257 *store_argc = argc; 258 return(argv); 258 259 } 259 260 … … 270 271 char * 271 272 Str_FindSubstring(string, substring) 272 register char *string;/* String to search. */273 char *substring;/* Substring to find in string */274 { 275 register char *a, *b;276 277 /*278 * First scan quickly through the two strings looking for a single-279 * character match. When it's found, then compare the rest of the280 * substring.281 */282 283 for (b = substring; *string != 0; string += 1) {284 if (*string != *b)285 continue;286 a = string;287 for (;;) {288 if (*b == 0)289 return(string);290 if (*a++ != *b++)291 break;292 }293 b = substring;294 }295 return((char *) NULL);273 register char *string; /* String to search. */ 274 char *substring; /* Substring to find in string */ 275 { 276 register char *a, *b; 277 278 /* 279 * First scan quickly through the two strings looking for a single- 280 * character match. When it's found, then compare the rest of the 281 * substring. 282 */ 283 284 for (b = substring; *string != 0; string += 1) { 285 if (*string != *b) 286 continue; 287 a = string; 288 for (;;) { 289 if (*b == 0) 290 return(string); 291 if (*a++ != *b++) 292 break; 293 } 294 b = substring; 295 } 296 return((char *) NULL); 296 297 } 297 298 … … 309 310 int 310 311 Str_Match(string, pattern) 311 register char *string;/* String */312 register char *pattern;/* Pattern */313 { 314 char c2;315 316 for (;;) {317 /*318 * See if we're at the end of both the pattern and the319 * string. If, we succeeded. If we're at the end of the320 * pattern but not at the end of the string, we failed.321 */322 if (*pattern == 0)323 return(!*string);324 if (*string == 0 && *pattern != '*')325 return(0);326 /*327 * Check for a "*" as the next pattern character. It matches328 * any substring. We handle this by calling ourselves329 * recursively for each postfix of string, until either we330 * match or we reach the end of the string.331 */332 if (*pattern == '*') {333 pattern += 1;334 if (*pattern == 0)335 return(1);336 while (*string != 0) {337 if (Str_Match(string, pattern))338 return(1);339 ++string;340 }341 return(0);342 }343 /*344 * Check for a "?" as the next pattern character. It matches345 * any single character.346 */347 if (*pattern == '?')348 goto thisCharOK;349 /*350 * Check for a "[" as the next pattern character. It is351 * followed by a list of characters that are acceptable, or352 * by a range (two characters separated by "-").353 */354 if (*pattern == '[') {355 ++pattern;356 for (;;) {357 if ((*pattern == ']') || (*pattern == 0))358 return(0);359 if (*pattern == *string)360 break;361 if (pattern[1] == '-') {362 c2 = pattern[2];363 if (c2 == 0)364 return(0);365 if ((*pattern <= *string) &&366 (c2 >= *string))367 break;368 if ((*pattern >= *string) &&369 (c2 <= *string))370 break;371 pattern += 2;372 }373 ++pattern;374 }375 while ((*pattern != ']') && (*pattern != 0))376 ++pattern;377 goto thisCharOK;378 }379 /*380 * If the next pattern character is '/', just strip off the381 * '/' so we do exact matching on the character that follows.382 */383 if (*pattern == '\\') {384 ++pattern;385 if (*pattern == 0)386 return(0);387 }388 /*389 * There's no special character. Just make sure that the390 * next characters of each string match.391 */392 if (*pattern != *string)393 return(0);394 thisCharOK: ++pattern;395 ++string;396 }312 register char *string; /* String */ 313 register char *pattern; /* Pattern */ 314 { 315 char c2; 316 317 for (;;) { 318 /* 319 * See if we're at the end of both the pattern and the 320 * string. If, we succeeded. If we're at the end of the 321 * pattern but not at the end of the string, we failed. 322 */ 323 if (*pattern == 0) 324 return(!*string); 325 if (*string == 0 && *pattern != '*') 326 return(0); 327 /* 328 * Check for a "*" as the next pattern character. It matches 329 * any substring. We handle this by calling ourselves 330 * recursively for each postfix of string, until either we 331 * match or we reach the end of the string. 332 */ 333 if (*pattern == '*') { 334 pattern += 1; 335 if (*pattern == 0) 336 return(1); 337 while (*string != 0) { 338 if (Str_Match(string, pattern)) 339 return(1); 340 ++string; 341 } 342 return(0); 343 } 344 /* 345 * Check for a "?" as the next pattern character. It matches 346 * any single character. 347 */ 348 if (*pattern == '?') 349 goto thisCharOK; 350 /* 351 * Check for a "[" as the next pattern character. It is 352 * followed by a list of characters that are acceptable, or 353 * by a range (two characters separated by "-"). 354 */ 355 if (*pattern == '[') { 356 ++pattern; 357 for (;;) { 358 if ((*pattern == ']') || (*pattern == 0)) 359 return(0); 360 if (*pattern == *string) 361 break; 362 if (pattern[1] == '-') { 363 c2 = pattern[2]; 364 if (c2 == 0) 365 return(0); 366 if ((*pattern <= *string) && 367 (c2 >= *string)) 368 break; 369 if ((*pattern >= *string) && 370 (c2 <= *string)) 371 break; 372 pattern += 2; 373 } 374 ++pattern; 375 } 376 while ((*pattern != ']') && (*pattern != 0)) 377 ++pattern; 378 goto thisCharOK; 379 } 380 /* 381 * If the next pattern character is '/', just strip off the 382 * '/' so we do exact matching on the character that follows. 383 */ 384 if (*pattern == '\\') { 385 ++pattern; 386 if (*pattern == 0) 387 return(0); 388 } 389 /* 390 * There's no special character. Just make sure that the 391 * next characters of each string match. 392 */ 393 if (*pattern != *string) 394 return(0); 395 thisCharOK: ++pattern; 396 ++string; 397 } 397 398 } 398 399 … … 401 402 *----------------------------------------------------------------------- 402 403 * Str_SYSVMatch -- 403 * Check word against pattern for a match (% is wild),404 * Check word against pattern for a match (% is wild), 404 405 * 405 406 * Results: 406 * Returns the beginning position of a match or null. The number407 * of characters matched is returned in len.407 * Returns the beginning position of a match or null. The number 408 * of characters matched is returned in len. 408 409 * 409 410 * Side Effects: 410 * None411 * None 411 412 * 412 413 *----------------------------------------------------------------------- … … 414 415 char * 415 416 Str_SYSVMatch(word, pattern, len) 416 char *word;/* Word to examine */417 char *pattern;/* Pattern to examine against */418 int *len;/* Number of characters to substitute */417 char *word; /* Word to examine */ 418 char *pattern; /* Pattern to examine against */ 419 int *len; /* Number of characters to substitute */ 419 420 { 420 421 char *p = pattern; … … 423 424 424 425 if (*w == '\0') { 425 /* Zero-length word cannot be matched against */426 *len = 0;427 return NULL;426 /* Zero-length word cannot be matched against */ 427 *len = 0; 428 return NULL; 428 429 } 429 430 430 431 if (*p == '\0') { 431 /* Null pattern is the whole string */432 *len = strlen(w);433 return w;432 /* Null pattern is the whole string */ 433 *len = strlen(w); 434 return w; 434 435 } 435 436 436 437 if ((m = strchr(p, '%')) != NULL) { 437 /* check that the prefix matches */438 for (; p != m && *w && *w == *p; w++, p++)439 continue;440 441 if (p != m)442 return NULL;/* No match */443 444 if (*++p == '\0') {445 /* No more pattern, return the rest of the string */446 *len = strlen(w);447 return w;448 }438 /* check that the prefix matches */ 439 for (; p != m && *w && *w == *p; w++, p++) 440 continue; 441 442 if (p != m) 443 return NULL; /* No match */ 444 445 if (*++p == '\0') { 446 /* No more pattern, return the rest of the string */ 447 *len = strlen(w); 448 return w; 449 } 449 450 } 450 451 … … 453 454 /* Find a matching tail */ 454 455 do 455 if (strcmp(p, w) == 0) {456 *len = w - m;457 return m;458 }456 if (strcmp(p, w) == 0) { 457 *len = w - m; 458 return m; 459 } 459 460 while (*w++ != '\0'); 460 461 … … 466 467 *----------------------------------------------------------------------- 467 468 * Str_SYSVSubst -- 468 * Substitute '%' on the pattern with len characters from src.469 * If the pattern does not contain a '%' prepend len characters470 * from src.469 * Substitute '%' on the pattern with len characters from src. 470 * If the pattern does not contain a '%' prepend len characters 471 * from src. 471 472 * 472 473 * Results: 473 * None474 * None 474 475 * 475 476 * Side Effects: 476 * Places result on buf477 * Places result on buf 477 478 * 478 479 *----------------------------------------------------------------------- … … 488 489 489 490 if ((m = strchr(pat, '%')) != NULL) { 490 /* Copy the prefix */491 Buf_AddBytes(buf, m - pat, (Byte *) pat);492 /* skip the % */493 pat = m + 1;491 /* Copy the prefix */ 492 Buf_AddBytes(buf, m - pat, (Byte *) pat); 493 /* skip the % */ 494 pat = m + 1; 494 495 } 495 496 -
trunk/src/kmk/suff.c
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94";41 static char sccsid[] = "@(#)suff.c 8.4 (Berkeley) 3/21/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/suff.c,v 1.12.2.1 2001/03/09 01:13:24 tmm Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * suff.c -- 50 * Functions to maintain suffix lists and find implicit dependents51 * using suffix transformation rules51 * Functions to maintain suffix lists and find implicit dependents 52 * using suffix transformation rules 52 53 * 53 54 * Interface: 54 * Suff_Init Initialize all things to do with suffixes. 55 * 56 * Suff_End Cleanup the module 57 * 58 * Suff_DoPaths This function is used to make life easier 59 * when searching for a file according to its 60 * suffix. It takes the global search path, 61 * as defined using the .PATH: target, and appends 62 * its directories to the path of each of the 63 * defined suffixes, as specified using 64 * .PATH<suffix>: targets. In addition, all 65 * directories given for suffixes labeled as 66 * include files or libraries, using the .INCLUDES 67 * or .LIBS targets, are played with using 68 * Dir_MakeFlags to create the .INCLUDES and 69 * .LIBS global variables. 70 * 71 * Suff_ClearSuffixes Clear out all the suffixes and defined 72 * transformations. 73 * 74 * Suff_IsTransform Return TRUE if the passed string is the lhs 75 * of a transformation rule. 76 * 77 * Suff_AddSuffix Add the passed string as another known suffix. 78 * 79 * Suff_GetPath Return the search path for the given suffix. 80 * 81 * Suff_AddInclude Mark the given suffix as denoting an include 82 * file. 83 * 84 * Suff_AddLib Mark the given suffix as denoting a library. 85 * 86 * Suff_AddTransform Add another transformation to the suffix 87 * graph. Returns GNode suitable for framing, I 88 * mean, tacking commands, attributes, etc. on. 89 * 90 * Suff_SetNull Define the suffix to consider the suffix of 91 * any file that doesn't have a known one. 92 * 93 * Suff_FindDeps Find implicit sources for and the location of 94 * a target based on its suffix. Returns the 95 * bottom-most node added to the graph or NILGNODE 96 * if the target had no implicit sources. 97 */ 98 99 #include <stdio.h> 100 #include "make.h" 101 #include "hash.h" 102 #include "dir.h" 103 104 static Lst sufflist; /* Lst of suffixes */ 105 static Lst suffClean; /* Lst of suffixes to be cleaned */ 106 static Lst srclist; /* Lst of sources */ 107 static Lst transforms; /* Lst of transformation rules */ 108 109 static int sNum = 0; /* Counter for assigning suffix numbers */ 55 * Suff_Init Initialize all things to do with suffixes. 56 * 57 * Suff_End Cleanup the module 58 * 59 * Suff_DoPaths This function is used to make life easier 60 * when searching for a file according to its 61 * suffix. It takes the global search path, 62 * as defined using the .PATH: target, and appends 63 * its directories to the path of each of the 64 * defined suffixes, as specified using 65 * .PATH<suffix>: targets. In addition, all 66 * directories given for suffixes labeled as 67 * include files or libraries, using the .INCLUDES 68 * or .LIBS targets, are played with using 69 * Dir_MakeFlags to create the .INCLUDES and 70 * .LIBS global variables. 71 * 72 * Suff_ClearSuffixes Clear out all the suffixes and defined 73 * transformations. 74 * 75 * Suff_IsTransform Return TRUE if the passed string is the lhs 76 * of a transformation rule. 77 * 78 * Suff_AddSuffix Add the passed string as another known suffix. 79 * 80 * Suff_GetPath Return the search path for the given suffix. 81 * 82 * Suff_AddInclude Mark the given suffix as denoting an include 83 * file. 84 * 85 * Suff_AddLib Mark the given suffix as denoting a library. 86 * 87 * Suff_AddTransform Add another transformation to the suffix 88 * graph. Returns GNode suitable for framing, I 89 * mean, tacking commands, attributes, etc. on. 90 * 91 * Suff_SetNull Define the suffix to consider the suffix of 92 * any file that doesn't have a known one. 93 * 94 * Suff_FindDeps Find implicit sources for and the location of 95 * a target based on its suffix. Returns the 96 * bottom-most node added to the graph or NILGNODE 97 * if the target had no implicit sources. 98 */ 99 100 #include <stdio.h> 101 #include <strings.h> 102 #include "make.h" 103 #include "hash.h" 104 #include "dir.h" 105 106 static Lst sufflist; /* Lst of suffixes */ 107 static Lst suffClean; /* Lst of suffixes to be cleaned */ 108 static Lst srclist; /* Lst of sources */ 109 static Lst transforms; /* Lst of transformation rules */ 110 111 static int sNum = 0; /* Counter for assigning suffix numbers */ 110 112 111 113 /* … … 113 115 */ 114 116 typedef struct _Suff { 115 char *name; /* The suffix itself */116 int nameLen;/* Length of the suffix */117 short flags;/* Type of suffix */118 #define SUFF_INCLUDE 0x01/* One which is #include'd */117 char *name; /* The suffix itself */ 118 int nameLen; /* Length of the suffix */ 119 short flags; /* Type of suffix */ 120 #define SUFF_INCLUDE 0x01 /* One which is #include'd */ 119 121 #ifdef USE_ARCHIVES 120 #define SUFF_LIBRARY 0x02/* One which contains a library */122 #define SUFF_LIBRARY 0x02 /* One which contains a library */ 121 123 #endif 122 #define SUFF_NULL 0x04/* The empty suffix */123 Lst searchPath;/* The path along which files of this suffix124 * may be found */125 int sNum; /* The suffix number */126 int refCount;/* Reference count of list membership */127 Lst parents; /* Suffixes we have a transformation to */128 Lst children; /* Suffixes we have a transformation from */129 Lst ref;/* List of lists this suffix is referenced */124 #define SUFF_NULL 0x04 /* The empty suffix */ 125 Lst searchPath; /* The path along which files of this suffix 126 * may be found */ 127 int sNum; /* The suffix number */ 128 int refCount; /* Reference count of list membership */ 129 Lst parents; /* Suffixes we have a transformation to */ 130 Lst children; /* Suffixes we have a transformation from */ 131 Lst ref; /* List of lists this suffix is referenced */ 130 132 } Suff; 131 133 … … 134 136 */ 135 137 typedef struct _Src { 136 char *file; /* The file to look for */137 char *pref;/* Prefix from which file was formed */138 Suff *suff; /* The suffix on the file */139 struct _Src *parent; /* The Src for which this is a source */140 GNode *node; /* The node describing the file */141 int children;/* Count of existing children (so we don't efree142 * this thing too early or never nuke it) */138 char *file; /* The file to look for */ 139 char *pref; /* Prefix from which file was formed */ 140 Suff *suff; /* The suffix on the file */ 141 struct _Src *parent; /* The Src for which this is a source */ 142 GNode *node; /* The node describing the file */ 143 int children; /* Count of existing children (so we don't efree 144 * this thing too early or never nuke it) */ 143 145 #ifdef DEBUG_SRC 144 Lst cp;/* Debug; children list */146 Lst cp; /* Debug; children list */ 145 147 #endif 146 148 } Src; … … 155 157 } LstSrc; 156 158 157 static Suff *suffNull;/* The NULL suffix for this run */158 static Suff *emptySuff;/* The empty suffix required for POSIX159 * single-suffix transformation rules */159 static Suff *suffNull; /* The NULL suffix for this run */ 160 static Suff *emptySuff; /* The empty suffix required for POSIX 161 * single-suffix transformation rules */ 160 162 161 163 … … 187 189 static int SuffPrintTrans __P((ClientData, ClientData)); 188 190 189 /*************** Lst Predicates ****************/191 /*************** Lst Predicates ****************/ 190 192 /*- 191 193 *----------------------------------------------------------------------- 192 194 * SuffStrIsPrefix -- 193 * See if pref is a prefix of str.194 * 195 * Results: 196 * NULL if it ain't, pointer to character in str after prefix if so197 * 198 * Side Effects: 199 * None195 * See if pref is a prefix of str. 196 * 197 * Results: 198 * NULL if it ain't, pointer to character in str after prefix if so 199 * 200 * Side Effects: 201 * None 200 202 *----------------------------------------------------------------------- 201 203 */ 202 204 static char * 203 205 SuffStrIsPrefix (pref, str) 204 register char *pref; /* possible prefix */205 register char *str; /* string to check */206 register char *pref; /* possible prefix */ 207 register char *str; /* string to check */ 206 208 { 207 209 while (*str && *pref == *str) { 208 pref++;209 str++;210 pref++; 211 str++; 210 212 } 211 213 … … 216 218 *----------------------------------------------------------------------- 217 219 * SuffSuffIsSuffix -- 218 * See if suff is a suffix of str. Str should point to THE END of the219 * string to check. (THE END == the null byte)220 * 221 * Results: 222 * NULL if it ain't, pointer to character in str before suffix if223 * it is.224 * 225 * Side Effects: 226 * None220 * See if suff is a suffix of str. Str should point to THE END of the 221 * string to check. (THE END == the null byte) 222 * 223 * Results: 224 * NULL if it ain't, pointer to character in str before suffix if 225 * it is. 226 * 227 * Side Effects: 228 * None 227 229 *----------------------------------------------------------------------- 228 230 */ 229 231 static char * 230 232 SuffSuffIsSuffix (s, str) 231 register Suff *s; /* possible suffix */232 char *str; /* string to examine */233 { 234 register char *p1; /* Pointer into suffix name */235 register char *p2; /* Pointer into string being examined */233 register Suff *s; /* possible suffix */ 234 char *str; /* string to examine */ 235 { 236 register char *p1; /* Pointer into suffix name */ 237 register char *p2; /* Pointer into string being examined */ 236 238 237 239 p1 = s->name + s->nameLen; … … 239 241 240 242 while (p1 >= s->name && *p1 == *p2) { 241 p1--;242 p2--;243 p1--; 244 p2--; 243 245 } 244 246 … … 249 251 *----------------------------------------------------------------------- 250 252 * SuffSuffIsSuffixP -- 251 * Predicate form of SuffSuffIsSuffix. Passed as the callback function252 * to Lst_Find.253 * 254 * Results: 255 * 0 if the suffix is the one desired, non-zero if not.256 * 257 * Side Effects: 258 * None.253 * Predicate form of SuffSuffIsSuffix. Passed as the callback function 254 * to Lst_Find. 255 * 256 * Results: 257 * 0 if the suffix is the one desired, non-zero if not. 258 * 259 * Side Effects: 260 * None. 259 261 * 260 262 *----------------------------------------------------------------------- … … 271 273 *----------------------------------------------------------------------- 272 274 * SuffSuffHasNameP -- 273 * Callback procedure for finding a suffix based on its name. Used by274 * Suff_GetPath.275 * 276 * Results: 277 * 0 if the suffix is of the given name. non-zero otherwise.278 * 279 * Side Effects: 280 * None275 * Callback procedure for finding a suffix based on its name. Used by 276 * Suff_GetPath. 277 * 278 * Results: 279 * 0 if the suffix is of the given name. non-zero otherwise. 280 * 281 * Side Effects: 282 * None 281 283 *----------------------------------------------------------------------- 282 284 */ 283 285 static int 284 286 SuffSuffHasNameP (s, sname) 285 ClientData s; /* Suffix to check */286 ClientData sname; /* Desired name */287 ClientData s; /* Suffix to check */ 288 ClientData sname; /* Desired name */ 287 289 { 288 290 return (strcmp ((char *) sname, ((Suff *) s)->name)); … … 292 294 *----------------------------------------------------------------------- 293 295 * SuffSuffIsPrefix -- 294 * See if the suffix described by s is a prefix of the string. Care295 * must be taken when using this to search for transformations and296 * what-not, since there could well be two suffixes, one of which297 * is a prefix of the other...298 * 299 * Results: 300 * 0 if s is a prefix of str. non-zero otherwise301 * 302 * Side Effects: 303 * None296 * See if the suffix described by s is a prefix of the string. Care 297 * must be taken when using this to search for transformations and 298 * what-not, since there could well be two suffixes, one of which 299 * is a prefix of the other... 300 * 301 * Results: 302 * 0 if s is a prefix of str. non-zero otherwise 303 * 304 * Side Effects: 305 * None 304 306 *----------------------------------------------------------------------- 305 307 */ 306 308 static int 307 309 SuffSuffIsPrefix (s, str) 308 ClientData s; /* suffix to compare */309 ClientData str; /* string to examine */310 ClientData s; /* suffix to compare */ 311 ClientData str; /* string to examine */ 310 312 { 311 313 return (SuffStrIsPrefix (((Suff *) s)->name, (char *) str) == NULL ? 1 : 0); … … 315 317 *----------------------------------------------------------------------- 316 318 * SuffGNHasNameP -- 317 * See if the graph node has the desired name318 * 319 * Results: 320 * 0 if it does. non-zero if it doesn't321 * 322 * Side Effects: 323 * None319 * See if the graph node has the desired name 320 * 321 * Results: 322 * 0 if it does. non-zero if it doesn't 323 * 324 * Side Effects: 325 * None 324 326 *----------------------------------------------------------------------- 325 327 */ 326 328 static int 327 329 SuffGNHasNameP (gn, name) 328 ClientData gn; /* current node we're looking at */329 ClientData name; /* name we're looking for */330 ClientData gn; /* current node we're looking at */ 331 ClientData name; /* name we're looking for */ 330 332 { 331 333 return (strcmp ((char *) name, ((GNode *) gn)->name)); 332 334 } 333 335 334 /*********** Maintenance Functions ************/336 /*********** Maintenance Functions ************/ 335 337 336 338 /*- 337 339 *----------------------------------------------------------------------- 338 340 * SuffFree -- 339 * Free up all memory associated with the given suffix structure.340 * 341 * Results: 342 * none343 * 344 * Side Effects: 345 * the suffix entry is detroyed341 * Free up all memory associated with the given suffix structure. 342 * 343 * Results: 344 * none 345 * 346 * Side Effects: 347 * the suffix entry is detroyed 346 348 *----------------------------------------------------------------------- 347 349 */ … … 353 355 354 356 if (s == suffNull) 355 suffNull = NULL;357 suffNull = NULL; 356 358 357 359 if (s == emptySuff) 358 emptySuff = NULL;360 emptySuff = NULL; 359 361 360 362 Lst_Destroy (s->ref, NOFREE); … … 370 372 *----------------------------------------------------------------------- 371 373 * SuffRemove -- 372 * Remove the suffix into the list373 * 374 * Results: 375 * None376 * 377 * Side Effects: 378 * The reference count for the suffix is decremented374 * Remove the suffix into the list 375 * 376 * Results: 377 * None 378 * 379 * Side Effects: 380 * The reference count for the suffix is decremented 379 381 *----------------------------------------------------------------------- 380 382 */ … … 386 388 LstNode ln = Lst_Member(l, (ClientData)s); 387 389 if (ln != NILLNODE) { 388 Lst_Remove(l, ln);389 s->refCount--;390 Lst_Remove(l, ln); 391 s->refCount--; 390 392 } 391 393 } … … 395 397 *----------------------------------------------------------------------- 396 398 * SuffInsert -- 397 * Insert the suffix into the list keeping the list ordered by suffix398 * numbers.399 * 400 * Results: 401 * None402 * 403 * Side Effects: 404 * The reference count of the suffix is incremented399 * Insert the suffix into the list keeping the list ordered by suffix 400 * numbers. 401 * 402 * Results: 403 * None 404 * 405 * Side Effects: 406 * The reference count of the suffix is incremented 405 407 *----------------------------------------------------------------------- 406 408 */ 407 409 static void 408 410 SuffInsert (l, s) 409 Lst l; /* the list where in s should be inserted */410 Suff *s; /* the suffix to insert */411 { 412 LstNode ln;/* current element in l we're examining */413 Suff *s2 = NULL; /* the suffix descriptor in this element */411 Lst l; /* the list where in s should be inserted */ 412 Suff *s; /* the suffix to insert */ 413 { 414 LstNode ln; /* current element in l we're examining */ 415 Suff *s2 = NULL; /* the suffix descriptor in this element */ 414 416 415 417 if (Lst_Open (l) == FAILURE) { 416 return;418 return; 417 419 } 418 420 while ((ln = Lst_Next (l)) != NILLNODE) { 419 s2 = (Suff *) Lst_Datum (ln);420 if (s2->sNum >= s->sNum) {421 break;422 }421 s2 = (Suff *) Lst_Datum (ln); 422 if (s2->sNum >= s->sNum) { 423 break; 424 } 423 425 } 424 426 425 427 Lst_Close (l); 426 428 if (DEBUG(SUFF)) { 427 printf("inserting %s(%d)...", s->name, s->sNum);429 printf("inserting %s(%d)...", s->name, s->sNum); 428 430 } 429 431 if (ln == NILLNODE) { 430 if (DEBUG(SUFF)) {431 printf("at end of list\n");432 }433 (void)Lst_AtEnd (l, (ClientData)s);434 s->refCount++;435 (void)Lst_AtEnd(s->ref, (ClientData) l);432 if (DEBUG(SUFF)) { 433 printf("at end of list\n"); 434 } 435 (void)Lst_AtEnd (l, (ClientData)s); 436 s->refCount++; 437 (void)Lst_AtEnd(s->ref, (ClientData) l); 436 438 } else if (s2->sNum != s->sNum) { 437 if (DEBUG(SUFF)) {438 printf("before %s(%d)\n", s2->name, s2->sNum);439 }440 (void)Lst_Insert (l, ln, (ClientData)s);441 s->refCount++;442 (void)Lst_AtEnd(s->ref, (ClientData) l);439 if (DEBUG(SUFF)) { 440 printf("before %s(%d)\n", s2->name, s2->sNum); 441 } 442 (void)Lst_Insert (l, ln, (ClientData)s); 443 s->refCount++; 444 (void)Lst_AtEnd(s->ref, (ClientData) l); 443 445 } else if (DEBUG(SUFF)) { 444 printf("already there\n");446 printf("already there\n"); 445 447 } 446 448 } … … 449 451 *----------------------------------------------------------------------- 450 452 * Suff_ClearSuffixes -- 451 * This is gross. Nuke the list of suffixes but keep all transformation452 * rules around. The transformation graph is destroyed in this process,453 * but we leave the list of rules so when a new graph is formed the rules454 * will remain.455 * This function is called from the parse module when a456 * .SUFFIXES:\n line is encountered.457 * 458 * Results: 459 * none460 * 461 * Side Effects: 462 * the sufflist and its graph nodes are destroyed453 * This is gross. Nuke the list of suffixes but keep all transformation 454 * rules around. The transformation graph is destroyed in this process, 455 * but we leave the list of rules so when a new graph is formed the rules 456 * will remain. 457 * This function is called from the parse module when a 458 * .SUFFIXES:\n line is encountered. 459 * 460 * Results: 461 * none 462 * 463 * Side Effects: 464 * the sufflist and its graph nodes are destroyed 463 465 *----------------------------------------------------------------------- 464 466 */ … … 483 485 *----------------------------------------------------------------------- 484 486 * SuffParseTransform -- 485 * Parse a transformation string to find its two component suffixes.486 * 487 * Results: 488 * TRUE if the string is a valid transformation and FALSE otherwise.489 * 490 * Side Effects: 491 * The passed pointers are overwritten.487 * Parse a transformation string to find its two component suffixes. 488 * 489 * Results: 490 * TRUE if the string is a valid transformation and FALSE otherwise. 491 * 492 * Side Effects: 493 * The passed pointers are overwritten. 492 494 * 493 495 *----------------------------------------------------------------------- … … 495 497 static Boolean 496 498 SuffParseTransform(str, srcPtr, targPtr) 497 char *str;/* String being parsed */498 Suff **srcPtr;/* Place to store source of trans. */499 Suff **targPtr;/* Place to store target of trans. */500 { 501 register LstNode srcLn;/* element in suffix list of trans source*/502 register Suff *src;/* Source of transformation */503 register LstNode targLn; /* element in suffix list of trans target*/504 register char *str2;/* Extra pointer (maybe target suffix) */505 LstNode singleLn; /* element in suffix list of any suffix506 * that exactly matches str */507 Suff *single = NULL;/* Source of possible transformation to508 * null suffix */499 char *str; /* String being parsed */ 500 Suff **srcPtr; /* Place to store source of trans. */ 501 Suff **targPtr; /* Place to store target of trans. */ 502 { 503 register LstNode srcLn; /* element in suffix list of trans source*/ 504 register Suff *src; /* Source of transformation */ 505 register LstNode targLn; /* element in suffix list of trans target*/ 506 register char *str2; /* Extra pointer (maybe target suffix) */ 507 LstNode singleLn; /* element in suffix list of any suffix 508 * that exactly matches str */ 509 Suff *single = NULL;/* Source of possible transformation to 510 * null suffix */ 509 511 510 512 srcLn = NILLNODE; … … 518 520 */ 519 521 for (;;) { 520 if (srcLn == NILLNODE) {521 srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix);522 } else {523 srcLn = Lst_FindFrom (sufflist, Lst_Succ(srcLn), (ClientData)str,524 SuffSuffIsPrefix);525 }526 if (srcLn == NILLNODE) {527 /*528 * Ran out of source suffixes -- no such rule529 */530 if (singleLn != NILLNODE) {531 /*532 * Not so fast Mr. Smith! There was a suffix that encompassed533 * the entire string, so we assume it was a transformation534 * to the null suffix (thank you POSIX). We still prefer to535 * find a double rule over a singleton, hence we leave this536 * check until the end.537 *538 * XXX: Use emptySuff over suffNull?539 */540 *srcPtr = single;541 *targPtr = suffNull;542 return(TRUE);543 }544 return (FALSE);545 }546 src = (Suff *) Lst_Datum (srcLn);547 str2 = str + src->nameLen;548 if (*str2 == '\0') {549 single = src;550 singleLn = srcLn;551 } else {552 targLn = Lst_Find(sufflist, (ClientData)str2, SuffSuffHasNameP);553 if (targLn != NILLNODE) {554 *srcPtr = src;555 *targPtr = (Suff *)Lst_Datum(targLn);556 return (TRUE);557 }558 }522 if (srcLn == NILLNODE) { 523 srcLn = Lst_Find(sufflist, (ClientData)str, SuffSuffIsPrefix); 524 } else { 525 srcLn = Lst_FindFrom (sufflist, Lst_Succ(srcLn), (ClientData)str, 526 SuffSuffIsPrefix); 527 } 528 if (srcLn == NILLNODE) { 529 /* 530 * Ran out of source suffixes -- no such rule 531 */ 532 if (singleLn != NILLNODE) { 533 /* 534 * Not so fast Mr. Smith! There was a suffix that encompassed 535 * the entire string, so we assume it was a transformation 536 * to the null suffix (thank you POSIX). We still prefer to 537 * find a double rule over a singleton, hence we leave this 538 * check until the end. 539 * 540 * XXX: Use emptySuff over suffNull? 541 */ 542 *srcPtr = single; 543 *targPtr = suffNull; 544 return(TRUE); 545 } 546 return (FALSE); 547 } 548 src = (Suff *) Lst_Datum (srcLn); 549 str2 = str + src->nameLen; 550 if (*str2 == '\0') { 551 single = src; 552 singleLn = srcLn; 553 } else { 554 targLn = Lst_Find(sufflist, (ClientData)str2, SuffSuffHasNameP); 555 if (targLn != NILLNODE) { 556 *srcPtr = src; 557 *targPtr = (Suff *)Lst_Datum(targLn); 558 return (TRUE); 559 } 560 } 559 561 } 560 562 } … … 563 565 *----------------------------------------------------------------------- 564 566 * Suff_IsTransform -- 565 * Return TRUE if the given string is a transformation rule566 * 567 * 568 * Results: 569 * TRUE if the string is a concatenation of two known suffixes.570 * FALSE otherwise571 * 572 * Side Effects: 573 * None567 * Return TRUE if the given string is a transformation rule 568 * 569 * 570 * Results: 571 * TRUE if the string is a concatenation of two known suffixes. 572 * FALSE otherwise 573 * 574 * Side Effects: 575 * None 574 576 *----------------------------------------------------------------------- 575 577 */ 576 578 Boolean 577 579 Suff_IsTransform (str) 578 char *str; /* string to check */579 { 580 Suff *src, *targ;580 char *str; /* string to check */ 581 { 582 Suff *src, *targ; 581 583 582 584 return (SuffParseTransform(str, &src, &targ)); … … 586 588 *----------------------------------------------------------------------- 587 589 * Suff_AddTransform -- 588 * Add the transformation rule described by the line to the589 * list of rules and place the transformation itself in the graph590 * 591 * Results: 592 * The node created for the transformation in the transforms list593 * 594 * Side Effects: 595 * The node is placed on the end of the transforms Lst and links are596 * made between the two suffixes mentioned in the target name590 * Add the transformation rule described by the line to the 591 * list of rules and place the transformation itself in the graph 592 * 593 * Results: 594 * The node created for the transformation in the transforms list 595 * 596 * Side Effects: 597 * The node is placed on the end of the transforms Lst and links are 598 * made between the two suffixes mentioned in the target name 597 599 *----------------------------------------------------------------------- 598 600 */ 599 601 GNode * 600 602 Suff_AddTransform (line) 601 char *line; /* name of transformation to add */602 { 603 GNode *gn; /* GNode of transformation rule */604 Suff *s, /* source suffix */605 *t; /* target suffix */606 LstNode ln;/* Node for existing transformation */603 char *line; /* name of transformation to add */ 604 { 605 GNode *gn; /* GNode of transformation rule */ 606 Suff *s, /* source suffix */ 607 *t; /* target suffix */ 608 LstNode ln; /* Node for existing transformation */ 607 609 608 610 ln = Lst_Find (transforms, (ClientData)line, SuffGNHasNameP); 609 611 if (ln == NILLNODE) { 610 /*611 * Make a new graph node for the transformation. It will be filled in612 * by the Parse module.613 */614 gn = Targ_NewGN (line);615 (void)Lst_AtEnd (transforms, (ClientData)gn);612 /* 613 * Make a new graph node for the transformation. It will be filled in 614 * by the Parse module. 615 */ 616 gn = Targ_NewGN (line); 617 (void)Lst_AtEnd (transforms, (ClientData)gn); 616 618 } else { 617 /*618 * New specification for transformation rule. Just nuke the old list619 * of commands so they can be filled in again... We don't actually620 * efree the commands themselves, because a given command can be621 * attached to several different transformations.622 */623 gn = (GNode *) Lst_Datum (ln);624 Lst_Destroy (gn->commands, NOFREE);625 Lst_Destroy (gn->children, NOFREE);626 gn->commands = Lst_Init (FALSE);627 gn->children = Lst_Init (FALSE);619 /* 620 * New specification for transformation rule. Just nuke the old list 621 * of commands so they can be filled in again... We don't actually 622 * efree the commands themselves, because a given command can be 623 * attached to several different transformations. 624 */ 625 gn = (GNode *) Lst_Datum (ln); 626 Lst_Destroy (gn->commands, NOFREE); 627 Lst_Destroy (gn->children, NOFREE); 628 gn->commands = Lst_Init (FALSE); 629 gn->children = Lst_Init (FALSE); 628 630 } 629 631 … … 636 638 */ 637 639 if (DEBUG(SUFF)) { 638 printf("defining transformation from `%s' to `%s'\n",639 s->name, t->name);640 printf("defining transformation from `%s' to `%s'\n", 641 s->name, t->name); 640 642 } 641 643 SuffInsert (t->children, s); … … 648 650 *----------------------------------------------------------------------- 649 651 * Suff_EndTransform -- 650 * Handle the finish of a transformation definition, removing the651 * transformation from the graph if it has neither commands nor652 * sources. This is a callback procedure for the Parse module via653 * Lst_ForEach654 * 655 * Results: 656 * === 0657 * 658 * Side Effects: 659 * If the node has no commands or children, the children and parents660 * lists of the affected suffices are altered.652 * Handle the finish of a transformation definition, removing the 653 * transformation from the graph if it has neither commands nor 654 * sources. This is a callback procedure for the Parse module via 655 * Lst_ForEach 656 * 657 * Results: 658 * === 0 659 * 660 * Side Effects: 661 * If the node has no commands or children, the children and parents 662 * lists of the affected suffices are altered. 661 663 * 662 664 *----------------------------------------------------------------------- … … 664 666 int 665 667 Suff_EndTransform(gnp, dummy) 666 ClientData gnp; /* Node for transformation */667 ClientData dummy; /* Node for transformation */668 ClientData gnp; /* Node for transformation */ 669 ClientData dummy; /* Node for transformation */ 668 670 { 669 671 GNode *gn = (GNode *) gnp; 670 672 671 673 if ((gn->type & OP_TRANSFORM) && Lst_IsEmpty(gn->commands) && 672 Lst_IsEmpty(gn->children))674 Lst_IsEmpty(gn->children)) 673 675 { 674 Suff*s, *t;675 676 (void)SuffParseTransform(gn->name, &s, &t);677 678 if (DEBUG(SUFF)) {679 printf("deleting transformation from `%s' to `%s'\n",680 s->name, t->name);681 }682 683 /*684 * Remove the source from the target's children list. We check for a685 * nil return to handle a beanhead saying something like686 * .c.o .c.o:687 *688 * We'll be called twice when the next target is seen, but .c and .o689 * are only linked once...690 */691 SuffRemove(t->children, s);692 693 /*694 * Remove the target from the source's parents list695 */696 SuffRemove(s->parents, t);676 Suff *s, *t; 677 678 (void)SuffParseTransform(gn->name, &s, &t); 679 680 if (DEBUG(SUFF)) { 681 printf("deleting transformation from `%s' to `%s'\n", 682 s->name, t->name); 683 } 684 685 /* 686 * Remove the source from the target's children list. We check for a 687 * nil return to handle a beanhead saying something like 688 * .c.o .c.o: 689 * 690 * We'll be called twice when the next target is seen, but .c and .o 691 * are only linked once... 692 */ 693 SuffRemove(t->children, s); 694 695 /* 696 * Remove the target from the source's parents list 697 */ 698 SuffRemove(s->parents, t); 697 699 } else if ((gn->type & OP_TRANSFORM) && DEBUG(SUFF)) { 698 printf("transformation %s complete\n", gn->name);700 printf("transformation %s complete\n", gn->name); 699 701 } 700 702 … … 705 707 *----------------------------------------------------------------------- 706 708 * SuffRebuildGraph -- 707 * Called from Suff_AddSuffix via Lst_ForEach to search through the708 * list of existing transformation rules and rebuild the transformation709 * graph when it has been destroyed by Suff_ClearSuffixes. If the710 * given rule is a transformation involving this suffix and another,711 * existing suffix, the proper relationship is established between712 * the two.713 * 714 * Results: 715 * Always 0.716 * 717 * Side Effects: 718 * The appropriate links will be made between this suffix and719 * others if transformation rules exist for it.709 * Called from Suff_AddSuffix via Lst_ForEach to search through the 710 * list of existing transformation rules and rebuild the transformation 711 * graph when it has been destroyed by Suff_ClearSuffixes. If the 712 * given rule is a transformation involving this suffix and another, 713 * existing suffix, the proper relationship is established between 714 * the two. 715 * 716 * Results: 717 * Always 0. 718 * 719 * Side Effects: 720 * The appropriate links will be made between this suffix and 721 * others if transformation rules exist for it. 720 722 * 721 723 *----------------------------------------------------------------------- … … 724 726 SuffRebuildGraph(transformp, sp) 725 727 ClientData transformp; /* Transformation to test */ 726 ClientData sp; /* Suffix to rebuild */727 { 728 GNode *transform = (GNode *) transformp;729 Suff *s = (Suff *) sp;730 char *cp;731 LstNode ln;732 Suff *s2 = NULL;728 ClientData sp; /* Suffix to rebuild */ 729 { 730 GNode *transform = (GNode *) transformp; 731 Suff *s = (Suff *) sp; 732 char *cp; 733 LstNode ln; 734 Suff *s2 = NULL; 733 735 734 736 /* … … 737 739 cp = SuffStrIsPrefix(s->name, transform->name); 738 740 if (cp != (char *)NULL) { 739 if (cp[0] == '\0') /* null rule */740 s2 = suffNull;741 else {742 ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP);743 if (ln != NILLNODE)744 s2 = (Suff *)Lst_Datum(ln);745 }746 if (s2 != NULL) {747 /*748 * Found target. Link in and return, since it can't be anything749 * else.750 */751 SuffInsert(s2->children, s);752 SuffInsert(s->parents, s2);753 return(0);754 }741 if (cp[0] == '\0') /* null rule */ 742 s2 = suffNull; 743 else { 744 ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffHasNameP); 745 if (ln != NILLNODE) 746 s2 = (Suff *)Lst_Datum(ln); 747 } 748 if (s2 != NULL) { 749 /* 750 * Found target. Link in and return, since it can't be anything 751 * else. 752 */ 753 SuffInsert(s2->children, s); 754 SuffInsert(s->parents, s2); 755 return(0); 756 } 755 757 } 756 758 … … 760 762 cp = SuffSuffIsSuffix(s, transform->name + strlen(transform->name)); 761 763 if (cp != (char *)NULL) { 762 /*763 * Null-terminate the source suffix in order to find it.764 */765 cp[1] = '\0';766 ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP);767 /*768 * Replace the start of the target suffix769 */770 cp[1] = s->name[0];771 if (ln != NILLNODE) {772 /*773 * Found it -- establish the proper relationship774 */775 s2 = (Suff *)Lst_Datum(ln);776 SuffInsert(s->children, s2);777 SuffInsert(s2->parents, s);778 }764 /* 765 * Null-terminate the source suffix in order to find it. 766 */ 767 cp[1] = '\0'; 768 ln = Lst_Find(sufflist, (ClientData)transform->name, SuffSuffHasNameP); 769 /* 770 * Replace the start of the target suffix 771 */ 772 cp[1] = s->name[0]; 773 if (ln != NILLNODE) { 774 /* 775 * Found it -- establish the proper relationship 776 */ 777 s2 = (Suff *)Lst_Datum(ln); 778 SuffInsert(s->children, s2); 779 SuffInsert(s2->parents, s); 780 } 779 781 } 780 782 return(0); … … 784 786 *----------------------------------------------------------------------- 785 787 * Suff_AddSuffix -- 786 * Add the suffix in string to the end of the list of known suffixes.787 * Should we restructure the suffix graph? Make doesn't...788 * 789 * Results: 790 * None791 * 792 * Side Effects: 793 * A GNode is created for the suffix and a Suff structure is created and794 * added to the suffixes list unless the suffix was already known.788 * Add the suffix in string to the end of the list of known suffixes. 789 * Should we restructure the suffix graph? Make doesn't... 790 * 791 * Results: 792 * None 793 * 794 * Side Effects: 795 * A GNode is created for the suffix and a Suff structure is created and 796 * added to the suffixes list unless the suffix was already known. 795 797 *----------------------------------------------------------------------- 796 798 */ 797 799 void 798 800 Suff_AddSuffix (str) 799 char *str; /* the name of the suffix to add */800 { 801 Suff *s; /* new suffix descriptor */802 LstNode ln;801 char *str; /* the name of the suffix to add */ 802 { 803 Suff *s; /* new suffix descriptor */ 804 LstNode ln; 803 805 804 806 ln = Lst_Find (sufflist, (ClientData)str, SuffSuffHasNameP); 805 807 if (ln == NILLNODE) { 806 s = (Suff *) emalloc (sizeof (Suff));807 808 s->name =estrdup (str);809 s->nameLen =strlen (s->name);810 s->searchPath = Lst_Init (FALSE);811 s->children =Lst_Init (FALSE);812 s->parents =Lst_Init (FALSE);813 s->ref =Lst_Init (FALSE);814 s->sNum =sNum++;815 s->flags =0;816 s->refCount =0;817 818 (void)Lst_AtEnd (sufflist, (ClientData)s);819 /*820 * Look for any existing transformations from or to this suffix.821 * XXX: Only do this after a Suff_ClearSuffixes?822 */823 Lst_ForEach (transforms, SuffRebuildGraph, (ClientData)s);808 s = (Suff *) emalloc (sizeof (Suff)); 809 810 s->name = estrdup (str); 811 s->nameLen = strlen (s->name); 812 s->searchPath = Lst_Init (FALSE); 813 s->children = Lst_Init (FALSE); 814 s->parents = Lst_Init (FALSE); 815 s->ref = Lst_Init (FALSE); 816 s->sNum = sNum++; 817 s->flags = 0; 818 s->refCount = 0; 819 820 (void)Lst_AtEnd (sufflist, (ClientData)s); 821 /* 822 * Look for any existing transformations from or to this suffix. 823 * XXX: Only do this after a Suff_ClearSuffixes? 824 */ 825 Lst_ForEach (transforms, SuffRebuildGraph, (ClientData)s); 824 826 } 825 827 } … … 828 830 *----------------------------------------------------------------------- 829 831 * Suff_GetPath -- 830 * Return the search path for the given suffix, if it's defined.831 * 832 * Results: 833 * The searchPath for the desired suffix or NILLST if the suffix isn't834 * defined.835 * 836 * Side Effects: 837 * None832 * Return the search path for the given suffix, if it's defined. 833 * 834 * Results: 835 * The searchPath for the desired suffix or NILLST if the suffix isn't 836 * defined. 837 * 838 * Side Effects: 839 * None 838 840 *----------------------------------------------------------------------- 839 841 */ 840 842 Lst 841 843 Suff_GetPath (sname) 842 char *sname;843 { 844 LstNode ln;845 Suff *s;844 char *sname; 845 { 846 LstNode ln; 847 Suff *s; 846 848 847 849 ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); 848 850 if (ln == NILLNODE) { 849 return (NILLST);851 return (NILLST); 850 852 } else { 851 s = (Suff *) Lst_Datum (ln);852 return (s->searchPath);853 s = (Suff *) Lst_Datum (ln); 854 return (s->searchPath); 853 855 } 854 856 } … … 857 859 *----------------------------------------------------------------------- 858 860 * Suff_DoPaths -- 859 * Extend the search paths for all suffixes to include the default860 * search path.861 * 862 * Results: 863 * None.864 * 865 * Side Effects: 866 * The searchPath field of all the suffixes is extended by the867 * directories in dirSearchPath. If paths were specified for the868 * ".h" suffix, the directories are stuffed into a global variable869 * called ".INCLUDES" with each directory preceeded by a -I. The same870 * is done for the ".a" suffix, except the variable is called871 * ".LIBS" and the flag is -L.861 * Extend the search paths for all suffixes to include the default 862 * search path. 863 * 864 * Results: 865 * None. 866 * 867 * Side Effects: 868 * The searchPath field of all the suffixes is extended by the 869 * directories in dirSearchPath. If paths were specified for the 870 * ".h" suffix, the directories are stuffed into a global variable 871 * called ".INCLUDES" with each directory preceeded by a -I. The same 872 * is done for the ".a" suffix, except the variable is called 873 * ".LIBS" and the flag is -L. 872 874 *----------------------------------------------------------------------- 873 875 */ … … 875 877 Suff_DoPaths() 876 878 { 877 register Suff *s;878 register LstNode ln;879 char *ptr;880 Lst inIncludes; /* Cumulative .INCLUDES path */881 Lst inLibs;/* Cumulative .LIBS path */879 register Suff *s; 880 register LstNode ln; 881 char *ptr; 882 Lst inIncludes; /* Cumulative .INCLUDES path */ 883 Lst inLibs; /* Cumulative .LIBS path */ 882 884 883 885 if (Lst_Open (sufflist) == FAILURE) { 884 return;886 return; 885 887 } 886 888 … … 889 891 890 892 while ((ln = Lst_Next (sufflist)) != NILLNODE) { 891 s = (Suff *) Lst_Datum (ln);892 if (!Lst_IsEmpty (s->searchPath)) {893 s = (Suff *) Lst_Datum (ln); 894 if (!Lst_IsEmpty (s->searchPath)) { 893 895 #ifdef INCLUDES 894 if (s->flags & SUFF_INCLUDE) {895 Dir_Concat(inIncludes, s->searchPath);896 }896 if (s->flags & SUFF_INCLUDE) { 897 Dir_Concat(inIncludes, s->searchPath); 898 } 897 899 #endif /* INCLUDES */ 898 900 #ifdef USE_ARCHIVES 899 901 #ifdef LIBRARIES 900 if (s->flags & SUFF_LIBRARY) {901 Dir_Concat(inLibs, s->searchPath);902 }902 if (s->flags & SUFF_LIBRARY) { 903 Dir_Concat(inLibs, s->searchPath); 904 } 903 905 #endif /* LIBRARIES */ 904 906 #endif 905 Dir_Concat(s->searchPath, dirSearchPath);906 } else {907 Lst_Destroy (s->searchPath, Dir_Destroy);908 s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir);909 }907 Dir_Concat(s->searchPath, dirSearchPath); 908 } else { 909 Lst_Destroy (s->searchPath, Dir_Destroy); 910 s->searchPath = Lst_Duplicate(dirSearchPath, Dir_CopyDir); 911 } 910 912 } 911 913 … … 924 926 *----------------------------------------------------------------------- 925 927 * Suff_AddInclude -- 926 * Add the given suffix as a type of file which gets included.927 * Called from the parse module when a .INCLUDES line is parsed.928 * The suffix must have already been defined.929 * 930 * Results: 931 * None.932 * 933 * Side Effects: 934 * The SUFF_INCLUDE bit is set in the suffix's flags field928 * Add the given suffix as a type of file which gets included. 929 * Called from the parse module when a .INCLUDES line is parsed. 930 * The suffix must have already been defined. 931 * 932 * Results: 933 * None. 934 * 935 * Side Effects: 936 * The SUFF_INCLUDE bit is set in the suffix's flags field 935 937 * 936 938 *----------------------------------------------------------------------- … … 938 940 void 939 941 Suff_AddInclude (sname) 940 char *sname; /* Name of suffix to mark */941 { 942 LstNode ln;943 Suff *s;942 char *sname; /* Name of suffix to mark */ 943 { 944 LstNode ln; 945 Suff *s; 944 946 945 947 ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); 946 948 if (ln != NILLNODE) { 947 s = (Suff *) Lst_Datum (ln);948 s->flags |= SUFF_INCLUDE;949 s = (Suff *) Lst_Datum (ln); 950 s->flags |= SUFF_INCLUDE; 949 951 } 950 952 } … … 954 956 *----------------------------------------------------------------------- 955 957 * Suff_AddLib -- 956 * Add the given suffix as a type of file which is a library.957 * Called from the parse module when parsing a .LIBS line. The958 * suffix must have been defined via .SUFFIXES before this is959 * called.960 * 961 * Results: 962 * None.963 * 964 * Side Effects: 965 * The SUFF_LIBRARY bit is set in the suffix's flags field958 * Add the given suffix as a type of file which is a library. 959 * Called from the parse module when parsing a .LIBS line. The 960 * suffix must have been defined via .SUFFIXES before this is 961 * called. 962 * 963 * Results: 964 * None. 965 * 966 * Side Effects: 967 * The SUFF_LIBRARY bit is set in the suffix's flags field 966 968 * 967 969 *----------------------------------------------------------------------- … … 969 971 void 970 972 Suff_AddLib (sname) 971 char *sname; /* Name of suffix to mark */972 { 973 LstNode ln;974 Suff *s;973 char *sname; /* Name of suffix to mark */ 974 { 975 LstNode ln; 976 Suff *s; 975 977 976 978 ln = Lst_Find (sufflist, (ClientData)sname, SuffSuffHasNameP); 977 979 if (ln != NILLNODE) { 978 s = (Suff *) Lst_Datum (ln);979 s->flags |= SUFF_LIBRARY;980 s = (Suff *) Lst_Datum (ln); 981 s->flags |= SUFF_LIBRARY; 980 982 } 981 983 } 982 984 #endif /* USE_ARCHIVES */ 983 985 984 /********** Implicit Source Search Functions *********/986 /********** Implicit Source Search Functions *********/ 985 987 986 988 /*- 987 989 *----------------------------------------------------------------------- 988 990 * SuffAddSrc -- 989 * Add a suffix as a Src structure to the given list with its parent990 * being the given Src structure. If the suffix is the null suffix,991 * the prefix is used unaltered as the file name in the Src structure.992 * 993 * Results: 994 * always returns 0995 * 996 * Side Effects: 997 * A Src structure is created and tacked onto the end of the list991 * Add a suffix as a Src structure to the given list with its parent 992 * being the given Src structure. If the suffix is the null suffix, 993 * the prefix is used unaltered as the file name in the Src structure. 994 * 995 * Results: 996 * always returns 0 997 * 998 * Side Effects: 999 * A Src structure is created and tacked onto the end of the list 998 1000 *----------------------------------------------------------------------- 999 1001 */ 1000 1002 static int 1001 1003 SuffAddSrc (sp, lsp) 1002 ClientData sp;/* suffix for which to create a Src structure */1003 ClientData lsp; /* list and parent for the new Src */1004 { 1005 Suff *s = (Suff *) sp;1004 ClientData sp; /* suffix for which to create a Src structure */ 1005 ClientData lsp; /* list and parent for the new Src */ 1006 { 1007 Suff *s = (Suff *) sp; 1006 1008 LstSrc *ls = (LstSrc *) lsp; 1007 Src *s2; /* new Src structure */1008 Src *targ;/* Target structure */1009 Src *s2; /* new Src structure */ 1010 Src *targ; /* Target structure */ 1009 1011 1010 1012 targ = ls->s; 1011 1013 1012 1014 if ((s->flags & SUFF_NULL) && (*s->name != '\0')) { 1013 /*1014 * If the suffix has been marked as the NULL suffix, also create a Src1015 * structure for a file with no suffix attached. Two birds, and all1016 * that...1017 */1018 s2 = (Src *) emalloc (sizeof (Src));1019 s2->file =estrdup(targ->pref);1020 s2->pref =targ->pref;1021 s2->parent =targ;1022 s2->node =NILGNODE;1023 s2->suff =s;1024 s->refCount++;1025 s2->children =0;1026 targ->children += 1;1027 (void)Lst_AtEnd (ls->l, (ClientData)s2);1015 /* 1016 * If the suffix has been marked as the NULL suffix, also create a Src 1017 * structure for a file with no suffix attached. Two birds, and all 1018 * that... 1019 */ 1020 s2 = (Src *) emalloc (sizeof (Src)); 1021 s2->file = estrdup(targ->pref); 1022 s2->pref = targ->pref; 1023 s2->parent = targ; 1024 s2->node = NILGNODE; 1025 s2->suff = s; 1026 s->refCount++; 1027 s2->children = 0; 1028 targ->children += 1; 1029 (void)Lst_AtEnd (ls->l, (ClientData)s2); 1028 1030 #ifdef DEBUG_SRC 1029 s2->cp = Lst_Init(FALSE);1030 Lst_AtEnd(targ->cp, (ClientData) s2);1031 printf("1 add %x %x to %x:", targ, s2, ls->l);1032 Lst_ForEach(ls->l, PrintAddr, (ClientData) 0);1033 printf("\n");1031 s2->cp = Lst_Init(FALSE); 1032 Lst_AtEnd(targ->cp, (ClientData) s2); 1033 printf("1 add %x %x to %x:", targ, s2, ls->l); 1034 Lst_ForEach(ls->l, PrintAddr, (ClientData) 0); 1035 printf("\n"); 1034 1036 #endif 1035 1037 } 1036 1038 s2 = (Src *) emalloc (sizeof (Src)); 1037 s2->file = str_concat (targ->pref, s->name, 0);1038 s2->pref = targ->pref;1039 s2->file = str_concat (targ->pref, s->name, 0); 1040 s2->pref = targ->pref; 1039 1041 s2->parent = targ; 1040 s2->node = NILGNODE;1041 s2->suff = s;1042 s2->node = NILGNODE; 1043 s2->suff = s; 1042 1044 s->refCount++; 1043 1045 s2->children = 0; … … 1058 1060 *----------------------------------------------------------------------- 1059 1061 * SuffAddLevel -- 1060 * Add all the children of targ as Src structures to the given list1061 * 1062 * Results: 1063 * None1064 * 1065 * Side Effects: 1066 * Lots of structures are created and added to the list1062 * Add all the children of targ as Src structures to the given list 1063 * 1064 * Results: 1065 * None 1066 * 1067 * Side Effects: 1068 * Lots of structures are created and added to the list 1067 1069 *----------------------------------------------------------------------- 1068 1070 */ 1069 1071 static void 1070 1072 SuffAddLevel (l, targ) 1071 Lst l; /* list to which to add the new level */1072 Src *targ; /* Src structure to use as the parent */1073 Lst l; /* list to which to add the new level */ 1074 Src *targ; /* Src structure to use as the parent */ 1073 1075 { 1074 1076 LstSrc ls; … … 1083 1085 *---------------------------------------------------------------------- 1084 1086 * SuffRemoveSrc -- 1085 * Free all src structures in list that don't have a reference count1086 * 1087 * Results: 1088 * Ture if an src was removed1089 * 1090 * Side Effects: 1091 * The memory is efree'd.1087 * Free all src structures in list that don't have a reference count 1088 * 1089 * Results: 1090 * Ture if an src was removed 1091 * 1092 * Side Effects: 1093 * The memory is efree'd. 1092 1094 *---------------------------------------------------------------------- 1093 1095 */ … … 1101 1103 1102 1104 if (Lst_Open (l) == FAILURE) { 1103 return 0;1105 return 0; 1104 1106 } 1105 1107 #ifdef DEBUG_SRC … … 1111 1113 1112 1114 while ((ln = Lst_Next (l)) != NILLNODE) { 1113 s = (Src *) Lst_Datum (ln);1114 if (s->children == 0) {1115 efree ((Address)s->file);1116 if (!s->parent)1117 efree((Address)s->pref);1118 else {1115 s = (Src *) Lst_Datum (ln); 1116 if (s->children == 0) { 1117 efree ((Address)s->file); 1118 if (!s->parent) 1119 efree((Address)s->pref); 1120 else { 1119 1121 #ifdef DEBUG_SRC 1120 LstNode ln = Lst_Member(s->parent->cp, (ClientData)s);1121 if (ln != NILLNODE)1122 Lst_Remove(s->parent->cp, ln);1122 LstNode ln = Lst_Member(s->parent->cp, (ClientData)s); 1123 if (ln != NILLNODE) 1124 Lst_Remove(s->parent->cp, ln); 1123 1125 #endif 1124 --s->parent->children;1125 }1126 --s->parent->children; 1127 } 1126 1128 #ifdef DEBUG_SRC 1127 printf("efree: [l=%x] p=%x %d\n", l, s, s->children);1128 Lst_Destroy(s->cp, NOFREE);1129 printf("efree: [l=%x] p=%x %d\n", l, s, s->children); 1130 Lst_Destroy(s->cp, NOFREE); 1129 1131 #endif 1130 Lst_Remove(l, ln);1131 efree ((Address)s);1132 t |= 1;1133 Lst_Close(l);1134 return TRUE;1135 }1132 Lst_Remove(l, ln); 1133 efree ((Address)s); 1134 t |= 1; 1135 Lst_Close(l); 1136 return TRUE; 1137 } 1136 1138 #ifdef DEBUG_SRC 1137 else {1138 printf("keep: [l=%x] p=%x %d: ", l, s, s->children);1139 Lst_ForEach(s->cp, PrintAddr, (ClientData) 0);1140 printf("\n");1141 }1139 else { 1140 printf("keep: [l=%x] p=%x %d: ", l, s, s->children); 1141 Lst_ForEach(s->cp, PrintAddr, (ClientData) 0); 1142 printf("\n"); 1143 } 1142 1144 #endif 1143 1145 } … … 1151 1153 *----------------------------------------------------------------------- 1152 1154 * SuffFindThem -- 1153 * Find the first existing file/target in the list srcs1154 * 1155 * Results: 1156 * The lowest structure in the chain of transformations1157 * 1158 * Side Effects: 1159 * None1155 * Find the first existing file/target in the list srcs 1156 * 1157 * Results: 1158 * The lowest structure in the chain of transformations 1159 * 1160 * Side Effects: 1161 * None 1160 1162 *----------------------------------------------------------------------- 1161 1163 */ 1162 1164 static Src * 1163 1165 SuffFindThem (srcs, slst) 1164 Lst srcs; /* list of Src structures to search through */1165 Lst slst;1166 { 1167 Src *s; /* current Src */1168 Src *rs;/* returned Src */1169 char *ptr;1166 Lst srcs; /* list of Src structures to search through */ 1167 Lst slst; 1168 { 1169 Src *s; /* current Src */ 1170 Src *rs; /* returned Src */ 1171 char *ptr; 1170 1172 1171 1173 rs = (Src *) NULL; 1172 1174 1173 1175 while (!Lst_IsEmpty (srcs)) { 1174 s = (Src *) Lst_DeQueue (srcs);1175 1176 if (DEBUG(SUFF)) {1177 printf ("\ttrying %s...", s->file);1178 }1179 1180 /*1181 * A file is considered to exist if either a node exists in the1182 * graph for it or the file actually exists.1183 */1184 if (Targ_FindNode(s->file, TARG_NOCREATE) != NILGNODE) {1176 s = (Src *) Lst_DeQueue (srcs); 1177 1178 if (DEBUG(SUFF)) { 1179 printf ("\ttrying %s...", s->file); 1180 } 1181 1182 /* 1183 * A file is considered to exist if either a node exists in the 1184 * graph for it or the file actually exists. 1185 */ 1186 if (Targ_FindNode(s->file, TARG_NOCREATE) != NILGNODE) { 1185 1187 #ifdef DEBUG_SRC 1186 printf("remove %x from %x\n", s, srcs);1188 printf("remove %x from %x\n", s, srcs); 1187 1189 #endif 1188 rs = s;1189 break;1190 }1191 1192 if ((ptr = Dir_FindFile (s->file, s->suff->searchPath)) != NULL) {1193 rs = s;1190 rs = s; 1191 break; 1192 } 1193 1194 if ((ptr = Dir_FindFile (s->file, s->suff->searchPath)) != NULL) { 1195 rs = s; 1194 1196 #ifdef DEBUG_SRC 1195 printf("remove %x from %x\n", s, srcs);1197 printf("remove %x from %x\n", s, srcs); 1196 1198 #endif 1197 efree(ptr);1198 break;1199 }1200 1201 if (DEBUG(SUFF)) {1202 printf ("not there\n");1203 }1204 1205 SuffAddLevel (srcs, s);1206 Lst_AtEnd(slst, (ClientData) s);1199 efree(ptr); 1200 break; 1201 } 1202 1203 if (DEBUG(SUFF)) { 1204 printf ("not there\n"); 1205 } 1206 1207 SuffAddLevel (srcs, s); 1208 Lst_AtEnd(slst, (ClientData) s); 1207 1209 } 1208 1210 1209 1211 if (DEBUG(SUFF) && rs) { 1210 printf ("got it\n");1212 printf ("got it\n"); 1211 1213 } 1212 1214 return (rs); … … 1216 1218 *----------------------------------------------------------------------- 1217 1219 * SuffFindCmds -- 1218 * See if any of the children of the target in the Src structure is1219 * one from which the target can be transformed. If there is one,1220 * a Src structure is put together for it and returned.1221 * 1222 * Results: 1223 * The Src structure of the "winning" child, or NIL if no such beast.1224 * 1225 * Side Effects: 1226 * A Src structure may be allocated.1220 * See if any of the children of the target in the Src structure is 1221 * one from which the target can be transformed. If there is one, 1222 * a Src structure is put together for it and returned. 1223 * 1224 * Results: 1225 * The Src structure of the "winning" child, or NIL if no such beast. 1226 * 1227 * Side Effects: 1228 * A Src structure may be allocated. 1227 1229 * 1228 1230 *----------------------------------------------------------------------- … … 1230 1232 static Src * 1231 1233 SuffFindCmds (targ, slst) 1232 Src *targ;/* Src structure to play with */1233 Lst slst;1234 { 1235 LstNode ln;/* General-purpose list node */1236 register GNode *t,/* Target GNode */1237 *s;/* Source GNode */1238 int prefLen;/* The length of the defined prefix */1239 Suff *suff;/* Suffix on matching beastie */1240 Src *ret;/* Return value */1241 char *cp;1234 Src *targ; /* Src structure to play with */ 1235 Lst slst; 1236 { 1237 LstNode ln; /* General-purpose list node */ 1238 register GNode *t, /* Target GNode */ 1239 *s; /* Source GNode */ 1240 int prefLen;/* The length of the defined prefix */ 1241 Suff *suff; /* Suffix on matching beastie */ 1242 Src *ret; /* Return value */ 1243 char *cp; 1242 1244 1243 1245 t = targ->node; … … 1246 1248 1247 1249 while ((ln = Lst_Next (t->children)) != NILLNODE) { 1248 s = (GNode *)Lst_Datum (ln);1249 1250 cp = strrchr (s->name, '/');1251 if (cp == (char *)NULL) {1252 cp = s->name;1253 } else {1254 cp++;1255 }1256 if (strncmp (cp, targ->pref, prefLen) == 0) {1257 /*1258 * The node matches the prefix ok, see if it has a known1259 * suffix.1260 */1261 ln = Lst_Find (sufflist, (ClientData)&cp[prefLen],1262 SuffSuffHasNameP);1263 if (ln != NILLNODE) {1264 /*1265 * It even has a known suffix, see if there's a transformation1266 * defined between the node's suffix and the target's suffix.1267 *1268 * XXX: Handle multi-stage transformations here, too.1269 */1270 suff = (Suff *)Lst_Datum (ln);1271 1272 if (Lst_Member (suff->parents,1273 (ClientData)targ->suff) != NILLNODE)1274 {1275 /*1276 * Hot Damn! Create a new Src structure to describe1277 * this transformation (making sure to duplicate the1278 * source node's name so Suff_FindDeps can efree it1279 * again (ick)), and return the new structure.1280 */1281 ret = (Src *)emalloc (sizeof (Src));1282 ret->file = estrdup(s->name);1283 ret->pref = targ->pref;1284 ret->suff = suff;1285 suff->refCount++;1286 ret->parent = targ;1287 ret->node = s;1288 ret->children = 0;1289 targ->children += 1;1250 s = (GNode *)Lst_Datum (ln); 1251 1252 cp = strrchr (s->name, '/'); 1253 if (cp == (char *)NULL) { 1254 cp = s->name; 1255 } else { 1256 cp++; 1257 } 1258 if (strncmp (cp, targ->pref, prefLen) == 0) { 1259 /* 1260 * The node matches the prefix ok, see if it has a known 1261 * suffix. 1262 */ 1263 ln = Lst_Find (sufflist, (ClientData)&cp[prefLen], 1264 SuffSuffHasNameP); 1265 if (ln != NILLNODE) { 1266 /* 1267 * It even has a known suffix, see if there's a transformation 1268 * defined between the node's suffix and the target's suffix. 1269 * 1270 * XXX: Handle multi-stage transformations here, too. 1271 */ 1272 suff = (Suff *)Lst_Datum (ln); 1273 1274 if (Lst_Member (suff->parents, 1275 (ClientData)targ->suff) != NILLNODE) 1276 { 1277 /* 1278 * Hot Damn! Create a new Src structure to describe 1279 * this transformation (making sure to duplicate the 1280 * source node's name so Suff_FindDeps can efree it 1281 * again (ick)), and return the new structure. 1282 */ 1283 ret = (Src *)emalloc (sizeof (Src)); 1284 ret->file = estrdup(s->name); 1285 ret->pref = targ->pref; 1286 ret->suff = suff; 1287 suff->refCount++; 1288 ret->parent = targ; 1289 ret->node = s; 1290 ret->children = 0; 1291 targ->children += 1; 1290 1292 #ifdef DEBUG_SRC 1291 ret->cp = Lst_Init(FALSE);1292 printf("3 add %x %x\n", targ, ret);1293 Lst_AtEnd(targ->cp, (ClientData) ret);1293 ret->cp = Lst_Init(FALSE); 1294 printf("3 add %x %x\n", targ, ret); 1295 Lst_AtEnd(targ->cp, (ClientData) ret); 1294 1296 #endif 1295 Lst_AtEnd(slst, (ClientData) ret);1296 if (DEBUG(SUFF)) {1297 printf ("\tusing existing source %s\n", s->name);1298 }1299 return (ret);1300 }1301 }1302 }1297 Lst_AtEnd(slst, (ClientData) ret); 1298 if (DEBUG(SUFF)) { 1299 printf ("\tusing existing source %s\n", s->name); 1300 } 1301 return (ret); 1302 } 1303 } 1304 } 1303 1305 } 1304 1306 Lst_Close (t->children); … … 1309 1311 *----------------------------------------------------------------------- 1310 1312 * SuffExpandChildren -- 1311 * Expand the names of any children of a given node that contain1312 * variable invocations or file wildcards into actual targets.1313 * 1314 * Results: 1315 * === 0 (continue)1316 * 1317 * Side Effects: 1318 * The expanded node is removed from the parent's list of children,1319 * and the parent's unmade counter is decremented, but other nodes1320 * may be added.1313 * Expand the names of any children of a given node that contain 1314 * variable invocations or file wildcards into actual targets. 1315 * 1316 * Results: 1317 * === 0 (continue) 1318 * 1319 * Side Effects: 1320 * The expanded node is removed from the parent's list of children, 1321 * and the parent's unmade counter is decremented, but other nodes 1322 * may be added. 1321 1323 * 1322 1324 *----------------------------------------------------------------------- … … 1324 1326 static int 1325 1327 SuffExpandChildren(cgnp, pgnp) 1326 ClientData cgnp; /* Child to examine */1327 ClientData pgnp; /* Parent node being processed */1328 { 1329 GNode *cgn = (GNode *) cgnp;1330 GNode *pgn = (GNode *) pgnp;1331 GNode *gn;/* New source 8) */1332 LstNode prevLN; /* Node after which new source should be put */1333 LstNode ln;/* List element for old source */1334 char *cp;/* Expanded value */1328 ClientData cgnp; /* Child to examine */ 1329 ClientData pgnp; /* Parent node being processed */ 1330 { 1331 GNode *cgn = (GNode *) cgnp; 1332 GNode *pgn = (GNode *) pgnp; 1333 GNode *gn; /* New source 8) */ 1334 LstNode prevLN; /* Node after which new source should be put */ 1335 LstNode ln; /* List element for old source */ 1336 char *cp; /* Expanded value */ 1335 1337 1336 1338 /* … … 1347 1349 */ 1348 1350 if (strchr(cgn->name, '$') != (char *)NULL) { 1349 if (DEBUG(SUFF)) {1350 printf("Expanding \"%s\"...", cgn->name);1351 }1352 cp = Var_Subst(NULL, cgn->name, pgn, TRUE);1353 1354 if (cp != (char *)NULL) {1355 Lstmembers = Lst_Init(FALSE);1351 if (DEBUG(SUFF)) { 1352 printf("Expanding \"%s\"...", cgn->name); 1353 } 1354 cp = Var_Subst(NULL, cgn->name, pgn, TRUE); 1355 1356 if (cp != (char *)NULL) { 1357 Lst members = Lst_Init(FALSE); 1356 1358 1357 1359 #ifdef USE_ARCHIVES 1358 if (cgn->type & OP_ARCHV) {1359 /*1360 * Node was an archive(member) target, so we want to call1361 * on the Arch module to find the nodes for us, expanding1362 * variables in the parent's context.1363 */1364 char*sacrifice = cp;1365 1366 (void)Arch_ParseArchive(&sacrifice, members, pgn);1367 } else1360 if (cgn->type & OP_ARCHV) { 1361 /* 1362 * Node was an archive(member) target, so we want to call 1363 * on the Arch module to find the nodes for us, expanding 1364 * variables in the parent's context. 1365 */ 1366 char *sacrifice = cp; 1367 1368 (void)Arch_ParseArchive(&sacrifice, members, pgn); 1369 } else 1368 1370 #endif 1369 1371 { 1370 /*1371 * Break the result into a vector of strings whose nodes1372 * we can find, then add those nodes to the members list.1373 * Unfortunately, we can't use brk_string b/c it1374 * doesn't understand about variable specifications with1375 * spaces in them...1376 */1377 char*start;1378 char*initcp = cp; /* For freeing... */1379 1380 for (start = cp; *start == ' ' || *start == '\t'; start++)1381 continue;1382 for (cp = start; *cp != '\0'; cp++) {1383 if (*cp == ' ' || *cp == '\t') {1384 /*1385 * White-space -- terminate element, find the node,1386 * add it, skip any further spaces.1387 */1388 *cp++ = '\0';1389 gn = Targ_FindNode(start, TARG_CREATE);1390 (void)Lst_AtEnd(members, (ClientData)gn);1391 while (*cp == ' ' || *cp == '\t') {1392 cp++;1393 }1394 /*1395 * Adjust cp for increment at start of loop, but1396 * set start to first non-space.1397 */1398 start = cp--;1399 } else if (*cp == '$') {1400 /*1401 * Start of a variable spec -- contact variable module1402 * to find the end so we can skip over it.1403 */1404 char*junk;1405 intlen;1406 BooleandoFree;1407 1408 junk = Var_Parse(cp, pgn, TRUE, &len, &doFree);1409 if (junk != var_Error) {1410 cp += len - 1;1411 }1412 1413 if (doFree) {1414 efree(junk);1415 }1416 } else if (*cp == '\\' && *cp != '\0') {1417 /*1418 * Escaped something -- skip over it1419 */1420 cp++;1421 }1422 }1423 1424 if (cp != start) {1425 /*1426 * Stuff left over -- add it to the list too1427 */1428 gn = Targ_FindNode(start, TARG_CREATE);1429 (void)Lst_AtEnd(members, (ClientData)gn);1430 }1431 /*1432 * Point cp back at the beginning again so the variable value1433 * can be freed.1434 */1435 cp = initcp;1436 }1437 /*1438 * Add all elements of the members list to the parent node.1439 */1440 while(!Lst_IsEmpty(members)) {1441 gn = (GNode *)Lst_DeQueue(members);1442 1443 if (DEBUG(SUFF)) {1444 printf("%s...", gn->name);1445 }1446 if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {1447 (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);1448 prevLN = Lst_Succ(prevLN);1449 (void)Lst_AtEnd(gn->parents, (ClientData)pgn);1450 pgn->unmade++;1451 }1452 }1453 Lst_Destroy(members, NOFREE);1454 /*1455 * Free the result1456 */1457 efree((char *)cp);1458 }1459 /*1460 * Now the source is expanded, remove it from the list of children to1461 * keep it from being processed.1462 */1463 ln = Lst_Member(pgn->children, (ClientData)cgn);1464 pgn->unmade--;1465 Lst_Remove(pgn->children, ln);1466 if (DEBUG(SUFF)) {1467 printf("\n");1468 }1372 /* 1373 * Break the result into a vector of strings whose nodes 1374 * we can find, then add those nodes to the members list. 1375 * Unfortunately, we can't use brk_string b/c it 1376 * doesn't understand about variable specifications with 1377 * spaces in them... 1378 */ 1379 char *start; 1380 char *initcp = cp; /* For freeing... */ 1381 1382 for (start = cp; *start == ' ' || *start == '\t'; start++) 1383 continue; 1384 for (cp = start; *cp != '\0'; cp++) { 1385 if (*cp == ' ' || *cp == '\t') { 1386 /* 1387 * White-space -- terminate element, find the node, 1388 * add it, skip any further spaces. 1389 */ 1390 *cp++ = '\0'; 1391 gn = Targ_FindNode(start, TARG_CREATE); 1392 (void)Lst_AtEnd(members, (ClientData)gn); 1393 while (*cp == ' ' || *cp == '\t') { 1394 cp++; 1395 } 1396 /* 1397 * Adjust cp for increment at start of loop, but 1398 * set start to first non-space. 1399 */ 1400 start = cp--; 1401 } else if (*cp == '$') { 1402 /* 1403 * Start of a variable spec -- contact variable module 1404 * to find the end so we can skip over it. 1405 */ 1406 char *junk; 1407 int len; 1408 Boolean doFree; 1409 1410 junk = Var_Parse(cp, pgn, TRUE, &len, &doFree); 1411 if (junk != var_Error) { 1412 cp += len - 1; 1413 } 1414 1415 if (doFree) { 1416 efree(junk); 1417 } 1418 } else if (*cp == '\\' && *cp != '\0') { 1419 /* 1420 * Escaped something -- skip over it 1421 */ 1422 cp++; 1423 } 1424 } 1425 1426 if (cp != start) { 1427 /* 1428 * Stuff left over -- add it to the list too 1429 */ 1430 gn = Targ_FindNode(start, TARG_CREATE); 1431 (void)Lst_AtEnd(members, (ClientData)gn); 1432 } 1433 /* 1434 * Point cp back at the beginning again so the variable value 1435 * can be freed. 1436 */ 1437 cp = initcp; 1438 } 1439 /* 1440 * Add all elements of the members list to the parent node. 1441 */ 1442 while(!Lst_IsEmpty(members)) { 1443 gn = (GNode *)Lst_DeQueue(members); 1444 1445 if (DEBUG(SUFF)) { 1446 printf("%s...", gn->name); 1447 } 1448 if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) { 1449 (void)Lst_Append(pgn->children, prevLN, (ClientData)gn); 1450 prevLN = Lst_Succ(prevLN); 1451 (void)Lst_AtEnd(gn->parents, (ClientData)pgn); 1452 pgn->unmade++; 1453 } 1454 } 1455 Lst_Destroy(members, NOFREE); 1456 /* 1457 * Free the result 1458 */ 1459 efree((char *)cp); 1460 } 1461 /* 1462 * Now the source is expanded, remove it from the list of children to 1463 * keep it from being processed. 1464 */ 1465 ln = Lst_Member(pgn->children, (ClientData)cgn); 1466 pgn->unmade--; 1467 Lst_Remove(pgn->children, ln); 1468 if (DEBUG(SUFF)) { 1469 printf("\n"); 1470 } 1469 1471 } else if (Dir_HasWildcards(cgn->name)) { 1470 Lst exp;/* List of expansions */1471 Lst path;/* Search path along which to expand */1472 1473 /*1474 * Find a path along which to expand the word.1475 *1476 * If the word has a known suffix, use that path.1477 * If it has no known suffix and we're allowed to use the null1478 * suffix, use its path.1479 * Else use the default system search path.1480 */1481 cp = cgn->name + strlen(cgn->name);1482 ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffIsSuffixP);1483 1484 if (DEBUG(SUFF)) {1485 printf("Wildcard expanding \"%s\"...", cgn->name);1486 }1487 1488 if (ln != NILLNODE) {1489 Suff *s = (Suff *)Lst_Datum(ln);1490 1491 if (DEBUG(SUFF)) {1492 printf("suffix is \"%s\"...", s->name);1493 }1494 path = s->searchPath;1495 } else {1496 /*1497 * Use default search path1498 */1499 path = dirSearchPath;1500 }1501 1502 /*1503 * Expand the word along the chosen path1504 */1505 exp = Lst_Init(FALSE);1506 Dir_Expand(cgn->name, path, exp);1507 1508 while (!Lst_IsEmpty(exp)) {1509 /*1510 * Fetch next expansion off the list and find its GNode1511 */1512 cp = (char *)Lst_DeQueue(exp);1513 1514 if (DEBUG(SUFF)) {1515 printf("%s...", cp);1516 }1517 gn = Targ_FindNode(cp, TARG_CREATE);1518 1519 /*1520 * If gn isn't already a child of the parent, make it so and1521 * up the parent's count of unmade children.1522 */1523 if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) {1524 (void)Lst_Append(pgn->children, prevLN, (ClientData)gn);1525 prevLN = Lst_Succ(prevLN);1526 (void)Lst_AtEnd(gn->parents, (ClientData)pgn);1527 pgn->unmade++;1528 }1529 }1530 1531 /*1532 * Nuke what's left of the list1533 */1534 Lst_Destroy(exp, NOFREE);1535 1536 /*1537 * Now the source is expanded, remove it from the list of children to1538 * keep it from being processed.1539 */1540 ln = Lst_Member(pgn->children, (ClientData)cgn);1541 pgn->unmade--;1542 Lst_Remove(pgn->children, ln);1543 if (DEBUG(SUFF)) {1544 printf("\n");1545 }1472 Lst exp; /* List of expansions */ 1473 Lst path; /* Search path along which to expand */ 1474 1475 /* 1476 * Find a path along which to expand the word. 1477 * 1478 * If the word has a known suffix, use that path. 1479 * If it has no known suffix and we're allowed to use the null 1480 * suffix, use its path. 1481 * Else use the default system search path. 1482 */ 1483 cp = cgn->name + strlen(cgn->name); 1484 ln = Lst_Find(sufflist, (ClientData)cp, SuffSuffIsSuffixP); 1485 1486 if (DEBUG(SUFF)) { 1487 printf("Wildcard expanding \"%s\"...", cgn->name); 1488 } 1489 1490 if (ln != NILLNODE) { 1491 Suff *s = (Suff *)Lst_Datum(ln); 1492 1493 if (DEBUG(SUFF)) { 1494 printf("suffix is \"%s\"...", s->name); 1495 } 1496 path = s->searchPath; 1497 } else { 1498 /* 1499 * Use default search path 1500 */ 1501 path = dirSearchPath; 1502 } 1503 1504 /* 1505 * Expand the word along the chosen path 1506 */ 1507 exp = Lst_Init(FALSE); 1508 Dir_Expand(cgn->name, path, exp); 1509 1510 while (!Lst_IsEmpty(exp)) { 1511 /* 1512 * Fetch next expansion off the list and find its GNode 1513 */ 1514 cp = (char *)Lst_DeQueue(exp); 1515 1516 if (DEBUG(SUFF)) { 1517 printf("%s...", cp); 1518 } 1519 gn = Targ_FindNode(cp, TARG_CREATE); 1520 1521 /* 1522 * If gn isn't already a child of the parent, make it so and 1523 * up the parent's count of unmade children. 1524 */ 1525 if (Lst_Member(pgn->children, (ClientData)gn) == NILLNODE) { 1526 (void)Lst_Append(pgn->children, prevLN, (ClientData)gn); 1527 prevLN = Lst_Succ(prevLN); 1528 (void)Lst_AtEnd(gn->parents, (ClientData)pgn); 1529 pgn->unmade++; 1530 } 1531 } 1532 1533 /* 1534 * Nuke what's left of the list 1535 */ 1536 Lst_Destroy(exp, NOFREE); 1537 1538 /* 1539 * Now the source is expanded, remove it from the list of children to 1540 * keep it from being processed. 1541 */ 1542 ln = Lst_Member(pgn->children, (ClientData)cgn); 1543 pgn->unmade--; 1544 Lst_Remove(pgn->children, ln); 1545 if (DEBUG(SUFF)) { 1546 printf("\n"); 1547 } 1546 1548 } 1547 1549 … … 1552 1554 *----------------------------------------------------------------------- 1553 1555 * SuffApplyTransform -- 1554 * Apply a transformation rule, given the source and target nodes1555 * and suffixes.1556 * 1557 * Results: 1558 * TRUE if successful, FALSE if not.1559 * 1560 * Side Effects: 1561 * The source and target are linked and the commands from the1562 * transformation are added to the target node's commands list.1563 * All attributes but OP_DEPMASK and OP_TRANSFORM are applied1564 * to the target. The target also inherits all the sources for1565 * the transformation rule.1556 * Apply a transformation rule, given the source and target nodes 1557 * and suffixes. 1558 * 1559 * Results: 1560 * TRUE if successful, FALSE if not. 1561 * 1562 * Side Effects: 1563 * The source and target are linked and the commands from the 1564 * transformation are added to the target node's commands list. 1565 * All attributes but OP_DEPMASK and OP_TRANSFORM are applied 1566 * to the target. The target also inherits all the sources for 1567 * the transformation rule. 1566 1568 * 1567 1569 *----------------------------------------------------------------------- … … 1569 1571 static Boolean 1570 1572 SuffApplyTransform(tGn, sGn, t, s) 1571 GNode *tGn;/* Target node */1572 GNode *sGn;/* Source node */1573 Suff *t;/* Target suffix */1574 Suff *s;/* Source suffix */1575 { 1576 LstNode ln;/* General node */1577 char *tname;/* Name of transformation rule */1578 GNode *gn;/* Node for same */1573 GNode *tGn; /* Target node */ 1574 GNode *sGn; /* Source node */ 1575 Suff *t; /* Target suffix */ 1576 Suff *s; /* Source suffix */ 1577 { 1578 LstNode ln; /* General node */ 1579 char *tname; /* Name of transformation rule */ 1580 GNode *gn; /* Node for same */ 1579 1581 1580 1582 if (Lst_Member(tGn->children, (ClientData)sGn) == NILLNODE) { 1581 /*1582 * Not already linked, so form the proper links between the1583 * target and source.1584 */1585 (void)Lst_AtEnd(tGn->children, (ClientData)sGn);1586 (void)Lst_AtEnd(sGn->parents, (ClientData)tGn);1587 tGn->unmade += 1;1583 /* 1584 * Not already linked, so form the proper links between the 1585 * target and source. 1586 */ 1587 (void)Lst_AtEnd(tGn->children, (ClientData)sGn); 1588 (void)Lst_AtEnd(sGn->parents, (ClientData)tGn); 1589 tGn->unmade += 1; 1588 1590 } 1589 1591 1590 1592 if ((sGn->type & OP_OPMASK) == OP_DOUBLEDEP) { 1591 /*1592 * When a :: node is used as the implied source of a node, we have1593 * to link all its cohorts in as sources as well. Only the initial1594 * sGn gets the target in its iParents list, however, as that1595 * will be sufficient to get the .IMPSRC variable set for tGn1596 */1597 for (ln=Lst_First(sGn->cohorts); ln != NILLNODE; ln=Lst_Succ(ln)) {1598 gn = (GNode *)Lst_Datum(ln);1599 1600 if (Lst_Member(tGn->children, (ClientData)gn) == NILLNODE) {1601 /*1602 * Not already linked, so form the proper links between the1603 * target and source.1604 */1605 (void)Lst_AtEnd(tGn->children, (ClientData)gn);1606 (void)Lst_AtEnd(gn->parents, (ClientData)tGn);1607 tGn->unmade += 1;1608 }1609 }1593 /* 1594 * When a :: node is used as the implied source of a node, we have 1595 * to link all its cohorts in as sources as well. Only the initial 1596 * sGn gets the target in its iParents list, however, as that 1597 * will be sufficient to get the .IMPSRC variable set for tGn 1598 */ 1599 for (ln=Lst_First(sGn->cohorts); ln != NILLNODE; ln=Lst_Succ(ln)) { 1600 gn = (GNode *)Lst_Datum(ln); 1601 1602 if (Lst_Member(tGn->children, (ClientData)gn) == NILLNODE) { 1603 /* 1604 * Not already linked, so form the proper links between the 1605 * target and source. 1606 */ 1607 (void)Lst_AtEnd(tGn->children, (ClientData)gn); 1608 (void)Lst_AtEnd(gn->parents, (ClientData)tGn); 1609 tGn->unmade += 1; 1610 } 1611 } 1610 1612 } 1611 1613 /* … … 1617 1619 1618 1620 if (ln == NILLNODE) { 1619 /*1620 * Not really such a transformation rule (can happen when we're1621 * called to link an OP_MEMBER and OP_ARCHV node), so return1622 * FALSE.1623 */1624 return(FALSE);1621 /* 1622 * Not really such a transformation rule (can happen when we're 1623 * called to link an OP_MEMBER and OP_ARCHV node), so return 1624 * FALSE. 1625 */ 1626 return(FALSE); 1625 1627 } 1626 1628 … … 1628 1630 1629 1631 if (DEBUG(SUFF)) { 1630 printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name);1632 printf("\tapplying %s -> %s to \"%s\"\n", s->name, t->name, tGn->name); 1631 1633 } 1632 1634 … … 1646 1648 ln = Lst_Succ(ln); 1647 1649 if (ln != NILLNODE) { 1648 Lst_ForEachFrom(tGn->children, ln,1649 SuffExpandChildren, (ClientData)tGn);1650 Lst_ForEachFrom(tGn->children, ln, 1651 SuffExpandChildren, (ClientData)tGn); 1650 1652 } 1651 1653 … … 1664 1666 *----------------------------------------------------------------------- 1665 1667 * SuffFindArchiveDeps -- 1666 * Locate dependencies for an OP_ARCHV node.1667 * 1668 * Results: 1669 * None1670 * 1671 * Side Effects: 1672 * Same as Suff_FindDeps1668 * Locate dependencies for an OP_ARCHV node. 1669 * 1670 * Results: 1671 * None 1672 * 1673 * Side Effects: 1674 * Same as Suff_FindDeps 1673 1675 * 1674 1676 *----------------------------------------------------------------------- … … 1676 1678 static void 1677 1679 SuffFindArchiveDeps(gn, slst) 1678 GNode *gn;/* Node for which to locate dependencies */1679 Lst slst;1680 { 1681 char *eoarch; /* End of archive portion */1682 char *eoname; /* End of member portion */1683 GNode *mem;/* Node for member */1684 static char *copy[] = { /* Variables to be copied from the member node */1685 TARGET,/* Must be first */1686 PREFIX,/* Must be second */1680 GNode *gn; /* Node for which to locate dependencies */ 1681 Lst slst; 1682 { 1683 char *eoarch; /* End of archive portion */ 1684 char *eoname; /* End of member portion */ 1685 GNode *mem; /* Node for member */ 1686 static char *copy[] = { /* Variables to be copied from the member node */ 1687 TARGET, /* Must be first */ 1688 PREFIX, /* Must be second */ 1687 1689 }; 1688 int i;/* Index into copy and vals */1689 Suff *ms;/* Suffix descriptor for member */1690 char *name;/* Start of member's name */1690 int i; /* Index into copy and vals */ 1691 Suff *ms; /* Suffix descriptor for member */ 1692 char *name; /* Start of member's name */ 1691 1693 1692 1694 /* … … 1697 1699 eoname = strchr (eoarch, ')'); 1698 1700 1699 *eoname = '\0'; /* Nuke parentheses during suffix search */1700 *eoarch = '\0'; /* So a suffix can be found */1701 *eoname = '\0'; /* Nuke parentheses during suffix search */ 1702 *eoarch = '\0'; /* So a suffix can be found */ 1701 1703 1702 1704 name = eoarch + 1; … … 1716 1718 */ 1717 1719 if (Lst_Member(gn->children, (ClientData)mem) == NILLNODE) { 1718 (void)Lst_AtEnd(gn->children, (ClientData)mem);1719 (void)Lst_AtEnd(mem->parents, (ClientData)gn);1720 gn->unmade += 1;1720 (void)Lst_AtEnd(gn->children, (ClientData)mem); 1721 (void)Lst_AtEnd(mem->parents, (ClientData)gn); 1722 gn->unmade += 1; 1721 1723 } 1722 1724 … … 1725 1727 */ 1726 1728 for (i = (sizeof(copy)/sizeof(copy[0]))-1; i >= 0; i--) { 1727 char *p1;1728 Var_Set(copy[i], Var_Value(copy[i], mem, &p1), gn);1729 efree(p1);1729 char *p1; 1730 Var_Set(copy[i], Var_Value(copy[i], mem, &p1), gn); 1731 efree(p1); 1730 1732 1731 1733 } … … 1733 1735 ms = mem->suffix; 1734 1736 if (ms == NULL) { 1735 /*1736 * Didn't know what it was -- use .NULL suffix if not in make mode1737 */1738 if (DEBUG(SUFF)) {1739 printf("using null suffix\n");1740 }1741 ms = suffNull;1737 /* 1738 * Didn't know what it was -- use .NULL suffix if not in make mode 1739 */ 1740 if (DEBUG(SUFF)) { 1741 printf("using null suffix\n"); 1742 } 1743 ms = suffNull; 1742 1744 } 1743 1745 … … 1750 1752 1751 1753 if (ms != NULL) { 1752 /*1753 * Member has a known suffix, so look for a transformation rule from1754 * it to a possible suffix of the archive. Rather than searching1755 * through the entire list, we just look at suffixes to which the1756 * member's suffix may be transformed...1757 */1758 LstNodeln;1759 1760 /*1761 * Use first matching suffix...1762 */1763 ln = Lst_Find(ms->parents, eoarch, SuffSuffIsSuffixP);1764 1765 if (ln != NILLNODE) {1766 /*1767 * Got one -- apply it1768 */1769 if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) &&1770 DEBUG(SUFF))1771 {1772 printf("\tNo transformation from %s -> %s\n",1773 ms->name, ((Suff *)Lst_Datum(ln))->name);1774 }1775 }1754 /* 1755 * Member has a known suffix, so look for a transformation rule from 1756 * it to a possible suffix of the archive. Rather than searching 1757 * through the entire list, we just look at suffixes to which the 1758 * member's suffix may be transformed... 1759 */ 1760 LstNode ln; 1761 1762 /* 1763 * Use first matching suffix... 1764 */ 1765 ln = Lst_Find(ms->parents, eoarch, SuffSuffIsSuffixP); 1766 1767 if (ln != NILLNODE) { 1768 /* 1769 * Got one -- apply it 1770 */ 1771 if (!SuffApplyTransform(gn, mem, (Suff *)Lst_Datum(ln), ms) && 1772 DEBUG(SUFF)) 1773 { 1774 printf("\tNo transformation from %s -> %s\n", 1775 ms->name, ((Suff *)Lst_Datum(ln))->name); 1776 } 1777 } 1776 1778 } 1777 1779 … … 1788 1790 */ 1789 1791 if (OP_NOP(gn->type)) { 1790 gn->type |= OP_DEPENDS;1792 gn->type |= OP_DEPENDS; 1791 1793 } 1792 1794 … … 1802 1804 *----------------------------------------------------------------------- 1803 1805 * SuffFindNormalDeps -- 1804 * Locate implicit dependencies for regular targets.1805 * 1806 * Results: 1807 * None.1808 * 1809 * Side Effects: 1810 * Same as Suff_FindDeps...1806 * Locate implicit dependencies for regular targets. 1807 * 1808 * Results: 1809 * None. 1810 * 1811 * Side Effects: 1812 * Same as Suff_FindDeps... 1811 1813 * 1812 1814 *----------------------------------------------------------------------- … … 1814 1816 static void 1815 1817 SuffFindNormalDeps(gn, slst) 1816 GNode *gn;/* Node for which to find sources */1817 Lst slst;1818 { 1819 char *eoname; /* End of name */1820 char *sopref; /* Start of prefix */1821 LstNode ln;/* Next suffix node to check */1822 Lst srcs;/* List of sources at which to look */1823 Lst targs;/* List of targets to which things can be1824 * transformed. They all have the same file,1825 * but different suff and pref fields */1826 Src *bottom; /* Start of found transformation path */1827 Src *src;/* General Src pointer */1828 char *pref;/* Prefix to use */1829 Src *targ;/* General Src target pointer */1818 GNode *gn; /* Node for which to find sources */ 1819 Lst slst; 1820 { 1821 char *eoname; /* End of name */ 1822 char *sopref; /* Start of prefix */ 1823 LstNode ln; /* Next suffix node to check */ 1824 Lst srcs; /* List of sources at which to look */ 1825 Lst targs; /* List of targets to which things can be 1826 * transformed. They all have the same file, 1827 * but different suff and pref fields */ 1828 Src *bottom; /* Start of found transformation path */ 1829 Src *src; /* General Src pointer */ 1830 char *pref; /* Prefix to use */ 1831 Src *targ; /* General Src target pointer */ 1830 1832 1831 1833 … … 1861 1863 1862 1864 while (ln != NILLNODE) { 1863 /*1864 * Look for next possible suffix...1865 */1866 ln = Lst_FindFrom(sufflist, ln, eoname, SuffSuffIsSuffixP);1867 1868 if (ln != NILLNODE) {1869 int prefLen;/* Length of the prefix */1870 Src*targ;1871 1872 /*1873 * Allocate a Src structure to which things can be transformed1874 */1875 targ = (Src *)emalloc(sizeof (Src));1876 targ->file = estrdup(gn->name);1877 targ->suff = (Suff *)Lst_Datum(ln);1878 targ->suff->refCount++;1879 targ->node = gn;1880 targ->parent = (Src *)NULL;1881 targ->children = 0;1865 /* 1866 * Look for next possible suffix... 1867 */ 1868 ln = Lst_FindFrom(sufflist, ln, eoname, SuffSuffIsSuffixP); 1869 1870 if (ln != NILLNODE) { 1871 int prefLen; /* Length of the prefix */ 1872 Src *targ; 1873 1874 /* 1875 * Allocate a Src structure to which things can be transformed 1876 */ 1877 targ = (Src *)emalloc(sizeof (Src)); 1878 targ->file = estrdup(gn->name); 1879 targ->suff = (Suff *)Lst_Datum(ln); 1880 targ->suff->refCount++; 1881 targ->node = gn; 1882 targ->parent = (Src *)NULL; 1883 targ->children = 0; 1882 1884 #ifdef DEBUG_SRC 1883 targ->cp = Lst_Init(FALSE);1885 targ->cp = Lst_Init(FALSE); 1884 1886 #endif 1885 1887 1886 /*1887 * Allocate room for the prefix, whose end is found by subtracting1888 * the length of the suffix from the end of the name.1889 */1890 prefLen = (eoname - targ->suff->nameLen) - sopref;1891 targ->pref = emalloc(prefLen + 1);1892 memcpy(targ->pref, sopref, prefLen);1893 targ->pref[prefLen] = '\0';1894 1895 /*1896 * Add nodes from which the target can be made1897 */1898 SuffAddLevel(srcs, targ);1899 1900 /*1901 * Record the target so we can nuke it1902 */1903 (void)Lst_AtEnd(targs, (ClientData)targ);1904 1905 /*1906 * Search from this suffix's successor...1907 */1908 ln = Lst_Succ(ln);1909 }1888 /* 1889 * Allocate room for the prefix, whose end is found by subtracting 1890 * the length of the suffix from the end of the name. 1891 */ 1892 prefLen = (eoname - targ->suff->nameLen) - sopref; 1893 targ->pref = emalloc(prefLen + 1); 1894 memcpy(targ->pref, sopref, prefLen); 1895 targ->pref[prefLen] = '\0'; 1896 1897 /* 1898 * Add nodes from which the target can be made 1899 */ 1900 SuffAddLevel(srcs, targ); 1901 1902 /* 1903 * Record the target so we can nuke it 1904 */ 1905 (void)Lst_AtEnd(targs, (ClientData)targ); 1906 1907 /* 1908 * Search from this suffix's successor... 1909 */ 1910 ln = Lst_Succ(ln); 1911 } 1910 1912 } 1911 1913 … … 1914 1916 */ 1915 1917 if (Lst_IsEmpty(targs) && suffNull != NULL) { 1916 if (DEBUG(SUFF)) {1917 printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name);1918 }1919 1920 targ = (Src *)emalloc(sizeof (Src));1921 targ->file = estrdup(gn->name);1922 targ->suff = suffNull;1923 targ->suff->refCount++;1924 targ->node = gn;1925 targ->parent = (Src *)NULL;1926 targ->children = 0;1927 targ->pref = estrdup(sopref);1918 if (DEBUG(SUFF)) { 1919 printf("\tNo known suffix on %s. Using .NULL suffix\n", gn->name); 1920 } 1921 1922 targ = (Src *)emalloc(sizeof (Src)); 1923 targ->file = estrdup(gn->name); 1924 targ->suff = suffNull; 1925 targ->suff->refCount++; 1926 targ->node = gn; 1927 targ->parent = (Src *)NULL; 1928 targ->children = 0; 1929 targ->pref = estrdup(sopref); 1928 1930 #ifdef DEBUG_SRC 1929 targ->cp = Lst_Init(FALSE);1931 targ->cp = Lst_Init(FALSE); 1930 1932 #endif 1931 1933 1932 /*1933 * Only use the default suffix rules if we don't have commands1934 * or dependencies defined for this gnode1935 */1936 if (Lst_IsEmpty(gn->commands) && Lst_IsEmpty(gn->children))1937 SuffAddLevel(srcs, targ);1938 else {1939 if (DEBUG(SUFF))1940 printf("not ");1941 }1942 1943 if (DEBUG(SUFF))1944 printf("adding suffix rules\n");1945 1946 (void)Lst_AtEnd(targs, (ClientData)targ);1934 /* 1935 * Only use the default suffix rules if we don't have commands 1936 * or dependencies defined for this gnode 1937 */ 1938 if (Lst_IsEmpty(gn->commands) && Lst_IsEmpty(gn->children)) 1939 SuffAddLevel(srcs, targ); 1940 else { 1941 if (DEBUG(SUFF)) 1942 printf("not "); 1943 } 1944 1945 if (DEBUG(SUFF)) 1946 printf("adding suffix rules\n"); 1947 1948 (void)Lst_AtEnd(targs, (ClientData)targ); 1947 1949 } 1948 1950 … … 1954 1956 1955 1957 if (bottom == (Src *)NULL) { 1956 /*1957 * No known transformations -- use the first suffix found for setting1958 * the local variables.1959 */1960 if (!Lst_IsEmpty(targs)) {1961 targ = (Src *)Lst_Datum(Lst_First(targs));1962 } else {1963 targ = (Src *)NULL;1964 }1958 /* 1959 * No known transformations -- use the first suffix found for setting 1960 * the local variables. 1961 */ 1962 if (!Lst_IsEmpty(targs)) { 1963 targ = (Src *)Lst_Datum(Lst_First(targs)); 1964 } else { 1965 targ = (Src *)NULL; 1966 } 1965 1967 } else { 1966 /*1967 * Work up the transformation path to find the suffix of the1968 * target to which the transformation was made.1969 */1970 for (targ = bottom; targ->parent != NULL; targ = targ->parent)1971 continue;1968 /* 1969 * Work up the transformation path to find the suffix of the 1970 * target to which the transformation was made. 1971 */ 1972 for (targ = bottom; targ->parent != NULL; targ = targ->parent) 1973 continue; 1972 1974 } 1973 1975 … … 1990 1992 1991 1993 if (targ == NULL) { 1992 if (DEBUG(SUFF)) {1993 printf("\tNo valid suffix on %s\n", gn->name);1994 }1994 if (DEBUG(SUFF)) { 1995 printf("\tNo valid suffix on %s\n", gn->name); 1996 } 1995 1997 1996 1998 sfnd_abort: 1997 /*1998 * Deal with finding the thing on the default search path if the1999 * node is only a source (not on the lhs of a dependency operator2000 * or [XXX] it has neither children or commands).2001 */2002 if (OP_NOP(gn->type) ||2003 (Lst_IsEmpty(gn->children) && Lst_IsEmpty(gn->commands)))2004 {2005 gn->path = Dir_FindFile(gn->name,2006 (targ == NULL ? dirSearchPath :2007 targ->suff->searchPath));2008 if (gn->path != NULL) {2009 char *ptr;2010 Var_Set(TARGET, gn->path, gn);2011 2012 if (targ != NULL) {2013 /*2014 * Suffix known for the thing -- trim the suffix off2015 * the path to form the proper .PREFIX variable.2016 */2017 intsavep = strlen(gn->path) - targ->suff->nameLen;2018 charsavec;2019 2020 if (gn->suffix)2021 gn->suffix->refCount--;2022 gn->suffix = targ->suff;2023 gn->suffix->refCount++;2024 2025 savec = gn->path[savep];2026 gn->path[savep] = '\0';2027 2028 if ((ptr = strrchr(gn->path, '/')) != NULL)2029 ptr++;2030 else2031 ptr = gn->path;2032 2033 Var_Set(PREFIX, ptr, gn);2034 2035 gn->path[savep] = savec;2036 } else {2037 /*2038 * The .PREFIX gets the full path if the target has2039 * no known suffix.2040 */2041 if (gn->suffix)2042 gn->suffix->refCount--;2043 gn->suffix = NULL;2044 2045 if ((ptr = strrchr(gn->path, '/')) != NULL)2046 ptr++;2047 else2048 ptr = gn->path;2049 2050 Var_Set(PREFIX, ptr, gn);2051 }2052 }2053 } else {2054 /*2055 * Not appropriate to search for the thing -- set the2056 * path to be the name so Dir_MTime won't go grovelling for2057 * it.2058 */2059 if (gn->suffix)2060 gn->suffix->refCount--;2061 gn->suffix = (targ == NULL) ? NULL : targ->suff;2062 if (gn->suffix)2063 gn->suffix->refCount++;2064 efree(gn->path);2065 gn->path = estrdup(gn->name);2066 }2067 2068 goto sfnd_return;1999 /* 2000 * Deal with finding the thing on the default search path if the 2001 * node is only a source (not on the lhs of a dependency operator 2002 * or [XXX] it has neither children or commands). 2003 */ 2004 if (OP_NOP(gn->type) || 2005 (Lst_IsEmpty(gn->children) && Lst_IsEmpty(gn->commands))) 2006 { 2007 gn->path = Dir_FindFile(gn->name, 2008 (targ == NULL ? dirSearchPath : 2009 targ->suff->searchPath)); 2010 if (gn->path != NULL) { 2011 char *ptr; 2012 Var_Set(TARGET, gn->path, gn); 2013 2014 if (targ != NULL) { 2015 /* 2016 * Suffix known for the thing -- trim the suffix off 2017 * the path to form the proper .PREFIX variable. 2018 */ 2019 int savep = strlen(gn->path) - targ->suff->nameLen; 2020 char savec; 2021 2022 if (gn->suffix) 2023 gn->suffix->refCount--; 2024 gn->suffix = targ->suff; 2025 gn->suffix->refCount++; 2026 2027 savec = gn->path[savep]; 2028 gn->path[savep] = '\0'; 2029 2030 if ((ptr = strrchr(gn->path, '/')) != NULL) 2031 ptr++; 2032 else 2033 ptr = gn->path; 2034 2035 Var_Set(PREFIX, ptr, gn); 2036 2037 gn->path[savep] = savec; 2038 } else { 2039 /* 2040 * The .PREFIX gets the full path if the target has 2041 * no known suffix. 2042 */ 2043 if (gn->suffix) 2044 gn->suffix->refCount--; 2045 gn->suffix = NULL; 2046 2047 if ((ptr = strrchr(gn->path, '/')) != NULL) 2048 ptr++; 2049 else 2050 ptr = gn->path; 2051 2052 Var_Set(PREFIX, ptr, gn); 2053 } 2054 } 2055 } else { 2056 /* 2057 * Not appropriate to search for the thing -- set the 2058 * path to be the name so Dir_MTime won't go grovelling for 2059 * it. 2060 */ 2061 if (gn->suffix) 2062 gn->suffix->refCount--; 2063 gn->suffix = (targ == NULL) ? NULL : targ->suff; 2064 if (gn->suffix) 2065 gn->suffix->refCount++; 2066 efree(gn->path); 2067 gn->path = estrdup(gn->name); 2068 } 2069 2070 goto sfnd_return; 2069 2071 } 2070 2072 … … 2075 2077 */ 2076 2078 if (targ->suff->flags & SUFF_LIBRARY) { 2077 gn->type |= OP_LIB;2079 gn->type |= OP_LIB; 2078 2080 } 2079 2081 #endif … … 2083 2085 */ 2084 2086 if (!Lst_IsEmpty(gn->children)) { 2085 src = SuffFindCmds(targ, slst);2086 2087 if (src != (Src *)NULL) {2088 /*2089 * Free up all the Src structures in the transformation path2090 * up to, but not including, the parent node.2091 */2092 while (bottom && bottom->parent != NULL) {2093 if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) {2094 Lst_AtEnd(slst, (ClientData) bottom);2095 }2096 bottom = bottom->parent;2097 }2098 bottom = src;2099 }2087 src = SuffFindCmds(targ, slst); 2088 2089 if (src != (Src *)NULL) { 2090 /* 2091 * Free up all the Src structures in the transformation path 2092 * up to, but not including, the parent node. 2093 */ 2094 while (bottom && bottom->parent != NULL) { 2095 if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) { 2096 Lst_AtEnd(slst, (ClientData) bottom); 2097 } 2098 bottom = bottom->parent; 2099 } 2100 bottom = src; 2101 } 2100 2102 } 2101 2103 2102 2104 if (bottom == NULL) { 2103 /*2104 * No idea from where it can come -- return now.2105 */2106 goto sfnd_abort;2105 /* 2106 * No idea from where it can come -- return now. 2107 */ 2108 goto sfnd_abort; 2107 2109 } 2108 2110 … … 2120 2122 */ 2121 2123 if (bottom->node == NILGNODE) { 2122 bottom->node = Targ_FindNode(bottom->file, TARG_CREATE);2124 bottom->node = Targ_FindNode(bottom->file, TARG_CREATE); 2123 2125 } 2124 2126 2125 2127 for (src = bottom; src->parent != (Src *)NULL; src = src->parent) { 2126 targ = src->parent;2127 2128 if (src->node->suffix)2129 src->node->suffix->refCount--;2130 src->node->suffix = src->suff;2131 src->node->suffix->refCount++;2132 2133 if (targ->node == NILGNODE) {2134 targ->node = Targ_FindNode(targ->file, TARG_CREATE);2135 }2136 2137 SuffApplyTransform(targ->node, src->node,2138 targ->suff, src->suff);2139 2140 if (targ->node != gn) {2141 /*2142 * Finish off the dependency-search process for any nodes2143 * between bottom and gn (no point in questing around the2144 * filesystem for their implicit source when it's already2145 * known). Note that the node can't have any sources that2146 * need expanding, since SuffFindThem will stop on an existing2147 * node, so all we need to do is set the standard and System V2148 * variables.2149 */2150 targ->node->type |= OP_DEPS_FOUND;2151 2152 Var_Set(PREFIX, targ->pref, targ->node);2153 2154 Var_Set(TARGET, targ->node->name, targ->node);2155 }2128 targ = src->parent; 2129 2130 if (src->node->suffix) 2131 src->node->suffix->refCount--; 2132 src->node->suffix = src->suff; 2133 src->node->suffix->refCount++; 2134 2135 if (targ->node == NILGNODE) { 2136 targ->node = Targ_FindNode(targ->file, TARG_CREATE); 2137 } 2138 2139 SuffApplyTransform(targ->node, src->node, 2140 targ->suff, src->suff); 2141 2142 if (targ->node != gn) { 2143 /* 2144 * Finish off the dependency-search process for any nodes 2145 * between bottom and gn (no point in questing around the 2146 * filesystem for their implicit source when it's already 2147 * known). Note that the node can't have any sources that 2148 * need expanding, since SuffFindThem will stop on an existing 2149 * node, so all we need to do is set the standard and System V 2150 * variables. 2151 */ 2152 targ->node->type |= OP_DEPS_FOUND; 2153 2154 Var_Set(PREFIX, targ->pref, targ->node); 2155 2156 Var_Set(TARGET, targ->node->name, targ->node); 2157 } 2156 2158 } 2157 2159 2158 2160 if (gn->suffix) 2159 gn->suffix->refCount--;2161 gn->suffix->refCount--; 2160 2162 gn->suffix = src->suff; 2161 2163 gn->suffix->refCount++; … … 2173 2175 sfnd_return: 2174 2176 if (bottom) 2175 if (Lst_Member(slst, (ClientData) bottom) == NILLNODE)2176 Lst_AtEnd(slst, (ClientData) bottom);2177 if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) 2178 Lst_AtEnd(slst, (ClientData) bottom); 2177 2179 2178 2180 while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs)) 2179 continue;2181 continue; 2180 2182 2181 2183 Lst_Concat(slst, srcs, LST_CONCLINK); … … 2187 2189 *----------------------------------------------------------------------- 2188 2190 * Suff_FindDeps -- 2189 * Find implicit sources for the target described by the graph node2190 * gn2191 * 2192 * Results: 2193 * Nothing.2194 * 2195 * Side Effects: 2196 * Nodes are added to the graph below the passed-in node. The nodes2197 * are marked to have their IMPSRC variable filled in. The2198 * PREFIX variable is set for the given node and all its2199 * implied children.2191 * Find implicit sources for the target described by the graph node 2192 * gn 2193 * 2194 * Results: 2195 * Nothing. 2196 * 2197 * Side Effects: 2198 * Nodes are added to the graph below the passed-in node. The nodes 2199 * are marked to have their IMPSRC variable filled in. The 2200 * PREFIX variable is set for the given node and all its 2201 * implied children. 2200 2202 * 2201 2203 * Notes: 2202 * The path found by this target is the shortest path in the2203 * transformation graph, which may pass through non-existent targets,2204 * to an existing target. The search continues on all paths from the2205 * root suffix until a file is found. I.e. if there's a path2206 * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but2207 * the .c and .l files don't, the search will branch out in2208 * all directions from .o and again from all the nodes on the2209 * next level until the .l,v node is encountered.2204 * The path found by this target is the shortest path in the 2205 * transformation graph, which may pass through non-existent targets, 2206 * to an existing target. The search continues on all paths from the 2207 * root suffix until a file is found. I.e. if there's a path 2208 * .o -> .c -> .l -> .l,v from the root and the .l,v file exists but 2209 * the .c and .l files don't, the search will branch out in 2210 * all directions from .o and again from all the nodes on the 2211 * next level until the .l,v node is encountered. 2210 2212 * 2211 2213 *----------------------------------------------------------------------- … … 2219 2221 SuffFindDeps(gn, srclist); 2220 2222 while (SuffRemoveSrc(srclist)) 2221 continue;2223 continue; 2222 2224 } 2223 2225 … … 2225 2227 static void 2226 2228 SuffFindDeps (gn, slst) 2227 GNode *gn; /* node we're dealing with */2228 Lst slst;2229 GNode *gn; /* node we're dealing with */ 2230 Lst slst; 2229 2231 { 2230 2232 if (gn->type & OP_DEPS_FOUND) { 2231 /*2232 * If dependencies already found, no need to do it again...2233 */2234 return;2233 /* 2234 * If dependencies already found, no need to do it again... 2235 */ 2236 return; 2235 2237 } else { 2236 gn->type |= OP_DEPS_FOUND;2238 gn->type |= OP_DEPS_FOUND; 2237 2239 } 2238 2240 2239 2241 if (DEBUG(SUFF)) { 2240 printf ("SuffFindDeps (%s)\n", gn->name);2242 printf ("SuffFindDeps (%s)\n", gn->name); 2241 2243 } 2242 2244 2243 2245 #ifdef USE_ARCHIVES 2244 2246 if (gn->type & OP_ARCHV) { 2245 SuffFindArchiveDeps(gn, slst);2247 SuffFindArchiveDeps(gn, slst); 2246 2248 } else if (gn->type & OP_LIB) { 2247 /*2248 * If the node is a library, it is the arch module's job to find it2249 * and set the TARGET variable accordingly. We merely provide the2250 * search path, assuming all libraries end in ".a" (if the suffix2251 * hasn't been defined, there's nothing we can do for it, so we just2252 * set the TARGET variable to the node's name in order to give it a2253 * value).2254 */2255 LstNodeln;2256 Suff*s;2257 2258 ln = Lst_Find (sufflist, (ClientData)LIBSUFF, SuffSuffHasNameP);2259 if (gn->suffix)2260 gn->suffix->refCount--;2261 if (ln != NILLNODE) {2262 gn->suffix = s = (Suff *) Lst_Datum (ln);2263 gn->suffix->refCount++;2264 Arch_FindLib (gn, s->searchPath);2265 } else {2266 gn->suffix = NULL;2267 Var_Set (TARGET, gn->name, gn);2268 }2269 /*2270 * Because a library (-lfoo) target doesn't follow the standard2271 * filesystem conventions, we don't set the regular variables for2272 * the thing. .PREFIX is simply made empty...2273 */2274 Var_Set(PREFIX, "", gn);2249 /* 2250 * If the node is a library, it is the arch module's job to find it 2251 * and set the TARGET variable accordingly. We merely provide the 2252 * search path, assuming all libraries end in ".a" (if the suffix 2253 * hasn't been defined, there's nothing we can do for it, so we just 2254 * set the TARGET variable to the node's name in order to give it a 2255 * value). 2256 */ 2257 LstNode ln; 2258 Suff *s; 2259 2260 ln = Lst_Find (sufflist, (ClientData)LIBSUFF, SuffSuffHasNameP); 2261 if (gn->suffix) 2262 gn->suffix->refCount--; 2263 if (ln != NILLNODE) { 2264 gn->suffix = s = (Suff *) Lst_Datum (ln); 2265 gn->suffix->refCount++; 2266 Arch_FindLib (gn, s->searchPath); 2267 } else { 2268 gn->suffix = NULL; 2269 Var_Set (TARGET, gn->name, gn); 2270 } 2271 /* 2272 * Because a library (-lfoo) target doesn't follow the standard 2273 * filesystem conventions, we don't set the regular variables for 2274 * the thing. .PREFIX is simply made empty... 2275 */ 2276 Var_Set(PREFIX, "", gn); 2275 2277 } else 2276 2278 #endif /* USE_ARCHIVES */ 2277 SuffFindNormalDeps(gn, slst);2279 SuffFindNormalDeps(gn, slst); 2278 2280 } 2279 2281 … … 2281 2283 *----------------------------------------------------------------------- 2282 2284 * Suff_SetNull -- 2283 * Define which suffix is the null suffix.2284 * 2285 * Results: 2286 * None.2287 * 2288 * Side Effects: 2289 * 'suffNull' is altered.2285 * Define which suffix is the null suffix. 2286 * 2287 * Results: 2288 * None. 2289 * 2290 * Side Effects: 2291 * 'suffNull' is altered. 2290 2292 * 2291 2293 * Notes: 2292 * Need to handle the changing of the null suffix gracefully so the2293 * old transformation rules don't just go away.2294 * Need to handle the changing of the null suffix gracefully so the 2295 * old transformation rules don't just go away. 2294 2296 * 2295 2297 *----------------------------------------------------------------------- … … 2297 2299 void 2298 2300 Suff_SetNull(name) 2299 char *name; /* Name of null suffix */2301 char *name; /* Name of null suffix */ 2300 2302 { 2301 2303 Suff *s; … … 2304 2306 ln = Lst_Find(sufflist, (ClientData)name, SuffSuffHasNameP); 2305 2307 if (ln != NILLNODE) { 2306 s = (Suff *)Lst_Datum(ln);2307 if (suffNull != (Suff *)NULL) {2308 suffNull->flags &= ~SUFF_NULL;2309 }2310 s->flags |= SUFF_NULL;2311 /*2312 * XXX: Here's where the transformation mangling would take place2313 */2314 suffNull = s;2308 s = (Suff *)Lst_Datum(ln); 2309 if (suffNull != (Suff *)NULL) { 2310 suffNull->flags &= ~SUFF_NULL; 2311 } 2312 s->flags |= SUFF_NULL; 2313 /* 2314 * XXX: Here's where the transformation mangling would take place 2315 */ 2316 suffNull = s; 2315 2317 } else { 2316 Parse_Error (PARSE_WARNING, "Desired null suffix %s not defined.",2317 name);2318 Parse_Error (PARSE_WARNING, "Desired null suffix %s not defined.", 2319 name); 2318 2320 } 2319 2321 } … … 2322 2324 *----------------------------------------------------------------------- 2323 2325 * Suff_Init -- 2324 * Initialize suffixes module2325 * 2326 * Results: 2327 * None2328 * 2329 * Side Effects: 2330 * Many2326 * Initialize suffixes module 2327 * 2328 * Results: 2329 * None 2330 * 2331 * Side Effects: 2332 * Many 2331 2333 *----------------------------------------------------------------------- 2332 2334 */ … … 2347 2349 emptySuff = suffNull = (Suff *) emalloc (sizeof (Suff)); 2348 2350 2349 suffNull->name = estrdup ("");2351 suffNull->name = estrdup (""); 2350 2352 suffNull->nameLen = 0; 2351 2353 suffNull->searchPath = Lst_Init (FALSE); 2352 2354 Dir_Concat(suffNull->searchPath, dirSearchPath); 2353 2355 suffNull->children = Lst_Init (FALSE); 2354 suffNull->parents = Lst_Init (FALSE);2355 suffNull->ref = Lst_Init (FALSE);2356 suffNull->sNum = sNum++;2357 suffNull->flags = SUFF_NULL;2356 suffNull->parents = Lst_Init (FALSE); 2357 suffNull->ref = Lst_Init (FALSE); 2358 suffNull->sNum = sNum++; 2359 suffNull->flags = SUFF_NULL; 2358 2360 suffNull->refCount = 1; 2359 2361 … … 2364 2366 *---------------------------------------------------------------------- 2365 2367 * Suff_End -- 2366 * Cleanup the this module2367 * 2368 * Results: 2369 * None2370 * 2371 * Side Effects: 2372 * The memory is efree'd.2368 * Cleanup the this module 2369 * 2370 * Results: 2371 * None 2372 * 2373 * Side Effects: 2374 * The memory is efree'd. 2373 2375 *---------------------------------------------------------------------- 2374 2376 */ … … 2380 2382 Lst_Destroy(suffClean, SuffFree); 2381 2383 if (suffNull) 2382 SuffFree(suffNull);2384 SuffFree(suffNull); 2383 2385 Lst_Destroy(srclist, NOFREE); 2384 2386 Lst_Destroy(transforms, NOFREE); … … 2402 2404 { 2403 2405 Suff *s = (Suff *) sp; 2404 int flags;2405 int flag;2406 int flags; 2407 int flag; 2406 2408 2407 2409 printf ("# `%s' [%d] ", s->name, s->refCount); … … 2409 2411 flags = s->flags; 2410 2412 if (flags) { 2411 fputs (" (", stdout);2412 while (flags) {2413 flag = 1 << (ffs(flags) - 1);2414 flags &= ~flag;2415 switch (flag) {2416 case SUFF_NULL:2417 printf ("NULL");2418 break;2419 case SUFF_INCLUDE:2420 printf ("INCLUDE");2421 break;2413 fputs (" (", stdout); 2414 while (flags) { 2415 flag = 1 << (ffs(flags) - 1); 2416 flags &= ~flag; 2417 switch (flag) { 2418 case SUFF_NULL: 2419 printf ("NULL"); 2420 break; 2421 case SUFF_INCLUDE: 2422 printf ("INCLUDE"); 2423 break; 2422 2424 #ifdef USE_ARCHIVES 2423 case SUFF_LIBRARY:2424 printf ("LIBRARY");2425 break;2425 case SUFF_LIBRARY: 2426 printf ("LIBRARY"); 2427 break; 2426 2428 #endif 2427 }2428 fputc(flags ? '|' : ')', stdout);2429 }2429 } 2430 fputc(flags ? '|' : ')', stdout); 2431 } 2430 2432 } 2431 2433 fputc ('\n', stdout); -
trunk/src/kmk/targ.c
r47 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94";41 static char sccsid[] = "@(#)targ.c 8.2 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/targ.c,v 1.10 1999/09/11 13:08:02 hoek Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * targ.c -- 50 * Functions for maintaining the Lst allTargets. Target nodes are51 * Functions for maintaining the Lst allTargets. Target nodes are 51 52 * kept in two structures: a Lst, maintained by the list library, and a 52 53 * hash table, maintained by the hash library. 53 54 * 54 55 * Interface: 55 * Targ_InitInitialization procedure.56 * 57 * Targ_EndCleanup the module58 * 59 * Targ_NewGNCreate a new GNode for the passed target60 * (string). The node is *not* placed in the61 * hash table, though all its fields are62 * initialized.63 * 64 * Targ_FindNodeFind the node for a given target, creating65 * and storing it if it doesn't exist and the66 * flags are right (TARG_CREATE)67 * 68 * Targ_FindListGiven a list of names, find nodes for all69 * of them. If a name doesn't exist and the70 * TARG_NOCREATE flag was given, an error message71 * is printed. Else, if a name doesn't exist,72 * its node is created.73 * 74 * Targ_IgnoreReturn TRUE if errors should be ignored when75 * creating the given target.76 * 77 * Targ_SilentReturn TRUE if we should be silent when78 * creating the given target.79 * 80 * Targ_PreciousReturn TRUE if the target is precious and81 * should not be removed if we are interrupted.56 * Targ_Init Initialization procedure. 57 * 58 * Targ_End Cleanup the module 59 * 60 * Targ_NewGN Create a new GNode for the passed target 61 * (string). The node is *not* placed in the 62 * hash table, though all its fields are 63 * initialized. 64 * 65 * Targ_FindNode Find the node for a given target, creating 66 * and storing it if it doesn't exist and the 67 * flags are right (TARG_CREATE) 68 * 69 * Targ_FindList Given a list of names, find nodes for all 70 * of them. If a name doesn't exist and the 71 * TARG_NOCREATE flag was given, an error message 72 * is printed. Else, if a name doesn't exist, 73 * its node is created. 74 * 75 * Targ_Ignore Return TRUE if errors should be ignored when 76 * creating the given target. 77 * 78 * Targ_Silent Return TRUE if we should be silent when 79 * creating the given target. 80 * 81 * Targ_Precious Return TRUE if the target is precious and 82 * should not be removed if we are interrupted. 82 83 * 83 84 * Debugging: 84 * Targ_PrintGraph Print out the entire graphm all variables 85 * and statistics for the directory cache. Should 86 * print something for suffixes, too, but... 87 */ 88 89 #include <stdio.h> 90 #include <time.h> 91 #include "make.h" 92 #include "hash.h" 93 #include "dir.h" 94 95 static Lst allTargets; /* the list of all targets found so far */ 96 static Lst allGNs; /* List of all the GNodes */ 97 static Hash_Table targets; /* a hash table of same */ 98 99 #define HTSIZE 191 /* initial size of hash table */ 85 * Targ_PrintGraph Print out the entire graphm all variables 86 * and statistics for the directory cache. Should 87 * print something for suffixes, too, but... 88 */ 89 90 #include <stdio.h> 91 #include <time.h> 92 #include <strings.h> 93 #include "make.h" 94 #include "hash.h" 95 #include "dir.h" 96 97 static Lst allTargets; /* the list of all targets found so far */ 98 static Lst allGNs; /* List of all the GNodes */ 99 static Hash_Table targets; /* a hash table of same */ 100 101 #define HTSIZE 191 /* initial size of hash table */ 100 102 101 103 static int TargPrintOnlySrc __P((ClientData, ClientData)); … … 107 109 *----------------------------------------------------------------------- 108 110 * Targ_Init -- 109 * Initialize this module110 * 111 * Results: 112 * None113 * 114 * Side Effects: 115 * The allTargets list and the targets hash table are initialized111 * Initialize this module 112 * 113 * Results: 114 * None 115 * 116 * Side Effects: 117 * The allTargets list and the targets hash table are initialized 116 118 *----------------------------------------------------------------------- 117 119 */ … … 126 128 *----------------------------------------------------------------------- 127 129 * Targ_End -- 128 * Finalize this module129 * 130 * Results: 131 * None132 * 133 * Side Effects: 134 * All lists and gnodes are cleared130 * Finalize this module 131 * 132 * Results: 133 * None 134 * 135 * Side Effects: 136 * All lists and gnodes are cleared 135 137 *----------------------------------------------------------------------- 136 138 */ … … 140 142 Lst_Destroy(allTargets, NOFREE); 141 143 if (allGNs) 142 Lst_Destroy(allGNs, TargFreeGN);144 Lst_Destroy(allGNs, TargFreeGN); 143 145 Hash_DeleteTable(&targets); 144 146 } … … 147 149 *----------------------------------------------------------------------- 148 150 * Targ_NewGN -- 149 * Create and initialize a new graph node150 * 151 * Results: 152 * An initialized graph node with the name field filled with a copy153 * of the passed name154 * 155 * Side Effects: 156 * The gnode is added to the list of all gnodes.151 * Create and initialize a new graph node 152 * 153 * Results: 154 * An initialized graph node with the name field filled with a copy 155 * of the passed name 156 * 157 * Side Effects: 158 * The gnode is added to the list of all gnodes. 157 159 *----------------------------------------------------------------------- 158 160 */ 159 161 GNode * 160 162 Targ_NewGN (name) 161 char *name; /* the name to stick in the new node */163 char *name; /* the name to stick in the new node */ 162 164 { 163 165 register GNode *gn; … … 168 170 #ifdef USE_ARCHIVES 169 171 if (name[0] == '-' && name[1] == 'l') { 170 gn->type = OP_LIB;172 gn->type = OP_LIB; 171 173 } else { 172 gn->type = 0;174 gn->type = 0; 173 175 } 174 176 #else 175 177 gn->type = 0; 176 178 #endif 177 gn->unmade = 0;178 gn->make = FALSE;179 gn->made = UNMADE;180 gn->childMade = FALSE;181 gn->order = 0;179 gn->unmade = 0; 180 gn->make = FALSE; 181 gn->made = UNMADE; 182 gn->childMade = FALSE; 183 gn->order = 0; 182 184 gn->mtime = gn->cmtime = 0; 183 gn->iParents = Lst_Init (FALSE);184 gn->cohorts = Lst_Init (FALSE);185 gn->parents = Lst_Init (FALSE);186 gn->children = Lst_Init (FALSE);187 gn->successors = Lst_Init (FALSE);188 gn->preds = Lst_Init (FALSE);189 gn->context = Lst_Init (FALSE);190 gn->commands = Lst_Init (FALSE);191 gn->suffix = NULL;185 gn->iParents = Lst_Init (FALSE); 186 gn->cohorts = Lst_Init (FALSE); 187 gn->parents = Lst_Init (FALSE); 188 gn->children = Lst_Init (FALSE); 189 gn->successors = Lst_Init (FALSE); 190 gn->preds = Lst_Init (FALSE); 191 gn->context = Lst_Init (FALSE); 192 gn->commands = Lst_Init (FALSE); 193 gn->suffix = NULL; 192 194 193 195 if (allGNs == NULL) 194 allGNs = Lst_Init(FALSE);196 allGNs = Lst_Init(FALSE); 195 197 Lst_AtEnd(allGNs, (ClientData) gn); 196 198 … … 201 203 *----------------------------------------------------------------------- 202 204 * TargFreeGN -- 203 * Destroy a GNode204 * 205 * Results: 206 * None.207 * 208 * Side Effects: 209 * None.205 * Destroy a GNode 206 * 207 * Results: 208 * None. 209 * 210 * Side Effects: 211 * None. 210 212 *----------------------------------------------------------------------- 211 213 */ … … 235 237 *----------------------------------------------------------------------- 236 238 * Targ_FindNode -- 237 * Find a node in the list using the given name for matching238 * 239 * Results: 240 * The node in the list if it was. If it wasn't, return NILGNODE of241 * flags was TARG_NOCREATE or the newly created and initialized node242 * if it was TARG_CREATE243 * 244 * Side Effects: 245 * Sometimes a node is created and added to the list239 * Find a node in the list using the given name for matching 240 * 241 * Results: 242 * The node in the list if it was. If it wasn't, return NILGNODE of 243 * flags was TARG_NOCREATE or the newly created and initialized node 244 * if it was TARG_CREATE 245 * 246 * Side Effects: 247 * Sometimes a node is created and added to the list 246 248 *----------------------------------------------------------------------- 247 249 */ 248 250 GNode * 249 251 Targ_FindNode (name, flags) 250 char *name; /* the name to find */251 int flags; /* flags governing events when target not252 * found */253 { 254 GNode *gn; /* node in that element */255 Hash_Entry *he;/* New or used hash entry for node */256 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */257 /* an entry for the node */252 char *name; /* the name to find */ 253 int flags; /* flags governing events when target not 254 * found */ 255 { 256 GNode *gn; /* node in that element */ 257 Hash_Entry *he; /* New or used hash entry for node */ 258 Boolean isNew; /* Set TRUE if Hash_CreateEntry had to create */ 259 /* an entry for the node */ 258 260 259 261 260 262 if (flags & TARG_CREATE) { 261 he = Hash_CreateEntry (&targets, name, &isNew);262 if (isNew) {263 gn = Targ_NewGN (name);264 Hash_SetValue (he, gn);265 (void) Lst_AtEnd (allTargets, (ClientData)gn);266 }263 he = Hash_CreateEntry (&targets, name, &isNew); 264 if (isNew) { 265 gn = Targ_NewGN (name); 266 Hash_SetValue (he, gn); 267 (void) Lst_AtEnd (allTargets, (ClientData)gn); 268 } 267 269 } else { 268 he = Hash_FindEntry (&targets, name);270 he = Hash_FindEntry (&targets, name); 269 271 } 270 272 271 273 if (he == (Hash_Entry *) NULL) { 272 return (NILGNODE);274 return (NILGNODE); 273 275 } else { 274 return ((GNode *) Hash_GetValue (he));276 return ((GNode *) Hash_GetValue (he)); 275 277 } 276 278 } … … 279 281 *----------------------------------------------------------------------- 280 282 * Targ_FindList -- 281 * Make a complete list of GNodes from the given list of names282 * 283 * Results: 284 * A complete list of graph nodes corresponding to all instances of all285 * the names in names.286 * 287 * Side Effects: 288 * If flags is TARG_CREATE, nodes will be created for all names in289 * names which do not yet have graph nodes. If flags is TARG_NOCREATE,290 * an error message will be printed for each name which can't be found.283 * Make a complete list of GNodes from the given list of names 284 * 285 * Results: 286 * A complete list of graph nodes corresponding to all instances of all 287 * the names in names. 288 * 289 * Side Effects: 290 * If flags is TARG_CREATE, nodes will be created for all names in 291 * names which do not yet have graph nodes. If flags is TARG_NOCREATE, 292 * an error message will be printed for each name which can't be found. 291 293 * ----------------------------------------------------------------------- 292 294 */ 293 295 Lst 294 296 Targ_FindList (names, flags) 295 Lst names;/* list of names to find */296 int flags; /* flags used if no node is found for a given297 * name */298 { 299 Lst nodes; /* result list */300 register LstNode ln; /* name list element */301 register GNode *gn; /* node in tLn */302 char *name;297 Lst names; /* list of names to find */ 298 int flags; /* flags used if no node is found for a given 299 * name */ 300 { 301 Lst nodes; /* result list */ 302 register LstNode ln; /* name list element */ 303 register GNode *gn; /* node in tLn */ 304 char *name; 303 305 304 306 nodes = Lst_Init (FALSE); 305 307 306 308 if (Lst_Open (names) == FAILURE) { 307 return (nodes);309 return (nodes); 308 310 } 309 311 while ((ln = Lst_Next (names)) != NILLNODE) { 310 name = (char *)Lst_Datum(ln);311 gn = Targ_FindNode (name, flags);312 if (gn != NILGNODE) {313 /*314 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes315 * are added to the list in the order in which they were316 * encountered in the makefile.317 */318 (void) Lst_AtEnd (nodes, (ClientData)gn);319 if (gn->type & OP_DOUBLEDEP) {320 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW);321 }322 } else if (flags == TARG_NOCREATE) {323 Error ("\"%s\" -- target unknown.", name);324 }312 name = (char *)Lst_Datum(ln); 313 gn = Targ_FindNode (name, flags); 314 if (gn != NILGNODE) { 315 /* 316 * Note: Lst_AtEnd must come before the Lst_Concat so the nodes 317 * are added to the list in the order in which they were 318 * encountered in the makefile. 319 */ 320 (void) Lst_AtEnd (nodes, (ClientData)gn); 321 if (gn->type & OP_DOUBLEDEP) { 322 (void)Lst_Concat (nodes, gn->cohorts, LST_CONCNEW); 323 } 324 } else if (flags == TARG_NOCREATE) { 325 Error ("\"%s\" -- target unknown.", name); 326 } 325 327 } 326 328 Lst_Close (names); … … 331 333 *----------------------------------------------------------------------- 332 334 * Targ_Ignore -- 333 * Return true if should ignore errors when creating gn334 * 335 * Results: 336 * TRUE if should ignore errors337 * 338 * Side Effects: 339 * None335 * Return true if should ignore errors when creating gn 336 * 337 * Results: 338 * TRUE if should ignore errors 339 * 340 * Side Effects: 341 * None 340 342 *----------------------------------------------------------------------- 341 343 */ 342 344 Boolean 343 345 Targ_Ignore (gn) 344 GNode *gn; /* node to check for */346 GNode *gn; /* node to check for */ 345 347 { 346 348 if (ignoreErrors || gn->type & OP_IGNORE) { 347 return (TRUE);349 return (TRUE); 348 350 } else { 349 return (FALSE);351 return (FALSE); 350 352 } 351 353 } … … 354 356 *----------------------------------------------------------------------- 355 357 * Targ_Silent -- 356 * Return true if be silent when creating gn357 * 358 * Results: 359 * TRUE if should be silent360 * 361 * Side Effects: 362 * None358 * Return true if be silent when creating gn 359 * 360 * Results: 361 * TRUE if should be silent 362 * 363 * Side Effects: 364 * None 363 365 *----------------------------------------------------------------------- 364 366 */ 365 367 Boolean 366 368 Targ_Silent (gn) 367 GNode *gn; /* node to check for */369 GNode *gn; /* node to check for */ 368 370 { 369 371 if (beSilent || gn->type & OP_SILENT) { 370 return (TRUE);372 return (TRUE); 371 373 } else { 372 return (FALSE);374 return (FALSE); 373 375 } 374 376 } … … 377 379 *----------------------------------------------------------------------- 378 380 * Targ_Precious -- 379 * See if the given target is precious380 * 381 * Results: 382 * TRUE if it is precious. FALSE otherwise383 * 384 * Side Effects: 385 * None381 * See if the given target is precious 382 * 383 * Results: 384 * TRUE if it is precious. FALSE otherwise 385 * 386 * Side Effects: 387 * None 386 388 *----------------------------------------------------------------------- 387 389 */ 388 390 Boolean 389 391 Targ_Precious (gn) 390 GNode *gn; /* the node to check */392 GNode *gn; /* the node to check */ 391 393 { 392 394 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 393 return (TRUE);395 return (TRUE); 394 396 } else { 395 return (FALSE);397 return (FALSE); 396 398 } 397 399 } … … 399 401 /******************* DEBUG INFO PRINTING ****************/ 400 402 401 static GNode *mainTarg;/* the main target, as set by Targ_SetMain */403 static GNode *mainTarg; /* the main target, as set by Targ_SetMain */ 402 404 /*- 403 405 *----------------------------------------------------------------------- 404 406 * Targ_SetMain -- 405 * Set our idea of the main target we'll be creating. Used for406 * debugging output.407 * 408 * Results: 409 * None.410 * 411 * Side Effects: 412 * "mainTarg" is set to the main target's node.407 * Set our idea of the main target we'll be creating. Used for 408 * debugging output. 409 * 410 * Results: 411 * None. 412 * 413 * Side Effects: 414 * "mainTarg" is set to the main target's node. 413 415 *----------------------------------------------------------------------- 414 416 */ 415 417 void 416 418 Targ_SetMain (gn) 417 GNode *gn; /* The main target we'll create */419 GNode *gn; /* The main target we'll create */ 418 420 { 419 421 mainTarg = gn; … … 423 425 TargPrintName (gnp, ppath) 424 426 ClientData gnp; 425 ClientData ppath;427 ClientData ppath; 426 428 { 427 429 GNode *gn = (GNode *) gnp; … … 429 431 #ifdef notdef 430 432 if (ppath) { 431 if (gn->path) {432 printf ("[%s] ", gn->path);433 }434 if (gn == mainTarg) {435 printf ("(MAIN NAME) ");436 }433 if (gn->path) { 434 printf ("[%s] ", gn->path); 435 } 436 if (gn == mainTarg) { 437 printf ("(MAIN NAME) "); 438 } 437 439 } 438 440 #endif /* notdef */ … … 453 455 *----------------------------------------------------------------------- 454 456 * Targ_FmtTime -- 455 * Format a modification time in some reasonable way and return it.456 * 457 * Results: 458 * The time reformatted.459 * 460 * Side Effects: 461 * The time is placed in a static area, so it is overwritten462 * with each call.457 * Format a modification time in some reasonable way and return it. 458 * 459 * Results: 460 * The time reformatted. 461 * 462 * Side Effects: 463 * The time is placed in a static area, so it is overwritten 464 * with each call. 463 465 * 464 466 *----------------------------------------------------------------------- … … 468 470 time_t time; 469 471 { 470 struct tm *parts;471 static char buf[128];472 struct tm *parts; 473 static char buf[128]; 472 474 473 475 parts = localtime(&time); … … 487 489 *----------------------------------------------------------------------- 488 490 * Targ_PrintType -- 489 * Print out a type field giving only those attributes the user can490 * set.491 * Print out a type field giving only those attributes the user can 492 * set. 491 493 * 492 494 * Results: … … 502 504 register int tbit; 503 505 504 #if def __STDC__505 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break506 #if defined(__STDC__) || defined(__IBMC__) 507 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf("." #attr " "); break 506 508 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf("." #attr " "); break 507 509 #else 508 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break509 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break510 #define PRINTBIT(attr) case CONCAT(OP_,attr): printf(".attr "); break 511 #define PRINTDBIT(attr) case CONCAT(OP_,attr): if (DEBUG(TARG)) printf(".attr "); break 510 512 #endif /* __STDC__ */ 511 513 … … 513 515 514 516 while (type) { 515 tbit = 1 << (ffs(type) - 1);516 type &= ~tbit;517 518 switch(tbit) {519 PRINTBIT(OPTIONAL);520 PRINTBIT(USE);521 PRINTBIT(EXEC);522 PRINTBIT(IGNORE);523 PRINTBIT(PRECIOUS);524 PRINTBIT(SILENT);525 PRINTBIT(MAKE);526 PRINTBIT(JOIN);527 PRINTBIT(INVISIBLE);528 PRINTBIT(NOTMAIN);517 tbit = 1 << (ffs(type) - 1); 518 type &= ~tbit; 519 520 switch(tbit) { 521 PRINTBIT(OPTIONAL); 522 PRINTBIT(USE); 523 PRINTBIT(EXEC); 524 PRINTBIT(IGNORE); 525 PRINTBIT(PRECIOUS); 526 PRINTBIT(SILENT); 527 PRINTBIT(MAKE); 528 PRINTBIT(JOIN); 529 PRINTBIT(INVISIBLE); 530 PRINTBIT(NOTMAIN); 529 531 #ifdef USE_ARCHIVES 530 PRINTDBIT(LIB);532 PRINTDBIT(LIB); 531 533 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 532 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break;533 PRINTDBIT(ARCHV);534 case OP_MEMBER: if (DEBUG(TARG)) printf(".MEMBER "); break; 535 PRINTDBIT(ARCHV); 534 536 #endif 535 }537 } 536 538 } 537 539 } … … 540 542 *----------------------------------------------------------------------- 541 543 * TargPrintNode -- 542 * print the contents of a node544 * print the contents of a node 543 545 *----------------------------------------------------------------------- 544 546 */ … … 546 548 TargPrintNode (gnp, passp) 547 549 ClientData gnp; 548 ClientData passp;550 ClientData passp; 549 551 { 550 552 GNode *gn = (GNode *) gnp; 551 int pass = *(int *) passp;553 int pass = *(int *) passp; 552 554 if (!OP_NOP(gn->type)) { 553 printf("#\n");554 if (gn == mainTarg) {555 printf("# *** MAIN TARGET ***\n");556 }557 if (pass == 2) {558 if (gn->unmade) {559 printf("# %d unmade children\n", gn->unmade);560 } else {561 printf("# No unmade children\n");562 }563 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) {564 if (gn->mtime != 0) {565 printf("# last modified %s: %s\n",566 Targ_FmtTime(gn->mtime),567 (gn->made == UNMADE ? "unmade" :568 (gn->made == MADE ? "made" :569 (gn->made == UPTODATE ? "up-to-date" :570 "error when made"))));571 } else if (gn->made != UNMADE) {572 printf("# non-existent (maybe): %s\n",573 (gn->made == MADE ? "made" :574 (gn->made == UPTODATE ? "up-to-date" :575 (gn->made == ERROR ? "error when made" :576 "aborted"))));577 } else {578 printf("# unmade\n");579 }580 }581 if (!Lst_IsEmpty (gn->iParents)) {582 printf("# implicit parents: ");583 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0);584 fputc ('\n', stdout);585 }586 }587 if (!Lst_IsEmpty (gn->parents)) {588 printf("# parents: ");589 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0);590 fputc ('\n', stdout);591 }592 593 printf("%-16s", gn->name);594 switch (gn->type & OP_OPMASK) {595 case OP_DEPENDS:596 printf(": "); break;597 case OP_FORCE:598 printf("! "); break;599 case OP_DOUBLEDEP:600 printf(":: "); break;601 }602 Targ_PrintType (gn->type);603 Lst_ForEach (gn->children, TargPrintName, (ClientData)0);604 fputc ('\n', stdout);605 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0);606 printf("\n\n");607 if (gn->type & OP_DOUBLEDEP) {608 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass);609 }555 printf("#\n"); 556 if (gn == mainTarg) { 557 printf("# *** MAIN TARGET ***\n"); 558 } 559 if (pass == 2) { 560 if (gn->unmade) { 561 printf("# %d unmade children\n", gn->unmade); 562 } else { 563 printf("# No unmade children\n"); 564 } 565 if (! (gn->type & (OP_JOIN|OP_USE|OP_EXEC))) { 566 if (gn->mtime != 0) { 567 printf("# last modified %s: %s\n", 568 Targ_FmtTime(gn->mtime), 569 (gn->made == UNMADE ? "unmade" : 570 (gn->made == MADE ? "made" : 571 (gn->made == UPTODATE ? "up-to-date" : 572 "error when made")))); 573 } else if (gn->made != UNMADE) { 574 printf("# non-existent (maybe): %s\n", 575 (gn->made == MADE ? "made" : 576 (gn->made == UPTODATE ? "up-to-date" : 577 (gn->made == ERROR ? "error when made" : 578 "aborted")))); 579 } else { 580 printf("# unmade\n"); 581 } 582 } 583 if (!Lst_IsEmpty (gn->iParents)) { 584 printf("# implicit parents: "); 585 Lst_ForEach (gn->iParents, TargPrintName, (ClientData)0); 586 fputc ('\n', stdout); 587 } 588 } 589 if (!Lst_IsEmpty (gn->parents)) { 590 printf("# parents: "); 591 Lst_ForEach (gn->parents, TargPrintName, (ClientData)0); 592 fputc ('\n', stdout); 593 } 594 595 printf("%-16s", gn->name); 596 switch (gn->type & OP_OPMASK) { 597 case OP_DEPENDS: 598 printf(": "); break; 599 case OP_FORCE: 600 printf("! "); break; 601 case OP_DOUBLEDEP: 602 printf(":: "); break; 603 } 604 Targ_PrintType (gn->type); 605 Lst_ForEach (gn->children, TargPrintName, (ClientData)0); 606 fputc ('\n', stdout); 607 Lst_ForEach (gn->commands, Targ_PrintCmd, (ClientData)0); 608 printf("\n\n"); 609 if (gn->type & OP_DOUBLEDEP) { 610 Lst_ForEach (gn->cohorts, TargPrintNode, (ClientData)&pass); 611 } 610 612 } 611 613 return (0); … … 615 617 *----------------------------------------------------------------------- 616 618 * TargPrintOnlySrc -- 617 * Print only those targets that are just a source.618 * 619 * Results: 620 * 0.621 * 622 * Side Effects: 623 * The name of each file is printed preceeded by #\t619 * Print only those targets that are just a source. 620 * 621 * Results: 622 * 0. 623 * 624 * Side Effects: 625 * The name of each file is printed preceeded by #\t 624 626 * 625 627 *----------------------------------------------------------------------- … … 627 629 static int 628 630 TargPrintOnlySrc(gnp, dummy) 629 ClientData gnp;630 ClientData dummy;631 { 632 GNode *gn = (GNode *) gnp;631 ClientData gnp; 632 ClientData dummy; 633 { 634 GNode *gn = (GNode *) gnp; 633 635 if (OP_NOP(gn->type)) 634 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name);636 printf("#\t%s [%s]\n", gn->name, gn->path ? gn->path : gn->name); 635 637 636 638 return (dummy ? 0 : 0); … … 640 642 *----------------------------------------------------------------------- 641 643 * Targ_PrintGraph -- 642 * print the entire graph. heh heh643 * 644 * Results: 645 * none646 * 647 * Side Effects: 648 * lots o' output644 * print the entire graph. heh heh 645 * 646 * Results: 647 * none 648 * 649 * Side Effects: 650 * lots o' output 649 651 *----------------------------------------------------------------------- 650 652 */ 651 653 void 652 654 Targ_PrintGraph (pass) 653 int pass;/* Which pass this is. 1 => no processing654 * 2 => processing done */655 int pass; /* Which pass this is. 1 => no processing 656 * 2 => processing done */ 655 657 { 656 658 printf("#*** Input graph:\n"); -
trunk/src/kmk/util.c
r35 r51 5 5 #ifndef lint 6 6 static char rcsid[] = "$FreeBSD: src/usr.bin/make/util.c,v 1.5.2.2 2001/02/13 03:13:58 will Exp $"; 7 #define KLIBFILEDEF rcsid 7 8 #endif 8 9 … … 27 28 static char buf[100]; 28 29 if (e < 0 || e >= sys_nerr) { 29 sprintf(buf, "Unknown error %d", e);30 return buf;30 sprintf(buf, "Unknown error %d", e); 31 return buf; 31 32 } 32 33 else 33 return sys_errlist[e];34 return sys_errlist[e]; 34 35 } 35 36 #endif … … 50 51 51 52 if (str == NULL) 52 return NULL;53 return NULL; 53 54 len = strlen(str) + 1; 54 55 if ((p = emalloc(len)) == NULL) 55 return NULL;56 return NULL; 56 57 57 58 return memcpy(p, str, len); … … 60 61 #endif 61 62 62 #if defined(sun) || defined(__hpux) || defined(__sgi) || defined(__EMX__) || (defined(OS2) && defined(__IBMC__)) 63 #ifndef USE_KLIB 64 #if defined(sun) || defined(__hpux) || defined(__sgi) || defined(__EMX__) 63 65 64 66 int … … 75 77 76 78 if (ptr == NULL) 77 return -1;79 return -1; 78 80 79 81 p = ptr; 80 82 81 83 while (*name) 82 *p++ = *name++;84 *p++ = *name++; 83 85 84 86 *p++ = '='; 85 87 86 88 while (*value) 87 *p++ = *value++;89 *p++ = *value++; 88 90 89 91 *p = '\0'; … … 93 95 return len; 94 96 } 97 #endif 95 98 #endif 96 99 … … 157 160 158 161 /* strrcpy(): 159 * Like strcpy, going backwards and returning the new pointer162 * Like strcpy, going backwards and returning the new pointer 160 163 */ 161 164 static char * … … 166 169 167 170 while (len) 168 *--ptr = str[--len];171 *--ptr = str[--len]; 169 172 170 173 return (ptr); … … 185 188 /* find the inode of root */ 186 189 if (stat("/", &st_root) == -1) { 187 (void) sprintf(pathname,188 "getwd: Cannot stat \"/\" (%s)", strerror(errno));189 return (NULL);190 (void) sprintf(pathname, 191 "getwd: Cannot stat \"/\" (%s)", strerror(errno)); 192 return (NULL); 190 193 } 191 194 pathbuf[MAXPATHLEN - 1] = '\0'; … … 196 199 /* find the inode of the current directory */ 197 200 if (lstat(".", &st_cur) == -1) { 198 (void) sprintf(pathname,199 "getwd: Cannot stat \".\" (%s)", strerror(errno));200 return (NULL);201 (void) sprintf(pathname, 202 "getwd: Cannot stat \".\" (%s)", strerror(errno)); 203 return (NULL); 201 204 } 202 205 nextpathptr = strrcpy(nextpathptr, "../"); … … 205 208 for (;;) { 206 209 207 /* look if we found root yet */208 if (st_cur.st_ino == st_root.st_ino &&209 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) {210 (void) strcpy(pathname, *pathptr != '/' ? "/" : pathptr);211 return (pathname);212 }213 214 /* open the parent directory */215 if (stat(nextpathptr, &st_dotdot) == -1) {216 snprintf(pathname, sizeof(pathname),217 "getwd: Cannot stat directory \"%s\" (%s)",218 nextpathptr, strerror(errno));219 return (NULL);220 }221 if ((dp = opendir(nextpathptr)) == NULL) {222 snprintf(pathname, sizeof(pathname),223 "getwd: Cannot open directory \"%s\" (%s)",224 nextpathptr, strerror(errno));225 return (NULL);226 }227 228 /* look in the parent for the entry with the same inode */229 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) {230 /* Parent has same device. No need to stat every member */231 for (d = readdir(dp); d != NULL; d = readdir(dp))232 if (d->d_fileno == st_cur.st_ino)233 break;234 }235 else {236 /*237 * Parent has a different device. This is a mount point so we238 * need to stat every member239 */240 for (d = readdir(dp); d != NULL; d = readdir(dp)) {241 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name))242 continue;243 (void) strcpy(cur_name_add, d->d_name);244 if (lstat(nextpathptr, &st_next) == -1) {245 snprintf(pathname, sizeof(pathname), "getwd: Cannot stat \"%s\" (%s)",246 d->d_name, strerror(errno));247 (void) closedir(dp);248 return (NULL);249 }250 /* check if we found it yet */251 if (st_next.st_ino == st_cur.st_ino &&252 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev))253 break;254 }255 }256 if (d == NULL) {257 (void) sprintf(pathname, "getwd: Cannot find \".\" in \"..\"");258 (void) closedir(dp);259 return (NULL);260 }261 st_cur = st_dotdot;262 pathptr = strrcpy(pathptr, d->d_name);263 pathptr = strrcpy(pathptr, "/");264 nextpathptr = strrcpy(nextpathptr, "../");265 (void) closedir(dp);266 *cur_name_add = '\0';210 /* look if we found root yet */ 211 if (st_cur.st_ino == st_root.st_ino && 212 DEV_DEV_COMPARE(st_cur.st_dev, st_root.st_dev)) { 213 (void) strcpy(pathname, *pathptr != '/' ? "/" : pathptr); 214 return (pathname); 215 } 216 217 /* open the parent directory */ 218 if (stat(nextpathptr, &st_dotdot) == -1) { 219 snprintf(pathname, sizeof(pathname), 220 "getwd: Cannot stat directory \"%s\" (%s)", 221 nextpathptr, strerror(errno)); 222 return (NULL); 223 } 224 if ((dp = opendir(nextpathptr)) == NULL) { 225 snprintf(pathname, sizeof(pathname), 226 "getwd: Cannot open directory \"%s\" (%s)", 227 nextpathptr, strerror(errno)); 228 return (NULL); 229 } 230 231 /* look in the parent for the entry with the same inode */ 232 if (DEV_DEV_COMPARE(st_dotdot.st_dev, st_cur.st_dev)) { 233 /* Parent has same device. No need to stat every member */ 234 for (d = readdir(dp); d != NULL; d = readdir(dp)) 235 if (d->d_fileno == st_cur.st_ino) 236 break; 237 } 238 else { 239 /* 240 * Parent has a different device. This is a mount point so we 241 * need to stat every member 242 */ 243 for (d = readdir(dp); d != NULL; d = readdir(dp)) { 244 if (ISDOT(d->d_name) || ISDOTDOT(d->d_name)) 245 continue; 246 (void) strcpy(cur_name_add, d->d_name); 247 if (lstat(nextpathptr, &st_next) == -1) { 248 snprintf(pathname, sizeof(pathname), "getwd: Cannot stat \"%s\" (%s)", 249 d->d_name, strerror(errno)); 250 (void) closedir(dp); 251 return (NULL); 252 } 253 /* check if we found it yet */ 254 if (st_next.st_ino == st_cur.st_ino && 255 DEV_DEV_COMPARE(st_next.st_dev, st_cur.st_dev)) 256 break; 257 } 258 } 259 if (d == NULL) { 260 (void) sprintf(pathname, "getwd: Cannot find \".\" in \"..\""); 261 (void) closedir(dp); 262 return (NULL); 263 } 264 st_cur = st_dotdot; 265 pathptr = strrcpy(pathptr, d->d_name); 266 pathptr = strrcpy(pathptr, "/"); 267 nextpathptr = strrcpy(nextpathptr, "../"); 268 (void) closedir(dp); 269 *cur_name_add = '\0'; 267 270 } 268 271 } /* end getwd */ … … 336 339 337 340 if (sigaction(s, &sa, &osa) == -1) 338 return SIG_ERR;341 return SIG_ERR; 339 342 else 340 return osa.sa_handler;341 } 342 343 #endif 343 return osa.sa_handler; 344 } 345 346 #endif -
trunk/src/kmk/var.c
r46 r51 1 1 /* 2 2 * Copyright (c) 1988, 1989, 1990, 1993 3 * The Regents of the University of California. All rights reserved.3 * The Regents of the University of California. All rights reserved. 4 4 * Copyright (c) 1989 by Berkeley Softworks 5 5 * All rights reserved. … … 18 18 * 3. All advertising materials mentioning features or use of this software 19 19 * must display the following acknowledgement: 20 * This product includes software developed by the University of21 * California, Berkeley and its contributors.20 * This product includes software developed by the University of 21 * California, Berkeley and its contributors. 22 22 * 4. Neither the name of the University nor the names of its contributors 23 23 * may be used to endorse or promote products derived from this software … … 39 39 #ifndef lint 40 40 #if 0 41 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94";41 static char sccsid[] = "@(#)var.c 8.3 (Berkeley) 3/19/94"; 42 42 #else 43 43 static const char rcsid[] = 44 44 "$FreeBSD: src/usr.bin/make/var.c,v 1.16.2.3 2002/02/27 14:18:57 cjc Exp $"; 45 45 #endif 46 #define KLIBFILEDEF rcsid 46 47 #endif /* not lint */ 47 48 48 49 /*- 49 50 * var.c -- 50 * Variable-handling functions51 * Variable-handling functions 51 52 * 52 53 * Interface: 53 * Var_SetSet the value of a variable in the given54 * context. The variable is created if it doesn't55 * yet exist. The value and variable name need not56 * be preserved.57 * 58 * Var_AppendAppend more characters to an existing variable59 * in the given context. The variable needn't60 * exist already -- it will be created if it doesn't.61 * A space is placed between the old value and the62 * new one.63 * 64 * Var_ExistsSee if a variable exists.65 * 66 * Var_ValueReturn the value of a variable in a context or67 * NULL if the variable is undefined.68 * 69 * Var_SubstSubstitute named variable, or all variables if70 * NULL in a string using71 * the given context as the top-most one. If the72 * third argument is non-zero, Parse_Error is73 * called if any variables are undefined.74 * 75 * Var_ParseParse a variable expansion from a string and76 * return the result and the number of characters77 * consumed.78 * 79 * Var_DeleteDelete a variable in a context.80 * 81 * Var_InitInitialize this module.54 * Var_Set Set the value of a variable in the given 55 * context. The variable is created if it doesn't 56 * yet exist. The value and variable name need not 57 * be preserved. 58 * 59 * Var_Append Append more characters to an existing variable 60 * in the given context. The variable needn't 61 * exist already -- it will be created if it doesn't. 62 * A space is placed between the old value and the 63 * new one. 64 * 65 * Var_Exists See if a variable exists. 66 * 67 * Var_Value Return the value of a variable in a context or 68 * NULL if the variable is undefined. 69 * 70 * Var_Subst Substitute named variable, or all variables if 71 * NULL in a string using 72 * the given context as the top-most one. If the 73 * third argument is non-zero, Parse_Error is 74 * called if any variables are undefined. 75 * 76 * Var_Parse Parse a variable expansion from a string and 77 * return the result and the number of characters 78 * consumed. 79 * 80 * Var_Delete Delete a variable in a context. 81 * 82 * Var_Init Initialize this module. 82 83 * 83 84 * Debugging: 84 * Var_DumpPrint out all variables defined in the given85 * context.85 * Var_Dump Print out all variables defined in the given 86 * context. 86 87 * 87 88 * XXX: There's a lot of duplication in these functions. … … 106 107 * a flag, as things outside this module don't give a hoot. 107 108 */ 108 char var_Error[] = "";109 char var_Error[] = ""; 109 110 110 111 /* … … 113 114 * identical string instances... 114 115 */ 115 static char varNoError[] = "";116 static char varNoError[] = ""; 116 117 117 118 /* 118 119 * Internally, variables are contained in four different contexts. 119 * 1) the environment. They may not be changed. If an environment120 * variable is appended-to, the result is placed in the global121 * context.122 * 2) the global context. Variables set in the Makefile are located in123 * the global context. It is the penultimate context searched when124 * substituting.125 * 3) the command-line context. All variables set on the command line126 * are placed in this context. They are UNALTERABLE once placed here.127 * 4) the local context. Each target has associated with it a context128 * list. On this list are located the structures describing such129 * local variables as $(@) and $(*)120 * 1) the environment. They may not be changed. If an environment 121 * variable is appended-to, the result is placed in the global 122 * context. 123 * 2) the global context. Variables set in the Makefile are located in 124 * the global context. It is the penultimate context searched when 125 * substituting. 126 * 3) the command-line context. All variables set on the command line 127 * are placed in this context. They are UNALTERABLE once placed here. 128 * 4) the local context. Each target has associated with it a context 129 * list. On this list are located the structures describing such 130 * local variables as $(@) and $(*) 130 131 * The four contexts are searched in the reverse order from which they are 131 132 * listed. … … 134 135 GNode *VAR_CMD; /* variables defined on the command-line */ 135 136 136 static Lst allVars; /* List of all variables */137 138 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */139 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */140 #define FIND_ENV 0x4 /* look in the environment also */137 static Lst allVars; /* List of all variables */ 138 139 #define FIND_CMD 0x1 /* look in VAR_CMD when searching */ 140 #define FIND_GLOBAL 0x2 /* look in VAR_GLOBAL as well */ 141 #define FIND_ENV 0x4 /* look in the environment also */ 141 142 142 143 typedef struct Var { 143 char *name; /* the variable's name */144 Buffer val;/* its value */145 int flags;/* miscellaneous status flags */146 #define VAR_IN_USE 1/* Variable's value currently being used.147 * Used to avoid recursion */148 #define VAR_FROM_ENV 2/* Variable comes from the environment */149 #define VAR_JUNK 4/* Variable is a junk variable that150 * should be destroyed when done with151 * it. Used by Var_Parse for undefined,152 * modified variables */144 char *name; /* the variable's name */ 145 Buffer val; /* its value */ 146 int flags; /* miscellaneous status flags */ 147 #define VAR_IN_USE 1 /* Variable's value currently being used. 148 * Used to avoid recursion */ 149 #define VAR_FROM_ENV 2 /* Variable comes from the environment */ 150 #define VAR_JUNK 4 /* Variable is a junk variable that 151 * should be destroyed when done with 152 * it. Used by Var_Parse for undefined, 153 * modified variables */ 153 154 } Var; 154 155 155 156 /* Var*Pattern flags */ 156 #define VAR_SUB_GLOBAL 0x01/* Apply substitution globally */157 #define VAR_SUB_ONE 0x02/* Apply substitution to one word */158 #define VAR_SUB_MATCHED 0x04/* There was a match */159 #define VAR_MATCH_START 0x08/* Match at start of word */160 #define VAR_MATCH_END 0x10/* Match at end of word */161 #define VAR_NOSUBST 0x20/* don't expand vars in VarGetPattern */157 #define VAR_SUB_GLOBAL 0x01 /* Apply substitution globally */ 158 #define VAR_SUB_ONE 0x02 /* Apply substitution to one word */ 159 #define VAR_SUB_MATCHED 0x04 /* There was a match */ 160 #define VAR_MATCH_START 0x08 /* Match at start of word */ 161 #define VAR_MATCH_END 0x10 /* Match at end of word */ 162 #define VAR_NOSUBST 0x20 /* don't expand vars in VarGetPattern */ 162 163 163 164 typedef struct { 164 char *lhs;/* String to match */165 int leftLen; /* Length of string */166 char *rhs;/* Replacement string (w/ &'s removed) */167 int rightLen; /* Length of replacement */168 int flags;165 char *lhs; /* String to match */ 166 int leftLen; /* Length of string */ 167 char *rhs; /* Replacement string (w/ &'s removed) */ 168 int rightLen; /* Length of replacement */ 169 int flags; 169 170 } VarPattern; 170 171 171 172 typedef struct { 172 regex_t re;173 int nsub;174 regmatch_t *matches;175 char *replace;176 int flags;173 regex_t re; 174 int nsub; 175 regmatch_t *matches; 176 char *replace; 177 int flags; 177 178 } VarREPattern; 178 179 … … 185 186 static Boolean VarSuffix __P((char *, Boolean, Buffer, ClientData)); 186 187 static Boolean VarRoot __P((char *, Boolean, Buffer, ClientData)); 187 #if defined(NMAKE) || defined(KMK)188 #ifdef USE_BASEANDROOT_MODIFIERS 188 189 static Boolean VarBase __P((char *, Boolean, Buffer, ClientData)); 189 190 #endif … … 197 198 static Boolean VarSubstitute __P((char *, Boolean, Buffer, ClientData)); 198 199 static char *VarGetPattern __P((GNode *, int, char **, int, int *, int *, 199 VarPattern *));200 VarPattern *)); 200 201 static char *VarQuote __P((char *)); 201 202 static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, 202 ClientData),203 ClientData));203 ClientData), 204 ClientData)); 204 205 static int VarPrintVar __P((ClientData, ClientData)); 205 206 … … 207 208 *----------------------------------------------------------------------- 208 209 * VarCmp -- 209 * See if the given variable matches the named one. Called from210 * Lst_Find when searching for a variable of a given name.211 * 212 * Results: 213 * 0 if they match. non-zero otherwise.214 * 215 * Side Effects: 216 * none210 * See if the given variable matches the named one. Called from 211 * Lst_Find when searching for a variable of a given name. 212 * 213 * Results: 214 * 0 if they match. non-zero otherwise. 215 * 216 * Side Effects: 217 * none 217 218 *----------------------------------------------------------------------- 218 219 */ 219 220 static int 220 221 VarCmp (v, name) 221 ClientData v; /* VAR structure to compare */222 ClientData name; /* name to look for */222 ClientData v; /* VAR structure to compare */ 223 ClientData name; /* name to look for */ 223 224 { 224 225 return (strcmp ((char *) name, ((Var *) v)->name)); … … 228 229 *----------------------------------------------------------------------- 229 230 * StrCmp -- 230 * See if the given strings matches. Called from231 * Lst_Find when searching for a environment-variable-overrided var.232 * 233 * Results: 234 * 0 if they match. non-zero otherwise.235 * 236 * Side Effects: 237 * none231 * See if the given strings matches. Called from 232 * Lst_Find when searching for a environment-variable-overrided var. 233 * 234 * Results: 235 * 0 if they match. non-zero otherwise. 236 * 237 * Side Effects: 238 * none 238 239 *----------------------------------------------------------------------- 239 240 */ … … 251 252 *----------------------------------------------------------------------- 252 253 * VarFind -- 253 * Find the given variable in the given context and any other contexts254 * indicated.255 * 256 * Results: 257 * A pointer to the structure describing the desired variable or258 * NIL if the variable does not exist.259 * 260 * Side Effects: 261 * None254 * Find the given variable in the given context and any other contexts 255 * indicated. 256 * 257 * Results: 258 * A pointer to the structure describing the desired variable or 259 * NIL if the variable does not exist. 260 * 261 * Side Effects: 262 * None 262 263 *----------------------------------------------------------------------- 263 264 */ 264 265 static Var * 265 266 VarFind (name, ctxt, flags) 266 char *name;/* name to find */267 GNode *ctxt;/* context in which to find it */268 int flags;/* FIND_GLOBAL set means to look in the269 * VAR_GLOBAL context as well.270 * FIND_CMD set means to look in the VAR_CMD271 * context also.272 * FIND_ENV set means to look in the273 * environment */274 { 275 Boolean localCheckEnvFirst;276 LstNode var;277 Var *v;278 279 /*280 * If the variable name begins with a '.', it could very well be one of281 * the local ones. We check the name against all the local variables282 * and substitute the short version in for 'name' if it matches one of283 * them.284 */285 if (*name == '.' && isupper((unsigned char) name[1]))286 switch (name[1]) {287 case 'A':288 if (!strcmp(name, ".ALLSRC"))289 name = ALLSRC;267 char *name; /* name to find */ 268 GNode *ctxt; /* context in which to find it */ 269 int flags; /* FIND_GLOBAL set means to look in the 270 * VAR_GLOBAL context as well. 271 * FIND_CMD set means to look in the VAR_CMD 272 * context also. 273 * FIND_ENV set means to look in the 274 * environment */ 275 { 276 Boolean localCheckEnvFirst; 277 LstNode var; 278 Var *v; 279 280 /* 281 * If the variable name begins with a '.', it could very well be one of 282 * the local ones. We check the name against all the local variables 283 * and substitute the short version in for 'name' if it matches one of 284 * them. 285 */ 286 if (*name == '.' && isupper((unsigned char) name[1])) 287 switch (name[1]) { 288 case 'A': 289 if (!strcmp(name, ".ALLSRC")) 290 name = ALLSRC; 290 291 #ifdef USE_ARCHIVES 291 if (!strcmp(name, ".ARCHIVE"))292 name = ARCHIVE;292 if (!strcmp(name, ".ARCHIVE")) 293 name = ARCHIVE; 293 294 #endif 294 break;295 case 'I':296 if (!strcmp(name, ".IMPSRC"))297 name = IMPSRC;298 break;295 break; 296 case 'I': 297 if (!strcmp(name, ".IMPSRC")) 298 name = IMPSRC; 299 break; 299 300 #ifdef USE_ARCHIVES 300 case 'M':301 if (!strcmp(name, ".MEMBER"))302 name = MEMBER;303 break;301 case 'M': 302 if (!strcmp(name, ".MEMBER")) 303 name = MEMBER; 304 break; 304 305 #endif 305 case 'O':306 if (!strcmp(name, ".OODATE"))307 name = OODATE;308 break;309 case 'P':310 if (!strcmp(name, ".PREFIX"))311 name = PREFIX;306 case 'O': 307 if (!strcmp(name, ".OODATE")) 308 name = OODATE; 309 break; 310 case 'P': 311 if (!strcmp(name, ".PREFIX")) 312 name = PREFIX; 312 313 #ifdef USE_PARENTS 313 314 else if (!strcmp(name, ".PARENTS")) 314 315 name = PARENTS; 315 316 #endif 316 break;317 case 'T':318 if (!strcmp(name, ".TARGET"))319 name = TARGET;320 break;321 }317 break; 318 case 'T': 319 if (!strcmp(name, ".TARGET")) 320 name = TARGET; 321 break; 322 } 322 323 323 324 /* … … 326 327 */ 327 328 if (Lst_Find (envFirstVars, (ClientData)name, 328 (int (*)(ClientData, ClientData)) VarStrCmp) != NILLNODE)329 (int (*)(ClientData, ClientData)) VarStrCmp) != NILLNODE) 329 330 { 330 localCheckEnvFirst = TRUE;331 localCheckEnvFirst = TRUE; 331 332 } else { 332 localCheckEnvFirst = FALSE;333 localCheckEnvFirst = FALSE; 333 334 } 334 335 … … 341 342 342 343 if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { 343 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp);344 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp); 344 345 } 345 346 if ((var == NILLNODE) && (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL) && 346 !checkEnvFirst && !localCheckEnvFirst)347 !checkEnvFirst && !localCheckEnvFirst) 347 348 { 348 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);349 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 349 350 } 350 351 if ((var == NILLNODE) && (flags & FIND_ENV)) { 351 352 #ifdef USE_KLIB 352 const char *env;353 if ((env = kEnvGet (name)) != NULL) {353 const char *env; 354 if ((env = kEnvGet (name)) != NULL) { 354 355 #else 355 356 char *env; 356 if ((env = getenv (name)) != NULL) {357 if ((env = getenv (name)) != NULL) { 357 358 #endif 358 intlen;359 360 v = (Var *) emalloc(sizeof(Var));361 v->name = estrdup(name);362 363 len = strlen(env);364 365 v->val = Buf_Init(len);366 Buf_AddBytes(v->val, len, (Byte *)env);367 368 v->flags = VAR_FROM_ENV;369 return (v);370 } else if ((checkEnvFirst || localCheckEnvFirst) &&371 (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL))372 {373 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp);374 if (var == NILLNODE) {375 return ((Var *) NIL);376 } else {377 return ((Var *)Lst_Datum(var));378 }379 } else {380 return((Var *)NIL);381 }359 int len; 360 361 v = (Var *) emalloc(sizeof(Var)); 362 v->name = estrdup(name); 363 364 len = strlen(env); 365 366 v->val = Buf_Init(len); 367 Buf_AddBytes(v->val, len, (Byte *)env); 368 369 v->flags = VAR_FROM_ENV; 370 return (v); 371 } else if ((checkEnvFirst || localCheckEnvFirst) && 372 (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL)) 373 { 374 var = Lst_Find (VAR_GLOBAL->context, (ClientData)name, VarCmp); 375 if (var == NILLNODE) { 376 return ((Var *) NIL); 377 } else { 378 return ((Var *)Lst_Datum(var)); 379 } 380 } else { 381 return((Var *)NIL); 382 } 382 383 } else if (var == NILLNODE) { 383 return ((Var *) NIL);384 return ((Var *) NIL); 384 385 } else { 385 return ((Var *) Lst_Datum (var));386 return ((Var *) Lst_Datum (var)); 386 387 } 387 388 } … … 390 391 *----------------------------------------------------------------------- 391 392 * VarAdd -- 392 * Add a new variable of name name and value val to the given context393 * 394 * Results: 395 * None396 * 397 * Side Effects: 398 * The new variable is placed at the front of the given context399 * The name and val arguments are duplicated so they may400 * safely be freed.393 * Add a new variable of name name and value val to the given context 394 * 395 * Results: 396 * None 397 * 398 * Side Effects: 399 * The new variable is placed at the front of the given context 400 * The name and val arguments are duplicated so they may 401 * safely be freed. 401 402 *----------------------------------------------------------------------- 402 403 */ 403 404 static void 404 405 VarAdd (name, val, ctxt) 405 char *name; /* name of variable to add */406 char *val; /* value to set it to */407 GNode *ctxt; /* context in which to set it */406 char *name; /* name of variable to add */ 407 char *val; /* value to set it to */ 408 GNode *ctxt; /* context in which to set it */ 408 409 { 409 410 register Var *v; 410 int len;411 int len; 411 412 412 413 v = (Var *) emalloc (sizeof (Var)); … … 423 424 (void) Lst_AtEnd (allVars, (ClientData) v); 424 425 if (DEBUG(VAR)) { 425 printf("%s:%s = %s\n", ctxt->name, name, val);426 printf("%s:%s = %s\n", ctxt->name, name, val); 426 427 } 427 428 } … … 431 432 *----------------------------------------------------------------------- 432 433 * VarDelete -- 433 * Delete a variable and all the space associated with it.434 * 435 * Results: 436 * None437 * 438 * Side Effects: 439 * None434 * Delete a variable and all the space associated with it. 435 * 436 * Results: 437 * None 438 * 439 * Side Effects: 440 * None 440 441 *----------------------------------------------------------------------- 441 442 */ … … 455 456 *----------------------------------------------------------------------- 456 457 * Var_Delete -- 457 * Remove a variable from a context.458 * 459 * Results: 460 * None.461 * 462 * Side Effects: 463 * The Var structure is removed and freed.458 * Remove a variable from a context. 459 * 460 * Results: 461 * None. 462 * 463 * Side Effects: 464 * The Var structure is removed and freed. 464 465 * 465 466 *----------------------------------------------------------------------- … … 467 468 void 468 469 Var_Delete(name, ctxt) 469 char *name;470 GNode *ctxt;471 { 472 LstNode ln;470 char *name; 471 GNode *ctxt; 472 { 473 LstNode ln; 473 474 474 475 if (DEBUG(VAR)) { 475 printf("%s:delete %s\n", ctxt->name, name);476 printf("%s:delete %s\n", ctxt->name, name); 476 477 } 477 478 ln = Lst_Find(ctxt->context, (ClientData)name, VarCmp); 478 479 if (ln != NILLNODE) { 479 register Var*v;480 481 v = (Var *)Lst_Datum(ln);482 Lst_Remove(ctxt->context, ln);483 ln = Lst_Member(allVars, v);484 Lst_Remove(allVars, ln);485 VarDelete((ClientData) v);480 register Var *v; 481 482 v = (Var *)Lst_Datum(ln); 483 Lst_Remove(ctxt->context, ln); 484 ln = Lst_Member(allVars, v); 485 Lst_Remove(allVars, ln); 486 VarDelete((ClientData) v); 486 487 } 487 488 } … … 490 491 *----------------------------------------------------------------------- 491 492 * Var_Set -- 492 * Set the variable name to the value val in the given context.493 * 494 * Results: 495 * None.496 * 497 * Side Effects: 498 * If the variable doesn't yet exist, a new record is created for it.499 * Else the old value is freed and the new one stuck in its place493 * Set the variable name to the value val in the given context. 494 * 495 * Results: 496 * None. 497 * 498 * Side Effects: 499 * If the variable doesn't yet exist, a new record is created for it. 500 * Else the old value is freed and the new one stuck in its place 500 501 * 501 502 * Notes: 502 * The variable is searched for only in its context before being503 * created in that context. I.e. if the context is VAR_GLOBAL,504 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only505 * VAR_CMD->context is searched. This is done to avoid the literally506 * thousands of unnecessary strcmp's that used to be done to507 * set, say, $(@) or $(<).503 * The variable is searched for only in its context before being 504 * created in that context. I.e. if the context is VAR_GLOBAL, 505 * only VAR_GLOBAL->context is searched. Likewise if it is VAR_CMD, only 506 * VAR_CMD->context is searched. This is done to avoid the literally 507 * thousands of unnecessary strcmp's that used to be done to 508 * set, say, $(@) or $(<). 508 509 *----------------------------------------------------------------------- 509 510 */ 510 511 void 511 512 Var_Set (name, val, ctxt) 512 char *name; /* name of variable to set */513 char *val; /* value to give to the variable */514 GNode *ctxt; /* context in which to set it */513 char *name; /* name of variable to set */ 514 char *val; /* value to give to the variable */ 515 GNode *ctxt; /* context in which to set it */ 515 516 { 516 517 register Var *v; … … 523 524 v = VarFind (name, ctxt, 0); 524 525 if (v == (Var *) NIL) { 525 VarAdd (name, val, ctxt);526 VarAdd (name, val, ctxt); 526 527 } else { 527 Buf_Discard(v->val, Buf_Size(v->val));528 Buf_AddBytes(v->val, strlen(val), (Byte *)val);529 530 if (DEBUG(VAR)) {531 printf("%s:%s = %s\n", ctxt->name, name, val);532 }528 Buf_Discard(v->val, Buf_Size(v->val)); 529 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 530 531 if (DEBUG(VAR)) { 532 printf("%s:%s = %s\n", ctxt->name, name, val); 533 } 533 534 } 534 535 /* … … 540 541 kEnvSet(name, val, TRUE); 541 542 #else 542 setenv(name, val, 1);543 setenv(name, val, 1); 543 544 #endif 544 545 } … … 548 549 *----------------------------------------------------------------------- 549 550 * Var_Append -- 550 * The variable of the given name has the given value appended to it in551 * the given context.552 * 553 * Results: 554 * None555 * 556 * Side Effects: 557 * If the variable doesn't exist, it is created. Else the strings558 * are concatenated (with a space in between).551 * The variable of the given name has the given value appended to it in 552 * the given context. 553 * 554 * Results: 555 * None 556 * 557 * Side Effects: 558 * If the variable doesn't exist, it is created. Else the strings 559 * are concatenated (with a space in between). 559 560 * 560 561 * Notes: 561 * Only if the variable is being sought in the global context is the562 * environment searched.563 * XXX: Knows its calling circumstances in that if called with ctxt564 * an actual target, it will only search that context since only565 * a local variable could be being appended to. This is actually566 * a big win and must be tolerated.562 * Only if the variable is being sought in the global context is the 563 * environment searched. 564 * XXX: Knows its calling circumstances in that if called with ctxt 565 * an actual target, it will only search that context since only 566 * a local variable could be being appended to. This is actually 567 * a big win and must be tolerated. 567 568 *----------------------------------------------------------------------- 568 569 */ 569 570 void 570 571 Var_Append (name, val, ctxt) 571 char *name; /* Name of variable to modify */572 char *val; /* String to append to it */573 GNode *ctxt; /* Context in which this should occur */572 char *name; /* Name of variable to modify */ 573 char *val; /* String to append to it */ 574 GNode *ctxt; /* Context in which this should occur */ 574 575 { 575 576 register Var *v; … … 578 579 579 580 if (v == (Var *) NIL) { 580 VarAdd (name, val, ctxt);581 VarAdd (name, val, ctxt); 581 582 } else { 582 Buf_AddByte(v->val, (Byte)' ');583 Buf_AddBytes(v->val, strlen(val), (Byte *)val);584 585 if (DEBUG(VAR)) {586 printf("%s:%s = %s\n", ctxt->name, name,587 (char *) Buf_GetAll(v->val, (int *)NULL));588 }589 590 if (v->flags & VAR_FROM_ENV) {591 /*592 * If the original variable came from the environment, we593 * have to install it in the global context (we could place594 * it in the environment, but then we should provide a way to595 * export other variables...)596 */597 v->flags &= ~VAR_FROM_ENV;598 Lst_AtFront(ctxt->context, (ClientData)v);599 }583 Buf_AddByte(v->val, (Byte)' '); 584 Buf_AddBytes(v->val, strlen(val), (Byte *)val); 585 586 if (DEBUG(VAR)) { 587 printf("%s:%s = %s\n", ctxt->name, name, 588 (char *) Buf_GetAll(v->val, (int *)NULL)); 589 } 590 591 if (v->flags & VAR_FROM_ENV) { 592 /* 593 * If the original variable came from the environment, we 594 * have to install it in the global context (we could place 595 * it in the environment, but then we should provide a way to 596 * export other variables...) 597 */ 598 v->flags &= ~VAR_FROM_ENV; 599 Lst_AtFront(ctxt->context, (ClientData)v); 600 } 600 601 } 601 602 } … … 604 605 *----------------------------------------------------------------------- 605 606 * Var_Exists -- 606 * See if the given variable exists.607 * 608 * Results: 609 * TRUE if it does, FALSE if it doesn't610 * 611 * Side Effects: 612 * None.607 * See if the given variable exists. 608 * 609 * Results: 610 * TRUE if it does, FALSE if it doesn't 611 * 612 * Side Effects: 613 * None. 613 614 * 614 615 *----------------------------------------------------------------------- … … 616 617 Boolean 617 618 Var_Exists(name, ctxt) 618 char *name;/* Variable to find */619 GNode *ctxt;/* Context in which to start search */620 { 621 Var *v;619 char *name; /* Variable to find */ 620 GNode *ctxt; /* Context in which to start search */ 621 { 622 Var *v; 622 623 623 624 v = VarFind(name, ctxt, FIND_CMD|FIND_GLOBAL|FIND_ENV); 624 625 625 626 if (v == (Var *)NIL) { 626 return(FALSE);627 return(FALSE); 627 628 } else if (v->flags & VAR_FROM_ENV) { 628 efree(v->name);629 Buf_Destroy(v->val, TRUE);630 efree((char *)v);629 efree(v->name); 630 Buf_Destroy(v->val, TRUE); 631 efree((char *)v); 631 632 } 632 633 return(TRUE); … … 636 637 *----------------------------------------------------------------------- 637 638 * Var_Value -- 638 * Return the value of the named variable in the given context639 * 640 * Results: 641 * The value if the variable exists, NULL if it doesn't642 * 643 * Side Effects: 644 * None639 * Return the value of the named variable in the given context 640 * 641 * Results: 642 * The value if the variable exists, NULL if it doesn't 643 * 644 * Side Effects: 645 * None 645 646 *----------------------------------------------------------------------- 646 647 */ 647 648 char * 648 649 Var_Value (name, ctxt, frp) 649 char *name; /* name to find */650 GNode *ctxt; /* context in which to search for it */651 char **frp;650 char *name; /* name to find */ 651 GNode *ctxt; /* context in which to search for it */ 652 char **frp; 652 653 { 653 654 Var *v; … … 656 657 *frp = NULL; 657 658 if (v != (Var *) NIL) { 658 char *p = ((char *)Buf_GetAll(v->val, (int *)NULL));659 if (v->flags & VAR_FROM_ENV) {660 Buf_Destroy(v->val, FALSE);661 efree((Address) v);662 *frp = p;663 }664 return p;659 char *p = ((char *)Buf_GetAll(v->val, (int *)NULL)); 660 if (v->flags & VAR_FROM_ENV) { 661 Buf_Destroy(v->val, FALSE); 662 efree((Address) v); 663 *frp = p; 664 } 665 return p; 665 666 } else { 666 return ((char *) NULL);667 return ((char *) NULL); 667 668 } 668 669 } … … 671 672 *----------------------------------------------------------------------- 672 673 * VarHead -- 673 * Remove the tail of the given word and place the result in the given674 * buffer.675 * 676 * Results: 677 * TRUE if characters were added to the buffer (a space needs to be678 * added to the buffer before the next word).679 * 680 * Side Effects: 681 * The trimmed word is added to the buffer.674 * Remove the tail of the given word and place the result in the given 675 * buffer. 676 * 677 * Results: 678 * TRUE if characters were added to the buffer (a space needs to be 679 * added to the buffer before the next word). 680 * 681 * Side Effects: 682 * The trimmed word is added to the buffer. 682 683 * 683 684 *----------------------------------------------------------------------- … … 685 686 static Boolean 686 687 VarHead (word, addSpace, buf, dummy) 687 char *word;/* Word to trim */688 Boolean addSpace;/* True if need to add a space to the buffer689 * before sticking in the head */690 Buffer buf;/* Buffer in which to store it */691 ClientData dummy;688 char *word; /* Word to trim */ 689 Boolean addSpace; /* True if need to add a space to the buffer 690 * before sticking in the head */ 691 Buffer buf; /* Buffer in which to store it */ 692 ClientData dummy; 692 693 { 693 694 register char *slash; … … 695 696 slash = strrchr (word, '/'); 696 697 if (slash != (char *)NULL) { 697 if (addSpace) {698 Buf_AddByte (buf, (Byte)' ');699 }700 *slash = '\0';701 Buf_AddBytes (buf, strlen (word), (Byte *)word);702 *slash = '/';703 return (TRUE);698 if (addSpace) { 699 Buf_AddByte (buf, (Byte)' '); 700 } 701 *slash = '\0'; 702 Buf_AddBytes (buf, strlen (word), (Byte *)word); 703 *slash = '/'; 704 return (TRUE); 704 705 } else { 705 /*706 * If no directory part, give . (q.v. the POSIX standard)707 */708 if (addSpace) {709 Buf_AddBytes(buf, 2, (Byte *)" .");710 } else {711 Buf_AddByte(buf, (Byte)'.');712 }706 /* 707 * If no directory part, give . (q.v. the POSIX standard) 708 */ 709 if (addSpace) { 710 Buf_AddBytes(buf, 2, (Byte *)" ."); 711 } else { 712 Buf_AddByte(buf, (Byte)'.'); 713 } 713 714 } 714 715 return(dummy ? TRUE : TRUE); … … 718 719 *----------------------------------------------------------------------- 719 720 * VarTail -- 720 * Remove the head of the given word and place the result in the given721 * buffer.722 * 723 * Results: 724 * TRUE if characters were added to the buffer (a space needs to be725 * added to the buffer before the next word).726 * 727 * Side Effects: 728 * The trimmed word is added to the buffer.721 * Remove the head of the given word and place the result in the given 722 * buffer. 723 * 724 * Results: 725 * TRUE if characters were added to the buffer (a space needs to be 726 * added to the buffer before the next word). 727 * 728 * Side Effects: 729 * The trimmed word is added to the buffer. 729 730 * 730 731 *----------------------------------------------------------------------- … … 732 733 static Boolean 733 734 VarTail (word, addSpace, buf, dummy) 734 char *word;/* Word to trim */735 Boolean addSpace;/* TRUE if need to stick a space in the736 * buffer before adding the tail */737 Buffer buf;/* Buffer in which to store it */738 ClientData dummy;735 char *word; /* Word to trim */ 736 Boolean addSpace; /* TRUE if need to stick a space in the 737 * buffer before adding the tail */ 738 Buffer buf; /* Buffer in which to store it */ 739 ClientData dummy; 739 740 { 740 741 register char *slash; 741 742 742 743 if (addSpace) { 743 Buf_AddByte (buf, (Byte)' ');744 Buf_AddByte (buf, (Byte)' '); 744 745 } 745 746 746 747 slash = strrchr (word, '/'); 747 748 if (slash != (char *)NULL) { 748 *slash++ = '\0';749 Buf_AddBytes (buf, strlen(slash), (Byte *)slash);750 slash[-1] = '/';749 *slash++ = '\0'; 750 Buf_AddBytes (buf, strlen(slash), (Byte *)slash); 751 slash[-1] = '/'; 751 752 } else { 752 Buf_AddBytes (buf, strlen(word), (Byte *)word);753 Buf_AddBytes (buf, strlen(word), (Byte *)word); 753 754 } 754 755 return (dummy ? TRUE : TRUE); … … 758 759 *----------------------------------------------------------------------- 759 760 * VarSuffix -- 760 * Place the suffix of the given word in the given buffer.761 * 762 * Results: 763 * TRUE if characters were added to the buffer (a space needs to be764 * added to the buffer before the next word).765 * 766 * Side Effects: 767 * The suffix from the word is placed in the buffer.761 * Place the suffix of the given word in the given buffer. 762 * 763 * Results: 764 * TRUE if characters were added to the buffer (a space needs to be 765 * added to the buffer before the next word). 766 * 767 * Side Effects: 768 * The suffix from the word is placed in the buffer. 768 769 * 769 770 *----------------------------------------------------------------------- … … 771 772 static Boolean 772 773 VarSuffix (word, addSpace, buf, dummy) 773 char *word;/* Word to trim */774 Boolean addSpace;/* TRUE if need to add a space before placing775 * the suffix in the buffer */776 Buffer buf;/* Buffer in which to store it */777 ClientData dummy;774 char *word; /* Word to trim */ 775 Boolean addSpace; /* TRUE if need to add a space before placing 776 * the suffix in the buffer */ 777 Buffer buf; /* Buffer in which to store it */ 778 ClientData dummy; 778 779 { 779 780 register char *dot; … … 781 782 dot = strrchr (word, '.'); 782 783 if (dot != (char *)NULL) { 783 if (addSpace) {784 Buf_AddByte (buf, (Byte)' ');785 }786 *dot++ = '\0';787 Buf_AddBytes (buf, strlen (dot), (Byte *)dot);788 dot[-1] = '.';789 addSpace = TRUE;784 if (addSpace) { 785 Buf_AddByte (buf, (Byte)' '); 786 } 787 *dot++ = '\0'; 788 Buf_AddBytes (buf, strlen (dot), (Byte *)dot); 789 dot[-1] = '.'; 790 addSpace = TRUE; 790 791 } 791 792 return (dummy ? addSpace : addSpace); … … 795 796 *----------------------------------------------------------------------- 796 797 * VarRoot -- 797 * Remove the suffix of the given word and place the result in the798 * buffer.799 * 800 * Results: 801 * TRUE if characters were added to the buffer (a space needs to be802 * added to the buffer before the next word).803 * 804 * Side Effects: 805 * The trimmed word is added to the buffer.798 * Remove the suffix of the given word and place the result in the 799 * buffer. 800 * 801 * Results: 802 * TRUE if characters were added to the buffer (a space needs to be 803 * added to the buffer before the next word). 804 * 805 * Side Effects: 806 * The trimmed word is added to the buffer. 806 807 * 807 808 *----------------------------------------------------------------------- … … 809 810 static Boolean 810 811 VarRoot (word, addSpace, buf, dummy) 811 char *word;/* Word to trim */812 Boolean addSpace;/* TRUE if need to add a space to the buffer813 * before placing the root in it */814 Buffer buf;/* Buffer in which to store it */815 ClientData dummy;812 char *word; /* Word to trim */ 813 Boolean addSpace; /* TRUE if need to add a space to the buffer 814 * before placing the root in it */ 815 Buffer buf; /* Buffer in which to store it */ 816 ClientData dummy; 816 817 { 817 818 register char *dot; 818 819 819 820 if (addSpace) { 820 Buf_AddByte (buf, (Byte)' ');821 Buf_AddByte (buf, (Byte)' '); 821 822 } 822 823 823 824 dot = strrchr (word, '.'); 824 825 if (dot != (char *)NULL) { 825 *dot = '\0';826 Buf_AddBytes (buf, strlen (word), (Byte *)word);827 *dot = '.';826 *dot = '\0'; 827 Buf_AddBytes (buf, strlen (word), (Byte *)word); 828 *dot = '.'; 828 829 } else { 829 Buf_AddBytes (buf, strlen(word), (Byte *)word);830 Buf_AddBytes (buf, strlen(word), (Byte *)word); 830 831 } 831 832 return (dummy ? TRUE : TRUE); 832 833 } 833 834 834 #if defined(NMAKE) || defined(KMK)835 #ifdef USE_BASEANDROOT_MODIFIERS 835 836 /*- 836 837 *----------------------------------------------------------------------- 837 838 * VarBase -- 838 * Remove the head and suffix of the given word and place the result839 * in the given buffer.840 * 841 * Results: 842 * TRUE if characters were added to the buffer (a space needs to be843 * added to the buffer before the next word).844 * 845 * Side Effects: 846 * The trimmed word is added to the buffer.839 * Remove the head and suffix of the given word and place the result 840 * in the given buffer. 841 * 842 * Results: 843 * TRUE if characters were added to the buffer (a space needs to be 844 * added to the buffer before the next word). 845 * 846 * Side Effects: 847 * The trimmed word is added to the buffer. 847 848 * 848 849 *----------------------------------------------------------------------- … … 850 851 static Boolean 851 852 VarBase (word, addSpace, buf, dummy) 852 char *word;/* Word to trim */853 Boolean addSpace;/* TRUE if need to stick a space in the854 * buffer before adding the tail */855 Buffer buf;/* Buffer in which to store it */856 ClientData dummy;853 char *word; /* Word to trim */ 854 Boolean addSpace; /* TRUE if need to stick a space in the 855 * buffer before adding the tail */ 856 Buffer buf; /* Buffer in which to store it */ 857 ClientData dummy; 857 858 { 858 859 register char *slash; 859 860 860 861 if (addSpace) { 861 Buf_AddByte (buf, (Byte)' ');862 Buf_AddByte (buf, (Byte)' '); 862 863 } 863 864 864 865 slash = strrchr (word, '/'); 865 866 if (slash != (char *)NULL) { 866 register char *dot;867 register char *dot; 867 868 *slash++ = '\0'; 868 869 dot = strrchr (slash, '.'); … … 875 876 else 876 877 Buf_AddBytes (buf, strlen(slash), (Byte *)slash); 877 slash[-1] = '/';878 slash[-1] = '/'; 878 879 } else { 879 register char *dot;880 register char *dot; 880 881 dot = strrchr (slash, '.'); 881 882 if (dot) … … 896 897 *----------------------------------------------------------------------- 897 898 * VarMatch -- 898 * Place the word in the buffer if it matches the given pattern.899 * Callback function for VarModify to implement the :M modifier.900 * 901 * Results: 902 * TRUE if a space should be placed in the buffer before the next903 * word.904 * 905 * Side Effects: 906 * The word may be copied to the buffer.899 * Place the word in the buffer if it matches the given pattern. 900 * Callback function for VarModify to implement the :M modifier. 901 * 902 * Results: 903 * TRUE if a space should be placed in the buffer before the next 904 * word. 905 * 906 * Side Effects: 907 * The word may be copied to the buffer. 907 908 * 908 909 *----------------------------------------------------------------------- … … 910 911 static Boolean 911 912 VarMatch (word, addSpace, buf, pattern) 912 char *word;/* Word to examine */913 Boolean addSpace;/* TRUE if need to add a space to the914 * buffer before adding the word, if it915 * matches */916 Buffer buf;/* Buffer in which to store it */917 ClientData pattern; /* Pattern the word must match */913 char *word; /* Word to examine */ 914 Boolean addSpace; /* TRUE if need to add a space to the 915 * buffer before adding the word, if it 916 * matches */ 917 Buffer buf; /* Buffer in which to store it */ 918 ClientData pattern; /* Pattern the word must match */ 918 919 { 919 920 if (Str_Match(word, (char *) pattern)) { 920 if (addSpace) {921 Buf_AddByte(buf, (Byte)' ');922 }923 addSpace = TRUE;924 Buf_AddBytes(buf, strlen(word), (Byte *)word);921 if (addSpace) { 922 Buf_AddByte(buf, (Byte)' '); 923 } 924 addSpace = TRUE; 925 Buf_AddBytes(buf, strlen(word), (Byte *)word); 925 926 } 926 927 return(addSpace); … … 931 932 *----------------------------------------------------------------------- 932 933 * VarSYSVMatch -- 933 * Place the word in the buffer if it matches the given pattern.934 * Callback function for VarModify to implement the System V %935 * modifiers.936 * 937 * Results: 938 * TRUE if a space should be placed in the buffer before the next939 * word.940 * 941 * Side Effects: 942 * The word may be copied to the buffer.934 * Place the word in the buffer if it matches the given pattern. 935 * Callback function for VarModify to implement the System V % 936 * modifiers. 937 * 938 * Results: 939 * TRUE if a space should be placed in the buffer before the next 940 * word. 941 * 942 * Side Effects: 943 * The word may be copied to the buffer. 943 944 * 944 945 *----------------------------------------------------------------------- … … 946 947 static Boolean 947 948 VarSYSVMatch (word, addSpace, buf, patp) 948 char *word;/* Word to examine */949 Boolean addSpace;/* TRUE if need to add a space to the950 * buffer before adding the word, if it951 * matches */952 Buffer buf;/* Buffer in which to store it */953 ClientData patp;/* Pattern the word must match */949 char *word; /* Word to examine */ 950 Boolean addSpace; /* TRUE if need to add a space to the 951 * buffer before adding the word, if it 952 * matches */ 953 Buffer buf; /* Buffer in which to store it */ 954 ClientData patp; /* Pattern the word must match */ 954 955 { 955 956 int len; 956 957 char *ptr; 957 VarPattern *pat = (VarPattern *) patp;958 VarPattern *pat = (VarPattern *) patp; 958 959 959 960 if (addSpace) 960 Buf_AddByte(buf, (Byte)' ');961 Buf_AddByte(buf, (Byte)' '); 961 962 962 963 addSpace = TRUE; 963 964 964 965 if ((ptr = Str_SYSVMatch(word, pat->lhs, &len)) != NULL) 965 Str_SYSVSubst(buf, pat->rhs, ptr, len);966 Str_SYSVSubst(buf, pat->rhs, ptr, len); 966 967 else 967 Buf_AddBytes(buf, strlen(word), (Byte *) word);968 Buf_AddBytes(buf, strlen(word), (Byte *) word); 968 969 969 970 return(addSpace); … … 975 976 *----------------------------------------------------------------------- 976 977 * VarNoMatch -- 977 * Place the word in the buffer if it doesn't match the given pattern.978 * Callback function for VarModify to implement the :N modifier.979 * 980 * Results: 981 * TRUE if a space should be placed in the buffer before the next982 * word.983 * 984 * Side Effects: 985 * The word may be copied to the buffer.978 * Place the word in the buffer if it doesn't match the given pattern. 979 * Callback function for VarModify to implement the :N modifier. 980 * 981 * Results: 982 * TRUE if a space should be placed in the buffer before the next 983 * word. 984 * 985 * Side Effects: 986 * The word may be copied to the buffer. 986 987 * 987 988 *----------------------------------------------------------------------- … … 989 990 static Boolean 990 991 VarNoMatch (word, addSpace, buf, pattern) 991 char *word;/* Word to examine */992 Boolean addSpace;/* TRUE if need to add a space to the993 * buffer before adding the word, if it994 * matches */995 Buffer buf;/* Buffer in which to store it */996 ClientData pattern; /* Pattern the word must match */992 char *word; /* Word to examine */ 993 Boolean addSpace; /* TRUE if need to add a space to the 994 * buffer before adding the word, if it 995 * matches */ 996 Buffer buf; /* Buffer in which to store it */ 997 ClientData pattern; /* Pattern the word must match */ 997 998 { 998 999 if (!Str_Match(word, (char *) pattern)) { 999 if (addSpace) {1000 Buf_AddByte(buf, (Byte)' ');1001 }1002 addSpace = TRUE;1003 Buf_AddBytes(buf, strlen(word), (Byte *)word);1000 if (addSpace) { 1001 Buf_AddByte(buf, (Byte)' '); 1002 } 1003 addSpace = TRUE; 1004 Buf_AddBytes(buf, strlen(word), (Byte *)word); 1004 1005 } 1005 1006 return(addSpace); … … 1010 1011 *----------------------------------------------------------------------- 1011 1012 * VarSubstitute -- 1012 * Perform a string-substitution on the given word, placing the1013 * result in the passed buffer.1014 * 1015 * Results: 1016 * TRUE if a space is needed before more characters are added.1017 * 1018 * Side Effects: 1019 * None.1013 * Perform a string-substitution on the given word, placing the 1014 * result in the passed buffer. 1015 * 1016 * Results: 1017 * TRUE if a space is needed before more characters are added. 1018 * 1019 * Side Effects: 1020 * None. 1020 1021 * 1021 1022 *----------------------------------------------------------------------- … … 1023 1024 static Boolean 1024 1025 VarSubstitute (word, addSpace, buf, patternp) 1025 char *word;/* Word to modify */1026 Boolean addSpace; /* True if space should be added before1027 * other characters */1028 Buffer buf;/* Buffer for result */1029 ClientData patternp; /* Pattern for substitution */1030 { 1031 register int wordLen; /* Length of word */1032 register char *cp;/* General pointer */1033 VarPattern *pattern = (VarPattern *) patternp;1026 char *word; /* Word to modify */ 1027 Boolean addSpace; /* True if space should be added before 1028 * other characters */ 1029 Buffer buf; /* Buffer for result */ 1030 ClientData patternp; /* Pattern for substitution */ 1031 { 1032 register int wordLen; /* Length of word */ 1033 register char *cp; /* General pointer */ 1034 VarPattern *pattern = (VarPattern *) patternp; 1034 1035 1035 1036 wordLen = strlen(word); 1036 1037 if (1) { /* substitute in each word of the variable */ 1037 /*1038 * Break substitution down into simple anchored cases1039 * and if none of them fits, perform the general substitution case.1040 */1041 if ((pattern->flags & VAR_MATCH_START) &&1042 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) {1043 /*1044 * Anchored at start and beginning of word matches pattern1045 */1046 if ((pattern->flags & VAR_MATCH_END) &&1047 (wordLen == pattern->leftLen)) {1048 /*1049 * Also anchored at end and matches to the end (word1050 * is same length as pattern) add space and rhs only1051 * if rhs is non-null.1052 */1053 if (pattern->rightLen != 0) {1054 if (addSpace) {1055 Buf_AddByte(buf, (Byte)' ');1056 }1057 addSpace = TRUE;1058 Buf_AddBytes(buf, pattern->rightLen,1059 (Byte *)pattern->rhs);1060 }1061 } else if (pattern->flags & VAR_MATCH_END) {1062 /*1063 * Doesn't match to end -- copy word wholesale1064 */1065 goto nosub;1066 } else {1067 /*1068 * Matches at start but need to copy in trailing characters1069 */1070 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){1071 if (addSpace) {1072 Buf_AddByte(buf, (Byte)' ');1073 }1074 addSpace = TRUE;1075 }1076 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);1077 Buf_AddBytes(buf, wordLen - pattern->leftLen,1078 (Byte *)(word + pattern->leftLen));1079 }1080 } else if (pattern->flags & VAR_MATCH_START) {1081 /*1082 * Had to match at start of word and didn't -- copy whole word.1083 */1084 goto nosub;1085 } else if (pattern->flags & VAR_MATCH_END) {1086 /*1087 * Anchored at end, Find only place match could occur (leftLen1088 * characters from the end of the word) and see if it does. Note1089 * that because the $ will be left at the end of the lhs, we have1090 * to use strncmp.1091 */1092 cp = word + (wordLen - pattern->leftLen);1093 if ((cp >= word) &&1094 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) {1095 /*1096 * Match found. If we will place characters in the buffer,1097 * add a space before hand as indicated by addSpace, then1098 * stuff in the initial, unmatched part of the word followed1099 * by the right-hand-side.1100 */1101 if (((cp - word) + pattern->rightLen) != 0) {1102 if (addSpace) {1103 Buf_AddByte(buf, (Byte)' ');1104 }1105 addSpace = TRUE;1106 }1107 Buf_AddBytes(buf, cp - word, (Byte *)word);1108 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);1109 } else {1110 /*1111 * Had to match at end and didn't. Copy entire word.1112 */1113 goto nosub;1114 }1115 } else {1116 /*1117 * Pattern is unanchored: search for the pattern in the word using1118 * String_FindSubstring, copying unmatched portions and the1119 * right-hand-side for each match found, handling non-global1120 * substitutions correctly, etc. When the loop is done, any1121 * remaining part of the word (word and wordLen are adjusted1122 * accordingly through the loop) is copied straight into the1123 * buffer.1124 * addSpace is set FALSE as soon as a space is added to the1125 * buffer.1126 */1127 register Boolean done;1128 int origSize;1129 1130 done = FALSE;1131 origSize = Buf_Size(buf);1132 while (!done) {1133 cp = Str_FindSubstring(word, pattern->lhs);1134 if (cp != (char *)NULL) {1135 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){1136 Buf_AddByte(buf, (Byte)' ');1137 addSpace = FALSE;1138 }1139 Buf_AddBytes(buf, cp-word, (Byte *)word);1140 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs);1141 wordLen -= (cp - word) + pattern->leftLen;1142 word = cp + pattern->leftLen;1143 if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){1144 done = TRUE;1145 }1146 } else {1147 done = TRUE;1148 }1149 }1150 if (wordLen != 0) {1151 if (addSpace) {1152 Buf_AddByte(buf, (Byte)' ');1153 }1154 Buf_AddBytes(buf, wordLen, (Byte *)word);1155 }1156 /*1157 * If added characters to the buffer, need to add a space1158 * before we add any more. If we didn't add any, just return1159 * the previous value of addSpace.1160 */1161 return ((Buf_Size(buf) != origSize) || addSpace);1162 }1163 /*1164 * Common code for anchored substitutions:1165 * addSpace was set TRUE if characters were added to the buffer.1166 */1167 return (addSpace);1038 /* 1039 * Break substitution down into simple anchored cases 1040 * and if none of them fits, perform the general substitution case. 1041 */ 1042 if ((pattern->flags & VAR_MATCH_START) && 1043 (strncmp(word, pattern->lhs, pattern->leftLen) == 0)) { 1044 /* 1045 * Anchored at start and beginning of word matches pattern 1046 */ 1047 if ((pattern->flags & VAR_MATCH_END) && 1048 (wordLen == pattern->leftLen)) { 1049 /* 1050 * Also anchored at end and matches to the end (word 1051 * is same length as pattern) add space and rhs only 1052 * if rhs is non-null. 1053 */ 1054 if (pattern->rightLen != 0) { 1055 if (addSpace) { 1056 Buf_AddByte(buf, (Byte)' '); 1057 } 1058 addSpace = TRUE; 1059 Buf_AddBytes(buf, pattern->rightLen, 1060 (Byte *)pattern->rhs); 1061 } 1062 } else if (pattern->flags & VAR_MATCH_END) { 1063 /* 1064 * Doesn't match to end -- copy word wholesale 1065 */ 1066 goto nosub; 1067 } else { 1068 /* 1069 * Matches at start but need to copy in trailing characters 1070 */ 1071 if ((pattern->rightLen + wordLen - pattern->leftLen) != 0){ 1072 if (addSpace) { 1073 Buf_AddByte(buf, (Byte)' '); 1074 } 1075 addSpace = TRUE; 1076 } 1077 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 1078 Buf_AddBytes(buf, wordLen - pattern->leftLen, 1079 (Byte *)(word + pattern->leftLen)); 1080 } 1081 } else if (pattern->flags & VAR_MATCH_START) { 1082 /* 1083 * Had to match at start of word and didn't -- copy whole word. 1084 */ 1085 goto nosub; 1086 } else if (pattern->flags & VAR_MATCH_END) { 1087 /* 1088 * Anchored at end, Find only place match could occur (leftLen 1089 * characters from the end of the word) and see if it does. Note 1090 * that because the $ will be left at the end of the lhs, we have 1091 * to use strncmp. 1092 */ 1093 cp = word + (wordLen - pattern->leftLen); 1094 if ((cp >= word) && 1095 (strncmp(cp, pattern->lhs, pattern->leftLen) == 0)) { 1096 /* 1097 * Match found. If we will place characters in the buffer, 1098 * add a space before hand as indicated by addSpace, then 1099 * stuff in the initial, unmatched part of the word followed 1100 * by the right-hand-side. 1101 */ 1102 if (((cp - word) + pattern->rightLen) != 0) { 1103 if (addSpace) { 1104 Buf_AddByte(buf, (Byte)' '); 1105 } 1106 addSpace = TRUE; 1107 } 1108 Buf_AddBytes(buf, cp - word, (Byte *)word); 1109 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 1110 } else { 1111 /* 1112 * Had to match at end and didn't. Copy entire word. 1113 */ 1114 goto nosub; 1115 } 1116 } else { 1117 /* 1118 * Pattern is unanchored: search for the pattern in the word using 1119 * String_FindSubstring, copying unmatched portions and the 1120 * right-hand-side for each match found, handling non-global 1121 * substitutions correctly, etc. When the loop is done, any 1122 * remaining part of the word (word and wordLen are adjusted 1123 * accordingly through the loop) is copied straight into the 1124 * buffer. 1125 * addSpace is set FALSE as soon as a space is added to the 1126 * buffer. 1127 */ 1128 register Boolean done; 1129 int origSize; 1130 1131 done = FALSE; 1132 origSize = Buf_Size(buf); 1133 while (!done) { 1134 cp = Str_FindSubstring(word, pattern->lhs); 1135 if (cp != (char *)NULL) { 1136 if (addSpace && (((cp - word) + pattern->rightLen) != 0)){ 1137 Buf_AddByte(buf, (Byte)' '); 1138 addSpace = FALSE; 1139 } 1140 Buf_AddBytes(buf, cp-word, (Byte *)word); 1141 Buf_AddBytes(buf, pattern->rightLen, (Byte *)pattern->rhs); 1142 wordLen -= (cp - word) + pattern->leftLen; 1143 word = cp + pattern->leftLen; 1144 if (wordLen == 0 || (pattern->flags & VAR_SUB_GLOBAL) == 0){ 1145 done = TRUE; 1146 } 1147 } else { 1148 done = TRUE; 1149 } 1150 } 1151 if (wordLen != 0) { 1152 if (addSpace) { 1153 Buf_AddByte(buf, (Byte)' '); 1154 } 1155 Buf_AddBytes(buf, wordLen, (Byte *)word); 1156 } 1157 /* 1158 * If added characters to the buffer, need to add a space 1159 * before we add any more. If we didn't add any, just return 1160 * the previous value of addSpace. 1161 */ 1162 return ((Buf_Size(buf) != origSize) || addSpace); 1163 } 1164 /* 1165 * Common code for anchored substitutions: 1166 * addSpace was set TRUE if characters were added to the buffer. 1167 */ 1168 return (addSpace); 1168 1169 } 1169 1170 nosub: 1170 1171 if (addSpace) { 1171 Buf_AddByte(buf, (Byte)' ');1172 Buf_AddByte(buf, (Byte)' '); 1172 1173 } 1173 1174 Buf_AddBytes(buf, wordLen, (Byte *)word); … … 1178 1179 *----------------------------------------------------------------------- 1179 1180 * VarREError -- 1180 * Print the error caused by a regcomp or regexec call.1181 * 1182 * Results: 1183 * None.1184 * 1185 * Side Effects: 1186 * An error gets printed.1181 * Print the error caused by a regcomp or regexec call. 1182 * 1183 * Results: 1184 * None. 1185 * 1186 * Side Effects: 1187 * An error gets printed. 1187 1188 * 1188 1189 *----------------------------------------------------------------------- … … 1208 1209 *----------------------------------------------------------------------- 1209 1210 * VarRESubstitute -- 1210 * Perform a regex substitution on the given word, placing the1211 * result in the passed buffer.1212 * 1213 * Results: 1214 * TRUE if a space is needed before more characters are added.1215 * 1216 * Side Effects: 1217 * None.1211 * Perform a regex substitution on the given word, placing the 1212 * result in the passed buffer. 1213 * 1214 * Results: 1215 * TRUE if a space is needed before more characters are added. 1216 * 1217 * Side Effects: 1218 * None. 1218 1219 * 1219 1220 *----------------------------------------------------------------------- … … 1233 1234 int flags = 0; 1234 1235 1235 #define MAYBE_ADD_SPACE() \1236 if (addSpace && !added)\1237 Buf_AddByte(buf, ' ');\1238 added = 11236 #define MAYBE_ADD_SPACE() \ 1237 if (addSpace && !added) \ 1238 Buf_AddByte(buf, ' '); \ 1239 added = 1 1239 1240 1240 1241 added = 0; … … 1243 1244 1244 1245 if ((pat->flags & (VAR_SUB_ONE|VAR_SUB_MATCHED)) == 1245 (VAR_SUB_ONE|VAR_SUB_MATCHED))1246 xrv = REG_NOMATCH;1246 (VAR_SUB_ONE|VAR_SUB_MATCHED)) 1247 xrv = REG_NOMATCH; 1247 1248 else { 1248 1249 tryagain: 1249 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags);1250 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); 1250 1251 } 1251 1252 1252 1253 switch (xrv) { 1253 1254 case 0: 1254 pat->flags |= VAR_SUB_MATCHED;1255 if (pat->matches[0].rm_so > 0) {1256 MAYBE_ADD_SPACE();1257 Buf_AddBytes(buf, pat->matches[0].rm_so, wp);1258 }1259 1260 for (rp = pat->replace; *rp; rp++) {1261 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) {1262 MAYBE_ADD_SPACE();1263 Buf_AddByte(buf,rp[1]);1264 rp++;1265 }1266 else if ((*rp == '&') ||1267 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) {1268 int n;1269 char *subbuf;1270 int sublen;1271 char errstr[3];1272 1273 if (*rp == '&') {1274 n = 0;1275 errstr[0] = '&';1276 errstr[1] = '\0';1277 } else {1278 n = rp[1] - '0';1279 errstr[0] = '\\';1280 errstr[1] = rp[1];1281 errstr[2] = '\0';1282 rp++;1283 }1284 1285 if (n > pat->nsub) {1286 Error("No subexpression %s", &errstr[0]);1287 subbuf = "";1288 sublen = 0;1289 } else if ((pat->matches[n].rm_so == -1) &&1290 (pat->matches[n].rm_eo == -1)) {1291 Error("No match for subexpression %s", &errstr[0]);1292 subbuf = "";1293 sublen = 0;1294 } else {1295 subbuf = wp + pat->matches[n].rm_so;1296 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so;1297 }1298 1299 if (sublen > 0) {1300 MAYBE_ADD_SPACE();1301 Buf_AddBytes(buf, sublen, subbuf);1302 }1303 } else {1304 MAYBE_ADD_SPACE();1305 Buf_AddByte(buf, *rp);1306 }1307 }1308 wp += pat->matches[0].rm_eo;1309 if (pat->flags & VAR_SUB_GLOBAL) {1310 flags |= REG_NOTBOL;1311 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) {1312 MAYBE_ADD_SPACE();1313 Buf_AddByte(buf, *wp);1314 wp++;1315 1316 }1317 if (*wp)1318 goto tryagain;1319 }1320 if (*wp) {1321 MAYBE_ADD_SPACE();1322 Buf_AddBytes(buf, strlen(wp), wp);1323 }1324 break;1255 pat->flags |= VAR_SUB_MATCHED; 1256 if (pat->matches[0].rm_so > 0) { 1257 MAYBE_ADD_SPACE(); 1258 Buf_AddBytes(buf, pat->matches[0].rm_so, wp); 1259 } 1260 1261 for (rp = pat->replace; *rp; rp++) { 1262 if ((*rp == '\\') && ((rp[1] == '&') || (rp[1] == '\\'))) { 1263 MAYBE_ADD_SPACE(); 1264 Buf_AddByte(buf,rp[1]); 1265 rp++; 1266 } 1267 else if ((*rp == '&') || 1268 ((*rp == '\\') && isdigit((unsigned char)rp[1]))) { 1269 int n; 1270 char *subbuf; 1271 int sublen; 1272 char errstr[3]; 1273 1274 if (*rp == '&') { 1275 n = 0; 1276 errstr[0] = '&'; 1277 errstr[1] = '\0'; 1278 } else { 1279 n = rp[1] - '0'; 1280 errstr[0] = '\\'; 1281 errstr[1] = rp[1]; 1282 errstr[2] = '\0'; 1283 rp++; 1284 } 1285 1286 if (n > pat->nsub) { 1287 Error("No subexpression %s", &errstr[0]); 1288 subbuf = ""; 1289 sublen = 0; 1290 } else if ((pat->matches[n].rm_so == -1) && 1291 (pat->matches[n].rm_eo == -1)) { 1292 Error("No match for subexpression %s", &errstr[0]); 1293 subbuf = ""; 1294 sublen = 0; 1295 } else { 1296 subbuf = wp + pat->matches[n].rm_so; 1297 sublen = pat->matches[n].rm_eo - pat->matches[n].rm_so; 1298 } 1299 1300 if (sublen > 0) { 1301 MAYBE_ADD_SPACE(); 1302 Buf_AddBytes(buf, sublen, subbuf); 1303 } 1304 } else { 1305 MAYBE_ADD_SPACE(); 1306 Buf_AddByte(buf, *rp); 1307 } 1308 } 1309 wp += pat->matches[0].rm_eo; 1310 if (pat->flags & VAR_SUB_GLOBAL) { 1311 flags |= REG_NOTBOL; 1312 if (pat->matches[0].rm_so == 0 && pat->matches[0].rm_eo == 0) { 1313 MAYBE_ADD_SPACE(); 1314 Buf_AddByte(buf, *wp); 1315 wp++; 1316 1317 } 1318 if (*wp) 1319 goto tryagain; 1320 } 1321 if (*wp) { 1322 MAYBE_ADD_SPACE(); 1323 Buf_AddBytes(buf, strlen(wp), wp); 1324 } 1325 break; 1325 1326 default: 1326 VarREError(xrv, &pat->re, "Unexpected regex error");1327 VarREError(xrv, &pat->re, "Unexpected regex error"); 1327 1328 /* fall through */ 1328 1329 case REG_NOMATCH: 1329 if (*wp) {1330 MAYBE_ADD_SPACE();1331 Buf_AddBytes(buf,strlen(wp),wp);1332 }1333 break;1330 if (*wp) { 1331 MAYBE_ADD_SPACE(); 1332 Buf_AddBytes(buf,strlen(wp),wp); 1333 } 1334 break; 1334 1335 } 1335 1336 return(addSpace||added); … … 1340 1341 *----------------------------------------------------------------------- 1341 1342 * VarModify -- 1342 * Modify each of the words of the passed string using the given1343 * function. Used to implement all modifiers.1344 * 1345 * Results: 1346 * A string of all the words modified appropriately.1347 * 1348 * Side Effects: 1349 * None.1343 * Modify each of the words of the passed string using the given 1344 * function. Used to implement all modifiers. 1345 * 1346 * Results: 1347 * A string of all the words modified appropriately. 1348 * 1349 * Side Effects: 1350 * None. 1350 1351 * 1351 1352 *----------------------------------------------------------------------- … … 1353 1354 static char * 1354 1355 VarModify (str, modProc, datum) 1355 char *str;/* String whose words should be trimmed */1356 /* Function to use to modify them */1357 Boolean (*modProc) __P((char *, Boolean, Buffer, ClientData));1358 ClientData datum;/* Datum to pass it */1359 { 1360 Buffer buf;/* Buffer for the new string */1361 Boolean addSpace;/* TRUE if need to add a space to the1362 * buffer before adding the trimmed1363 * word */1364 char **av; /* word list [first word does not count] */1356 char *str; /* String whose words should be trimmed */ 1357 /* Function to use to modify them */ 1358 Boolean (*modProc) __P((char *, Boolean, Buffer, ClientData)); 1359 ClientData datum; /* Datum to pass it */ 1360 { 1361 Buffer buf; /* Buffer for the new string */ 1362 Boolean addSpace; /* TRUE if need to add a space to the 1363 * buffer before adding the trimmed 1364 * word */ 1365 char **av; /* word list [first word does not count] */ 1365 1366 int ac, i; 1366 1367 … … 1371 1372 1372 1373 for (i = 1; i < ac; i++) 1373 addSpace = (*modProc)(av[i], addSpace, buf, datum);1374 addSpace = (*modProc)(av[i], addSpace, buf, datum); 1374 1375 1375 1376 Buf_AddByte (buf, '\0'); … … 1382 1383 *----------------------------------------------------------------------- 1383 1384 * VarGetPattern -- 1384 * Pass through the tstr looking for 1) escaped delimiters,1385 * '$'s and backslashes (place the escaped character in1386 * uninterpreted) and 2) unescaped $'s that aren't before1387 * the delimiter (expand the variable substitution unless flags1388 * has VAR_NOSUBST set).1389 * Return the expanded string or NULL if the delimiter was missing1390 * If pattern is specified, handle escaped ampersands, and replace1391 * unescaped ampersands with the lhs of the pattern.1392 * 1393 * Results: 1394 * A string of all the words modified appropriately.1395 * If length is specified, return the string length of the buffer1396 * If flags is specified and the last character of the pattern is a1397 * $ set the VAR_MATCH_END bit of flags.1398 * 1399 * Side Effects: 1400 * None.1385 * Pass through the tstr looking for 1) escaped delimiters, 1386 * '$'s and backslashes (place the escaped character in 1387 * uninterpreted) and 2) unescaped $'s that aren't before 1388 * the delimiter (expand the variable substitution unless flags 1389 * has VAR_NOSUBST set). 1390 * Return the expanded string or NULL if the delimiter was missing 1391 * If pattern is specified, handle escaped ampersands, and replace 1392 * unescaped ampersands with the lhs of the pattern. 1393 * 1394 * Results: 1395 * A string of all the words modified appropriately. 1396 * If length is specified, return the string length of the buffer 1397 * If flags is specified and the last character of the pattern is a 1398 * $ set the VAR_MATCH_END bit of flags. 1399 * 1400 * Side Effects: 1401 * None. 1401 1402 *----------------------------------------------------------------------- 1402 1403 */ … … 1415 1416 int junk; 1416 1417 if (length == NULL) 1417 length = &junk;1418 length = &junk; 1418 1419 1419 1420 #define IS_A_MATCH(cp, delim) \ … … 1428 1429 */ 1429 1430 for (cp = *tstr; *cp && (*cp != delim); cp++) { 1430 if (IS_A_MATCH(cp, delim)) {1431 Buf_AddByte(buf, (Byte) cp[1]);1432 cp++;1433 } else if (*cp == '$') {1434 if (cp[1] == delim) {1435 if (flags == NULL)1436 Buf_AddByte(buf, (Byte) *cp);1437 else1438 /*1439 * Unescaped $ at end of pattern => anchor1440 * pattern at end.1441 */1442 *flags |= VAR_MATCH_END;1443 } else {1444 if (flags == NULL || (*flags & VAR_NOSUBST) == 0) {1445 char *cp2;1446 intlen;1447 Boolean freeIt;1448 1449 /*1450 * If unescaped dollar sign not before the1451 * delimiter, assume it's a variable1452 * substitution and recurse.1453 */1454 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);1455 Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2);1456 if (freeIt)1457 efree(cp2);1458 cp += len - 1;1459 } else {1460 char *cp2 = &cp[1];1461 1462 if (*cp2 == '(' || *cp2 == '{') {1463 /*1464 * Find the end of this variable reference1465 * and suck it in without further ado.1466 * It will be interperated later.1467 */1468 int have = *cp2;1469 int want = (*cp2 == '(') ? ')' : '}';1470 int depth = 1;1471 1472 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) {1473 if (cp2[-1] != '\\') {1474 if (*cp2 == have)1475 ++depth;1476 if (*cp2 == want)1477 --depth;1478 }1479 }1480 Buf_AddBytes(buf, cp2 - cp, (Byte *)cp);1481 cp = --cp2;1482 } else1483 Buf_AddByte(buf, (Byte) *cp);1484 }1485 }1486 }1487 else if (pattern && *cp == '&')1488 Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs);1489 else1490 Buf_AddByte(buf, (Byte) *cp);1431 if (IS_A_MATCH(cp, delim)) { 1432 Buf_AddByte(buf, (Byte) cp[1]); 1433 cp++; 1434 } else if (*cp == '$') { 1435 if (cp[1] == delim) { 1436 if (flags == NULL) 1437 Buf_AddByte(buf, (Byte) *cp); 1438 else 1439 /* 1440 * Unescaped $ at end of pattern => anchor 1441 * pattern at end. 1442 */ 1443 *flags |= VAR_MATCH_END; 1444 } else { 1445 if (flags == NULL || (*flags & VAR_NOSUBST) == 0) { 1446 char *cp2; 1447 int len; 1448 Boolean freeIt; 1449 1450 /* 1451 * If unescaped dollar sign not before the 1452 * delimiter, assume it's a variable 1453 * substitution and recurse. 1454 */ 1455 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 1456 Buf_AddBytes(buf, strlen(cp2), (Byte *) cp2); 1457 if (freeIt) 1458 efree(cp2); 1459 cp += len - 1; 1460 } else { 1461 char *cp2 = &cp[1]; 1462 1463 if (*cp2 == '(' || *cp2 == '{') { 1464 /* 1465 * Find the end of this variable reference 1466 * and suck it in without further ado. 1467 * It will be interperated later. 1468 */ 1469 int have = *cp2; 1470 int want = (*cp2 == '(') ? ')' : '}'; 1471 int depth = 1; 1472 1473 for (++cp2; *cp2 != '\0' && depth > 0; ++cp2) { 1474 if (cp2[-1] != '\\') { 1475 if (*cp2 == have) 1476 ++depth; 1477 if (*cp2 == want) 1478 --depth; 1479 } 1480 } 1481 Buf_AddBytes(buf, cp2 - cp, (Byte *)cp); 1482 cp = --cp2; 1483 } else 1484 Buf_AddByte(buf, (Byte) *cp); 1485 } 1486 } 1487 } 1488 else if (pattern && *cp == '&') 1489 Buf_AddBytes(buf, pattern->leftLen, (Byte *)pattern->lhs); 1490 else 1491 Buf_AddByte(buf, (Byte) *cp); 1491 1492 } 1492 1493 … … 1494 1495 1495 1496 if (*cp != delim) { 1496 *tstr = cp;1497 *length = 0;1498 return NULL;1497 *tstr = cp; 1498 *length = 0; 1499 return NULL; 1499 1500 } 1500 1501 else { 1501 *tstr = ++cp;1502 cp = (char *) Buf_GetAll(buf, length);1503 *length -= 1;/* Don't count the NULL */1504 Buf_Destroy(buf, FALSE);1505 return cp;1502 *tstr = ++cp; 1503 cp = (char *) Buf_GetAll(buf, length); 1504 *length -= 1; /* Don't count the NULL */ 1505 Buf_Destroy(buf, FALSE); 1506 return cp; 1506 1507 } 1507 1508 } … … 1511 1512 *----------------------------------------------------------------------- 1512 1513 * VarQuote -- 1513 * Quote shell meta-characters in the string1514 * 1515 * Results: 1516 * The quoted string1517 * 1518 * Side Effects: 1519 * None.1514 * Quote shell meta-characters in the string 1515 * 1516 * Results: 1517 * The quoted string 1518 * 1519 * Side Effects: 1520 * None. 1520 1521 * 1521 1522 *----------------------------------------------------------------------- … … 1523 1524 static char * 1524 1525 VarQuote(str) 1525 char *str;1526 { 1527 1528 Buffer buf;1526 char *str; 1527 { 1528 1529 Buffer buf; 1529 1530 /* This should cover most shells :-( */ 1530 1531 static char meta[] = "\n \t'`\";&<>()|*?{}[]\\$!#^~"; … … 1532 1533 buf = Buf_Init (MAKE_BSIZE); 1533 1534 for (; *str; str++) { 1534 if (strchr(meta, *str) != NULL)1535 Buf_AddByte(buf, (Byte)'\\');1536 Buf_AddByte(buf, (Byte)*str);1535 if (strchr(meta, *str) != NULL) 1536 Buf_AddByte(buf, (Byte)'\\'); 1537 Buf_AddByte(buf, (Byte)*str); 1537 1538 } 1538 1539 Buf_AddByte(buf, (Byte) '\0'); … … 1545 1546 *----------------------------------------------------------------------- 1546 1547 * Var_Parse -- 1547 * Given the start of a variable invocation, extract the variable1548 * name and find its value, then modify it according to the1549 * specification.1550 * 1551 * Results: 1552 * The (possibly-modified) value of the variable or var_Error if the1553 * specification is invalid. The length of the specification is1554 * placed in *lengthPtr (for invalid specifications, this is just1555 * 2...?).1556 * A Boolean in *freePtr telling whether the returned string should1557 * be freed by the caller.1558 * 1559 * Side Effects: 1560 * None.1548 * Given the start of a variable invocation, extract the variable 1549 * name and find its value, then modify it according to the 1550 * specification. 1551 * 1552 * Results: 1553 * The (possibly-modified) value of the variable or var_Error if the 1554 * specification is invalid. The length of the specification is 1555 * placed in *lengthPtr (for invalid specifications, this is just 1556 * 2...?). 1557 * A Boolean in *freePtr telling whether the returned string should 1558 * be freed by the caller. 1559 * 1560 * Side Effects: 1561 * None. 1561 1562 * 1562 1563 *----------------------------------------------------------------------- … … 1564 1565 char * 1565 1566 Var_Parse (str, ctxt, err, lengthPtr, freePtr) 1566 char *str;/* The string to parse */1567 GNode *ctxt;/* The context for the variable */1568 Boolean err;/* TRUE if undefined variables are an error */1569 int *lengthPtr;/* OUT: The length of the specification */1570 Boolean *freePtr;/* OUT: TRUE if caller should efree result */1571 { 1572 register char *tstr; /* Pointer into str */1573 Var *v;/* Variable in invocation */1574 char *cp;/* Secondary pointer into str (place marker1575 * for tstr) */1576 Boolean haveModifier;/* TRUE if have modifiers for the variable */1577 register char endc; /* Ending character when variable in parens1578 * or braces */1579 register char startc=0; /* Starting character when variable in parens1580 * or braces */1581 int cnt; /* Used to count brace pairs when variable in1582 * in parens or braces */1583 char *start;1584 char delim;1585 Boolean dynamic;/* TRUE if the variable is local and we're1586 * expanding it in a non-local context. This1587 * is done to support dynamic sources. The1588 * result is just the invocation, unaltered */1589 int vlen;/* length of variable name, after embedded variable1590 * expansion */1567 char *str; /* The string to parse */ 1568 GNode *ctxt; /* The context for the variable */ 1569 Boolean err; /* TRUE if undefined variables are an error */ 1570 int *lengthPtr; /* OUT: The length of the specification */ 1571 Boolean *freePtr; /* OUT: TRUE if caller should efree result */ 1572 { 1573 register char *tstr; /* Pointer into str */ 1574 Var *v; /* Variable in invocation */ 1575 char *cp; /* Secondary pointer into str (place marker 1576 * for tstr) */ 1577 Boolean haveModifier;/* TRUE if have modifiers for the variable */ 1578 register char endc; /* Ending character when variable in parens 1579 * or braces */ 1580 register char startc=0; /* Starting character when variable in parens 1581 * or braces */ 1582 int cnt; /* Used to count brace pairs when variable in 1583 * in parens or braces */ 1584 char *start; 1585 char delim; 1586 Boolean dynamic; /* TRUE if the variable is local and we're 1587 * expanding it in a non-local context. This 1588 * is done to support dynamic sources. The 1589 * result is just the invocation, unaltered */ 1590 int vlen; /* length of variable name, after embedded variable 1591 * expansion */ 1591 1592 1592 1593 *freePtr = FALSE; 1593 1594 dynamic = FALSE; 1594 1595 start = str; 1595 //debugkso: fprintf(stderr, "var: str=%s\n", str);1596 1596 1597 1597 if (str[1] != '(' && str[1] != '{') { 1598 /*1599 * If it's not bounded by braces of some sort, life is much simpler.1600 * We just need to check for the first character and return the1601 * value if it exists.1602 */1603 charname[2];1604 1605 name[0] = str[1];1606 name[1] = '\0';1607 1608 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);1609 if (v == (Var *)NIL) {1610 *lengthPtr = 2;1611 1612 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) {1613 /*1614 * If substituting a local variable in a non-local context,1615 * assume it's for dynamic source stuff. We have to handle1616 * this specially and return the longhand for the variable1617 * with the dollar sign escaped so it makes it back to the1618 * caller. Only four of the local variables are treated1619 * specially as they are the only four that will be set1620 * when dynamic sources are expanded.1621 */1622 /* XXX: It looks like $% and $! are reversed here */1623 switch (str[1]) {1624 case '@':1625 return("$(.TARGET)");1626 case '%':1627 return("$(.ARCHIVE)");1628 case '*':1629 return("$(.PREFIX)");1630 case '!':1631 return("$(.MEMBER)");1598 /* 1599 * If it's not bounded by braces of some sort, life is much simpler. 1600 * We just need to check for the first character and return the 1601 * value if it exists. 1602 */ 1603 char name[2]; 1604 1605 name[0] = str[1]; 1606 name[1] = '\0'; 1607 1608 v = VarFind (name, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1609 if (v == (Var *)NIL) { 1610 *lengthPtr = 2; 1611 1612 if ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)) { 1613 /* 1614 * If substituting a local variable in a non-local context, 1615 * assume it's for dynamic source stuff. We have to handle 1616 * this specially and return the longhand for the variable 1617 * with the dollar sign escaped so it makes it back to the 1618 * caller. Only four of the local variables are treated 1619 * specially as they are the only four that will be set 1620 * when dynamic sources are expanded. 1621 */ 1622 /* XXX: It looks like $% and $! are reversed here */ 1623 switch (str[1]) { 1624 case '@': 1625 return("$(.TARGET)"); 1626 case '%': 1627 return("$(.ARCHIVE)"); 1628 case '*': 1629 return("$(.PREFIX)"); 1630 case '!': 1631 return("$(.MEMBER)"); 1632 1632 #ifdef USE_PARENTS 1633 case '^':1634 return("$(.PARENTS)");1633 case '^': 1634 return("$(.PARENTS)"); 1635 1635 #endif 1636 }1637 }1638 /*1639 * Error1640 */1641 return (err ? var_Error : varNoError);1642 } else {1643 haveModifier = FALSE;1644 tstr = &str[1];1645 endc = str[1];1646 }1636 } 1637 } 1638 /* 1639 * Error 1640 */ 1641 return (err ? var_Error : varNoError); 1642 } else { 1643 haveModifier = FALSE; 1644 tstr = &str[1]; 1645 endc = str[1]; 1646 } 1647 1647 } else { 1648 /* build up expanded variable name in this buffer */1649 Bufferbuf = Buf_Init(MAKE_BSIZE);1650 1651 startc = str[1];1652 endc = startc == '(' ? ')' : '}';1653 1654 /*1655 * Skip to the end character or a colon, whichever comes first,1656 * replacing embedded variables as we go.1657 */1658 for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':'; tstr++)1659 if (*tstr == '$') {1660 intrlen;1661 Booleanrfree;1662 char*rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);1663 1664 if (rval == var_Error) {1665 Fatal("Error expanding embedded variable.");1666 } else if (rval != NULL) {1667 Buf_AddBytes(buf, strlen(rval), (Byte *) rval);1668 if (rfree)1669 efree(rval);1670 }1671 tstr += rlen - 1;1672 } else1673 Buf_AddByte(buf, (Byte) *tstr);1674 1675 if (*tstr == '\0') {1676 /*1677 * If we never did find the end character, return NULL1678 * right now, setting the length to be the distance to1679 * the end of the string, since that's what make does.1680 */1681 *lengthPtr = tstr - str;1682 return (var_Error);1683 }1684 1685 haveModifier = (*tstr == ':');1686 *tstr = '\0';1687 1688 Buf_AddByte(buf, (Byte) '\0');1689 str = Buf_GetAll(buf, NULL);1690 vlen = strlen(str);1691 1692 v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD);1693 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) &&1694 #if defined(NMAKE) || defined(KMK)1695 (vlen == 2) && (str[1] == 'F' || str[1] == 'D' || str[1] == 'B' || str[1] == 'R'))1648 /* build up expanded variable name in this buffer */ 1649 Buffer buf = Buf_Init(MAKE_BSIZE); 1650 1651 startc = str[1]; 1652 endc = startc == '(' ? ')' : '}'; 1653 1654 /* 1655 * Skip to the end character or a colon, whichever comes first, 1656 * replacing embedded variables as we go. 1657 */ 1658 for (tstr = str + 2; *tstr != '\0' && *tstr != endc && *tstr != ':'; tstr++) 1659 if (*tstr == '$') { 1660 int rlen; 1661 Boolean rfree; 1662 char* rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree); 1663 1664 if (rval == var_Error) { 1665 Fatal("Error expanding embedded variable."); 1666 } else if (rval != NULL) { 1667 Buf_AddBytes(buf, strlen(rval), (Byte *) rval); 1668 if (rfree) 1669 efree(rval); 1670 } 1671 tstr += rlen - 1; 1672 } else 1673 Buf_AddByte(buf, (Byte) *tstr); 1674 1675 if (*tstr == '\0') { 1676 /* 1677 * If we never did find the end character, return NULL 1678 * right now, setting the length to be the distance to 1679 * the end of the string, since that's what make does. 1680 */ 1681 *lengthPtr = tstr - str; 1682 return (var_Error); 1683 } 1684 1685 haveModifier = (*tstr == ':'); 1686 *tstr = '\0'; 1687 1688 Buf_AddByte(buf, (Byte) '\0'); 1689 str = Buf_GetAll(buf, NULL); 1690 vlen = strlen(str); 1691 1692 v = VarFind (str, ctxt, FIND_ENV | FIND_GLOBAL | FIND_CMD); 1693 if ((v == (Var *)NIL) && (ctxt != VAR_CMD) && (ctxt != VAR_GLOBAL) && 1694 #ifdef USE_BASEANDROOT_MODIFIERS 1695 (vlen == 2) && (str[1] == 'F' || str[1] == 'D' || str[1] == 'B' || str[1] == 'R')) 1696 1696 #else 1697 (vlen == 2) && (str[1] == 'F' || str[1] == 'D'))1697 (vlen == 2) && (str[1] == 'F' || str[1] == 'D')) 1698 1698 #endif 1699 {1700 /*1701 * Check for bogus D and F forms of local variables since we're1702 * in a local context and the name is the right length.1703 */1704 switch(str[0]) {1705 case '@':1706 case '%':1707 case '*':1708 case '!':1709 case '>':1710 case '<':1711 {1712 char vname[2];1713 char *val;1714 1715 /*1716 * Well, it's local -- go look for it.1717 */1718 vname[0] = str[0];1719 vname[1] = '\0';1720 v = VarFind(vname, ctxt, 0);1721 1722 if (v != (Var *)NIL && !haveModifier) {1723 /*1724 * No need for nested expansion or anything, as we're1725 * the only one who sets these things and we sure don't1726 * put nested invocations in them...1727 */1728 val = (char *)Buf_GetAll(v->val, (int *)NULL);1729 1730 #if defined(NMAKE) || defined(KMK)1731 switch (str[1])1699 { 1700 /* 1701 * Check for bogus D and F forms of local variables since we're 1702 * in a local context and the name is the right length. 1703 */ 1704 switch(str[0]) { 1705 case '@': 1706 case '%': 1707 case '*': 1708 case '!': 1709 case '>': 1710 case '<': 1711 { 1712 char vname[2]; 1713 char *val; 1714 1715 /* 1716 * Well, it's local -- go look for it. 1717 */ 1718 vname[0] = str[0]; 1719 vname[1] = '\0'; 1720 v = VarFind(vname, ctxt, 0); 1721 1722 if (v != (Var *)NIL && !haveModifier) { 1723 /* 1724 * No need for nested expansion or anything, as we're 1725 * the only one who sets these things and we sure don't 1726 * put nested invocations in them... 1727 */ 1728 val = (char *)Buf_GetAll(v->val, (int *)NULL); 1729 1730 #ifdef USE_BASEANDROOT_MODIFIERS 1731 switch (str[1]) 1732 1732 { 1733 1733 case 'D': val = VarModify(val, VarHead, (ClientData)0); break; … … 1735 1735 case 'R': val = VarModify(val, VarRoot, (ClientData)0); break; 1736 1736 default: val = VarModify(val, VarTail, (ClientData)0); break; 1737 }1737 } 1738 1738 #else 1739 if (str[1] == 'D') {1740 val = VarModify(val, VarHead, (ClientData)0);1741 } else {1742 val = VarModify(val, VarTail, (ClientData)0);1743 }1739 if (str[1] == 'D') { 1740 val = VarModify(val, VarHead, (ClientData)0); 1741 } else { 1742 val = VarModify(val, VarTail, (ClientData)0); 1743 } 1744 1744 #endif 1745 /* 1746 * Resulting string is dynamically allocated, so 1747 * tell caller to efree it. 1748 */ 1749 *freePtr = TRUE; 1750 *lengthPtr = tstr-start+1; 1751 *tstr = endc; 1752 Buf_Destroy(buf, TRUE); 1753 return(val); 1754 } 1755 break; 1756 } 1757 } 1758 } 1759 1760 if (v == (Var *)NIL) { 1761 //debugkso: fprintf(stderr, "\tv == (Var *)NIL vlen=%d str=%s\n", vlen, str); 1762 1763 if (((vlen == 1) || 1764 (((vlen == 2) && (str[1] == 'F' || 1765 #if defined(NMAKE) || defined(KMK) 1745 /* 1746 * Resulting string is dynamically allocated, so 1747 * tell caller to efree it. 1748 */ 1749 *freePtr = TRUE; 1750 *lengthPtr = tstr-start+1; 1751 *tstr = endc; 1752 Buf_Destroy(buf, TRUE); 1753 return(val); 1754 } 1755 break; 1756 } 1757 } 1758 } 1759 1760 if (v == (Var *)NIL) { 1761 1762 if (((vlen == 1) || 1763 (((vlen == 2) && (str[1] == 'F' || 1764 #ifdef USE_BASEANDROOT_MODIFIERS 1766 1765 str[1] == 'D' || str[1] == 'B' || str[1] == 'R')))) && 1767 1766 #else 1768 str[1] == 'D')))) &&1767 str[1] == 'D')))) && 1769 1768 #endif 1770 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))1771 {1772 /*1773 * If substituting a local variable in a non-local context,1774 * assume it's for dynamic source stuff. We have to handle1775 * this specially and return the longhand for the variable1776 * with the dollar sign escaped so it makes it back to the1777 * caller. Only four of the local variables are treated1778 * specially as they are the only four that will be set1779 * when dynamic sources are expanded.1780 */1781 switch (str[0]) {1782 case '@':1783 case '%':1784 case '*':1785 case '!':1769 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1770 { 1771 /* 1772 * If substituting a local variable in a non-local context, 1773 * assume it's for dynamic source stuff. We have to handle 1774 * this specially and return the longhand for the variable 1775 * with the dollar sign escaped so it makes it back to the 1776 * caller. Only four of the local variables are treated 1777 * specially as they are the only four that will be set 1778 * when dynamic sources are expanded. 1779 */ 1780 switch (str[0]) { 1781 case '@': 1782 case '%': 1783 case '*': 1784 case '!': 1786 1785 #ifdef USE_PARENTS 1787 case '^':1786 case '^': 1788 1787 #endif 1789 dynamic = TRUE;1790 break;1791 }1792 } else if ((vlen > 2) && (str[0] == '.') &&1793 isupper((unsigned char) str[1]) &&1794 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL)))1795 {1796 intlen;1797 1798 len = vlen - 1;1799 if ((strncmp(str, ".TARGET", len) == 0) ||1800 (strncmp(str, ".ARCHIVE", len) == 0) ||1801 (strncmp(str, ".PREFIX", len) == 0) ||1788 dynamic = TRUE; 1789 break; 1790 } 1791 } else if ((vlen > 2) && (str[0] == '.') && 1792 isupper((unsigned char) str[1]) && 1793 ((ctxt == VAR_CMD) || (ctxt == VAR_GLOBAL))) 1794 { 1795 int len; 1796 1797 len = vlen - 1; 1798 if ((strncmp(str, ".TARGET", len) == 0) || 1799 (strncmp(str, ".ARCHIVE", len) == 0) || 1800 (strncmp(str, ".PREFIX", len) == 0) || 1802 1801 #ifdef USE_PARENTS 1803 (strncmp(str, ".PARENTS", len) == 0) ||1802 (strncmp(str, ".PARENTS", len) == 0) || 1804 1803 #endif 1805 (strncmp(str, ".MEMBER", len) == 0))1806 {1807 dynamic = TRUE;1808 }1809 }1810 1811 if (!haveModifier) {1812 /*1813 * No modifiers -- have specification length so we can return1814 * now.1815 */1816 *lengthPtr = tstr - start + 1;1817 *tstr = endc;1818 if (dynamic) {1819 str = emalloc(*lengthPtr + 1);1820 strncpy(str, start, *lengthPtr);1821 str[*lengthPtr] = '\0';1822 *freePtr = TRUE;1823 Buf_Destroy(buf, TRUE);1824 return(str);1825 } else {1826 Buf_Destroy(buf, TRUE);1827 return (err ? var_Error : varNoError);1828 }1829 } else {1830 /*1831 * Still need to get to the end of the variable specification,1832 * so kludge up a Var structure for the modifications1833 */1834 v = (Var *) emalloc(sizeof(Var));1835 v->name = &str[1];1836 v->val = Buf_Init(1);1837 v->flags = VAR_JUNK;1838 }1839 }1840 Buf_Destroy(buf, TRUE);1804 (strncmp(str, ".MEMBER", len) == 0)) 1805 { 1806 dynamic = TRUE; 1807 } 1808 } 1809 1810 if (!haveModifier) { 1811 /* 1812 * No modifiers -- have specification length so we can return 1813 * now. 1814 */ 1815 *lengthPtr = tstr - start + 1; 1816 *tstr = endc; 1817 if (dynamic) { 1818 str = emalloc(*lengthPtr + 1); 1819 strncpy(str, start, *lengthPtr); 1820 str[*lengthPtr] = '\0'; 1821 *freePtr = TRUE; 1822 Buf_Destroy(buf, TRUE); 1823 return(str); 1824 } else { 1825 Buf_Destroy(buf, TRUE); 1826 return (err ? var_Error : varNoError); 1827 } 1828 } else { 1829 /* 1830 * Still need to get to the end of the variable specification, 1831 * so kludge up a Var structure for the modifications 1832 */ 1833 v = (Var *) emalloc(sizeof(Var)); 1834 v->name = &str[1]; 1835 v->val = Buf_Init(1); 1836 v->flags = VAR_JUNK; 1837 } 1838 } 1839 Buf_Destroy(buf, TRUE); 1841 1840 } 1842 1841 1843 1842 if (v->flags & VAR_IN_USE) { 1844 Fatal("Variable %s is recursive.", v->name);1845 /*NOTREACHED*/1843 Fatal("Variable %s is recursive.", v->name); 1844 /*NOTREACHED*/ 1846 1845 } else { 1847 v->flags |= VAR_IN_USE;1846 v->flags |= VAR_IN_USE; 1848 1847 } 1849 1848 /* … … 1858 1857 str = (char *)Buf_GetAll(v->val, (int *)NULL); 1859 1858 if (strchr (str, '$') != (char *)NULL) { 1860 str = Var_Subst(NULL, str, ctxt, err);1861 *freePtr = TRUE;1859 str = Var_Subst(NULL, str, ctxt, err); 1860 *freePtr = TRUE; 1862 1861 } 1863 1862 … … 1867 1866 * Now we need to apply any modifiers the user wants applied. 1868 1867 * These are: 1869 * :M<pattern>words which match the given <pattern>.1870 * <pattern> is of the standard file1871 * wildcarding form.1872 * :S<d><pat1><d><pat2><d>[g]1873 * Substitute <pat2> for <pat1> in the value1874 * :C<d><pat1><d><pat2><d>[g]1875 * Substitute <pat2> for regex <pat1> in the value1876 * :HSubstitute the head of each word1877 * :TSubstitute the tail of each word1878 * :ESubstitute the extension (minus '.') of1879 * each word1880 * :RSubstitute the root of each word1881 * (pathname minus the suffix).1882 * :lhs=rhsLike :S, but the rhs goes to the end of1883 * the invocation.1884 * :UConverts variable to upper-case.1885 * :LConverts variable to lower-case.1868 * :M<pattern> words which match the given <pattern>. 1869 * <pattern> is of the standard file 1870 * wildcarding form. 1871 * :S<d><pat1><d><pat2><d>[g] 1872 * Substitute <pat2> for <pat1> in the value 1873 * :C<d><pat1><d><pat2><d>[g] 1874 * Substitute <pat2> for regex <pat1> in the value 1875 * :H Substitute the head of each word 1876 * :T Substitute the tail of each word 1877 * :E Substitute the extension (minus '.') of 1878 * each word 1879 * :R Substitute the root of each word 1880 * (pathname minus the suffix). 1881 * :lhs=rhs Like :S, but the rhs goes to the end of 1882 * the invocation. 1883 * :U Converts variable to upper-case. 1884 * :L Converts variable to lower-case. 1886 1885 */ 1887 1886 if ((str != (char *)NULL) && haveModifier) { 1888 /*1889 * Skip initial colon while putting it back.1890 */1891 *tstr++ = ':';1892 while (*tstr != endc) {1893 char*newStr; /* New value to return */1894 char termc;/* Character which terminated scan */1895 1896 if (DEBUG(VAR)) {1897 printf("Applying :%c to \"%s\"\n", *tstr, str);1898 }1899 switch (*tstr) {1900 case 'U':1901 if (tstr[1] == endc || tstr[1] == ':') {1902 Buffer buf;1903 buf = Buf_Init(MAKE_BSIZE);1904 for (cp = str; *cp ; cp++)1905 Buf_AddByte(buf, (Byte) toupper(*cp));1906 1907 Buf_AddByte(buf, (Byte) '\0');1908 newStr = (char *) Buf_GetAll(buf, (int *) NULL);1909 Buf_Destroy(buf, FALSE);1910 1911 cp = tstr + 1;1912 termc = *cp;1913 break;1914 }1915 /* FALLTHROUGH */1916 case 'L':1917 if (tstr[1] == endc || tstr[1] == ':') {1918 Buffer buf;1919 buf = Buf_Init(MAKE_BSIZE);1920 for (cp = str; *cp ; cp++)1921 Buf_AddByte(buf, (Byte) tolower(*cp));1922 1923 Buf_AddByte(buf, (Byte) '\0');1924 newStr = (char *) Buf_GetAll(buf, (int *) NULL);1925 Buf_Destroy(buf, FALSE);1926 1927 cp = tstr + 1;1928 termc = *cp;1929 break;1930 }1931 /* FALLTHROUGH */1932 case 'N':1933 case 'M':1934 {1935 char *pattern;1936 char *cp2;1937 Boolean copy;1938 1939 copy = FALSE;1940 for (cp = tstr + 1;1941 *cp != '\0' && *cp != ':' && *cp != endc;1942 cp++)1943 {1944 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){1945 copy = TRUE;1946 cp++;1947 }1948 }1949 termc = *cp;1950 *cp = '\0';1951 if (copy) {1952 /*1953 * Need to compress the \:'s out of the pattern, so1954 * allocate enough room to hold the uncompressed1955 * pattern (note that cp started at tstr+1, so1956 * cp - tstr takes the null byte into account) and1957 * compress the pattern into the space.1958 */1959 pattern = emalloc(cp - tstr);1960 for (cp2 = pattern, cp = tstr + 1;1961 *cp != '\0';1962 cp++, cp2++)1963 {1964 if ((*cp == '\\') &&1965 (cp[1] == ':' || cp[1] == endc)) {1966 cp++;1967 }1968 *cp2 = *cp;1969 }1970 *cp2 = '\0';1971 } else {1972 pattern = &tstr[1];1973 }1974 if (*tstr == 'M' || *tstr == 'm') {1975 newStr = VarModify(str, VarMatch, (ClientData)pattern);1976 } else {1977 newStr = VarModify(str, VarNoMatch,1978 (ClientData)pattern);1979 }1980 if (copy) {1981 efree(pattern);1982 }1983 break;1984 }1985 case 'S':1986 {1987 VarPatternpattern;1988 register char delim;1989 Buffer buf;/* Buffer for patterns */1990 1991 pattern.flags = 0;1992 delim = tstr[1];1993 tstr += 2;1994 1995 /*1996 * If pattern begins with '^', it is anchored to the1997 * start of the word -- skip over it and flag pattern.1998 */1999 if (*tstr == '^') {2000 pattern.flags |= VAR_MATCH_START;2001 tstr += 1;2002 }2003 2004 buf = Buf_Init(0);2005 2006 /*2007 * Pass through the lhs looking for 1) escaped delimiters,2008 * '$'s and backslashes (place the escaped character in2009 * uninterpreted) and 2) unescaped $'s that aren't before2010 * the delimiter (expand the variable substitution).2011 * The result is left in the Buffer buf.2012 */2013 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {2014 if ((*cp == '\\') &&2015 ((cp[1] == delim) ||2016 (cp[1] == '$') ||2017 (cp[1] == '\\')))2018 {2019 Buf_AddByte(buf, (Byte)cp[1]);2020 cp++;2021 } else if (*cp == '$') {2022 if (cp[1] != delim) {2023 /*2024 * If unescaped dollar sign not before the2025 * delimiter, assume it's a variable2026 * substitution and recurse.2027 */2028 char*cp2;2029 intlen;2030 BooleanfreeIt;2031 2032 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);2033 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);2034 if (freeIt) {2035 efree(cp2);2036 }2037 cp += len - 1;2038 } else {2039 /*2040 * Unescaped $ at end of pattern => anchor2041 * pattern at end.2042 */2043 pattern.flags |= VAR_MATCH_END;2044 }2045 } else {2046 Buf_AddByte(buf, (Byte)*cp);2047 }2048 }2049 2050 Buf_AddByte(buf, (Byte)'\0');2051 2052 /*2053 * If lhs didn't end with the delimiter, complain and2054 * return NULL2055 */2056 if (*cp != delim) {2057 *lengthPtr = cp - start + 1;2058 if (*freePtr) {2059 efree(str);2060 }2061 Buf_Destroy(buf, TRUE);2062 Error("Unclosed substitution for %s (%c missing)",2063 v->name, delim);2064 return (var_Error);2065 }2066 2067 /*2068 * Fetch pattern and destroy buffer, but preserve the data2069 * in it, since that's our lhs. Note that Buf_GetAll2070 * will return the actual number of bytes, which includes2071 * the null byte, so we have to decrement the length by2072 * one.2073 */2074 pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen);2075 pattern.leftLen--;2076 Buf_Destroy(buf, FALSE);2077 2078 /*2079 * Now comes the replacement string. Three things need to2080 * be done here: 1) need to compress escaped delimiters and2081 * ampersands and 2) need to replace unescaped ampersands2082 * with the l.h.s. (since this isn't regexp, we can do2083 * it right here) and 3) expand any variable substitutions.2084 */2085 buf = Buf_Init(0);2086 2087 tstr = cp + 1;2088 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) {2089 if ((*cp == '\\') &&2090 ((cp[1] == delim) ||2091 (cp[1] == '&') ||2092 (cp[1] == '\\') ||2093 (cp[1] == '$')))2094 {2095 Buf_AddByte(buf, (Byte)cp[1]);2096 cp++;2097 } else if ((*cp == '$') && (cp[1] != delim)) {2098 char *cp2;2099 intlen;2100 Boolean freeIt;2101 2102 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt);2103 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2);2104 cp += len - 1;2105 if (freeIt) {2106 efree(cp2);2107 }2108 } else if (*cp == '&') {2109 Buf_AddBytes(buf, pattern.leftLen,2110 (Byte *)pattern.lhs);2111 } else {2112 Buf_AddByte(buf, (Byte)*cp);2113 }2114 }2115 2116 Buf_AddByte(buf, (Byte)'\0');2117 2118 /*2119 * If didn't end in delimiter character, complain2120 */2121 if (*cp != delim) {2122 *lengthPtr = cp - start + 1;2123 if (*freePtr) {2124 efree(str);2125 }2126 Buf_Destroy(buf, TRUE);2127 Error("Unclosed substitution for %s (%c missing)",2128 v->name, delim);2129 return (var_Error);2130 }2131 2132 pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen);2133 pattern.rightLen--;2134 Buf_Destroy(buf, FALSE);2135 2136 /*2137 * Check for global substitution. If 'g' after the final2138 * delimiter, substitution is global and is marked that2139 * way.2140 */2141 cp++;2142 if (*cp == 'g') {2143 pattern.flags |= VAR_SUB_GLOBAL;2144 cp++;2145 }2146 2147 termc = *cp;2148 newStr = VarModify(str, VarSubstitute,2149 (ClientData)&pattern);2150 /*2151 * Free the two strings.2152 */2153 efree(pattern.lhs);2154 efree(pattern.rhs);2155 break;2156 }2157 case 'C':2158 {2159 VarREPattern pattern;2160 char*re;2161 interror;2162 2163 pattern.flags = 0;2164 delim = tstr[1];2165 tstr += 2;2166 2167 cp = tstr;2168 2169 if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL,2170 NULL, NULL)) == NULL) {2171 /* was: goto cleanup */2172 *lengthPtr = cp - start + 1;2173 if (*freePtr)2174 efree(str);2175 if (delim != '\0')2176 Error("Unclosed substitution for %s (%c missing)",2177 v->name, delim);2178 return (var_Error);2179 }2180 2181 if ((pattern.replace = VarGetPattern(ctxt, err, &cp,2182 delim, NULL, NULL, NULL)) == NULL){2183 efree(re);2184 2185 /* was: goto cleanup */2186 *lengthPtr = cp - start + 1;2187 if (*freePtr)2188 efree(str);2189 if (delim != '\0')2190 Error("Unclosed substitution for %s (%c missing)",2191 v->name, delim);2192 return (var_Error);2193 }2194 2195 for (;; cp++) {2196 switch (*cp) {2197 case 'g':2198 pattern.flags |= VAR_SUB_GLOBAL;2199 continue;2200 case '1':2201 pattern.flags |= VAR_SUB_ONE;2202 continue;2203 }2204 break;2205 }2206 2207 termc = *cp;2208 2209 error = regcomp(&pattern.re, re, REG_EXTENDED);2210 efree(re);2211 if (error){2212 *lengthPtr = cp - start + 1;2213 VarREError(error, &pattern.re, "RE substitution error");2214 efree(pattern.replace);2215 return (var_Error);2216 }2217 2218 pattern.nsub = pattern.re.re_nsub + 1;2219 if (pattern.nsub < 1)2220 pattern.nsub = 1;2221 if (pattern.nsub > 10)2222 pattern.nsub = 10;2223 pattern.matches = emalloc(pattern.nsub *2224 sizeof(regmatch_t));2225 newStr = VarModify(str, VarRESubstitute,2226 (ClientData) &pattern);2227 regfree(&pattern.re);2228 efree(pattern.replace);2229 efree(pattern.matches);2230 break;2231 }2232 case 'Q':2233 if (tstr[1] == endc || tstr[1] == ':') {2234 newStr = VarQuote (str);2235 cp = tstr + 1;2236 termc = *cp;2237 break;2238 }2239 /*FALLTHRU*/2240 case 'T':2241 if (tstr[1] == endc || tstr[1] == ':') {2242 newStr = VarModify (str, VarTail, (ClientData)0);2243 cp = tstr + 1;2244 termc = *cp;2245 break;2246 }2247 /*FALLTHRU*/2248 case 'H':2249 if (tstr[1] == endc || tstr[1] == ':') {2250 newStr = VarModify (str, VarHead, (ClientData)0);2251 cp = tstr + 1;2252 termc = *cp;2253 break;2254 }2255 /*FALLTHRU*/2256 case 'E':2257 if (tstr[1] == endc || tstr[1] == ':') {2258 newStr = VarModify (str, VarSuffix, (ClientData)0);2259 cp = tstr + 1;2260 termc = *cp;2261 break;2262 }2263 /*FALLTHRU*/2264 case 'R':2265 if (tstr[1] == endc || tstr[1] == ':') {2266 newStr = VarModify (str, VarRoot, (ClientData)0);2267 cp = tstr + 1;2268 termc = *cp;2269 break;2270 }2271 /*FALLTHRU*/1887 /* 1888 * Skip initial colon while putting it back. 1889 */ 1890 *tstr++ = ':'; 1891 while (*tstr != endc) { 1892 char *newStr; /* New value to return */ 1893 char termc; /* Character which terminated scan */ 1894 1895 if (DEBUG(VAR)) { 1896 printf("Applying :%c to \"%s\"\n", *tstr, str); 1897 } 1898 switch (*tstr) { 1899 case 'U': 1900 if (tstr[1] == endc || tstr[1] == ':') { 1901 Buffer buf; 1902 buf = Buf_Init(MAKE_BSIZE); 1903 for (cp = str; *cp ; cp++) 1904 Buf_AddByte(buf, (Byte) toupper(*cp)); 1905 1906 Buf_AddByte(buf, (Byte) '\0'); 1907 newStr = (char *) Buf_GetAll(buf, (int *) NULL); 1908 Buf_Destroy(buf, FALSE); 1909 1910 cp = tstr + 1; 1911 termc = *cp; 1912 break; 1913 } 1914 /* FALLTHROUGH */ 1915 case 'L': 1916 if (tstr[1] == endc || tstr[1] == ':') { 1917 Buffer buf; 1918 buf = Buf_Init(MAKE_BSIZE); 1919 for (cp = str; *cp ; cp++) 1920 Buf_AddByte(buf, (Byte) tolower(*cp)); 1921 1922 Buf_AddByte(buf, (Byte) '\0'); 1923 newStr = (char *) Buf_GetAll(buf, (int *) NULL); 1924 Buf_Destroy(buf, FALSE); 1925 1926 cp = tstr + 1; 1927 termc = *cp; 1928 break; 1929 } 1930 /* FALLTHROUGH */ 1931 case 'N': 1932 case 'M': 1933 { 1934 char *pattern; 1935 char *cp2; 1936 Boolean copy; 1937 1938 copy = FALSE; 1939 for (cp = tstr + 1; 1940 *cp != '\0' && *cp != ':' && *cp != endc; 1941 cp++) 1942 { 1943 if (*cp == '\\' && (cp[1] == ':' || cp[1] == endc)){ 1944 copy = TRUE; 1945 cp++; 1946 } 1947 } 1948 termc = *cp; 1949 *cp = '\0'; 1950 if (copy) { 1951 /* 1952 * Need to compress the \:'s out of the pattern, so 1953 * allocate enough room to hold the uncompressed 1954 * pattern (note that cp started at tstr+1, so 1955 * cp - tstr takes the null byte into account) and 1956 * compress the pattern into the space. 1957 */ 1958 pattern = emalloc(cp - tstr); 1959 for (cp2 = pattern, cp = tstr + 1; 1960 *cp != '\0'; 1961 cp++, cp2++) 1962 { 1963 if ((*cp == '\\') && 1964 (cp[1] == ':' || cp[1] == endc)) { 1965 cp++; 1966 } 1967 *cp2 = *cp; 1968 } 1969 *cp2 = '\0'; 1970 } else { 1971 pattern = &tstr[1]; 1972 } 1973 if (*tstr == 'M' || *tstr == 'm') { 1974 newStr = VarModify(str, VarMatch, (ClientData)pattern); 1975 } else { 1976 newStr = VarModify(str, VarNoMatch, 1977 (ClientData)pattern); 1978 } 1979 if (copy) { 1980 efree(pattern); 1981 } 1982 break; 1983 } 1984 case 'S': 1985 { 1986 VarPattern pattern; 1987 register char delim; 1988 Buffer buf; /* Buffer for patterns */ 1989 1990 pattern.flags = 0; 1991 delim = tstr[1]; 1992 tstr += 2; 1993 1994 /* 1995 * If pattern begins with '^', it is anchored to the 1996 * start of the word -- skip over it and flag pattern. 1997 */ 1998 if (*tstr == '^') { 1999 pattern.flags |= VAR_MATCH_START; 2000 tstr += 1; 2001 } 2002 2003 buf = Buf_Init(0); 2004 2005 /* 2006 * Pass through the lhs looking for 1) escaped delimiters, 2007 * '$'s and backslashes (place the escaped character in 2008 * uninterpreted) and 2) unescaped $'s that aren't before 2009 * the delimiter (expand the variable substitution). 2010 * The result is left in the Buffer buf. 2011 */ 2012 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 2013 if ((*cp == '\\') && 2014 ((cp[1] == delim) || 2015 (cp[1] == '$') || 2016 (cp[1] == '\\'))) 2017 { 2018 Buf_AddByte(buf, (Byte)cp[1]); 2019 cp++; 2020 } else if (*cp == '$') { 2021 if (cp[1] != delim) { 2022 /* 2023 * If unescaped dollar sign not before the 2024 * delimiter, assume it's a variable 2025 * substitution and recurse. 2026 */ 2027 char *cp2; 2028 int len; 2029 Boolean freeIt; 2030 2031 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 2032 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 2033 if (freeIt) { 2034 efree(cp2); 2035 } 2036 cp += len - 1; 2037 } else { 2038 /* 2039 * Unescaped $ at end of pattern => anchor 2040 * pattern at end. 2041 */ 2042 pattern.flags |= VAR_MATCH_END; 2043 } 2044 } else { 2045 Buf_AddByte(buf, (Byte)*cp); 2046 } 2047 } 2048 2049 Buf_AddByte(buf, (Byte)'\0'); 2050 2051 /* 2052 * If lhs didn't end with the delimiter, complain and 2053 * return NULL 2054 */ 2055 if (*cp != delim) { 2056 *lengthPtr = cp - start + 1; 2057 if (*freePtr) { 2058 efree(str); 2059 } 2060 Buf_Destroy(buf, TRUE); 2061 Error("Unclosed substitution for %s (%c missing)", 2062 v->name, delim); 2063 return (var_Error); 2064 } 2065 2066 /* 2067 * Fetch pattern and destroy buffer, but preserve the data 2068 * in it, since that's our lhs. Note that Buf_GetAll 2069 * will return the actual number of bytes, which includes 2070 * the null byte, so we have to decrement the length by 2071 * one. 2072 */ 2073 pattern.lhs = (char *)Buf_GetAll(buf, &pattern.leftLen); 2074 pattern.leftLen--; 2075 Buf_Destroy(buf, FALSE); 2076 2077 /* 2078 * Now comes the replacement string. Three things need to 2079 * be done here: 1) need to compress escaped delimiters and 2080 * ampersands and 2) need to replace unescaped ampersands 2081 * with the l.h.s. (since this isn't regexp, we can do 2082 * it right here) and 3) expand any variable substitutions. 2083 */ 2084 buf = Buf_Init(0); 2085 2086 tstr = cp + 1; 2087 for (cp = tstr; *cp != '\0' && *cp != delim; cp++) { 2088 if ((*cp == '\\') && 2089 ((cp[1] == delim) || 2090 (cp[1] == '&') || 2091 (cp[1] == '\\') || 2092 (cp[1] == '$'))) 2093 { 2094 Buf_AddByte(buf, (Byte)cp[1]); 2095 cp++; 2096 } else if ((*cp == '$') && (cp[1] != delim)) { 2097 char *cp2; 2098 int len; 2099 Boolean freeIt; 2100 2101 cp2 = Var_Parse(cp, ctxt, err, &len, &freeIt); 2102 Buf_AddBytes(buf, strlen(cp2), (Byte *)cp2); 2103 cp += len - 1; 2104 if (freeIt) { 2105 efree(cp2); 2106 } 2107 } else if (*cp == '&') { 2108 Buf_AddBytes(buf, pattern.leftLen, 2109 (Byte *)pattern.lhs); 2110 } else { 2111 Buf_AddByte(buf, (Byte)*cp); 2112 } 2113 } 2114 2115 Buf_AddByte(buf, (Byte)'\0'); 2116 2117 /* 2118 * If didn't end in delimiter character, complain 2119 */ 2120 if (*cp != delim) { 2121 *lengthPtr = cp - start + 1; 2122 if (*freePtr) { 2123 efree(str); 2124 } 2125 Buf_Destroy(buf, TRUE); 2126 Error("Unclosed substitution for %s (%c missing)", 2127 v->name, delim); 2128 return (var_Error); 2129 } 2130 2131 pattern.rhs = (char *)Buf_GetAll(buf, &pattern.rightLen); 2132 pattern.rightLen--; 2133 Buf_Destroy(buf, FALSE); 2134 2135 /* 2136 * Check for global substitution. If 'g' after the final 2137 * delimiter, substitution is global and is marked that 2138 * way. 2139 */ 2140 cp++; 2141 if (*cp == 'g') { 2142 pattern.flags |= VAR_SUB_GLOBAL; 2143 cp++; 2144 } 2145 2146 termc = *cp; 2147 newStr = VarModify(str, VarSubstitute, 2148 (ClientData)&pattern); 2149 /* 2150 * Free the two strings. 2151 */ 2152 efree(pattern.lhs); 2153 efree(pattern.rhs); 2154 break; 2155 } 2156 case 'C': 2157 { 2158 VarREPattern pattern; 2159 char *re; 2160 int error; 2161 2162 pattern.flags = 0; 2163 delim = tstr[1]; 2164 tstr += 2; 2165 2166 cp = tstr; 2167 2168 if ((re = VarGetPattern(ctxt, err, &cp, delim, NULL, 2169 NULL, NULL)) == NULL) { 2170 /* was: goto cleanup */ 2171 *lengthPtr = cp - start + 1; 2172 if (*freePtr) 2173 efree(str); 2174 if (delim != '\0') 2175 Error("Unclosed substitution for %s (%c missing)", 2176 v->name, delim); 2177 return (var_Error); 2178 } 2179 2180 if ((pattern.replace = VarGetPattern(ctxt, err, &cp, 2181 delim, NULL, NULL, NULL)) == NULL){ 2182 efree(re); 2183 2184 /* was: goto cleanup */ 2185 *lengthPtr = cp - start + 1; 2186 if (*freePtr) 2187 efree(str); 2188 if (delim != '\0') 2189 Error("Unclosed substitution for %s (%c missing)", 2190 v->name, delim); 2191 return (var_Error); 2192 } 2193 2194 for (;; cp++) { 2195 switch (*cp) { 2196 case 'g': 2197 pattern.flags |= VAR_SUB_GLOBAL; 2198 continue; 2199 case '1': 2200 pattern.flags |= VAR_SUB_ONE; 2201 continue; 2202 } 2203 break; 2204 } 2205 2206 termc = *cp; 2207 2208 error = regcomp(&pattern.re, re, REG_EXTENDED); 2209 efree(re); 2210 if (error) { 2211 *lengthPtr = cp - start + 1; 2212 VarREError(error, &pattern.re, "RE substitution error"); 2213 efree(pattern.replace); 2214 return (var_Error); 2215 } 2216 2217 pattern.nsub = pattern.re.re_nsub + 1; 2218 if (pattern.nsub < 1) 2219 pattern.nsub = 1; 2220 if (pattern.nsub > 10) 2221 pattern.nsub = 10; 2222 pattern.matches = emalloc(pattern.nsub * 2223 sizeof(regmatch_t)); 2224 newStr = VarModify(str, VarRESubstitute, 2225 (ClientData) &pattern); 2226 regfree(&pattern.re); 2227 efree(pattern.replace); 2228 efree(pattern.matches); 2229 break; 2230 } 2231 case 'Q': 2232 if (tstr[1] == endc || tstr[1] == ':') { 2233 newStr = VarQuote (str); 2234 cp = tstr + 1; 2235 termc = *cp; 2236 break; 2237 } 2238 /*FALLTHRU*/ 2239 case 'T': 2240 if (tstr[1] == endc || tstr[1] == ':') { 2241 newStr = VarModify (str, VarTail, (ClientData)0); 2242 cp = tstr + 1; 2243 termc = *cp; 2244 break; 2245 } 2246 /*FALLTHRU*/ 2247 case 'H': 2248 if (tstr[1] == endc || tstr[1] == ':') { 2249 newStr = VarModify (str, VarHead, (ClientData)0); 2250 cp = tstr + 1; 2251 termc = *cp; 2252 break; 2253 } 2254 /*FALLTHRU*/ 2255 case 'E': 2256 if (tstr[1] == endc || tstr[1] == ':') { 2257 newStr = VarModify (str, VarSuffix, (ClientData)0); 2258 cp = tstr + 1; 2259 termc = *cp; 2260 break; 2261 } 2262 /*FALLTHRU*/ 2263 case 'R': 2264 if (tstr[1] == endc || tstr[1] == ':') { 2265 newStr = VarModify (str, VarRoot, (ClientData)0); 2266 cp = tstr + 1; 2267 termc = *cp; 2268 break; 2269 } 2270 /*FALLTHRU*/ 2272 2271 #ifdef SUNSHCMD 2273 case 's':2274 if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) {2275 char *err;2276 newStr = Cmd_Exec (str, &err);2277 if (err)2278 Error (err, str);2279 cp = tstr + 2;2280 termc = *cp;2281 break;2282 }2283 /*FALLTHRU*/2272 case 's': 2273 if (tstr[1] == 'h' && (tstr[2] == endc || tstr[2] == ':')) { 2274 char *err; 2275 newStr = Cmd_Exec (str, &err); 2276 if (err) 2277 Error (err, str); 2278 cp = tstr + 2; 2279 termc = *cp; 2280 break; 2281 } 2282 /*FALLTHRU*/ 2284 2283 #endif 2285 default:2286 {2284 default: 2285 { 2287 2286 #if defined(SYSVVARSUB) || defined(NMAKE) 2288 /*2289 * This can either be a bogus modifier or a System-V2290 * substitution command.2291 */2292 VarPattern pattern;2293 Boolean eqFound;2294 2295 pattern.flags = 0;2296 eqFound = FALSE;2297 /*2298 * First we make a pass through the string trying2299 * to verify it is a SYSV-make-style translation:2300 * it must be: <string1>=<string2>)2301 */2302 cp = tstr;2303 cnt = 1;2304 while (*cp != '\0' && cnt) {2305 if (*cp == '=') {2306 eqFound = TRUE;2307 /* continue looking for endc */2308 }2309 else if (*cp == endc)2310 cnt--;2311 else if (*cp == startc)2312 cnt++;2313 if (cnt)2314 cp++;2315 }2287 /* 2288 * This can either be a bogus modifier or a System-V 2289 * substitution command. 2290 */ 2291 VarPattern pattern; 2292 Boolean eqFound; 2293 2294 pattern.flags = 0; 2295 eqFound = FALSE; 2296 /* 2297 * First we make a pass through the string trying 2298 * to verify it is a SYSV-make-style translation: 2299 * it must be: <string1>=<string2>) 2300 */ 2301 cp = tstr; 2302 cnt = 1; 2303 while (*cp != '\0' && cnt) { 2304 if (*cp == '=') { 2305 eqFound = TRUE; 2306 /* continue looking for endc */ 2307 } 2308 else if (*cp == endc) 2309 cnt--; 2310 else if (*cp == startc) 2311 cnt++; 2312 if (cnt) 2313 cp++; 2314 } 2316 2315 fprintf(stderr, "debug: cp=\"%s\" endc=%c eqFound=%d tstr=\"%s\"\n", cp, endc, eqFound, tstr); 2317 if (*cp == endc && eqFound) {2318 2319 /*2320 * Now we break this sucker into the lhs and2321 * rhs. We must null terminate them of course.2322 */2323 for (cp = tstr; *cp != '='; cp++)2324 continue;2325 pattern.lhs = tstr;2326 pattern.leftLen = cp - tstr;2327 *cp++ = '\0';2328 2329 pattern.rhs = cp;2330 cnt = 1;2331 while (cnt) {2332 if (*cp == endc)2333 cnt--;2334 else if (*cp == startc)2335 cnt++;2336 if (cnt)2337 cp++;2338 }2339 pattern.rightLen = cp - pattern.rhs;2340 *cp = '\0';2341 2342 /*2343 * SYSV modifications happen through the whole2344 * string. Note the pattern is anchored at the end.2345 */2346 newStr = VarModify(str, VarSYSVMatch,2347 (ClientData)&pattern);2348 2349 /*2350 * Restore the nulled characters2351 */2352 pattern.lhs[pattern.leftLen] = '=';2353 pattern.rhs[pattern.rightLen] = endc;2354 termc = endc;2355 } else2316 if (*cp == endc && eqFound) { 2317 2318 /* 2319 * Now we break this sucker into the lhs and 2320 * rhs. We must null terminate them of course. 2321 */ 2322 for (cp = tstr; *cp != '='; cp++) 2323 continue; 2324 pattern.lhs = tstr; 2325 pattern.leftLen = cp - tstr; 2326 *cp++ = '\0'; 2327 2328 pattern.rhs = cp; 2329 cnt = 1; 2330 while (cnt) { 2331 if (*cp == endc) 2332 cnt--; 2333 else if (*cp == startc) 2334 cnt++; 2335 if (cnt) 2336 cp++; 2337 } 2338 pattern.rightLen = cp - pattern.rhs; 2339 *cp = '\0'; 2340 2341 /* 2342 * SYSV modifications happen through the whole 2343 * string. Note the pattern is anchored at the end. 2344 */ 2345 newStr = VarModify(str, VarSYSVMatch, 2346 (ClientData)&pattern); 2347 2348 /* 2349 * Restore the nulled characters 2350 */ 2351 pattern.lhs[pattern.leftLen] = '='; 2352 pattern.rhs[pattern.rightLen] = endc; 2353 termc = endc; 2354 } else 2356 2355 #endif 2357 {2358 Error ("Unknown modifier '%c'\n", *tstr);2359 for (cp = tstr+1;2360 *cp != ':' && *cp != endc && *cp != '\0';2361 cp++)2362 continue;2363 termc = *cp;2364 newStr = var_Error;2365 }2366 }2367 }2368 if (DEBUG(VAR)) {2369 printf("Result is \"%s\"\n", newStr);2370 }2371 2372 if (*freePtr) {2373 efree (str);2374 }2375 str = newStr;2376 if (str != var_Error) {2377 *freePtr = TRUE;2378 } else {2379 *freePtr = FALSE;2380 }2381 if (termc == '\0') {2382 Error("Unclosed variable specification for %s", v->name);2383 } else if (termc == ':') {2384 *cp++ = termc;2385 } else {2386 *cp = termc;2387 }2388 tstr = cp;2389 }2390 *lengthPtr = tstr - start + 1;2356 { 2357 Error ("Unknown modifier '%c'\n", *tstr); 2358 for (cp = tstr+1; 2359 *cp != ':' && *cp != endc && *cp != '\0'; 2360 cp++) 2361 continue; 2362 termc = *cp; 2363 newStr = var_Error; 2364 } 2365 } 2366 } 2367 if (DEBUG(VAR)) { 2368 printf("Result is \"%s\"\n", newStr); 2369 } 2370 2371 if (*freePtr) { 2372 efree (str); 2373 } 2374 str = newStr; 2375 if (str != var_Error) { 2376 *freePtr = TRUE; 2377 } else { 2378 *freePtr = FALSE; 2379 } 2380 if (termc == '\0') { 2381 Error("Unclosed variable specification for %s", v->name); 2382 } else if (termc == ':') { 2383 *cp++ = termc; 2384 } else { 2385 *cp = termc; 2386 } 2387 tstr = cp; 2388 } 2389 *lengthPtr = tstr - start + 1; 2391 2390 } else { 2392 *lengthPtr = tstr - start + 1;2393 *tstr = endc;2391 *lengthPtr = tstr - start + 1; 2392 *tstr = endc; 2394 2393 } 2395 2394 2396 2395 if (v->flags & VAR_FROM_ENV) { 2397 Booleandestroy = FALSE;2398 2399 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) {2400 destroy = TRUE;2401 } else {2402 /*2403 * Returning the value unmodified, so tell the caller to efree2404 * the thing.2405 */2406 *freePtr = TRUE;2407 }2408 Buf_Destroy(v->val, destroy);2409 efree((Address)v);2396 Boolean destroy = FALSE; 2397 2398 if (str != (char *)Buf_GetAll(v->val, (int *)NULL)) { 2399 destroy = TRUE; 2400 } else { 2401 /* 2402 * Returning the value unmodified, so tell the caller to efree 2403 * the thing. 2404 */ 2405 *freePtr = TRUE; 2406 } 2407 Buf_Destroy(v->val, destroy); 2408 efree((Address)v); 2410 2409 } else if (v->flags & VAR_JUNK) { 2411 /*2412 * Perform any efree'ing needed and set *freePtr to FALSE so the caller2413 * doesn't try to efree a static pointer.2414 */2415 if (*freePtr) {2416 efree(str);2417 }2418 *freePtr = FALSE;2419 Buf_Destroy(v->val, TRUE);2420 efree((Address)v);2421 if (dynamic) {2422 str = emalloc(*lengthPtr + 1);2423 strncpy(str, start, *lengthPtr);2424 str[*lengthPtr] = '\0';2425 *freePtr = TRUE;2426 } else {2427 str = err ? var_Error : varNoError;2428 }2410 /* 2411 * Perform any efree'ing needed and set *freePtr to FALSE so the caller 2412 * doesn't try to efree a static pointer. 2413 */ 2414 if (*freePtr) { 2415 efree(str); 2416 } 2417 *freePtr = FALSE; 2418 Buf_Destroy(v->val, TRUE); 2419 efree((Address)v); 2420 if (dynamic) { 2421 str = emalloc(*lengthPtr + 1); 2422 strncpy(str, start, *lengthPtr); 2423 str[*lengthPtr] = '\0'; 2424 *freePtr = TRUE; 2425 } else { 2426 str = err ? var_Error : varNoError; 2427 } 2429 2428 } 2430 2429 return (str); … … 2434 2433 *----------------------------------------------------------------------- 2435 2434 * Var_Subst -- 2436 * Substitute for all variables in the given string in the given context2437 * If undefErr is TRUE, Parse_Error will be called when an undefined2438 * variable is encountered.2439 * 2440 * Results: 2441 * The resulting string.2442 * 2443 * Side Effects: 2444 * None. The old string must be freed by the caller2435 * Substitute for all variables in the given string in the given context 2436 * If undefErr is TRUE, Parse_Error will be called when an undefined 2437 * variable is encountered. 2438 * 2439 * Results: 2440 * The resulting string. 2441 * 2442 * Side Effects: 2443 * None. The old string must be freed by the caller 2445 2444 *----------------------------------------------------------------------- 2446 2445 */ 2447 2446 char * 2448 2447 Var_Subst (var, str, ctxt, undefErr) 2449 char *var;/* Named variable || NULL for all */2450 char *str;/* the string in which to substitute */2451 GNode *ctxt; /* the context wherein to find variables */2452 Boolean undefErr;/* TRUE if undefineds are an error */2453 { 2454 Buffer buf;/* Buffer for forming things */2455 char *val;/* Value to substitute for a variable */2456 int length;/* Length of the variable invocation */2457 Boolean doFree;/* Set true if val should be freed */2448 char *var; /* Named variable || NULL for all */ 2449 char *str; /* the string in which to substitute */ 2450 GNode *ctxt; /* the context wherein to find variables */ 2451 Boolean undefErr; /* TRUE if undefineds are an error */ 2452 { 2453 Buffer buf; /* Buffer for forming things */ 2454 char *val; /* Value to substitute for a variable */ 2455 int length; /* Length of the variable invocation */ 2456 Boolean doFree; /* Set true if val should be freed */ 2458 2457 static Boolean errorReported; /* Set true if an error has already 2459 * been reported to prevent a plethora2460 * of messages when recursing */2458 * been reported to prevent a plethora 2459 * of messages when recursing */ 2461 2460 2462 2461 buf = Buf_Init (MAKE_BSIZE); … … 2464 2463 2465 2464 while (*str) { 2466 if (var == NULL && (*str == '$') && (str[1] == '$')) {2467 /*2468 * A dollar sign may be escaped either with another dollar sign.2469 * In such a case, we skip over the escape character and store the2470 * dollar sign into the buffer directly.2471 */2472 str++;2473 Buf_AddByte(buf, (Byte)*str);2474 str++;2475 } else if (*str != '$') {2476 /*2477 * Skip as many characters as possible -- either to the end of2478 * the string or to the next dollar sign (variable invocation).2479 */2480 char *cp;2481 2482 for (cp = str++; *str != '$' && *str != '\0'; str++)2483 continue;2484 Buf_AddBytes(buf, str - cp, (Byte *)cp);2485 } else {2486 if (var != NULL) {2487 int expand;2488 for (;;) {2489 if (str[1] != '(' && str[1] != '{') {2490 if (str[1] != *var) {2491 Buf_AddBytes(buf, 2, (Byte *) str);2492 str += 2;2493 expand = FALSE;2494 }2495 else2496 expand = TRUE;2497 break;2498 }2499 else {2500 char *p;2501 2502 /*2503 * Scan up to the end of the variable name.2504 */2505 for (p = &str[2]; *p &&2506 *p != ':' && *p != ')' && *p != '}'; p++)2507 if (*p == '$')2508 break;2509 /*2510 * A variable inside the variable. We cannot expand2511 * the external variable yet, so we try again with2512 * the nested one2513 */2514 if (*p == '$') {2515 Buf_AddBytes(buf, p - str, (Byte *) str);2516 str = p;2517 continue;2518 }2519 2520 if (strncmp(var, str + 2, p - str - 2) != 0 ||2521 var[p - str - 2] != '\0') {2522 /*2523 * Not the variable we want to expand, scan2524 * until the next variable2525 */2526 for (;*p != '$' && *p != '\0'; p++)2527 continue;2528 Buf_AddBytes(buf, p - str, (Byte *) str);2529 str = p;2530 expand = FALSE;2531 }2532 else2533 expand = TRUE;2534 break;2535 }2536 }2537 if (!expand)2538 continue;2539 }2540 2541 val = Var_Parse (str, ctxt, undefErr, &length, &doFree);2542 2543 /*2544 * When we come down here, val should either point to the2545 * value of this variable, suitably modified, or be NULL.2546 * Length should be the total length of the potential2547 * variable invocation (from $ to end character...)2548 */2549 if (val == var_Error || val == varNoError) {2550 /*2551 * If performing old-time variable substitution, skip over2552 * the variable and continue with the substitution. Otherwise,2553 * store the dollar sign and advance str so we continue with2554 * the string...2555 */2556 if (oldVars) {2557 str += length;2558 } else if (undefErr) {2559 /*2560 * If variable is undefined, complain and skip the2561 * variable. The complaint will stop us from doing anything2562 * when the file is parsed.2563 */2564 if (!errorReported) {2565 Parse_Error (PARSE_FATAL,2566 "Undefined variable \"%.*s\"",length,str);2567 }2568 str += length;2569 errorReported = TRUE;2570 } else {2571 Buf_AddByte (buf, (Byte)*str);2572 str += 1;2573 }2574 } else {2575 /*2576 * We've now got a variable structure to store in. But first,2577 * advance the string pointer.2578 */2579 str += length;2580 2581 /*2582 * Copy all the characters from the variable value straight2583 * into the new string.2584 */2585 Buf_AddBytes (buf, strlen (val), (Byte *)val);2586 if (doFree) {2587 efree ((Address)val);2588 }2589 }2590 }2465 if (var == NULL && (*str == '$') && (str[1] == '$')) { 2466 /* 2467 * A dollar sign may be escaped either with another dollar sign. 2468 * In such a case, we skip over the escape character and store the 2469 * dollar sign into the buffer directly. 2470 */ 2471 str++; 2472 Buf_AddByte(buf, (Byte)*str); 2473 str++; 2474 } else if (*str != '$') { 2475 /* 2476 * Skip as many characters as possible -- either to the end of 2477 * the string or to the next dollar sign (variable invocation). 2478 */ 2479 char *cp; 2480 2481 for (cp = str++; *str != '$' && *str != '\0'; str++) 2482 continue; 2483 Buf_AddBytes(buf, str - cp, (Byte *)cp); 2484 } else { 2485 if (var != NULL) { 2486 int expand; 2487 for (;;) { 2488 if (str[1] != '(' && str[1] != '{') { 2489 if (str[1] != *var) { 2490 Buf_AddBytes(buf, 2, (Byte *) str); 2491 str += 2; 2492 expand = FALSE; 2493 } 2494 else 2495 expand = TRUE; 2496 break; 2497 } 2498 else { 2499 char *p; 2500 2501 /* 2502 * Scan up to the end of the variable name. 2503 */ 2504 for (p = &str[2]; *p && 2505 *p != ':' && *p != ')' && *p != '}'; p++) 2506 if (*p == '$') 2507 break; 2508 /* 2509 * A variable inside the variable. We cannot expand 2510 * the external variable yet, so we try again with 2511 * the nested one 2512 */ 2513 if (*p == '$') { 2514 Buf_AddBytes(buf, p - str, (Byte *) str); 2515 str = p; 2516 continue; 2517 } 2518 2519 if (strncmp(var, str + 2, p - str - 2) != 0 || 2520 var[p - str - 2] != '\0') { 2521 /* 2522 * Not the variable we want to expand, scan 2523 * until the next variable 2524 */ 2525 for (;*p != '$' && *p != '\0'; p++) 2526 continue; 2527 Buf_AddBytes(buf, p - str, (Byte *) str); 2528 str = p; 2529 expand = FALSE; 2530 } 2531 else 2532 expand = TRUE; 2533 break; 2534 } 2535 } 2536 if (!expand) 2537 continue; 2538 } 2539 2540 val = Var_Parse (str, ctxt, undefErr, &length, &doFree); 2541 2542 /* 2543 * When we come down here, val should either point to the 2544 * value of this variable, suitably modified, or be NULL. 2545 * Length should be the total length of the potential 2546 * variable invocation (from $ to end character...) 2547 */ 2548 if (val == var_Error || val == varNoError) { 2549 /* 2550 * If performing old-time variable substitution, skip over 2551 * the variable and continue with the substitution. Otherwise, 2552 * store the dollar sign and advance str so we continue with 2553 * the string... 2554 */ 2555 if (oldVars) { 2556 str += length; 2557 } else if (undefErr) { 2558 /* 2559 * If variable is undefined, complain and skip the 2560 * variable. The complaint will stop us from doing anything 2561 * when the file is parsed. 2562 */ 2563 if (!errorReported) { 2564 Parse_Error (PARSE_FATAL, 2565 "Undefined variable \"%.*s\"",length,str); 2566 } 2567 str += length; 2568 errorReported = TRUE; 2569 } else { 2570 Buf_AddByte (buf, (Byte)*str); 2571 str += 1; 2572 } 2573 } else { 2574 /* 2575 * We've now got a variable structure to store in. But first, 2576 * advance the string pointer. 2577 */ 2578 str += length; 2579 2580 /* 2581 * Copy all the characters from the variable value straight 2582 * into the new string. 2583 */ 2584 Buf_AddBytes (buf, strlen (val), (Byte *)val); 2585 if (doFree) { 2586 efree ((Address)val); 2587 } 2588 } 2589 } 2591 2590 } 2592 2591 … … 2600 2599 *----------------------------------------------------------------------- 2601 2600 * Var_GetTail -- 2602 * Return the tail from each of a list of words. Used to set the2603 * System V local variables.2604 * 2605 * Results: 2606 * The resulting string.2607 * 2608 * Side Effects: 2609 * None.2601 * Return the tail from each of a list of words. Used to set the 2602 * System V local variables. 2603 * 2604 * Results: 2605 * The resulting string. 2606 * 2607 * Side Effects: 2608 * None. 2610 2609 * 2611 2610 *----------------------------------------------------------------------- … … 2613 2612 char * 2614 2613 Var_GetTail(file) 2615 char *file;/* Filename to modify */2614 char *file; /* Filename to modify */ 2616 2615 { 2617 2616 return(VarModify(file, VarTail, (ClientData)0)); … … 2621 2620 *----------------------------------------------------------------------- 2622 2621 * Var_GetHead -- 2623 * Find the leading components of a (list of) filename(s).2624 * XXX: VarHead does not replace foo by ., as (sun) System V make2625 * does.2626 * 2627 * Results: 2628 * The leading components.2629 * 2630 * Side Effects: 2631 * None.2622 * Find the leading components of a (list of) filename(s). 2623 * XXX: VarHead does not replace foo by ., as (sun) System V make 2624 * does. 2625 * 2626 * Results: 2627 * The leading components. 2628 * 2629 * Side Effects: 2630 * None. 2632 2631 * 2633 2632 *----------------------------------------------------------------------- … … 2635 2634 char * 2636 2635 Var_GetHead(file) 2637 char *file;/* Filename to manipulate */2636 char *file; /* Filename to manipulate */ 2638 2637 { 2639 2638 return(VarModify(file, VarHead, (ClientData)0)); … … 2643 2642 *----------------------------------------------------------------------- 2644 2643 * Var_Init -- 2645 * Initialize the module2646 * 2647 * Results: 2648 * None2649 * 2650 * Side Effects: 2651 * The VAR_CMD and VAR_GLOBAL contexts are created2644 * Initialize the module 2645 * 2646 * Results: 2647 * None 2648 * 2649 * Side Effects: 2650 * The VAR_CMD and VAR_GLOBAL contexts are created 2652 2651 *----------------------------------------------------------------------- 2653 2652 */ … … 2683 2682 *----------------------------------------------------------------------- 2684 2683 * Var_Dump -- 2685 * print all variables in a context2684 * print all variables in a context 2686 2685 *----------------------------------------------------------------------- 2687 2686 */ -
trunk/src/makefile.os2.icc.mk
r48 r51 33 33 POSTFIX = .prf 34 34 !endif 35 OBJDIR = ..\obj\os2-icc-kmk .$(POSTFIX)35 OBJDIR = ..\obj\os2-icc-kmk$(POSTFIX) 36 36 37 37 # paths … … 40 40 41 41 # compiler setup 42 CC = icc.exe 42 43 !ifdef DEBUG 43 44 CFLAGS_1 = /O- -DDEBUG … … 46 47 CFLAGS_1 = /O+ /Gh 47 48 !endif 48 CFLAGS = /Q /Ti+ /Gm /Ge /Gl -DOS2 -D__i386__ -DKMK -I$(PATH_KLIB)\Generic\include -I$(PATH_TOOLKIT)\h -I$(PATH_VAC308)\include $(CFLAGS_1) 49 CFLAGS_KMK = /IkMk\include $(CFLAGS) 49 CFLAGS = /Q /Ti+ /Gm /Ge /Gl /W3 -DOS2 -D__i386__ -DKMK \ 50 -I$(PATH_KLIB)\Generic\include \ 51 -I$(PATH_KLIB)\Generic\include\kLibCRT \ 52 -I$(PATH_TOOLKIT)\h \ 53 -I$(PATH_VAC308)\include \ 54 $(CFLAGS_1) 55 CFLAGS_KMK = -IkMk\include -IkMk -DUSE_KLIB $(CFLAGS) -UDEBUG -DMACHINE=\"ibmos2\" -DMACHINE_ARCH=\"x86\" -DMACHINE_CPU=\"386\" \ 50 56 51 57 # linker setup 58 LD = ilink.exe 59 STRIP = 52 60 !ifdef DEBUG 53 61 LDFLAGS_1 = /NOEXEPACK … … 57 65 !endif 58 66 !ifndef LDFLAGS_1 #releas 59 LDFLAGS_1 = /EXEPACK:2 /Packcode /Packdata 67 LDFLAGS_1 = /Packcode /Packdata 68 STRIP = lxlite.exe 60 69 !endif 61 70 LDFLAGS = /NoLogo /NoExtDictionary /Optfunc /Base:0x10000 /Map /Linenumbers /Debug /PmType:vio $(LDFLAGS_1) … … 73 82 74 83 {.\kMk\lst.lib}.c{$(OBJDIR)}.obj: 75 $(CC) -c $(CFLAGS_KMK) -Fo$(OBJDIR)\$(@F) $(MAKEDIR)\kMk\lst.lib $(<F)84 $(CC) -c $(CFLAGS_KMK) -Fo$(OBJDIR)\$(@F) $(MAKEDIR)\kMk\lst.lib\$(<F) 76 85 77 86 … … 143 152 !endif 144 153 !endif 145 $(PATH_TOOLKIT)\ os2386.lib \146 $( VAC308_TOOLKIT)\cppom30.lib \147 148 149 # the rules 154 $(PATH_TOOLKIT)\lib\os2386.lib \ 155 $(PATH_VAC308)\lib\cppom30.lib \ 156 157 158 # the rules 150 159 all: $(OBJDIR) $(OBJDIR)\kMk.exe 151 160 152 161 153 162 $(OBJDIR): 154 - mkdir ..\obj155 - mkdir $(OBJDIR)163 -if not exist ..\obj mkdir ..\obj 164 -if not exist $(OBJDIR) mkdir $(OBJDIR) 156 165 157 166 $(OBJDIR)\kMk.exe: $(OBJS) … … 162 171 $(LIBS) 163 172 <<KEEP 173 !if "$(STRIP)" != "" 174 copy $(OBJDIR)\kMk.exe $(OBJDIR)\kMk.dbg 175 $(STRIP) $(OBJDIR)\kMk.exe 176 !endif 164 177 178 179 clean: 180 !if "$(OBJDIR)" != "" && "$(OBJDIR)" != "\" 181 !if "$(COMSPEC:CMD.EXE=sure)" != "$(COMSPEC)" 182 -del /N $(OBJDIR)\* 183 !else # assume 4os2 184 -del /Y /E $(OBJDIR)\* 185 !endif 186 !endif
Note:
See TracChangeset
for help on using the changeset viewer.

