Changeset 51 in kBuild
- Timestamp:
- Apr 7, 2003 1:30:32 AM (22 years ago)
- Location:
- trunk/src
- Files:
-
- 21 edited
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 * 21 * 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 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 * 51 * Functions for automatically-expanded buffers. 51 52 */ 52 53 … … 61 62 /* 62 63 * BufExpand -- 63 * 64 * 65 * 66 * 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 70 71 72 73 74 75 76 77 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 * 88 * 89 * Results: 90 * 91 * 92 * Side Effects: 93 * 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 * 120 * 121 * Results: 122 * 123 * 124 * Side Effects: 125 * 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 133 int numBytes; 133 134 const Byte *bytesPtr; 134 135 { … … 150 151 *----------------------------------------------------------------------- 151 152 * Buf_UngetByte -- 152 * 153 * 154 * Results: 155 * 156 * 157 * Side Effects: 158 * 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 170 170 bp->outPtr--; 171 *bp->outPtr = byte; 171 172 } else if (bp->outPtr == bp->inPtr) { 172 173 174 175 173 *bp->inPtr = byte; 174 bp->inPtr++; 175 bp->left--; 176 *bp->inPtr = 0; 176 177 } else { 177 178 179 180 181 182 183 intnumBytes = bp->inPtr - bp->outPtr;184 Byte*newBuf;185 186 187 188 189 190 191 192 193 194 195 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 * 204 * 205 * Results: 206 * 207 * 208 * Side Effects: 209 * 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 217 int numBytes; 217 218 Byte *bytesPtr; 218 219 { 219 220 220 221 if (bp->outPtr - bp->buffer >= numBytes) { 221 222 222 bp->outPtr -= numBytes; 223 memcpy (bp->outPtr, bytesPtr, numBytes); 223 224 } else if (bp->outPtr == bp->inPtr) { 224 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 231 232 233 234 235 236 237 238 239 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 * 248 * 249 * Results: 250 * 251 * 252 * 253 * Side Effects: 254 * 255 * 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 264 int res; 264 265 265 266 if (bp->inPtr == bp->outPtr) { 266 267 return (BUF_ERROR); 267 268 } else { 268 269 270 271 272 273 274 275 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 * 284 * 285 * Results: 286 * 287 * 288 * Side Effects: 289 * 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 297 int numBytes; 297 298 Byte *bytesPtr; 298 299 { 299 300 300 301 if (bp->inPtr - bp->outPtr < numBytes) { 301 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 308 309 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 * 319 * 320 * Results: 321 * 322 * 323 * Side Effects: 324 * 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 332 int *numBytesPtr; 332 333 { 333 334 334 335 if (numBytesPtr != (int *)NULL) { 335 336 *numBytesPtr = bp->inPtr - bp->outPtr; 336 337 } 337 338 … … 343 344 *----------------------------------------------------------------------- 344 345 * Buf_Discard -- 345 * 346 * 347 * Results: 348 * 349 * 350 * Side Effects: 351 * 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 359 int numBytes; 359 360 { 360 361 361 362 if (bp->inPtr - bp->outPtr <= numBytes) { 362 363 364 363 bp->inPtr = bp->outPtr = bp->buffer; 364 bp->left = bp->size; 365 *bp->inPtr = 0; 365 366 } else { 366 367 bp->outPtr += numBytes; 367 368 } 368 369 } … … 372 373 *----------------------------------------------------------------------- 373 374 * Buf_Size -- 374 * 375 * 376 * 377 * Results: 378 * 379 * 380 * Side Effects: 381 * 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 * 397 * 398 * 399 * Results: 400 * 401 * 402 * Side Effects: 403 * 404 * 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; 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 418 size = BUF_DEF_SIZE; 418 419 } 419 420 bp->left = bp->size = size; … … 429 430 *----------------------------------------------------------------------- 430 431 * Buf_Destroy -- 431 * 432 * 433 * Results: 434 * 435 * 436 * Side Effects: 437 * 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; 444 Boolean freeData; 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 449 efree ((char *)buf->buffer); 449 450 } 450 451 efree ((char *)buf); … … 468 469 void 469 470 Buf_ReplaceLastByte (buf, byte) 470 Buffer buf; 471 int byte; 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 * 21 * 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 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 * 51 * 52 * 53 * 54 * 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 * 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 90 91 static GNode 92 static GNode 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 99 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 * 105 * 105 * Interrupt the creation of the current target and remove it if 106 * it ain't precious. 106 107 * 107 108 * Results: 108 * 109 * None. 109 110 * 110 111 * Side Effects: 111 * 112 * 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 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 127 128 129 130 131 132 133 134 135 136 137 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 145 exit(signo); 145 146 #endif 146 147 (void) signal(signo, SIG_DFL); … … 152 153 *----------------------------------------------------------------------- 153 154 * shellneed -- 154 * 155 * 155 156 * Results: 156 * 157 * 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 * 161 * 161 * None. 162 * 162 163 *----------------------------------------------------------------------- 163 164 */ 164 165 static int 165 166 shellneed (cmd) 166 167 char *cmd; 167 168 { 168 169 170 171 172 173 174 175 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 * 183 * 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 * 187 * 0 if the command succeeded, 1 if an error occurred. 187 188 * 188 189 * Side Effects: 189 * 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; 196 ClientData gnp; 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; 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 210 Boolean local;/* TRUE if command should be executed211 212 int internal;/* Various values.. */213 char 214 GNode 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 239 240 239 efree(cmdStart); 240 Error("%s expands to empty string", cmd); 241 return(0); 241 242 } else { 242 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 248 248 (void)Lst_AtEnd(ENDNode->commands, (ClientData)cmdStart); 249 return(0); 249 250 } else if (strcmp(cmdStart, "...") == 0) { 250 251 251 gn->type |= OP_SAVE_CMDS; 252 return(0); 252 253 } 253 254 254 255 while ((*cmd == '@') || (*cmd == '-')) { 255 256 257 258 259 260 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 265 cmd++; 265 266 266 267 /* … … 270 271 */ 271 272 for (cp = cmd; !meta[(unsigned char)*cp]; cp++) { 272 273 continue; 273 274 } 274 275 … … 278 279 */ 279 280 if (!silent || noExecute) { 280 281 281 printf ("%s\n", cmd); 282 fflush(stdout); 282 283 } 283 284 … … 287 288 */ 288 289 if (noExecute) { 289 290 return (0); 290 291 } 291 292 292 293 if (*cp != '\0') { 293 294 295 296 297 298 299 static char*shargv[4] = { "/bin/sh" };300 301 302 303 304 305 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 309 310 311 static char*shargv[4] = { "/bin/sh" };312 313 314 315 316 317 318 319 320 321 322 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 326 327 328 329 330 331 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 345 Fatal("Could not fork"); 345 346 } 346 347 if (cpid == 0) { 347 348 349 350 351 352 353 354 355 356 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 368 368 efree(cmdStart); 369 Lst_Replace (cmdNode, cmdp); 369 370 } 370 371 … … 374 375 while (1) { 375 376 376 377 378 379 380 381 382 383 384 status = WSTOPSIG(reason);/* stopped */385 386 status = WEXITSTATUS(reason);/* exited */387 388 389 390 391 status = WTERMSIG(reason);/* signaled */392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 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 * 430 * Make a target. 430 431 * 431 432 * Results: 432 * 433 * 0 433 434 * 434 435 * Side Effects: 435 * 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; 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 448 Make_HandleUse(gn, pgn); 448 449 } else if (gn->made == UNMADE) { 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 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 545 546 547 548 549 550 551 *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 557 558 559 560 561 562 563 564 565 566 567 568 569 570 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 575 576 577 *cmp -s y.tab.h parse.h || cp y.tab.h parse.h578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 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 601 602 603 604 605 606 607 608 609 610 611 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 616 617 618 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 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 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 * 655 * Initialize this mode and start making. 655 656 * 656 657 * Results: 657 * 658 * None. 658 659 * 659 660 * Side Effects: 660 * 661 * Guess what? 661 662 * 662 663 *----------------------------------------------------------------------- … … 664 665 void 665 666 Compat_Run(targs) 666 Lst 667 Lst targs; /* List of target nodes to re-create */ 667 668 { 668 char *cp;/* Pointer to string of shell meta-characters */669 GNode 670 int 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 674 signal(SIGINT, CompatInterrupt); 674 675 } 675 676 if (signal(SIGTERM, SIG_IGN) != SIG_IGN) { 676 677 signal(SIGTERM, CompatInterrupt); 677 678 } 678 679 #if !(defined(OS2) && defined(__IBMC__)) 679 680 if (signal(SIGHUP, SIG_IGN) != SIG_IGN) { 680 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 686 signal(SIGQUIT, CompatInterrupt); 686 687 } 687 688 #endif 688 689 689 690 for (cp = "#=|^(){};&<>*?[]:$`\\\n"; *cp != '\0'; cp++) { 690 691 meta[(unsigned char) *cp] = 1; 691 692 } 692 693 /* … … 701 702 */ 702 703 if (!queryFlag) { 703 704 705 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 * 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 726 727 728 729 730 731 732 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 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 * 21 * 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 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 * 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 * 67 * 68 * 69 * 70 * 71 * 72 * 73 * 74 * 75 * 76 * 77 * 78 * 79 * 80 * 81 * 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 118 Boolean doNot;/* TRUE if default function should be negated */119 Boolean 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 132 static char *condExpr;/* The expression to parse */133 static Token condPushBack=None;/* Single push-back token used in134 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 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 * 148 * 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 * 152 * None. 152 153 * 153 154 * Side Effects: 154 * 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 * 170 * Find the argument of a built-in function. 170 171 * 171 172 * Results: 172 * 173 * The length of the argument and the address of the argument. 173 174 * 174 175 * Side Effects: 175 * 176 * 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 183 char 184 char 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 189 int argLen; 189 190 register Buffer buf; 190 191 191 192 cp = *linePtr; 192 193 if (parens) { 193 194 195 196 197 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 204 205 206 207 208 209 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 214 cp++; 214 215 } 215 216 … … 221 222 222 223 while ((strchr(" \t)&|", *cp) == (char *)NULL) && (*cp != '\0')) { 223 224 225 226 227 228 229 230 char*cp2;231 intlen;232 BooleandoFree;233 234 235 236 237 238 239 240 241 242 243 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 253 cp++; 253 254 } 254 255 if (parens && *cp != ')') { 255 256 257 256 Parse_Error (PARSE_WARNING, "Missing closing parenthesis for %s()", 257 func); 258 return (0); 258 259 } else if (parens) { 259 260 261 262 260 /* 261 * Advance pointer past close parenthesis. 262 */ 263 cp++; 263 264 } 264 265 … … 271 272 *----------------------------------------------------------------------- 272 273 * CondDoDefined -- 273 * 274 * Handle the 'defined' function for conditionals. 274 275 * 275 276 * Results: 276 * 277 * TRUE if the given variable is defined. 277 278 * 278 279 * Side Effects: 279 * 280 * None. 280 281 * 281 282 *----------------------------------------------------------------------- … … 283 284 static Boolean 284 285 CondDoDefined (argLen, arg) 285 int 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 295 result = TRUE; 295 296 } else { 296 297 result = FALSE; 297 298 } 298 299 efree(p1); … … 305 306 *----------------------------------------------------------------------- 306 307 * CondStrMatch -- 307 * 308 * 308 * 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 * 312 * 0 if string matches pattern 312 313 * 313 314 * Side Effects: 314 * 315 * None 315 316 * 316 317 *----------------------------------------------------------------------- … … 328 329 *----------------------------------------------------------------------- 329 330 * CondDoMake -- 330 * 331 * Handle the 'make' function for conditionals. 331 332 * 332 333 * Results: 333 * 334 * TRUE if the given target is being made. 334 335 * 335 336 * Side Effects: 336 * 337 * None. 337 338 * 338 339 *----------------------------------------------------------------------- … … 340 341 static Boolean 341 342 CondDoMake (argLen, arg) 342 int 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 351 result = FALSE; 351 352 } else { 352 353 result = TRUE; 353 354 } 354 355 arg[argLen] = savec; … … 360 361 *----------------------------------------------------------------------- 361 362 * CondDoExists -- 362 * 363 * See if the given file exists. 363 364 * 364 365 * Results: 365 * 366 * TRUE if the file exists and FALSE if it does not. 366 367 * 367 368 * Side Effects: 368 * 369 * None. 369 370 * 370 371 *----------------------------------------------------------------------- … … 372 373 static Boolean 373 374 CondDoExists (argLen, arg) 374 int 375 int argLen; 375 376 char *arg; 376 377 { … … 382 383 path = Dir_FindFile(arg, dirSearchPath); 383 384 if (path != (char *)NULL) { 384 385 385 result = TRUE; 386 efree(path); 386 387 } else { 387 388 result = FALSE; 388 389 } 389 390 arg[argLen] = savec; … … 395 396 *----------------------------------------------------------------------- 396 397 * CondDoTarget -- 397 * 398 * See if the given node exists and is an actual target. 398 399 * 399 400 * Results: 400 * 401 * TRUE if the node exists as a target and FALSE if it does not. 401 402 * 402 403 * Side Effects: 403 * 404 * None. 404 405 * 405 406 *----------------------------------------------------------------------- … … 407 408 static Boolean 408 409 CondDoTarget (argLen, arg) 409 int 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 420 result = TRUE; 420 421 } else { 421 422 result = FALSE; 422 423 } 423 424 arg[argLen] = savec; … … 430 431 *----------------------------------------------------------------------- 431 432 * CondCvtArg -- 432 * 433 * 434 * 435 * 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 * 439 * 440 * 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 * 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 451 double 451 register char *str; 452 double *value; 452 453 { 453 454 if ((*str == '0') && (str[1] == 'x')) { 454 455 456 457 458 459 460 461 462 463 464 465 466 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 471 472 471 char *eptr; 472 *value = strtod(str, &eptr); 473 return eptr; 473 474 } 474 475 } … … 478 479 *----------------------------------------------------------------------- 479 480 * CondToken -- 480 * 481 * Return the next token from the input. 481 482 * 482 483 * Results: 483 * 484 * A Token for the next lexical token in the stream. 484 485 * 485 486 * Side Effects: 486 * 487 * condPushback will be set back to None if it is used. 487 488 * 488 489 *----------------------------------------------------------------------- … … 492 493 Boolean doEval; 493 494 { 494 Token 495 Token t; 495 496 496 497 if (condPushBack == None) { 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 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 536 Parse_Error(PARSE_WARNING, "Unsupported NMAKE construct ([])"); 536 537 t = False; 537 538 condExpr += strlen(condExpr); … … 543 544 case '"': 544 545 #endif 545 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 559 560 561 562 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 571 572 573 574 575 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 579 condExpr += varSpecLen; 579 580 580 581 #ifdef NMAKE … … 583 584 ) 584 585 #else 585 586 586 if (!isspace((unsigned char) *condExpr) && 587 strchr("!=><", *condExpr) == NULL) 587 588 #endif 588 589 { 589 590 591 592 593 594 595 596 597 598 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 603 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 608 608 for (;*condExpr && !isspace((unsigned char) *condExpr); condExpr++) 609 Buf_AddByte(buf, (Byte)*condExpr); 609 610 #endif 610 611 611 612 613 614 615 616 617 618 619 620 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 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 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 662 663 664 665 666 667 668 intqt;669 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 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 intlen;694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 doubleleft, right;742 char*string;743 744 745 746 747 intlen;748 BooleanfreeIt;749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 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 818 819 820 821 822 823 824 char*arg;825 intarglen;826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 intlength;872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 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 951 951 t = condPushBack; 952 condPushBack = None; 952 953 } 953 954 return (t); … … 958 959 *----------------------------------------------------------------------- 959 960 * CondT -- 960 * 961 * 962 * 963 * 964 * 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 * 968 * True, False or Err. 968 969 * 969 970 * Side Effects: 970 * 971 * Tokens are consumed. 971 972 * 972 973 *----------------------------------------------------------------------- … … 981 982 982 983 if (t == EndOfFile) { 983 984 985 986 987 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 991 992 993 994 995 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 1000 1001 1002 1003 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 * 1014 * 1014 * Parse a conjunctive factor (nice name, wot?) 1015 * F -> T && F | T 1015 1016 * 1016 1017 * Results: 1017 * 1018 * True, False or Err 1018 1019 * 1019 1020 * Side Effects: 1020 * 1021 * Tokens are consumed. 1021 1022 * 1022 1023 *----------------------------------------------------------------------- … … 1030 1031 l = CondT(doEval); 1031 1032 if (l != Err) { 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 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 * 1062 * 1062 * Main expression production. 1063 * E -> F || E | F 1063 1064 * 1064 1065 * Results: 1065 * 1066 * True, False or Err. 1066 1067 * 1067 1068 * Side Effects: 1068 * 1069 * Tokens are, of course, consumed. 1069 1070 * 1070 1071 *----------------------------------------------------------------------- … … 1078 1079 l = CondF(doEval); 1079 1080 if (l != Err) { 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 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 * 1111 * 1112 * 1113 * 1114 * 1115 * 1116 * 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 * 1125 * None. 1125 1126 * 1126 1127 *----------------------------------------------------------------------- … … 1128 1129 int 1129 1130 Cond_Eval (line) 1130 char 1131 char *line; /* Line to parse */ 1131 1132 { 1132 struct If 1133 Boolean 1134 Boolean 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 1141 continue; 1141 1142 } 1142 1143 … … 1146 1147 */ 1147 1148 if (line[0] == 'e' && line[1] == 'l') { 1148 1149 1149 line += 2; 1150 isElse = TRUE; 1150 1151 } else if (strncmp (line, "endif", 5) == 0) { 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 1169 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 1174 isElse = FALSE; 1174 1175 } 1175 1176 … … 1179 1180 */ 1180 1181 for (ifp = ifs; ifp->form != (char *)0; ifp++) { 1181 1182 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 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 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 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 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 1270 condTop -= 1; 1270 1271 } else if ((skipIfLevel != 0) || condStack[condTop]) { 1271 1272 1273 1274 1275 1276 1277 1278 1279 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 1285 1286 1287 1288 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 1291 1292 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 * 1301 * Make sure everything's clean at the end of a makefile. 1301 1302 * 1302 1303 * Results: 1303 * 1304 * None. 1304 1305 * 1305 1306 * Side Effects: 1306 * 1307 * Parse_Error will be called if open conditionals are around. 1307 1308 * 1308 1309 *----------------------------------------------------------------------- … … 1312 1313 { 1313 1314 if (condTop != MAXIF) { 1314 1315 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 * 21 * 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 * 48 * 49 * 50 * 51 * 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 54 #define DEFMAXLOCAL 53 #define DEFMAXJOBS 4 54 #define DEFMAXLOCAL 1 55 55 56 56 /* 57 57 * INCLUDES 58 58 * LIBRARIES 59 * 60 * 61 * 62 * 63 * 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 * 71 * 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 * 75 * 76 * 77 * 78 * 79 * 80 * 81 * 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 83 #define LIBSUFF ".a" 84 #define RECHECK 85 85 86 86 /* 87 87 * POSIX 88 * 89 * 90 * 91 * 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 * 97 * Recognize system V like include directives [include "filename"] 98 98 * SYSVVARSUB 99 * 99 * Recognize system V like ${VAR:x=y} variable substitutions 100 100 */ 101 101 #define SYSVINCLUDE … … 104 104 /* 105 105 * SUNSHCMD 106 * 107 * VAR :sh= CMD# Assign VAR to the command substitution of CMD108 * ${VAR:sh}# Return the command substitution of the value109 * 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 * 21 * 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 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 * 51 * 52 * 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 * 60 * 61 * 62 * Dir_ExpandGiven a pattern and a path, return a Lst of names63 * 64 * 65 * Dir_FindFileSearches for a file on a given search path.66 * 67 * 68 * 69 * Dir_MTimeReturn the modification time of a node. The file70 * 71 * 72 * 73 * 74 * Dir_AddDirAdd a directory to a search path.75 * 76 * Dir_MakeFlagsGiven a search path and a command flag, create77 * 78 * 79 * 80 * 81 * Dir_DestroyDestroy an element of a search path. Frees up all82 * 83 * 84 * 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 * 101 * 102 * 103 * 104 * 105 * 106 * 107 * 108 * 109 * 110 * 111 * 112 * 113 * 114 * 115 * 116 * 117 * 118 * 119 * 120 * 121 * 122 * 123 * 124 * 125 * 126 * 127 * 128 * 129 * 130 * 131 * 132 * 133 * 134 * 135 * 136 * 137 * 138 * 139 * 140 * 141 * 142 * 143 * 144 * 145 * 146 * 147 * 148 * 149 * 150 * 151 * 152 * 153 * 154 * 155 * 156 * 157 * 158 * 159 * 160 * 161 * 162 * 163 * 164 * 165 * 166 * 167 */ 168 169 Lst dirSearchPath; 170 171 static Lst openDirectories; 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, 178 misses,/* Sad, but not evil misses */179 180 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 185 186 187 188 189 190 191 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 * 205 * 206 * Results: 207 * 208 * 209 * Side Effects: 210 * 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 230 err(1, "cannot open current directory"); 230 231 231 232 /* … … 239 240 *----------------------------------------------------------------------- 240 241 * Dir_End -- 241 * 242 * 243 * Results: 244 * 245 * 246 * Side Effects: 247 * 242 * 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 * 266 * 267 * 268 * 269 * Results: 270 * 271 * 272 * Side Effects: 273 * 266 * 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; 279 ClientData 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 * 288 * 289 * Results: 290 * 291 * 292 * Side Effects: 293 * 288 * 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; 299 char *name; /* name to check */ 299 300 { 300 301 register char *cp; 301 302 302 303 for (cp = name; *cp; cp++) { 303 304 305 306 307 308 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 * 318 * 319 * 320 * 321 * 322 * 323 * Results: 324 * 325 * 326 * Side Effects: 327 * 328 * 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 345 345 entry != (Hash_Entry *)NULL; 346 entry = Hash_EnumNext(&search)) 346 347 { 347 348 349 350 351 352 353 354 355 356 357 358 359 360 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 * 370 * 371 * 372 * 373 * 374 * Results: 375 * 376 * 377 * Side Effects: 378 * 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 394 395 char *file;/* Current expansion */396 int otherLen;/* The length of the other pieces of the397 398 399 char *cp2;/* Pointer for checking for wildcards in400 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 410 411 412 413 410 if (*end == '{') { 411 bracelevel++; 412 } else if ((*end == '}') && (bracelevel-- == 0)) { 413 break; 414 } 414 415 } 415 416 if (*end == '\0') { 416 417 417 Error("Unterminated {} clause \"%s\"", start); 418 return; 418 419 } else { 419 420 end++; 420 421 } 421 422 otherLen = brace - word + strlen(end); 422 423 423 424 for (cp = start; cp < end; cp++) { 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 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 * 482 * 483 * 484 * 485 * Results: 486 * 487 * 488 * Side Effects: 489 * 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 504 505 506 507 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 * 515 * 516 * 517 * Results: 518 * 519 * 520 * Side Effects: 521 * 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 * 539 * 540 * 541 * Results: 542 * 543 * 544 * 545 * Side Effects: 546 * 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; 553 554 Lst expansions;/* the list on which to place the results */555 { 556 char 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 560 printf("expanding \"%s\"...", word); 560 561 } 561 562 562 563 cp = strchr(word, '{'); 563 564 if (cp) { 564 565 DirExpandCurly(word, cp, path, expansions); 565 566 } else { 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 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 644 644 Lst_ForEach(expansions, DirPrintWord, (ClientData) 0); 645 fputc('\n', stdout); 645 646 } 646 647 } … … 649 650 *----------------------------------------------------------------------- 650 651 * Dir_FindFile -- 651 * 652 * 653 * Results: 654 * 655 * 656 * 657 * Side Effects: 658 * 659 * 660 * 661 * 662 * 663 * 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 669 Lst path; 670 { 671 register char *p1; 672 register char *p2; 673 LstNode ln; 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; 676 register char *cp; 677 Boolean 678 struct stat stb;/* Buffer for stat, if necessary */679 Hash_Entry 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 694 694 hasSlash = TRUE; 695 cp += 1; 695 696 } else { 696 697 697 hasSlash = FALSE; 698 cp = name; 698 699 } 699 700 700 701 if (DEBUG(DIR)) { 701 702 printf("Searching for %s...", name); 702 703 } 703 704 /* … … 708 709 */ 709 710 if ((!hasSlash || (cp - name == 2 && *name == '.')) && 710 711 712 713 714 715 716 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 721 722 723 724 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 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 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 806 807 808 809 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 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 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 918 return ((char *) NULL); 918 919 } else { 919 920 p = (Path *) Lst_Datum (ln); 920 921 } 921 922 922 923 if (Hash_FindEntry (&p->files, cp) != (Hash_Entry *)NULL) { 923 924 return (estrdup (name)); 924 925 } else { 925 926 return ((char *) NULL); 926 927 } 927 928 #else /* !notdef */ 928 929 if (DEBUG(DIR)) { 929 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 936 937 938 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 941 942 943 944 945 946 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 949 950 951 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 * 960 * 961 * 962 * Results: 963 * 964 * 965 * Side Effects: 966 * 967 * 968 * 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; 974 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 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 983 return Arch_MTime (gn); 983 984 } else 984 985 #endif 985 986 if (gn->path == (char *)NULL) { 986 987 fullName = Dir_FindFile (gn->name, dirSearchPath); 987 988 } else { 988 989 fullName = gn->path; 989 990 } 990 991 991 992 if (fullName == (char *)NULL) { 992 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 999 1000 1001 1002 1003 1004 1005 1006 1007 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 1011 1012 1013 1014 1011 if (gn->type & OP_MEMBER) { 1012 if (fullName != gn->path) 1013 efree(fullName); 1014 return Arch_MemMTime (gn); 1015 } else 1015 1016 #endif 1016 1017 stb.st_mtime = 0; 1017 1018 } 1018 1019 if (fullName && gn->path == (char *)NULL) { 1019 1020 gn->path = fullName; 1020 1021 } 1021 1022 … … 1027 1028 *----------------------------------------------------------------------- 1028 1029 * Dir_AddDir -- 1029 * 1030 * 1031 * 1032 * 1033 * Results: 1034 * 1035 * 1036 * Side Effects: 1037 * 1038 * 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; 1044 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; 1048 register Path *p; 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 1055 1056 1057 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 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 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 1076 1077 1078 1079 1080 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 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 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 * 1110 * 1111 * 1112 * Results: 1113 * 1114 * 1115 * Side Effects: 1116 * 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 * 1133 * 1134 * 1135 * 1136 * 1137 * Results: 1138 * 1139 * 1140 * 1141 * 1142 * Side Effects: 1143 * 1133 * 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 1149 Lst path;/* list of directories */1150 { 1151 char *str;/* the string which will be returned */1152 char 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 1160 1161 1162 1163 1164 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 * 1174 * 1175 * 1176 * Results: 1177 * 1178 * 1179 * Side Effects: 1180 * 1181 * 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 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 1196 1197 1198 1199 1200 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 * 1208 * 1209 * 1210 * Results: 1211 * 1212 * 1213 * Side Effects: 1214 * 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 1225 1225 p = (Path *)Lst_DeQueue(path); 1226 Dir_Destroy((ClientData) p); 1226 1227 } 1227 1228 } … … 1231 1232 *----------------------------------------------------------------------- 1232 1233 * Dir_Concat -- 1233 * 1234 * 1235 * 1236 * Results: 1237 * 1238 * 1239 * Side Effects: 1240 * 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 1254 1255 1256 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 1266 Path 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 1271 1272 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 1276 1277 1278 1279 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 1285 ClientData 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 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 * 16 * 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 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 * 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 88 static int ForExec __P((ClientData, ClientData)); 88 89 89 90 … … 94 95 *----------------------------------------------------------------------- 95 96 * For_Eval -- 96 * 97 * 98 * 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 * 102 * 103 * 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 * 107 * None. 107 108 * 108 109 *----------------------------------------------------------------------- … … 110 111 int 111 112 For_Eval (line) 112 char 113 char *line; /* Line to parse */ 113 114 { 114 char 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 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 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 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 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 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 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 233 234 233 Buf_AddBytes(forBuf, strlen(line), (Byte *) line); 234 Buf_AddByte(forBuf, (Byte) '\n'); 235 return 1; 235 236 } 236 237 else { 237 238 return 0; 238 239 } 239 240 } … … 242 243 *----------------------------------------------------------------------- 243 244 * ForExec -- 244 * 245 * Expand the for loop for this index and push it in the Makefile 245 246 * 246 247 * Results: 247 * 248 * None. 248 249 * 249 250 * Side Effects: 250 * 251 * None. 251 252 * 252 253 *----------------------------------------------------------------------- … … 262 263 Var_Set(arg->var, name, VAR_GLOBAL); 263 264 if (DEBUG(FOR)) 264 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 267 VAR_GLOBAL, FALSE)); 267 268 Var_Delete(arg->var, VAR_GLOBAL); 268 269 … … 275 276 *----------------------------------------------------------------------- 276 277 * For_Run -- 277 * 278 * Run the for loop, immitating the actions of an include file 278 279 * 279 280 * Results: 280 * 281 * None. 281 282 * 282 283 * Side Effects: 283 * 284 * None. 284 285 * 285 286 *----------------------------------------------------------------------- … … 291 292 292 293 if (forVar == NULL || forBuf == NULL || forLst == NULL) 293 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 * 21 * 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 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 * 51 * 52 * 53 * 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 * 79 * 80 * Results: 81 * 82 * 83 * Side Effects: 84 * 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 94 95 96 97 { 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 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 * 124 * 125 * 126 * 127 * Results: 128 * 129 * 130 * Side Effects: 131 * 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 139 { 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 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 * 164 * 165 * Results: 166 * 167 * 168 * 169 * 170 * Side Effects: 171 * 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 182 183 184 185 186 187 188 189 190 191 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 * 200 * 201 * 202 * Results: 203 * 204 * 205 * 206 * 207 * 208 * Side Effects: 209 * 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 219 { 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 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 * 269 * 270 * 271 * Results: 272 * 273 * 274 * Side Effects: 275 * 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 283 284 { 285 286 287 288 289 290 291 292 293 294 295 296 297 298 (void) write(2, "bad call to Hash_DeleteEntry\n", 29);299 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 * 307 * 308 * 309 * Results: 310 * 311 * 312 * 313 * Side Effects: 314 * 315 * 316 * 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 325 326 { 327 328 329 330 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 354 355 { 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 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 * 385 * 386 * 387 * Results: 388 * 389 * 390 * Side Effects: 391 * 392 * 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 400 { 401 402 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 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 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 54 void err(int flags, const char *pszFormat, ...) 54 55 { 55 56 va_list args; … … 60 61 } 61 62 62 void 63 void errx(int flags, const char *pszFormat, ...) 63 64 { 64 65 va_list args; … … 69 70 } 70 71 71 void 72 void warnx(const char *pszFormat, ...) 72 73 { 73 74 va_list args; … … 78 79 } 79 80 80 void 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 * 21 * 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 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 * 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 * 65 * 66 * 67 * 68 * 69 * 70 * 71 * Job_CatchOutputPrint any output our children have produced.72 * 73 * 74 * 75 * 76 * 77 * 78 * Job_InitCalled to intialize this module. in addition,79 * 80 * 81 * 82 * 83 * 84 * Job_FullReturn TRUE if the job table is filled.85 * 86 * Job_EmptyReturn TRUE if the job table is completely87 * 88 * 89 * Job_ParseShellGiven the line following a .SHELL target, parse90 * 91 * 92 * 93 * Job_EndPerform any final processing which needs doing.94 * 95 * 96 * 97 * 98 * 99 * Job_AbortAllAbort all currently running jobs. It doesn't100 * 101 * 102 * 103 * 104 * Job_CheckCommandsVerify that the commands for a target are105 * 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 173 174 static int numCommands;/* The number of commands actually printed175 176 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 232 233 234 235 236 static char *shellPath = NULL,/* full pathname of237 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 249 250 251 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 255 #endif 256 257 STATIC GNode *lastNode;/* The node for which output was most recently258 259 STATIC char *targFmt;/* Format string to use to head output from a260 261 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 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 281 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) 287 # define KILL(pid, sig) killpg(-(pid), (sig)) 286 288 #else 287 289 # if defined(USE_PGRP) 288 # define KILL(pid, sig) 290 # define KILL(pid, sig) killpg((pid), (sig)) 289 291 # else 290 # define 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 * 344 * 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 * 355 * === 0 348 356 * 349 357 * Side Effects: 350 * 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 360 int 367 Job *job = (Job *) jobp; 368 int signo = *(int *) signop; 361 369 #ifdef RMT_WANTS_SIGNALS 362 370 if (job->flags & JOB_REMOTE) { 363 371 (void) Rmt_Signal(job, signo); 364 372 } else { 365 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 * 387 * 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 * 414 * None. 391 415 * 392 416 * Side Effects: 393 * 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 444 445 446 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 * 465 * 466 * 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 * 545 * 0 if the pid's match 470 546 * 471 547 * Side Effects: 472 * 548 * None 473 549 *----------------------------------------------------------------------- 474 550 */ 475 551 static int 476 552 JobCmpPid(job, pid) 477 ClientData job; 478 ClientData pid; 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 * 488 * 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 * 567 * 0 if the rmtID's match 492 568 * 493 569 * Side Effects: 494 * 570 * None. 495 571 *----------------------------------------------------------------------- 496 572 */ 497 573 static int 498 574 JobCmpRmtID(job, rmtID) 499 ClientData job; 500 ClientData rmtID; 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 * 510 * 511 * 512 * 513 * 514 * 515 * 516 * 517 * 518 * 519 * 520 * 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 * 599 * Always 0, unless the command was "..." 524 600 * 525 601 * Side Effects: 526 * 527 * 528 * 529 * 530 * 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; 536 ClientData jobp; 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 540 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 543 Boolean 544 545 546 char *cmdTemplate;/* Template to use when printing the547 548 char *cmdStart;/* Start of expanded command */549 LstNode cmdNode;/* Node for replacing the command */550 char 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 557 558 559 560 561 562 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 589 590 591 592 593 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 673 cmd++; 598 674 599 675 #ifndef KMK 600 676 if (shutUp) { 601 602 603 604 605 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 687 if ( !(job->flags & JOB_IGNERR) && !noSpecials) { 612 688 #ifdef KMK 613 689 errOff = FALSE; 614 690 #else 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 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 662 663 737 } else { 738 errOff = FALSE; 739 } 664 740 } 665 741 … … 668 744 #ifndef KMK /*todo*/ 669 745 if (errOff) { 670 671 672 673 674 675 676 677 678 679 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 758 DBPRINTF("%s\n", commandShell->echoOn); 683 759 } 684 760 #endif … … 689 765 *----------------------------------------------------------------------- 690 766 * JobSaveCommand -- 691 * 692 * 767 * Save a command to be executed when everything else is done. 768 * Callback function for JobFinish... 693 769 * 694 770 * Results: 695 * 771 * Always returns 0 696 772 * 697 773 * Side Effects: 698 * 774 * The command is tacked onto the end of postCommands's commands list. 699 775 * 700 776 *----------------------------------------------------------------------- … … 714 790 *----------------------------------------------------------------------- 715 791 * JobClose -- 716 * 792 * Called to close both input and output pipes when a job is finished. 717 793 * 718 794 * Results: 719 * 795 * Nada 720 796 * 721 797 * Side Effects: 722 * 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 809 Rmt_Ignore(job->inPipe); 733 810 #else 734 735 #endif 736 737 738 739 740 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 * 751 * 752 * 753 * 754 * 755 * 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 * 840 * None 759 841 * 760 842 * Side Effects: 761 * 762 * 763 * 764 * 765 * 766 * 767 * 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 780 1059 (((WEXITSTATUS(*status) != 0) && !(job->flags & JOB_IGNERR)))) || 1060 (WIFSIGNALED(*status) && (WTERMSIG(*status) != SIGCONT))) 781 1061 { 782 783 784 785 786 787 788 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 792 #endif 793 794 795 796 797 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 800 1079 if (job->flags & JOB_REMOTE) 1080 Rmt_Done(job->rmtID, job->node); 801 1081 #endif 802 1082 } else if (WIFEXITED(*status)) { 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 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 820 1099 if (job->flags & JOB_REMOTE) 1100 Rmt_Done(job->rmtID, job->node); 821 1101 #endif /* REMOTE */ 822 1102 } else { 823 824 825 826 1103 /* 1104 * No need to close things down or anything. 1105 */ 1106 done = FALSE; 827 1107 } 828 1108 829 1109 if (done || 830 831 832 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 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 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 1273 done = TRUE; 982 1274 } 983 1275 984 1276 985 1277 if (done && 986 987 988 1278 (aborting != ABORT_ERROR) && 1279 (aborting != ABORT_INTERRUPT) && 1280 (*status == 0)) 989 1281 { 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 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 1017 1018 1019 1020 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 * 1034 * 1328 * Touch the given target. Called by JobStart when the -t flag was 1329 * given 1035 1330 * 1036 1331 * Results: 1037 * 1332 * None 1038 1333 * 1039 1334 * Side Effects: 1040 * 1041 * 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; 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; 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 1055 1056 1057 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 1062 1356 (void) fprintf(stdout, "touch %s\n", gn->name); 1357 (void) fflush(stdout); 1063 1358 } 1064 1359 1065 1360 if (noExecute) { 1066 1361 return; 1067 1362 } 1068 1363 1069 1364 #ifdef USE_ARCHIVES 1070 1365 if (gn->type & OP_ARCHV) { 1071 1366 Arch_Touch(gn); 1072 1367 } else if (gn->type & OP_LIB) { 1073 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 1082 1083 1084 1085 1086 charc;1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 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 * 1405 * Make sure the given node has all the commands it needs. 1111 1406 * 1112 1407 * Results: 1113 * 1408 * TRUE if the commands list is/was ok. 1114 1409 * 1115 1410 * Side Effects: 1116 * 1117 * 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; 1123 1124 void 1125 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 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 1168 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 1171 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 1469 (*abortProc)("No match."); 1175 1470 #endif 1176 1471 else 1177 1472 #endif 1178 1179 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 * 1484 * Handle a pipe becoming readable. Callback function for Rmt_Watch 1190 1485 * 1191 1486 * Results: 1192 * 1487 * None 1193 1488 * 1194 1489 * Side Effects: 1195 * 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 * 1213 * 1507 * Execute the shell for the given job. Called from JobStart and 1508 * JobRestart. 1214 1509 * 1215 1510 * Results: 1216 * 1511 * None. 1217 1512 * 1218 1513 * Side Effects: 1219 * 1220 * 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 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 1235 1236 1237 1238 1239 1240 1241 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 1252 1253 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 1645 goto jobExecFinish; 1259 1646 } 1260 1647 #endif /* RMT_NO_EXEC */ … … 1265 1652 if ((cpid = vfork()) == -1) { 1266 1653 #endif 1267 1654 Punt("Cannot fork"); 1268 1655 } else if (cpid == 0) { 1269 1656 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 if (dup2(job->outPipe, 1) == -1)1286 1287 1288 1289 1290 1291 1292 1293 if (dup2(job->outFd, 1) == -1)1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 if (dup2(1, 2) == -1)1304 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 1309 1310 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 1700 (void) setsid(); 1314 1701 # else 1315 1702 (void) setpgid(0, getpid()); 1316 1703 # endif 1317 1704 #endif /* USE_PGRP */ 1318 1705 1319 1706 #ifdef REMOTE 1320 1321 1322 1707 if (job->flags & JOB_REMOTE) { 1708 Rmt_Exec(shellPath, argv, FALSE); 1709 } else 1323 1710 #endif /* REMOTE */ 1324 1711 #ifdef KMK 1325 1712 (void) execv(argv[0], argv); 1326 1713 #else 1327 1328 #endif 1329 1330 1331 1332 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 1736 Rmt_Watch(job->inPipe, JobLocalInput, job); 1349 1737 #else 1350 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 1745 job->rmtID = 0; 1357 1746 #else 1358 1747 job->rmtID = Rmt_LastID(job->pid); 1359 1748 #endif /* REMOTE */ 1360 1361 1362 1363 1364 1365 1366 1367 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 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 * 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 1404 char 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 1816 (commandShell->echo && (*commandShell->echo != '-'))) 1419 1817 { 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 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 1438 1439 1440 1441 1442 1443 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 * 1853 * Restart a job that stopped for some reason. 1455 1854 * 1456 1855 * Results: 1457 * 1856 * None. 1458 1857 * 1459 1858 * Side Effects: 1460 * 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 1872 if ( 1474 1873 #ifdef REMOTE 1475 1476 #endif 1477 1478 1479 1480 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 1485 1486 1487 1488 1489 #endif 1490 1491 1492 1493 1494 1495 1496 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 1499 #endif 1500 1501 1502 1503 1504 1505 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 1508 1906 job->flags &= ~(JOB_REMIGRATE|JOB_RESUME|JOB_REMOTE); 1907 job->flags |= JOB_CONTINUING; 1509 1908 #else 1510 1511 #endif 1512 1513 1514 1515 1516 1517 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 1520 #endif 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 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 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 #endif 1545 1546 1547 1548 1549 1550 1551 1552 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 1558 1559 1560 1561 1562 1563 1564 char*argv[4];1565 1566 1567 1568 1569 1570 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 1574 1972 if ((job->node->type&OP_NOEXPORT) || 1973 (nLocal < maxLocal && runLocalFirst) 1575 1974 # ifdef RMT_NO_EXEC 1576 1975 || !Rmt_Export(shellPath, argv, job) 1577 1976 # else 1578 1977 || !Rmt_Begin(shellPath, argv, job->node) 1579 1978 # endif 1580 1979 #endif 1581 1582 1583 1584 1585 1586 1587 1588 1589 1590 1591 1592 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 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 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 #endif 1621 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 1625 1626 1627 1628 1629 1630 1631 1632 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 1635 1636 2033 (((job->flags & JOB_SPECIAL) && 2034 (job->node->type & OP_NOEXPORT)) && 2035 (maxLocal == 0))) && 1637 2036 #else 1638 1639 1640 #endif 1641 1642 1643 1644 1645 1646 1647 1648 1649 1650 1651 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 1655 1656 1657 #endif 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 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 * 1704 * 2103 * Start a target-creation process going for the target described 2104 * by the graph node gn. 1705 2105 * 1706 2106 * Results: 1707 * 1708 * 1709 * 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 * 1713 * 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; 1719 int 1720 1721 Job 1722 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 1726 Boolean 1727 Boolean 1728 Boolean 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 1733 2132 previous->flags &= ~(JOB_FIRST|JOB_IGNERR|JOB_SILENT|JOB_REMOTE); 2133 job = previous; 1734 2134 } else { 1735 1736 1737 1738 1739 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 2152 job->flags |= JOB_IGNERR; 1753 2153 } 1754 2154 if (Targ_Silent(gn)) { 1755 2155 job->flags |= JOB_SILENT; 1756 2156 } 1757 2157 job->flags |= flags; … … 1762 2162 */ 1763 2163 if (!compatMake && job->flags & JOB_FIRST) { 1764 2164 cmdsOK = Job_CheckCommands(gn, Error); 1765 2165 } else { 1766 2166 cmdsOK = TRUE; 1767 2167 } 1768 2168 … … 1774 2174 */ 1775 2175 if ((gn->type & OP_MAKE) || (!noExecute && !touchFlag)) { 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 LstNodeln = Lst_Next(gn->commands);1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 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 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 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 1880 1881 1882 1883 1884 1885 1886 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 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 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 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 2364 local = !Rmt_Export(shellPath, argv, job); 1961 2365 #else 1962 2366 local = !Rmt_Begin(shellPath, argv, job->node); 1963 2367 #endif /* RMT_NO_EXEC */ 1964 1965 1966 2368 if (!local) { 2369 job->flags |= JOB_REMOTE; 2370 } 1967 2371 } else 1968 2372 #endif 1969 2373 local = TRUE; 1970 2374 1971 2375 if (local && (((nLocal >= maxLocal) && 1972 2376 !(job->flags & JOB_SPECIAL) && 1973 2377 #ifdef REMOTE 1974 2378 (!(gn->type & OP_NOEXPORT) || (maxLocal != 0)) 1975 2379 #else 1976 1977 #endif 1978 2380 (maxLocal != 0) 2381 #endif 2382 ))) 1979 2383 { 1980 1981 1982 1983 1984 1985 1986 1987 1988 1989 1990 1991 1992 1993 1994 1995 1996 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 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 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 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 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 * 2066 * 2067 * 2068 * 2069 * 2070 * 2071 * 2072 * 2073 * 2074 * 2075 * 2076 * 2077 * 2078 * 2079 * 2080 * 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 * 2487 * None 2084 2488 * 2085 2489 * Side Effects: 2086 * 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; 2092 Boolean finish;/* TRUE if this is the last time we'll be2093 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; 2097 register int nr; 2098 register int i; 2099 register int max; 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 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 * 2677 * Handle the exit of a child. Called from Make_Make. 2270 2678 * 2271 2679 * Results: 2272 * 2680 * none. 2273 2681 * 2274 2682 * Side Effects: 2275 * 2683 * The job descriptor is removed from the list of children. 2276 2684 * 2277 2685 * Notes: 2278 * 2279 * 2280 * 2281 * 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 2749 (block?0:WNOHANG)|WUNTRACED)) > 0) 2303 2750 { 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 2315 2316 2317 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 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 2336 2337 2338 2339 2340 2341 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 * 2356 * 2357 * 2358 * 2359 * 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 * 2810 * None 2363 2811 * 2364 2812 * Side Effects: 2365 * 2813 * Output is read from pipes if we're piping. 2366 2814 * ----------------------------------------------------------------------- 2367 2815 */ … … 2369 2817 Job_CatchOutput() 2370 2818 { 2371 int 2372 struct timeval 2373 fd_set 2374 register LstNode 2375 register 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 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 * 2433 * 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 * 2886 * None. 2437 2887 * 2438 2888 * Side Effects: 2439 * 2889 * Another job is started. 2440 2890 * 2441 2891 *----------------------------------------------------------------------- … … 2451 2901 *----------------------------------------------------------------------- 2452 2902 * Job_Init -- 2453 * 2903 * Initialize the process module 2454 2904 * 2455 2905 * Results: 2456 * 2906 * none 2457 2907 * 2458 2908 * Side Effects: 2459 * 2909 * 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 2466 int 2467 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 2487 #endif 2488 2489 2490 2491 2492 2493 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 2947 targFmt = TARG_FMT; 2496 2948 } 2497 2949 2498 2950 #ifndef KMK 2499 2951 if (shellPath == NULL) { 2500 2501 2502 2503 2504 2505 2506 2507 2508 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 2964 commandShell->exit = ""; 2513 2965 } 2514 2966 if (commandShell->echo == NULL) { 2515 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 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 2999 (void) signal(SIGTSTP, JobPassSig); 2544 3000 } 2545 3001 if (signal(SIGTTOU, SIG_IGN) != SIG_IGN) { 2546 3002 (void) signal(SIGTTOU, JobPassSig); 2547 3003 } 2548 3004 if (signal(SIGTTIN, SIG_IGN) != SIG_IGN) { 2549 3005 (void) signal(SIGTTIN, JobPassSig); 2550 3006 } 2551 3007 if (signal(SIGWINCH, SIG_IGN) != SIG_IGN) { 2552 3008 (void) signal(SIGWINCH, JobPassSig); 2553 3009 } 2554 3010 #endif … … 2557 3013 2558 3014 if (begin != NILGNODE) { 2559 2560 2561 3015 JobStart(begin, JOB_SPECIAL, (Job *)0); 3016 while (nJobs) { 3017 Job_CatchOutput(); 2562 3018 #ifndef RMT_WILL_WATCH 2563 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 * 2574 * 2575 * 2576 * 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 * 3035 * TRUE if the job table is full, FALSE otherwise 2580 3036 * Side Effects: 2581 * 3037 * None. 2582 3038 *----------------------------------------------------------------------- 2583 3039 */ … … 2591 3047 *----------------------------------------------------------------------- 2592 3048 * Job_Empty -- 2593 * 2594 * 2595 * 2596 * 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 * 3055 * TRUE if it is. FALSE if it ain't. 2600 3056 * 2601 3057 * Side Effects: 2602 * 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 3080 return(FALSE); 2623 3081 } 2624 3082 } … … 2628 3086 *----------------------------------------------------------------------- 2629 3087 * JobMatchShell -- 2630 * 3088 * Find a matching shell in 'shells' given its final component. 2631 3089 * 2632 3090 * Results: 2633 * 3091 * A pointer to the Shell structure. 2634 3092 * 2635 3093 * Side Effects: 2636 * 3094 * None. 2637 3095 * 2638 3096 *----------------------------------------------------------------------- … … 2640 3098 static Shell * 2641 3099 JobMatchShell(name) 2642 char 3100 char *name; /* Final component of shell path */ 2643 3101 { 2644 register Shell *sh; 2645 Shell 3102 register Shell *sh; /* Pointer into shells table */ 3103 Shell *match; /* Longest-matching shell */ 2646 3104 register char *cp1, 2647 2648 char 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 2656 2657 2658 2659 2660 2661 2662 2663 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 * 2675 * 3132 * Parse a shell specification and set up commandShell, shellPath 3133 * and shellName appropriately. 2676 3134 * 2677 3135 * Results: 2678 * 3136 * FAILURE if the specification was incorrect. 2679 3137 * 2680 3138 * Side Effects: 2681 * 2682 * 2683 * 2684 * 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 * 2688 * 2689 * 2690 * 2691 * 2692 * 2693 * 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 * 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 * 2705 * 2706 * 2707 * ignoreCommand to turn off error checking if hasErrCtl2708 * 2709 * 2710 * 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 3174 char *line; /* The shell spec */ 2717 3175 { 2718 char 2719 int 3176 char **words; 3177 int wordCount; 2720 3178 register char **argv; 2721 3179 register int argc; 2722 char 2723 Shell 2724 Boolean 3180 char *path; 3181 Shell newShell; 3182 Boolean fullSpec = FALSE; 2725 3183 2726 3184 while (isspace(*line)) { 2727 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 2738 2739 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 2750 2751 2752 2753 2754 2755 2756 2757 2758 2759 2760 2761 2762 2763 2764 2765 2766 2767 2768 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 2775 2776 2777 2778 2779 2780 2781 2782 2783 2784 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 2789 2790 2791 2792 2793 2794 2795 2796 2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810 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 3273 commandShell->hasEchoCtl = TRUE; 2816 3274 } 2817 3275 2818 3276 if (!commandShell->hasErrCtl) { 2819 2820 2821 2822 2823 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 * 3297 * Handle the receipt of an interrupt. 2840 3298 * 2841 3299 * Results: 2842 * 3300 * None 2843 3301 * 2844 3302 * Side Effects: 2845 * 2846 * 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 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; 2857 GNode *interrupt; 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 2864 2865 2866 char*file = (job->node->path == NULL ?2867 2868 2869 2870 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 2875 2876 2877 2878 2879 2880 2881 2882 2883 2884 2885 2886 2887 2888 2889 2890 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 2894 2895 2896 2897 2898 2899 2900 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 2909 2910 2911 2912 2913 2914 2915 2916 2917 2918 2919 2920 char*file = (job->node->path == NULL ?2921 2922 2923 2924 2925 2926 2927 2928 2929 2930 2931 2932 2933 2934 2935 2936 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 2939 2940 2941 2942 2943 2944 2945 2946 2947 2948 2949 2950 2951 2952 2953 2954 2955 2956 2957 2958 2959 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 2968 2969 2970 2971 2972 2973 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 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 * 2986 * 3443 * Do final processing such as the running of the commands 3444 * attached to the .END target. 2987 3445 * 2988 3446 * Results: 2989 * 3447 * Number of errors reported. 2990 3448 *----------------------------------------------------------------------- 2991 3449 */ … … 2994 3452 { 2995 3453 if (postCommands != NILGNODE && !Lst_IsEmpty(postCommands->commands)) { 2996 2997 2998 2999 3000 3001 3002 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 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 * 3016 * 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 * 3477 * None. 3020 3478 * 3021 3479 * Side Effects: 3022 * 3480 * Currently running jobs finish. 3023 3481 * 3024 3482 *----------------------------------------------------------------------- … … 3029 3487 aborting = ABORT_WAIT; 3030 3488 while (nJobs != 0) { 3031 3489 Job_CatchOutput(); 3032 3490 #ifndef RMT_WILL_WATCH 3033 3491 Job_CatchChildren(!usePipes); 3034 3492 #endif /* RMT_WILL_WATCH */ 3035 3493 } … … 3040 3498 *----------------------------------------------------------------------- 3041 3499 * Job_AbortAll -- 3042 * 3043 * 3044 * 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 * 3505 * None 3048 3506 * 3049 3507 * Side Effects: 3050 * 3508 * 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 3065 3066 3067 3068 3069 3070 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 3074 3075 3076 3077 3078 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 3082 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 * 3099 * 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 * 3593 * none. 3103 3594 * 3104 3595 * Side Effects: 3105 * 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; 3114 LstNode jnode; 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 3118 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 3124 3125 3126 3127 3128 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 3135 3136 3137 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 * 3152 * 3153 * 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 * 3648 * None. 3157 3649 * 3158 3650 * Side Effects: 3159 * 3651 * Resumes(and possibly migrates) jobs. 3160 3652 * 3161 3653 *----------------------------------------------------------------------- … … 3165 3657 { 3166 3658 while (!jobFull && !Lst_IsEmpty(stoppedJobs)) { 3167 3168 3169 3170 3171 3172 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 * 21 * 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 * 45 * 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 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 58 #define SEL_USEC 57 #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 * 67 * 68 * 69 * 70 * 71 * 72 * 73 * 74 * 75 * 76 * 77 * 78 * 79 * 80 * 81 * 82 * 83 * 84 * 66 * 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 99 GNode 100 LstNode 101 102 FILE 103 104 int 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 110 #define JOB_IGNDOTS 0x008/* Ignore "..." lines when processing111 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 118 #define JOB_CONTINUING 0x200/* We are in the process of resuming this job.119 120 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 123 int op_inPipe;/* Input side of pipe associated124 125 int op_outPipe;/* Output side of pipe associated with126 127 charop_outBuf[JOB_BUFSIZE + 1];128 129 130 int op_curPos;/* Current position in op_outBuf */131 } o_pipe;/* data used when catching the output via132 133 134 char of_outFile[sizeof(TMPPAT)];135 136 137 int of_outFd;/* Stream open to the output138 139 140 141 142 } o_file;/* Data used when catching the output in143 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 148 #define inPipe 149 #define outBuf 150 #define curPos 151 #define outFile 152 #define outFd 148 #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 * 160 * 161 * 162 * 163 * 164 * 165 * 166 * 167 * 168 * 169 * 170 * 171 * 172 * 173 * 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 185 186 187 188 189 Boolean hasEchoCtl;/* True if both echoOff and echoOn defined */190 char *echoOff; 191 char *echoOn; 192 char *noPrint; 193 194 195 int noPLen; 196 Boolean hasErrCtl;/* set if can control error checking for197 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; 204 char *exit; 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 210 211 212 extern GNode *lastNode;/* Last node for which a banner was printed.213 214 215 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 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 * 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 * 21 * 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 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 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 * 57 * 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 * 62 * 63 * 64 * 65 * ErrorPrint a tagged error message. The global66 * 67 * 68 * 69 * 70 * FatalPrint an error message and exit. Also takes71 * 72 * 73 * PuntAborts all jobs and exits with a message. Also74 * 75 * 76 * FinishFinish things up by printing the number of77 * 78 * 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 139 #define 140 #endif 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 * 185 * 186 * 187 * 189 * 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 * 195 * None 191 196 * 192 197 * Side Effects: 193 * 194 * 198 * 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 199 200 { 201 202 203 204 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: 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 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 247 248 249 250 251 252 253 254 255 256 257 258 259 #endif 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 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 283 debug |= DEBUG_ARCH; 279 284 #endif /* else ignore */ 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 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 315 debug |= DEBUG_PARSE; 311 316 break; 312 317 case 's': 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 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 359 #endif 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 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 381 break; 382 #endif 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 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 * 437 * 438 * 439 * 440 * 441 * 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 * 449 * None 445 450 * 446 451 * Side Effects: 447 * 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 457 458 459 460 461 462 463 464 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 470 474 char *path; 475 char *obpath; 471 476 { 472 477 struct stat sb; … … 476 481 #endif 477 482 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 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 * 501 * 502 * 503 * 504 * 505 * 506 * 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 * 510 * 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 * 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 522 523 { 524 Lst targs;/* target nodes to create -- passed to Make_Init */525 Boolean outOfDate = TRUE;/* FALSE if all targets up to date */526 527 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 530 531 #endif 532 533 534 535 536 537 538 Lst sysMkPath;/* Path of sys.mk */539 540 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 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 548 549 550 551 552 553 554 555 556 557 #endif 558 559 560 561 562 563 564 565 566 567 568 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 572 573 574 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 582 583 584 585 586 587 588 589 590 intispc98;591 size_tlen;592 593 594 595 596 597 598 599 #endif 600 601 602 603 604 605 606 607 608 609 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 612 613 614 615 616 617 618 #else 619 620 #endif 621 622 623 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 626 #else 627 628 #endif 629 630 631 632 633 634 635 636 637 638 639 640 641 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 649 650 651 *1. MAKEOBJDIRPREFIX`cwd`652 *2. MAKEOBJDIR653 *3. _PATH_OBJDIR.${MACHINE}654 *4. _PATH_OBJDIR655 *5. _PATH_OBJDIRPREFIX`cwd`656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 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 704 kEnvSet("PWD", objdir); 693 705 #else 694 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 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 724 #endif 725 726 compatMake = FALSE;/* No compat mode */727 728 729 730 731 732 733 734 Dir_Init();/* Initialize directory structures so -I flags735 736 Parse_Init();/* Need to initialize the paths of #include737 738 Var_Init();/* As well as the lists of variables for739 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 742 743 744 745 746 747 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 753 754 755 756 757 758 759 760 761 762 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 785 #endif 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 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 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 838 839 840 841 842 843 844 845 846 847 848 849 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 857 858 859 860 861 862 863 864 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 892 if (!Lst_IsEmpty(sysMkPath)) 867 893 { 868 894 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); … … 872 898 873 899 #elif defined(KMK) 874 900 if (!Lst_IsEmpty(sysMkPath)) 875 901 { 876 902 ln = Lst_Find(sysMkPath, (ClientData)NULL, ReadMakefile); … … 879 905 880 906 } 881 882 #else 883 884 885 886 887 888 #endif 889 890 891 892 893 894 895 896 897 907 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 914 915 916 917 918 919 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 950 setenv("MAKEFLAGS", p, 1); 925 951 #endif 926 952 #else 927 953 #ifdef USE_KLIB 928 954 kEnvSet("MAKE", p, TRUE); 929 955 #else 930 956 setenv("MAKE", p, 1); 931 957 #endif 932 958 #endif 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 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 1046 #endif 1047 1048 1049 1050 1051 1052 1053 1054 1055 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 * 1086 * Open and parse the given makefile. 1061 1087 * 1062 1088 * Results: 1063 * 1089 * TRUE if ok. FALSE if couldn't open file. 1064 1090 * 1065 1091 * Side Effects: 1066 * 1092 * lots 1067 1093 */ 1068 1094 static Boolean 1069 1095 ReadMakefile(p, q) 1070 1071 { 1072 char *fname = p;/* makefile to read */1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 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 1114 1115 1116 1117 1118 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 * 1124 * 1149 * Execute the command in cmd, and return the output of that command 1150 * in a string. 1125 1151 * 1126 1152 * Results: 1127 * 1128 * 1153 * 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 * 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 1164 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 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 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 1322 (void) execv(psz, args); 1197 1323 } 1198 1324 #else 1199 1325 (void) execv("/bin/sh", args); 1200 1326 #endif 1201 1202 1327 _exit(1); 1328 /*NOTREACHED*/ 1203 1329 1204 1330 case -1: 1205 1206 1331 *err = "Couldn't exec \"%s\""; 1332 goto bad; 1207 1333 1208 1334 default: 1209 1210 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 1223 1224 1225 1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 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 * 1401 * Print an error message given its format. 1275 1402 * 1276 1403 * Results: 1277 * 1404 * None. 1278 1405 * 1279 1406 * Side Effects: 1280 * 1407 * The message is printed. 1281 1408 */ 1282 1409 /* VARARGS */ … … 1286 1413 #else 1287 1414 Error(va_alist) 1288 1289 #endif 1290 { 1291 1415 va_dcl 1416 #endif 1417 { 1418 va_list ap; 1292 1419 #if defined(__STDC__) || defined(__IBMC__) 1293 1294 #else 1295 1296 1297 1298 1299 #endif 1300 1301 1302 1303 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 * 1309 * 1435 * Produce a Fatal error message. If jobs are running, waits for them 1436 * to finish. 1310 1437 * 1311 1438 * Results: 1312 * 1439 * None 1313 1440 * 1314 1441 * Side Effects: 1315 * 1442 * The program exits 1316 1443 */ 1317 1444 /* VARARGS */ … … 1321 1448 #else 1322 1449 Fatal(va_alist) 1323 1324 #endif 1325 { 1326 1450 va_dcl 1451 #endif 1452 { 1453 va_list ap; 1327 1454 #if defined(__STDC__) || defined(__IBMC__) 1328 1329 #else 1330 1331 1332 1333 1334 #endif 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 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 * 1351 * 1477 * Major exception once jobs are being created. Kills all jobs, prints 1478 * a message and exits. 1352 1479 * 1353 1480 * Results: 1354 * 1481 * None 1355 1482 * 1356 1483 * Side Effects: 1357 * 1484 * All children are killed indiscriminately and the program Lib_Exits 1358 1485 */ 1359 1486 /* VARARGS */ … … 1363 1490 #else 1364 1491 Punt(va_alist) 1365 1366 #endif 1367 { 1368 1492 va_dcl 1493 #endif 1494 { 1495 va_list ap; 1369 1496 #if defined(__STDC__) || defined(__IBMC__) 1370 1371 #else 1372 1373 1374 1375 1376 #endif 1377 1378 1379 1380 1381 1382 1383 1384 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 * 1516 * Exit without giving a message. 1390 1517 * 1391 1518 * Results: 1392 * 1519 * None 1393 1520 * 1394 1521 * Side Effects: 1395 * 1522 * A big one... 1396 1523 */ 1397 1524 void 1398 1525 DieHorribly() 1399 1526 { 1400 1401 1402 1403 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 * 1410 * 1536 * Called when aborting due to errors in child shell to signal 1537 * abnormal exit. 1411 1538 * 1412 1539 * Results: 1413 * 1540 * None 1414 1541 * 1415 1542 * Side Effects: 1416 * 1543 * The program exits 1417 1544 */ 1418 1545 void 1419 1546 Finish(errors) 1420 int errors;/* number of errors encountered in Make_Make */1421 { 1422 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 * 1554 * malloc, but die on error. 1428 1555 */ 1429 1556 void * 1430 1557 emalloc(len) 1431 1432 { 1433 1434 1435 1436 1437 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 * 1569 * strdup, but die on error. 1443 1570 */ 1444 1571 char * 1445 1572 estrdup(str) 1446 1447 { 1448 1449 1450 1451 1452 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 * 1584 * realloc, but die on error. 1458 1585 */ 1459 1586 void * 1460 1587 erealloc(ptr, size) 1461 1462 1463 { 1464 1465 1466 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 * 1610 * die when out of memory. 1484 1611 */ 1485 1612 void 1486 1613 enomem() 1487 1614 { 1488 1615 err(2, NULL); 1489 1616 } 1490 1617 1491 1618 /* 1492 1619 * enunlink -- 1493 * 1620 * Remove a file carefully, avoiding directories. 1494 1621 */ 1495 1622 int 1496 1623 eunlink(file) 1497 1498 { 1499 1500 1501 #if def __EMX__1502 1503 #else 1504 1505 #endif 1506 1507 1508 1509 1510 1511 1512 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 * 1644 * exit with usage message 1518 1645 */ 1519 1646 static void 1520 1647 usage() 1521 1648 { 1522 1649 (void)fprintf(stderr, "%s\n%s\n%s\n" 1523 1650 #ifdef NMAKE 1524 1651 "%s\n" … … 1538 1665 #endif 1539 1666 ); 1540 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 * 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 * 21 * 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 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 * 51 * 51 * 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 * 56 * 57 * 58 * 59 * Make_UpdateUpdate all parents of a given child. Performs60 * 61 * 62 * 63 * 64 * 65 * 66 * Make_TimeStampFunction to set the parent's cmtime field67 * 68 * 69 * Make_DoAllVarSet up the various local variables for a70 * 71 * 72 * 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 * 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 87 88 89 90 static int numNodes;/* Number of nodes to be processed. If this91 92 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 * 104 * 105 * 106 * Results: 107 * 108 * 109 * Side Effects: 110 * 111 * 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; 117 GNode *cgn; 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 121 pgn->cmtime = cgn->mtime; 121 122 } 122 123 return (0); … … 125 126 static int 126 127 MakeTimeStamp (pgn, cgn) 127 ClientData pgn; 128 ClientData cgn; 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 * 138 * 139 * 140 * 141 * 142 * 143 * 144 * Results: 145 * 146 * 147 * Side Effects: 148 * 149 * 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; 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 164 165 166 167 168 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 * 176 * 177 * 178 * 179 * 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 190 191 192 193 194 195 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 199 200 201 202 203 204 205 206 207 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 212 213 214 215 216 217 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 221 222 223 224 225 226 227 228 229 230 231 232 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 235 235 ((gn->cmtime == 0) && 236 ((gn->mtime==0) || (gn->type & OP_DOUBLEDEP)))) 236 237 { 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 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 257 258 259 260 257 /* WHY? */ 258 if (DEBUG(MAKE)) { 259 printf("source %smade...", gn->childMade ? "" : "not "); 260 } 261 oodate = gn->childMade; 261 262 #else 262 263 oodate = FALSE; 263 264 #endif /* 0 */ 264 265 } … … 272 273 */ 273 274 if (!oodate) { 274 275 Lst_ForEach (gn->parents, MakeTimeStamp, (ClientData)gn); 275 276 } 276 277 … … 282 283 *----------------------------------------------------------------------- 283 284 * MakeAddChild -- 284 * 285 * 286 * 287 * Results: 288 * 289 * 290 * Side Effects: 291 * 285 * 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; 297 ClientData lp; 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 304 (void)Lst_EnQueue (l, (ClientData)gn); 304 305 } 305 306 return (0); … … 310 311 *----------------------------------------------------------------------- 311 312 * Make_HandleUse -- 312 * 313 * 314 * 315 * 316 * 317 * 318 * 319 * 320 * 321 * 322 * 323 * Results: 324 * 325 * 326 * Side Effects: 327 * 328 * 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 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 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; 380 ClientData cgn; 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 * 390 * 391 * 392 * 393 * Results: 394 * 395 * 396 * Side Effects: 397 * 398 * 399 * 400 * 401 * 402 * 403 * 404 * 405 * 406 * 407 * 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; 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 432 433 434 435 436 437 438 *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 444 445 446 447 448 449 450 451 452 453 454 455 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 460 461 462 *cmp -s y.tab.h parse.h || cp y.tab.h parse.h463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 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 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 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 529 530 531 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 541 char*cpref = Var_Value(PREFIX, cgn, &p1);542 543 544 545 546 547 548 549 550 551 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 * 560 * 561 * 562 * 563 * 564 * 565 * 566 * 567 * 568 * 569 * Results: 570 * 571 * 572 * Side Effects: 573 * 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 581 { 582 GNode 583 GNode 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 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 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 * 635 * 636 * Side Effects: 637 * 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 646 GNode 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 649 650 651 652 653 654 655 } 656 657 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 * 668 * 669 * 670 * 671 * 672 * 673 * 674 * 675 * 676 * 677 * Results: 678 * 679 * 680 * Side Effects: 681 * 682 * 683 * 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 689 GNode *gn; 689 690 { 690 691 Lst_ForEach (gn->children, MakeAddAllSrc, (ClientData) gn); … … 694 695 695 696 if (!Var_Exists (OODATE, gn)) { 696 697 Var_Set (OODATE, "", gn); 697 698 } 698 699 if (!Var_Exists (ALLSRC, gn)) { 699 700 Var_Set (ALLSRC, "", gn); 700 701 } 701 702 702 703 if (gn->type & OP_JOIN) { 703 704 705 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 * 714 * 715 * Results: 716 * 717 * 718 * 719 * 720 * Side Effects: 721 * 722 * 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 730 register GNode *gn; 730 731 731 732 while (!Job_Full() && !Lst_IsEmpty (toBeMade)) { 732 733 734 735 736 737 738 739 740 741 742 743 744 GNode*pgn = (GNode *)Lst_Datum(ln);745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 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 * 800 * 801 * 802 * 803 * Results: 804 * 805 * 806 * Side Effects: 807 * 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; 814 ClientData cyclep;/* True if gn->unmade being non-zero implies815 816 817 { 818 GNode 819 Boolean 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 822 printf ("`%s' is up to date.\n", gn->name); 822 823 } else if (gn->unmade != 0) { 823 824 825 826 827 828 829 *a : b830 *b : c831 *c : b832 833 834 835 836 837 838 839 840 841 842 843 844 845 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 * 856 * 857 * 858 * 859 * 860 * 861 * 862 * 863 * 864 * Results: 865 * 866 * 867 * Side Effects: 868 * 869 * 870 * 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; 876 { 877 register GNode *gn; 878 register Lst 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 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 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 921 922 923 924 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 928 929 930 931 932 933 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 948 949 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 * 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 * 21 * 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 * 44 * 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 * 96 * 97 * 98 * 99 * 100 * 101 * 102 * 103 * 104 * 105 * 106 * 107 * 108 * 109 * 110 * 111 * 112 * 113 * 114 * 115 * 116 * 117 * 118 * 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; 122 char *path;/* The full pathname of the file */123 int type; 124 int order;/* Its wait weight */125 126 Boolean make; 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 129 130 } made;/* Set to reflect the state of processing131 132 133 134 *Indicates a cycle in the graph. (compat135 *mode only)136 137 138 139 *made (used only in compat mode)140 141 *an error making an inferior (compat).142 143 *a graph cycle. If we come back to a144 *node marked this way, it is printed145 *and 'made' is changed to ENDCYCLE.146 147 *printed. Go back and unmark all its148 *members.149 150 Boolean childMade;/* TRUE if one of this target's children was151 152 int unmade; 153 154 int mtime; 155 int cmtime;/* The modification time of its youngest156 157 158 Lst iParents;/* Links to parents for which this is an159 160 Lst cohorts;/* Other nodes for the :: operator */161 Lst parents; 162 Lst children; 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; 167 Lst commands; 168 169 struct _Suff *suffix; 170 171 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 173 #define NILGNODE ((GNode *) NIL) 178 174 179 175 /* … … 186 182 * righthand side... 187 183 */ 188 #define OP_DEPENDS 189 190 #define OP_FORCE 191 #define OP_DOUBLEDEP 192 193 #define OP_OPMASK 194 195 #define OP_OPTIONAL 196 197 #define OP_USE 198 #define OP_EXEC 199 200 201 202 #define OP_IGNORE 203 #define OP_PRECIOUS 204 205 #define OP_SILENT 206 #define OP_MAKE 207 208 209 210 #define OP_JOIN 211 212 #define OP_INVISIBLE 213 214 215 #define OP_NOTMAIN 216 217 #define OP_PHONY 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 215 #define OP_TRANSFORM 0x80000000 /* The node is a transformation rule */ 220 216 #ifdef USE_ARCHIVES 221 #define OP_MEMBER 222 #define OP_LIB 223 #define OP_ARCHV 224 #endif 225 #define OP_HAS_COMMANDS 226 227 228 #define OP_SAVE_CMDS 229 #define OP_DEPS_FOUND 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) 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 278 #define PARSE_FATAL 273 #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 315 316 extern Lst dirSearchPath;/* The list of directories to search when317 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; 322 extern Boolean beVerbose;/* True if should print extra cruft */323 extern Boolean noExecute; 324 extern Boolean allPrecious; 325 extern Boolean keepgoing; 326 327 328 extern Boolean touchFlag;/* TRUE if targets should just be 'touched'329 330 extern Boolean usePipes; 331 332 333 334 extern Boolean queryFlag;/* TRUE if we aren't supposed to really make335 336 337 338 extern Boolean checkEnvFirst;/* TRUE if environment should be searched for339 340 extern Lst envFirstVars;/* List of specific variables for which the341 342 343 344 extern GNode *DEFAULT; 345 346 extern GNode *VAR_GLOBAL; 347 348 extern GNode *VAR_CMD; 349 extern char var_Error[];/* Value returned by Var_Parse when an error350 351 352 353 354 extern time_t now;/* The time at the start of this whole355 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 * 364 * 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 380 #define DEBUG_LOUD 364 #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) 381 #define CONCAT(a,b) a##b 386 382 #else 387 #define I(a) 388 #define CONCAT(a,b) 383 #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 * 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 * 21 * 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 * 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 * 21 * 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 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 * 51 * 52 * 53 * 54 * 55 * 56 * 57 * 58 * 59 * 60 * 61 * 62 * 63 * 64 * 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 * 69 * 70 * 71 * Parse_EndCleanup the module72 * 73 * Parse_FileFunction used to parse a makefile. It must74 * 75 * 76 * 77 * 78 * Parse_IsVarReturns TRUE if the given line is a79 * 80 * 81 * 82 * 83 * 84 * Parse_ErrorFunction called when an error occurs in85 * 86 * 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 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; 127 static FILE *curFILE = NULL;/* current makefile */128 129 static PTR *curPTR = NULL;/* current makefile */130 131 static int 132 133 static GNode *mainNode;/* The main target to create. This is the134 135 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; 141 int lineno; 142 FILE * F; 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; 147 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, 159 Default, 160 End, 161 Ignore, 162 Includes, 163 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, 166 #endif 167 MFlags, 168 Main, 169 170 NoExport, 171 Not, 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, 174 Order, 175 Parallel, 176 ExPath, 177 Phony, 174 Null, /* .NULL */ 175 Order, /* .ORDER */ 176 Parallel, /* .PARALLEL */ 177 ExPath, /* .PATH */ 178 Phony, /* .PHONY */ 178 179 #ifdef POSIX 179 Posix, 180 #endif 181 Precious, 182 ExShell, 183 Silent, 180 Posix, /* .POSIX */ 181 #endif 182 Precious, /* .PRECIOUS */ 183 ExShell, /* .SHELL */ 184 Silent, /* .SILENT */ 184 185 SingleShell, /* .SINGLESHELL */ 185 Suffixes, 186 Wait, 187 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 198 static GNode *predecessor; 198 199 199 200 /* … … 205 206 */ 206 207 static struct { 207 char *name;/* Name of keyword */208 ParseSpecial spec; 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, 229 { ".NO_PARALLEL", NotParallel, 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, 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 * 280 * Look in the table of keywords for one matching the given string. 280 281 * 281 282 * Results: 282 * 283 * The index of the keyword, or -1 if it isn't there. 283 284 * 284 285 * Side Effects: 285 * 286 * 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 294 294 end, 295 cur; 295 296 register int diff; 296 297 … … 299 300 300 301 do { 301 302 303 304 305 306 307 308 309 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 * 318 * 319 * 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 * 323 * None 323 324 * 324 325 * Side Effects: 325 * 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 334 #endif 335 { 336 334 va_dcl 335 #endif 336 { 337 va_list ap; 337 338 #if defined(__STDC__) || defined(__IBMC__) 338 339 va_start(ap, fmt); 339 340 #else 340 int type;/* Error type (PARSE_WARNING, PARSE_FATAL) */341 342 343 344 345 346 #endif 347 348 349 350 351 352 353 354 355 356 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 * 363 * 364 * 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 * 368 * Always = 0 368 369 * 369 370 * Side Effects: 370 * 371 * 372 * 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; 378 ClientData cgnp; 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 384 385 386 387 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 * 396 * 397 * 398 * 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 * 402 * Always 0 402 403 * 403 404 * Side Effects: 404 * 405 * 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; 411 412 ClientData opp; 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 423 !OP_NOP(gn->type) && !OP_NOP(op)) 423 424 { 424 425 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 431 432 433 434 435 436 437 register GNode*cohort;438 LstNodeln;439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 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 * 474 * 475 * 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 * 479 * 479 * 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 * 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 497 498 499 500 501 502 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 506 return 1; 506 507 } 507 508 … … 510 511 *--------------------------------------------------------------------- 511 512 * ParseDoSrc -- 512 * 513 * 514 * 515 * 516 * 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 * 520 * None 520 521 * 521 522 * Side Effects: 522 * 523 * 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 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 536 537 538 539 540 541 542 543 544 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 553 554 555 556 557 558 559 560 561 562 563 564 565 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 570 571 572 573 574 575 576 577 578 579 580 581 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 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 register GNode*cohort;603 register LstNodeln;604 605 606 607 608 609 610 611 612 613 614 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 621 Lst_ForEach(allsrc, ParseAddDep, (ClientData)gn); 621 622 } 622 623 } … … 625 626 *----------------------------------------------------------------------- 626 627 * ParseFindMain -- 627 * 628 * 629 * 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 * 633 * 0 if main not found yet, 1 if it is. 633 634 * 634 635 * Side Effects: 635 * 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 645 GNode *gn = (GNode *) gnp; 645 646 if ((gn->type & (OP_NOTMAIN|OP_USE|OP_EXEC|OP_TRANSFORM)) == 0) { 646 647 648 647 mainNode = gn; 648 Targ_SetMain(gn); 649 return (dummy ? 1 : 1); 649 650 } else { 650 651 return (dummy ? 0 : 0); 651 652 } 652 653 } … … 655 656 *----------------------------------------------------------------------- 656 657 * ParseAddDir -- 657 * 658 * Front-end for Dir_AddDir to make sure Lst_ForEach keeps going 658 659 * 659 660 * Results: 660 * 661 * === 0 661 662 * 662 663 * Side Effects: 663 * 664 * See Dir_AddDir. 664 665 * 665 666 *----------------------------------------------------------------------- … … 667 668 static int 668 669 ParseAddDir(path, name) 669 ClientData 670 ClientData path; 670 671 ClientData name; 671 672 { … … 677 678 *----------------------------------------------------------------------- 678 679 * ParseClearPath -- 679 * 680 * Front-end for Dir_ClearPath to make sure Lst_ForEach keeps going 680 681 * 681 682 * Results: 682 * 683 * === 0 683 684 * 684 685 * Side Effects: 685 * 686 * See Dir_ClearPath 686 687 * 687 688 *----------------------------------------------------------------------- … … 699 700 *--------------------------------------------------------------------- 700 701 * ParseDoDependency -- 701 * 702 * Parse the dependency line in line. 702 703 * 703 704 * Results: 704 * 705 * None 705 706 * 706 707 * Side Effects: 707 * 708 * 709 * 710 * 708 * 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 * 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 * 719 * 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 * 724 * Certain targets are handled specially. These are the ones detailed 724 725 * by the specType variable. 725 * 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; 735 { 736 char *cp;/* our current position */737 GNode *gn;/* a general purpose temporary node */738 int op; 739 char savec; 740 Lst paths;/* List of search paths to alter when parsing741 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 746 #endif 747 Lst curTargs;/* list of target names to be found and added748 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 762 763 764 765 766 767 768 769 770 771 772 773 774 intlength;775 BooleanfreeIt;776 char*result;777 778 779 780 781 782 783 784 785 786 787 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 791 792 793 794 795 796 797 798 799 800 801 802 803 804 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 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 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 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 Lstpath;916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 LstemptyPath = Lst_Init(FALSE);946 947 948 949 950 951 952 953 954 955 956 957 958 959 char*targName = (char *)Lst_DeQueue(curTargs);960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 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 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 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 1030 op = OP_FORCE; 1030 1031 } else if (*cp == ':') { 1031 1032 1033 1034 1035 1036 1032 if (cp[1] == ':') { 1033 op = OP_DOUBLEDEP; 1034 cp++; 1035 } else { 1036 op = OP_DEPENDS; 1037 } 1037 1038 } else { 1038 1039 1040 } 1041 1042 cp++; 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 1051 cp++; 1051 1052 } 1052 1053 line = cp; … … 1055 1056 * Several special targets take different actions if present with no 1056 1057 * sources: 1057 * 1058 * 1059 * 1060 * 1061 * 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 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 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 1082 1083 1084 #endif 1085 1086 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 1091 1092 1093 1094 1095 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 1102 1103 1104 1102 if (Job_ParseShell (line) != SUCCESS) { 1103 Parse_Error (PARSE_FATAL, "improper shell specification"); 1104 return; 1105 } 1105 1106 #endif 1106 1107 *line = '\0'; 1107 1108 } else if ((specType == NotParallel) || (specType == SingleShell)) { 1108 1109 *line = '\0'; 1109 1110 } 1110 1111 … … 1113 1114 */ 1114 1115 if ((specType == Suffixes) || (specType == ExPath) || 1115 1116 (specType == Includes) || 1116 1117 #ifdef USE_ARCHIVES 1117 1118 (specType == Libs) || 1118 1119 #endif 1119 1120 (specType == Null)) 1120 1121 { 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 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 1164 1165 1166 #endif 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 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 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 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 1211 1212 1213 1214 1215 1216 1217 1218 1219 1220 1221 1222 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 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 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 1245 1246 1247 1248 1249 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 * 1262 * 1263 * 1264 * 1265 * 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 * 1269 * TRUE if it is. FALSE if it ain't 1269 1270 * 1270 1271 * Side Effects: 1271 * 1272 * none 1272 1273 *--------------------------------------------------------------------- 1273 1274 */ 1274 1275 Boolean 1275 1276 Parse_IsVar (line) 1276 register char *line; 1277 { 1278 register Boolean wasSpace = FALSE; 1279 register Boolean haveName = FALSE; 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 1283 (((c) == '+') || ((c) == ':') || ((c) == '?') || ((c) == '!')) 1283 1284 1284 1285 /* … … 1286 1287 */ 1287 1288 for (;(*line == ' ') || (*line == '\t'); line++) 1288 1289 continue; 1289 1290 1290 1291 for (; *line != '=' || level != 0; line++) 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 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 1336 1337 1338 1339 #endif 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 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 * 1360 * 1361 * 1362 * 1363 * 1364 * 1365 * 1366 * 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 * 1370 * none 1370 1371 * 1371 1372 * Side Effects: 1372 * 1373 * 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; 1379 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 1385 } type;/* Type of assignment */1386 char *opc; 1387 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 1402 line++; 1402 1403 } 1403 1404 … … 1406 1407 */ 1407 1408 for (cp = line + 1; *cp != '='; cp++) { 1408 1409 1410 1411 } 1412 opc = cp-1; 1413 *cp++ = '\0'; 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 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 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 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 #endif 1460 1461 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 1466 cp++; 1466 1467 } 1467 1468 1468 1469 if (type == VAR_APPEND) { 1469 1470 Var_Append (line, cp, ctxt); 1470 1471 } else if (type == VAR_SUBST) { 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 BooleanoldOldVars = oldVars;1483 1484 1485 1486 1487 1488 1489 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 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 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 1517 1518 1516 /* 1517 * Normal assignment -- just do it. 1518 */ 1519 Var_Set(line, cp, ctxt); 1519 1520 } 1520 1521 } … … 1523 1524 /*- 1524 1525 * ParseAddCmd -- 1525 * 1526 * Lst_ForEach function to add a command line to all targets 1526 1527 * 1527 1528 * Results: 1528 * 1529 * Always 0 1529 1530 * 1530 1531 * Side Effects: 1531 * 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; 1536 ClientData cmd; 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 1542 (void)Lst_AtEnd(gn->commands, cmd); 1542 1543 return(0); 1543 1544 } … … 1548 1549 /*- 1549 1550 * ParseAppendInline -- 1550 * 1551 * Lst_ForEach function to append the line to the last command 1551 1552 * 1552 1553 * Results: 1553 * 1554 * Always 0 1554 1555 * 1555 1556 * Side Effects: 1556 * 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; 1561 ClientData line; 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 * 1588 * returns TRUE if it is, FALSE if not. 1588 1589 * 1589 1590 * Side Effects: 1590 * 1591 * OP_HAS_COMMANDS may be set for the target. 1591 1592 * 1592 1593 *----------------------------------------------------------------------- … … 1641 1642 *----------------------------------------------------------------------- 1642 1643 * ParseHasCommands -- 1643 * 1644 * 1645 * 1646 * 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 * 1650 * None 1650 1651 * 1651 1652 * Side Effects: 1652 * 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 1663 gn->type |= OP_HAS_COMMANDS; 1663 1664 } 1664 1665 } … … 1667 1668 *----------------------------------------------------------------------- 1668 1669 * Parse_AddIncludeDir -- 1669 * 1670 * 1670 * 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 * 1674 * None. 1674 1675 * 1675 1676 * Side Effects: 1676 * 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 * 1690 * 1691 * 1692 * 1693 * 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; 1700 { 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 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 * 1720 * 1721 * 1722 * 1723 * 1724 * 1720 * 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 * 1728 * None 1728 1729 * 1729 1730 * Side Effects: 1730 * 1731 * 1731 * 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; 1737 char *file; /* file specification */ 1737 1738 char chPre; /* Preprocessor char */ 1738 1739 { 1739 char *fullname; 1740 IFile *oldFile; 1741 char endc; 1742 char *cp; 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 1750 file++; 1750 1751 } 1751 1752 1752 1753 #ifndef NMAKE 1753 1754 if ((*file != '"') && (*file != '<')) { 1754 1755 1756 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 1767 1767 isSystem = TRUE; 1768 endc = '>'; 1768 1769 } else { 1769 1770 isSystem = FALSE; 1770 1771 #ifdef NMAKE 1771 1772 if (*file == '"') 1772 1773 endc = '"'; 1773 1774 else 1774 1775 { … … 1777 1778 } 1778 1779 #else 1779 1780 endc = '"'; 1780 1781 #endif 1781 1782 } … … 1785 1786 */ 1786 1787 for (cp = ++file; *cp && *cp != endc; cp++) { 1787 1788 continue; 1788 1789 } 1789 1790 … … 1793 1794 if (*cp != endc) { 1794 1795 #endif 1795 1796 1797 1798 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 1816 1817 1818 1819 1820 1821 char*prefEnd, *Fname;1822 1823 1824 1825 1826 1827 1828 char*newName;1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841 1842 1843 1844 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 1847 fullname = (char *)NULL; 1847 1848 } 1848 1849 1849 1850 if (fullname == (char *)NULL) { 1850 1851 1852 1853 1854 1855 1856 1857 1858 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 1865 1866 1867 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 1872 1873 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 1907 1908 1909 1910 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 * 1920 * Start Parsing from the given string 1920 1921 * 1921 1922 * Results: 1922 * 1923 * None 1923 1924 * 1924 1925 * Side Effects: 1925 * 1926 * 1926 * 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; 1934 IFile *oldFile; /* state associated with this file */ 1934 1935 1935 1936 if (DEBUG(FOR)) 1936 1937 (void) fprintf(stderr, "%s\n----\n", str); 1937 1938 1938 1939 oldFile = (IFile *) emalloc (sizeof (IFile)); … … 1956 1957 *--------------------------------------------------------------------- 1957 1958 * ParseTraditionalInclude -- 1958 * 1959 * 1960 * 1961 * 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 * 1965 * None 1965 1966 * 1966 1967 * Side Effects: 1967 * 1968 * 1968 * 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; 1974 { 1975 char *fullname; 1976 IFile *oldFile; 1977 char *cp; 1978 char 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 1985 file++; 1985 1986 } 1986 1987 1987 1988 if (*file == '\0') { 1988 1989 1990 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 1998 continue; 1998 1999 } 1999 2000 … … 2019 2020 prefEnd = strrchr (fname, '/'); 2020 2021 if (prefEnd != (char *)NULL) { 2021 char*newName;2022 2023 2024 2025 2026 2027 2028 2029 2030 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 2033 fullname = (char *)NULL; 2033 2034 } 2034 2035 2035 2036 if (fullname == (char *)NULL) { 2036 2037 2038 2039 2040 2041 2042 2043 2044 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 2051 2052 2053 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 2058 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 2090 2091 2092 2093 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 * 2102 * 2103 * 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 * 2107 * CONTINUE if there's more to do. DONE if not. 2107 2108 * 2108 2109 * Side Effects: 2109 * 2110 * 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; 2118 IFile *ifile; /* the state on the top of the includes stack */ 2118 2119 2119 2120 if (Lst_IsEmpty (includes)) { 2120 2121 return (DONE); 2121 2122 } 2122 2123 … … 2126 2127 lineno = ifile->lineno; 2127 2128 if (opened && curFILE) 2128 2129 (void) fclose (curFILE); 2129 2130 if (curPTR) { 2130 2131 2131 efree((Address) curPTR->str); 2132 efree((Address) curPTR); 2132 2133 } 2133 2134 curFILE = ifile->F; … … 2140 2141 *--------------------------------------------------------------------- 2141 2142 * ParseReadc -- 2142 * 2143 * Read a character from the current file 2143 2144 * 2144 2145 * Results: 2145 * 2146 * The character that was read 2146 2147 * 2147 2148 * Side Effects: … … 2152 2153 { 2153 2154 if (curFILE) 2154 2155 return fgetc(curFILE); 2155 2156 2156 2157 if (curPTR && *curPTR->ptr) 2157 2158 return *curPTR->ptr++; 2158 2159 return EOF; 2159 2160 } … … 2163 2164 *--------------------------------------------------------------------- 2164 2165 * ParseUnreadc -- 2165 * 2166 * Put back a character to the current file 2166 2167 * 2167 2168 * Results: 2168 * 2169 * None. 2169 2170 * 2170 2171 * Side Effects: … … 2176 2177 { 2177 2178 if (curFILE) { 2178 2179 2179 ungetc(c, curFILE); 2180 return; 2180 2181 } 2181 2182 if (curPTR) { 2182 2183 2183 *--(curPTR->ptr) = c; 2184 return; 2184 2185 } 2185 2186 } … … 2187 2188 2188 2189 /* ParseSkipLine(): 2189 * 2190 * Grab the next line 2190 2191 */ 2191 2192 static char * 2192 2193 ParseSkipLine(skip) 2193 int skip; 2194 int skip; /* Skip lines that don't start with . */ 2194 2195 { 2195 2196 char *line; … … 2242 2243 *--------------------------------------------------------------------- 2243 2244 * ParseReadLine -- 2244 * 2245 * 2246 * 2247 * 2248 * 2249 * 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 * 2253 * A line w/o its newline 2253 2254 * 2254 2255 * Side Effects: 2255 * 2256 * 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; 2263 register int lastc; 2264 Boolean semiNL;/* treat semi-colons as newlines */2265 Boolean ignDepOp;/* TRUE if should ignore dependency operators2266 2267 Boolean ignComment;/* TRUE if should ignore comments (in a2268 2269 char *line;/* Result */2270 char *ep; 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 2290 c = ParseReadc(); 2290 2291 #ifdef USE_INLINEFILES 2291 2292 if (inInlineFile) … … 2293 2294 #endif 2294 2295 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 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 2313 2313 lastc = c; 2314 buf = Buf_Init(MAKE_BSIZE); 2314 2315 2315 2316 /* @todo any inline changes here? */ 2316 2317 #ifdef NMAKE 2317 2318 while (((c = ParseReadc ()) != '\n' || (lastc == '\\') || (lastc == '^')) && (c != EOF)) 2318 2319 #else 2319 2320 while (((c = ParseReadc ()) != '\n' || (lastc == '\\')) && (c != EOF)) 2320 2321 #endif 2321 2322 { 2322 2323 test_char: 2323 2324 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 2341 2342 2343 2344 2345 2346 2347 2348 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 2352 lastc = '\n'; 2352 2353 2353 2354 do { 2354 2355 while ((c = ParseReadc ()) == ' ' || c == '\t') { 2355 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 2362 2362 continue; 2363 } 2363 2364 if (c == EOF) 2364 2365 break; 2365 2366 } while (1); 2366 2367 #else 2367 2368 2369 2370 #endif 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 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 2386 case ';': 2386 2387 #ifdef USE_INLINEFILES 2387 2388 if (inInlineFile) 2388 2389 break; 2389 2390 #endif 2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405 2406 2407 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 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 2428 2429 2430 2431 2432 2433 2434 2435 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 2438 #endif 2439 2440 2441 2442 2443 2444 2445 2446 2447 2448 2449 2450 2451 2452 2453 2454 2455 2456 2457 2458 2459 2460 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 2466 2467 2468 2469 2470 2471 2472 2473 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 2478 2479 2480 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 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 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 2502 2503 2504 2505 2506 2507 2508 2509 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 2516 if (line[0] == '.' || line[0] == '!') { 2516 2517 #else 2517 2518 #endif 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 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 2569 2570 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 * 2578 * Handle the end of a dependency group. 2578 2579 * 2579 2580 * Results: 2580 * 2581 * Nothing. 2581 2582 * 2582 2583 * Side Effects: 2583 * 2584 * inLine set FALSE. 'targets' list destroyed. 2584 2585 * 2585 2586 *----------------------------------------------------------------------- … … 2589 2590 { 2590 2591 if (inLine) { 2591 2592 2593 2594 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 * 2603 * 2604 * 2603 * 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 * 2608 * None 2608 2609 * 2609 2610 * Side Effects: 2610 * 2611 * 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; 2617 FILE * stream;/* Stream open to makefile to parse */2618 { 2619 register char *cp, 2620 *line; 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 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 2637 if (*line == '.' || *line == '!') { 2637 2638 #else 2638 2639 if (*line == '.') { 2639 2640 #endif 2640 2641 2642 2643 2644 2645 2646 2647 2648 2649 2650 2651 2652 goto nextLine; 2653 2654 2655 2656 2657 2658 2659 2660 2661 2662 2663 2664 2665 2666 2667 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 2708 goto nextLine; 2708 2709 } 2709 2710 #endif 2710 2711 2711 2712 2713 2714 2715 2716 2717 2718 2719 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 2723 #endif 2724 2725 2726 2727 2728 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 2740 2741 2742 2743 2744 2745 2746 2747 2748 2749 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 2754 2755 2756 2757 2758 2759 2760 2761 #endif 2762 2763 2764 2765 2766 2767 2768 2769 2770 2771 2772 2773 2774 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 2781 2782 2783 2784 2785 2786 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 2790 2791 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 2798 2798 if (*cp == '\0') { 2799 if (inLine) { 2799 2800 #if !defined(USE_NO_STUPID_TABS) 2800 2801 2802 #endif 2803 2804 2805 2806 2807 2808 #endif 2809 2810 2811 2812 2813 2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 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 2831 2832 2833 2834 2835 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 2846 errx(1, "fatal errors encountered -- cannot continue"); 2846 2847 } 2847 2848 … … 2849 2850 *--------------------------------------------------------------------- 2850 2851 * Parse_Init -- 2851 * 2852 * initialize the parsing module 2852 2853 * 2853 2854 * Results: 2854 * 2855 * none 2855 2856 * 2856 2857 * Side Effects: 2857 * 2858 * the parseIncPath list is initialized... 2858 2859 *--------------------------------------------------------------------- 2859 2860 */ … … 2873 2874 /*Lst_Destroy(targCmds, (void (*) __P((ClientData))) efree);*/ 2874 2875 if (targets) 2875 2876 Lst_Destroy(targets, NOFREE); 2876 2877 Lst_Destroy(sysIncPath, Dir_Destroy); 2877 2878 Lst_Destroy(parseIncPath, Dir_Destroy); 2878 Lst_Destroy(includes, NOFREE); 2879 Lst_Destroy(includes, NOFREE); /* Should be empty now */ 2879 2880 } 2880 2881 … … 2883 2884 *----------------------------------------------------------------------- 2884 2885 * Parse_MainName -- 2885 * 2886 * 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 * 2890 * A Lst of the single node to create. 2890 2891 * 2891 2892 * Side Effects: 2892 * 2893 * None. 2893 2894 * 2894 2895 *----------------------------------------------------------------------- … … 2897 2898 Parse_MainName() 2898 2899 { 2899 Lst listmain; 2900 Lst listmain; /* result list */ 2900 2901 2901 2902 listmain = Lst_Init (FALSE); 2902 2903 2903 2904 if (mainNode == NILGNODE) { 2904 2905 2905 Punt ("no target to make."); 2906 /*NOTREACHED*/ 2906 2907 } else if (mainNode->type & OP_DOUBLEDEP) { 2907 2908 2908 (void) Lst_AtEnd (listmain, (ClientData)mainNode); 2909 Lst_Concat(listmain, mainNode->cohorts, LST_CONCNEW); 2909 2910 } 2910 2911 else 2911 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 * 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 * 21 * 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 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 * 56 * Initialize the strings package 56 57 * 57 58 */ … … 67 68 /* 68 69 * str_end -- 69 * 70 * Cleanup the strings package 70 71 * 71 72 */ … … 74 75 { 75 76 if (argv) { 76 77 78 77 if (argv[0]) 78 efree(argv[0]); 79 efree((Address) argv); 79 80 } 80 81 if (buffer) 81 82 efree(buffer); 82 83 } 83 84 84 85 /*- 85 86 * str_concat -- 86 * 87 * 87 * concatenate the two strings, inserting a space or slash between them, 88 * freeing them if requested. 88 89 * 89 90 * returns -- 90 * 91 * the resulting string in allocated space. 91 92 */ 92 93 char * 93 94 str_concat(s1, s2, flags) 94 95 96 { 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 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 * 133 * 134 * 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 * 138 * 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 143 144 145 { 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 argmax *= 2;/* ramp up fast */209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 done: 256 257 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 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 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 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 thisCharOK: 395 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 * 404 * Check word against pattern for a match (% is wild), 404 405 * 405 406 * Results: 406 * 407 * 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 * 411 * 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 426 427 426 /* Zero-length word cannot be matched against */ 427 *len = 0; 428 return NULL; 428 429 } 429 430 430 431 if (*p == '\0') { 431 432 433 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 438 439 440 441 442 return NULL;/* No match */443 444 445 446 447 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 456 457 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 * 469 * 470 * 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 * 474 * None 474 475 * 475 476 * Side Effects: 476 * 477 * Places result on buf 477 478 * 478 479 *----------------------------------------------------------------------- … … 488 489 489 490 if ((m = strchr(pat, '%')) != NULL) { 490 491 492 493 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 * 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 * 21 * 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 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 * 51 * 51 * 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; 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 125 int sNum; 126 int refCount;/* Reference count of list membership */127 Lst parents; 128 Lst children; 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; 137 char *pref;/* Prefix from which file was formed */138 Suff *suff; 139 struct _Src *parent; 140 GNode *node; 141 int children;/* Count of existing children (so we don't efree142 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 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 191 /*************** Lst Predicates ****************/ 190 192 /*- 191 193 *----------------------------------------------------------------------- 192 194 * SuffStrIsPrefix -- 193 * 194 * 195 * Results: 196 * 197 * 198 * Side Effects: 199 * 195 * 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; 205 register char *str; 206 register char *pref; /* possible prefix */ 207 register char *str; /* string to check */ 206 208 { 207 209 while (*str && *pref == *str) { 208 209 210 pref++; 211 str++; 210 212 } 211 213 … … 216 218 *----------------------------------------------------------------------- 217 219 * SuffSuffIsSuffix -- 218 * 219 * 220 * 221 * Results: 222 * 223 * 224 * 225 * Side Effects: 226 * 220 * 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; 232 char *str; 233 { 234 register char *p1; 235 register char *p2; 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 242 243 p1--; 244 p2--; 243 245 } 244 246 … … 249 251 *----------------------------------------------------------------------- 250 252 * SuffSuffIsSuffixP -- 251 * 252 * 253 * 254 * Results: 255 * 256 * 257 * Side Effects: 258 * 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 * 274 * 275 * 276 * Results: 277 * 278 * 279 * Side Effects: 280 * 275 * 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; 286 ClientData sname; 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 * 295 * 296 * 297 * 298 * 299 * Results: 300 * 301 * 302 * Side Effects: 303 * 296 * 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; 309 ClientData str; 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 * 318 * 319 * Results: 320 * 321 * 322 * Side Effects: 323 * 319 * 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; 329 ClientData name; 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 336 /*********** Maintenance Functions ************/ 335 337 336 338 /*- 337 339 *----------------------------------------------------------------------- 338 340 * SuffFree -- 339 * 340 * 341 * Results: 342 * 343 * 344 * Side Effects: 345 * 341 * 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 357 suffNull = NULL; 356 358 357 359 if (s == emptySuff) 358 360 emptySuff = NULL; 359 361 360 362 Lst_Destroy (s->ref, NOFREE); … … 370 372 *----------------------------------------------------------------------- 371 373 * SuffRemove -- 372 * 373 * 374 * Results: 375 * 376 * 377 * Side Effects: 378 * 374 * 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 389 390 Lst_Remove(l, ln); 391 s->refCount--; 390 392 } 391 393 } … … 395 397 *----------------------------------------------------------------------- 396 398 * SuffInsert -- 397 * 398 * 399 * 400 * Results: 401 * 402 * 403 * Side Effects: 404 * 399 * 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; 410 Suff *s; 411 { 412 LstNode ln;/* current element in l we're examining */413 Suff *s2 = NULL; 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 418 return; 417 419 } 418 420 while ((ln = Lst_Next (l)) != NILLNODE) { 419 420 421 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 429 printf("inserting %s(%d)...", s->name, s->sNum); 428 430 } 429 431 if (ln == NILLNODE) { 430 431 432 433 434 435 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 438 439 440 441 442 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 446 printf("already there\n"); 445 447 } 446 448 } … … 449 451 *----------------------------------------------------------------------- 450 452 * Suff_ClearSuffixes -- 451 * 452 * 453 * 454 * 455 * 456 * 457 * 458 * Results: 459 * 460 * 461 * Side Effects: 462 * 453 * 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 * 486 * 487 * Results: 488 * 489 * 490 * Side Effects: 491 * 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; 504 register char *str2;/* Extra pointer (maybe target suffix) */505 LstNode 506 507 Suff 508 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 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 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 * 566 * 567 * 568 * Results: 569 * 570 * 571 * 572 * Side Effects: 573 * 567 * 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; 579 { 580 Suff 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 * 589 * 590 * 591 * Results: 592 * 593 * 594 * Side Effects: 595 * 596 * 590 * 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; 602 { 603 GNode *gn; 604 Suff *s, 605 *t; 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 612 613 614 615 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 619 620 621 622 623 624 625 626 627 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 639 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 * 651 * 652 * 653 * 654 * 655 * Results: 656 * 657 * 658 * Side Effects: 659 * 660 * 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; 667 ClientData dummy; 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 674 Lst_IsEmpty(gn->children)) 673 675 { 674 Suff*s, *t;675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 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 700 printf("transformation %s complete\n", gn->name); 699 701 } 700 702 … … 705 707 *----------------------------------------------------------------------- 706 708 * SuffRebuildGraph -- 707 * 708 * 709 * 710 * 711 * 712 * 713 * 714 * Results: 715 * 716 * 717 * Side Effects: 718 * 719 * 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; 727 { 728 GNode 729 Suff 730 char 731 LstNode 732 Suff 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 740 741 742 743 744 745 746 747 748 749 750 751 752 753 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 764 765 766 767 768 769 770 771 772 773 774 775 776 777 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 * 787 * 788 * 789 * Results: 790 * 791 * 792 * Side Effects: 793 * 794 * 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; 800 { 801 Suff *s; 802 LstNode 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 807 808 s->name =estrdup (str);809 s->nameLen =strlen (s->name);810 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 819 820 821 822 823 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 * 831 * 832 * Results: 833 * 834 * 835 * 836 * Side Effects: 837 * 832 * 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 843 { 844 LstNode 845 Suff 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 851 return (NILLST); 850 852 } else { 851 852 853 s = (Suff *) Lst_Datum (ln); 854 return (s->searchPath); 853 855 } 854 856 } … … 857 859 *----------------------------------------------------------------------- 858 860 * Suff_DoPaths -- 859 * 860 * 861 * 862 * Results: 863 * 864 * 865 * Side Effects: 866 * 867 * 868 * 869 * 870 * 871 * 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 878 register LstNode 879 char 880 Lst 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 886 return; 885 887 } 886 888 … … 889 891 890 892 while ((ln = Lst_Next (sufflist)) != NILLNODE) { 891 892 893 s = (Suff *) Lst_Datum (ln); 894 if (!Lst_IsEmpty (s->searchPath)) { 893 895 #ifdef INCLUDES 894 895 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 901 902 902 if (s->flags & SUFF_LIBRARY) { 903 Dir_Concat(inLibs, s->searchPath); 904 } 903 905 #endif /* LIBRARIES */ 904 906 #endif 905 906 907 908 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 * 927 * 928 * 929 * 930 * Results: 931 * 932 * 933 * Side Effects: 934 * 928 * 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 941 { 942 LstNode 943 Suff 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 948 949 s = (Suff *) Lst_Datum (ln); 950 s->flags |= SUFF_INCLUDE; 949 951 } 950 952 } … … 954 956 *----------------------------------------------------------------------- 955 957 * Suff_AddLib -- 956 * 957 * 958 * 959 * 960 * 961 * Results: 962 * 963 * 964 * Side Effects: 965 * 958 * 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 972 { 973 LstNode 974 Suff 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 979 980 s = (Suff *) Lst_Datum (ln); 981 s->flags |= SUFF_LIBRARY; 980 982 } 981 983 } 982 984 #endif /* USE_ARCHIVES */ 983 985 984 986 /********** Implicit Source Search Functions *********/ 985 987 986 988 /*- 987 989 *----------------------------------------------------------------------- 988 990 * SuffAddSrc -- 989 * 990 * 991 * 992 * 993 * Results: 994 * 995 * 996 * Side Effects: 997 * 991 * 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; 1004 { 1005 Suff 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; 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 1015 1016 1017 1018 1019 s2->file =estrdup(targ->pref);1020 s2->pref =targ->pref;1021 s2->parent =targ;1022 s2->node =NILGNODE;1023 s2->suff =s;1024 1025 s2->children =0;1026 1027 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 1030 1031 1032 1033 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 = 1038 s2->pref = 1039 s2->file = str_concat (targ->pref, s->name, 0); 1040 s2->pref = targ->pref; 1039 1041 s2->parent = targ; 1040 s2->node = 1041 s2->suff = 1042 s2->node = NILGNODE; 1043 s2->suff = s; 1042 1044 s->refCount++; 1043 1045 s2->children = 0; … … 1058 1060 *----------------------------------------------------------------------- 1059 1061 * SuffAddLevel -- 1060 * 1061 * 1062 * Results: 1063 * 1064 * 1065 * Side Effects: 1066 * 1062 * 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; 1072 Src *targ; 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 * 1086 * 1087 * Results: 1088 * 1089 * 1090 * Side Effects: 1091 * 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 1105 return 0; 1104 1106 } 1105 1107 #ifdef DEBUG_SRC … … 1111 1113 1112 1114 while ((ln = Lst_Next (l)) != NILLNODE) { 1113 1114 1115 1116 1117 1118 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 1121 1122 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 1125 1126 --s->parent->children; 1127 } 1126 1128 #ifdef DEBUG_SRC 1127 1128 1129 printf("efree: [l=%x] p=%x %d\n", l, s, s->children); 1130 Lst_Destroy(s->cp, NOFREE); 1129 1131 #endif 1130 1131 1132 1133 1134 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 1138 1139 1140 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 * 1154 * 1155 * Results: 1156 * 1157 * 1158 * Side Effects: 1159 * 1155 * 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; 1165 Lst 1166 { 1167 Src *s; 1168 Src *rs;/* returned Src */1169 char 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 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 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 1188 printf("remove %x from %x\n", s, srcs); 1187 1189 #endif 1188 1189 1190 1191 1192 1193 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 1197 printf("remove %x from %x\n", s, srcs); 1196 1198 #endif 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 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 1212 printf ("got it\n"); 1211 1213 } 1212 1214 return (rs); … … 1216 1218 *----------------------------------------------------------------------- 1217 1219 * SuffFindCmds -- 1218 * 1219 * 1220 * 1221 * 1222 * Results: 1223 * 1224 * 1225 * Side Effects: 1226 * 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 1234 { 1235 LstNode ln;/* General-purpose list node */1236 register GNode *t,/* Target GNode */1237 *s;/* Source GNode */1238 int 1239 Suff *suff;/* Suffix on matching beastie */1240 Src *ret;/* Return value */1241 char 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 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 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 1292 1293 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 1296 1297 1298 1299 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 * 1312 * 1313 * 1314 * Results: 1315 * 1316 * 1317 * Side Effects: 1318 * 1319 * 1320 * 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; 1327 ClientData pgnp; 1328 { 1329 GNode 1330 GNode 1331 GNode *gn;/* New source 8) */1332 LstNode 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 1350 1351 1352 1353 1354 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 1359 1360 1361 1362 1363 1364 char*sacrifice = cp;1365 1366 1367 1360 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 1372 1373 1374 1375 1376 1377 char*start;1378 char*initcp = cp; /* For freeing... */1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391 1392 1393 1394 1395 1396 1397 1398 1399 1400 1401 1402 1403 1404 char*junk;1405 intlen;1406 BooleandoFree;1407 1408 1409 1410 1411 1412 1413 1414 1415 1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 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 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511 1512 1513 1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528 1529 1530 1531 1532 1533 1534 1535 1536 1537 1538 1539 1540 1541 1542 1543 1544 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 * 1555 * 1556 * 1557 * Results: 1558 * 1559 * 1560 * Side Effects: 1561 * 1562 * 1563 * 1564 * 1565 * 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 1583 1584 1585 1586 1587 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 1593 1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 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 1621 1622 1623 1624 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 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 1649 1650 Lst_ForEachFrom(tGn->children, ln, 1651 SuffExpandChildren, (ClientData)tGn); 1650 1652 } 1651 1653 … … 1664 1666 *----------------------------------------------------------------------- 1665 1667 * SuffFindArchiveDeps -- 1666 * 1667 * 1668 * Results: 1669 * 1670 * 1671 * Side Effects: 1672 * 1668 * 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 1680 { 1681 char 1682 char 1683 GNode *mem;/* Node for member */1684 static char 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'; 1700 *eoarch = '\0'; 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 1719 1720 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 1728 1729 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 1737 1738 1739 1740 1741 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 1754 1755 1756 1757 1758 LstNodeln;1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 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 1792 gn->type |= OP_DEPENDS; 1791 1793 } 1792 1794 … … 1802 1804 *----------------------------------------------------------------------- 1803 1805 * SuffFindNormalDeps -- 1804 * 1805 * 1806 * Results: 1807 * 1808 * 1809 * Side Effects: 1810 * 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 1818 { 1819 char 1820 char 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 1825 1826 Src 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 1865 1866 1867 1868 1869 int prefLen;/* Length of the prefix */1870 Src*targ;1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 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 1885 targ->cp = Lst_Init(FALSE); 1884 1886 #endif 1885 1887 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 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 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 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 1931 targ->cp = Lst_Init(FALSE); 1930 1932 #endif 1931 1933 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 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 1958 1959 1960 1961 1962 1963 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 1968 1969 1970 1971 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 1993 1994 1994 if (DEBUG(SUFF)) { 1995 printf("\tNo valid suffix on %s\n", gn->name); 1996 } 1995 1997 1996 1998 sfnd_abort: 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 intsavep = strlen(gn->path) - targ->suff->nameLen;2018 charsavec;2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 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 2079 gn->type |= OP_LIB; 2078 2080 } 2079 2081 #endif … … 2083 2085 */ 2084 2086 if (!Lst_IsEmpty(gn->children)) { 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 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 2105 2106 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 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 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 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 2161 gn->suffix->refCount--; 2160 2162 gn->suffix = src->suff; 2161 2163 gn->suffix->refCount++; … … 2173 2175 sfnd_return: 2174 2176 if (bottom) 2175 2176 2177 if (Lst_Member(slst, (ClientData) bottom) == NILLNODE) 2178 Lst_AtEnd(slst, (ClientData) bottom); 2177 2179 2178 2180 while (SuffRemoveSrc(srcs) || SuffRemoveSrc(targs)) 2179 2181 continue; 2180 2182 2181 2183 Lst_Concat(slst, srcs, LST_CONCLINK); … … 2187 2189 *----------------------------------------------------------------------- 2188 2190 * Suff_FindDeps -- 2189 * 2190 * 2191 * 2192 * Results: 2193 * 2194 * 2195 * Side Effects: 2196 * 2197 * 2198 * 2199 * 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 * 2203 * 2204 * 2205 * 2206 * 2207 * 2208 * 2209 * 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 2223 continue; 2222 2224 } 2223 2225 … … 2225 2227 static void 2226 2228 SuffFindDeps (gn, slst) 2227 GNode *gn; 2228 Lst 2229 GNode *gn; /* node we're dealing with */ 2230 Lst slst; 2229 2231 { 2230 2232 if (gn->type & OP_DEPS_FOUND) { 2231 2232 2233 2234 2233 /* 2234 * If dependencies already found, no need to do it again... 2235 */ 2236 return; 2235 2237 } else { 2236 2238 gn->type |= OP_DEPS_FOUND; 2237 2239 } 2238 2240 2239 2241 if (DEBUG(SUFF)) { 2240 2242 printf ("SuffFindDeps (%s)\n", gn->name); 2241 2243 } 2242 2244 2243 2245 #ifdef USE_ARCHIVES 2244 2246 if (gn->type & OP_ARCHV) { 2245 2247 SuffFindArchiveDeps(gn, slst); 2246 2248 } else if (gn->type & OP_LIB) { 2247 2248 2249 2250 2251 2252 2253 2254 2255 LstNodeln;2256 Suff*s;2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 2272 2273 2274 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 2279 SuffFindNormalDeps(gn, slst); 2278 2280 } 2279 2281 … … 2281 2283 *----------------------------------------------------------------------- 2282 2284 * Suff_SetNull -- 2283 * 2284 * 2285 * Results: 2286 * 2287 * 2288 * Side Effects: 2289 * 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 * 2293 * 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; 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 2307 2308 2309 2310 2311 2312 2313 2314 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 2317 2318 Parse_Error (PARSE_WARNING, "Desired null suffix %s not defined.", 2319 name); 2318 2320 } 2319 2321 } … … 2322 2324 *----------------------------------------------------------------------- 2323 2325 * Suff_Init -- 2324 * 2325 * 2326 * Results: 2327 * 2328 * 2329 * Side Effects: 2330 * 2326 * 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 = 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 = 2355 suffNull->ref = 2356 suffNull->sNum = 2357 suffNull->flags = 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 * 2367 * 2368 * Results: 2369 * 2370 * 2371 * Side Effects: 2372 * 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 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 2405 int 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 2412 2413 2414 2415 2416 2417 2418 2419 2420 2421 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 2424 2425 2425 case SUFF_LIBRARY: 2426 printf ("LIBRARY"); 2427 break; 2426 2428 #endif 2427 2428 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 * 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 * 21 * 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 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 * 51 * 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 * 61 * 62 * 63 * 64 * Targ_FindNodeFind the node for a given target, creating65 * 66 * 67 * 68 * Targ_FindListGiven a list of names, find nodes for all69 * 70 * 71 * 72 * 73 * 74 * Targ_IgnoreReturn TRUE if errors should be ignored when75 * 76 * 77 * Targ_SilentReturn TRUE if we should be silent when78 * 79 * 80 * Targ_PreciousReturn TRUE if the target is precious and81 * 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 * 110 * 111 * Results: 112 * 113 * 114 * Side Effects: 115 * 111 * 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 * 129 * 130 * Results: 131 * 132 * 133 * Side Effects: 134 * 130 * 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 144 Lst_Destroy(allGNs, TargFreeGN); 143 145 Hash_DeleteTable(&targets); 144 146 } … … 147 149 *----------------------------------------------------------------------- 148 150 * Targ_NewGN -- 149 * 150 * 151 * Results: 152 * 153 * 154 * 155 * Side Effects: 156 * 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; 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 172 gn->type = OP_LIB; 171 173 } else { 172 174 gn->type = 0; 173 175 } 174 176 #else 175 177 gn->type = 0; 176 178 #endif 177 gn->unmade = 178 gn->make = 179 gn->made = 180 gn->childMade = 181 gn->order = 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 = 184 gn->cohorts = 185 gn->parents = 186 gn->children = 187 gn->successors = 188 gn->preds = 189 gn->context = 190 gn->commands = 191 gn->suffix = 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 196 allGNs = Lst_Init(FALSE); 195 197 Lst_AtEnd(allGNs, (ClientData) gn); 196 198 … … 201 203 *----------------------------------------------------------------------- 202 204 * TargFreeGN -- 203 * 204 * 205 * Results: 206 * 207 * 208 * Side Effects: 209 * 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 * 238 * 239 * Results: 240 * 241 * 242 * 243 * 244 * Side Effects: 245 * 239 * 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; 251 int flags; 252 253 { 254 GNode *gn; 255 Hash_Entry *he;/* New or used hash entry for node */256 Boolean 257 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 262 263 264 265 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 270 he = Hash_FindEntry (&targets, name); 269 271 } 270 272 271 273 if (he == (Hash_Entry *) NULL) { 272 274 return (NILGNODE); 273 275 } else { 274 276 return ((GNode *) Hash_GetValue (he)); 275 277 } 276 278 } … … 279 281 *----------------------------------------------------------------------- 280 282 * Targ_FindList -- 281 * 282 * 283 * Results: 284 * 285 * 286 * 287 * Side Effects: 288 * 289 * 290 * 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; 297 298 { 299 Lst nodes; 300 register LstNode ln; 301 register GNode *gn; 302 char 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 309 return (nodes); 308 310 } 309 311 while ((ln = Lst_Next (names)) != NILLNODE) { 310 311 312 313 314 315 316 317 318 319 320 321 322 323 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 * 334 * 335 * Results: 336 * 337 * 338 * Side Effects: 339 * 335 * 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; 346 GNode *gn; /* node to check for */ 345 347 { 346 348 if (ignoreErrors || gn->type & OP_IGNORE) { 347 349 return (TRUE); 348 350 } else { 349 351 return (FALSE); 350 352 } 351 353 } … … 354 356 *----------------------------------------------------------------------- 355 357 * Targ_Silent -- 356 * 357 * 358 * Results: 359 * 360 * 361 * Side Effects: 362 * 358 * 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; 369 GNode *gn; /* node to check for */ 368 370 { 369 371 if (beSilent || gn->type & OP_SILENT) { 370 372 return (TRUE); 371 373 } else { 372 374 return (FALSE); 373 375 } 374 376 } … … 377 379 *----------------------------------------------------------------------- 378 380 * Targ_Precious -- 379 * 380 * 381 * Results: 382 * 383 * 384 * Side Effects: 385 * 381 * 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; 392 GNode *gn; /* the node to check */ 391 393 { 392 394 if (allPrecious || (gn->type & (OP_PRECIOUS|OP_DOUBLEDEP))) { 393 395 return (TRUE); 394 396 } else { 395 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 * 406 * 407 * 408 * Results: 409 * 410 * 411 * Side Effects: 412 * 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; 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 427 ClientData ppath; 426 428 { 427 429 GNode *gn = (GNode *) gnp; … … 429 431 #ifdef notdef 430 432 if (ppath) { 431 432 433 434 435 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 * 456 * 457 * Results: 458 * 459 * 460 * Side Effects: 461 * 462 * 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 471 static char 472 struct tm *parts; 473 static char buf[128]; 472 474 473 475 parts = localtime(&time); … … 487 489 *----------------------------------------------------------------------- 488 490 * Targ_PrintType -- 489 * 490 * 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) 506 #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) 509 #define PRINTDBIT(attr) 510 #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 516 517 518 519 520 521 522 523 524 525 526 527 528 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 532 PRINTDBIT(LIB); 531 533 /*XXX: MEMBER is defined, so CONCAT(OP_,MEMBER) gives OP_"%" */ 532 533 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 * 544 * print the contents of a node 543 545 *----------------------------------------------------------------------- 544 546 */ … … 546 548 TargPrintNode (gnp, passp) 547 549 ClientData gnp; 548 ClientData 550 ClientData passp; 549 551 { 550 552 GNode *gn = (GNode *) gnp; 551 int 553 int pass = *(int *) passp; 552 554 if (!OP_NOP(gn->type)) { 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 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 * 618 * 619 * Results: 620 * 621 * 622 * Side Effects: 623 * 619 * 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 630 ClientData 631 { 632 GNode 631 ClientData gnp; 632 ClientData dummy; 633 { 634 GNode *gn = (GNode *) gnp; 633 635 if (OP_NOP(gn->type)) 634 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 * 643 * 644 * Results: 645 * 646 * 647 * Side Effects: 648 * 644 * 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 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 30 30 sprintf(buf, "Unknown error %d", e); 31 return buf; 31 32 } 32 33 else 33 34 return sys_errlist[e]; 34 35 } 35 36 #endif … … 50 51 51 52 if (str == NULL) 52 53 return NULL; 53 54 len = strlen(str) + 1; 54 55 if ((p = emalloc(len)) == NULL) 55 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 79 return -1; 78 80 79 81 p = ptr; 80 82 81 83 while (*name) 82 84 *p++ = *name++; 83 85 84 86 *p++ = '='; 85 87 86 88 while (*value) 87 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 * 162 * Like strcpy, going backwards and returning the new pointer 160 163 */ 161 164 static char * … … 166 169 167 170 while (len) 168 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 188 189 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 199 200 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 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 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 341 return SIG_ERR; 339 342 else 340 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 * 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 * 21 * 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 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 * 51 * Variable-handling functions 51 52 * 52 53 * Interface: 53 * Var_SetSet the value of a variable in the given54 * 55 * 56 * 57 * 58 * Var_AppendAppend more characters to an existing variable59 * 60 * 61 * 62 * 63 * 64 * Var_ExistsSee if a variable exists.65 * 66 * Var_ValueReturn the value of a variable in a context or67 * 68 * 69 * Var_SubstSubstitute named variable, or all variables if70 * 71 * 72 * 73 * 74 * 75 * Var_ParseParse a variable expansion from a string and76 * 77 * 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 * 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 109 char var_Error[] = ""; 109 110 110 111 /* … … 113 114 * identical string instances... 114 115 */ 115 static char 116 static char varNoError[] = ""; 116 117 117 118 /* 118 119 * Internally, variables are contained in four different contexts. 119 * 120 * 121 * 122 * 123 * 124 * 125 * 126 * 127 * 128 * 129 * 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 137 138 #define FIND_CMD 139 #define FIND_GLOBAL 140 #define FIND_ENV 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; 144 Buffer val;/* its value */145 int flags;/* miscellaneous status flags */146 #define VAR_IN_USE 1/* Variable's value currently being used.147 148 #define VAR_FROM_ENV 2/* Variable comes from the environment */149 #define VAR_JUNK 4/* Variable is a junk variable that150 151 152 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 166 char *rhs;/* Replacement string (w/ &'s removed) */167 int 168 int 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 173 int 174 regmatch_t 175 char 176 int 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 200 VarPattern *)); 200 201 static char *VarQuote __P((char *)); 201 202 static char *VarModify __P((char *, Boolean (*)(char *, Boolean, Buffer, 202 203 203 ClientData), 204 ClientData)); 204 205 static int VarPrintVar __P((ClientData, ClientData)); 205 206 … … 207 208 *----------------------------------------------------------------------- 208 209 * VarCmp -- 209 * 210 * 211 * 212 * Results: 213 * 214 * 215 * Side Effects: 216 * 210 * 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; 222 ClientData name; 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 * 231 * 232 * 233 * Results: 234 * 235 * 236 * Side Effects: 237 * 231 * 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 * 254 * 255 * 256 * Results: 257 * 258 * 259 * 260 * Side Effects: 261 * 254 * 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 270 271 272 273 274 { 275 Boolean 276 LstNode 277 Var 278 279 280 281 282 283 284 285 286 287 288 289 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 292 292 if (!strcmp(name, ".ARCHIVE")) 293 name = ARCHIVE; 293 294 #endif 294 295 296 297 298 295 break; 296 case 'I': 297 if (!strcmp(name, ".IMPSRC")) 298 name = IMPSRC; 299 break; 299 300 #ifdef USE_ARCHIVES 300 301 302 303 301 case 'M': 302 if (!strcmp(name, ".MEMBER")) 303 name = MEMBER; 304 break; 304 305 #endif 305 306 307 308 309 310 311 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 317 318 319 320 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 329 (int (*)(ClientData, ClientData)) VarStrCmp) != NILLNODE) 329 330 { 330 331 localCheckEnvFirst = TRUE; 331 332 } else { 332 333 localCheckEnvFirst = FALSE; 333 334 } 334 335 … … 341 342 342 343 if ((var == NILLNODE) && (flags & FIND_CMD) && (ctxt != VAR_CMD)) { 343 344 var = Lst_Find (VAR_CMD->context, (ClientData)name, VarCmp); 344 345 } 345 346 if ((var == NILLNODE) && (flags & FIND_GLOBAL) && (ctxt != VAR_GLOBAL) && 346 347 !checkEnvFirst && !localCheckEnvFirst) 347 348 { 348 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 353 353 const char *env; 354 if ((env = kEnvGet (name)) != NULL) { 354 355 #else 355 356 char *env; 356 357 if ((env = getenv (name)) != NULL) { 357 358 #endif 358 intlen;359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 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 384 return ((Var *) NIL); 384 385 } else { 385 386 return ((Var *) Lst_Datum (var)); 386 387 } 387 388 } … … 390 391 *----------------------------------------------------------------------- 391 392 * VarAdd -- 392 * 393 * 394 * Results: 395 * 396 * 397 * Side Effects: 398 * 399 * 400 * 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; 406 char *val; 407 GNode *ctxt; 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 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 426 printf("%s:%s = %s\n", ctxt->name, name, val); 426 427 } 427 428 } … … 431 432 *----------------------------------------------------------------------- 432 433 * VarDelete -- 433 * 434 * 435 * Results: 436 * 437 * 438 * Side Effects: 439 * 434 * 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 * 458 * 459 * Results: 460 * 461 * 462 * Side Effects: 463 * 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 470 GNode 471 { 472 LstNode 470 char *name; 471 GNode *ctxt; 472 { 473 LstNode ln; 473 474 474 475 if (DEBUG(VAR)) { 475 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 482 483 484 485 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 * 493 * 494 * Results: 495 * 496 * 497 * Side Effects: 498 * 499 * 493 * 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 * 503 * 504 * 505 * 506 * 507 * 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; 513 char *val; 514 GNode *ctxt; 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 526 VarAdd (name, val, ctxt); 526 527 } else { 527 528 529 530 531 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 543 setenv(name, val, 1); 543 544 #endif 544 545 } … … 548 549 *----------------------------------------------------------------------- 549 550 * Var_Append -- 550 * 551 * 552 * 553 * Results: 554 * 555 * 556 * Side Effects: 557 * 558 * 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 * 562 * 563 * 564 * 565 * 566 * 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; 572 char *val; 573 GNode *ctxt; 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 581 VarAdd (name, val, ctxt); 581 582 } else { 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 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 * 607 * 608 * Results: 609 * 610 * 611 * Side Effects: 612 * 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 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 627 return(FALSE); 627 628 } else if (v->flags & VAR_FROM_ENV) { 628 629 630 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 * 639 * 640 * Results: 641 * 642 * 643 * Side Effects: 644 * 639 * 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; 650 GNode *ctxt; 651 char 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 659 660 661 662 663 664 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 667 return ((char *) NULL); 667 668 } 668 669 } … … 671 672 *----------------------------------------------------------------------- 672 673 * VarHead -- 673 * 674 * 675 * 676 * Results: 677 * 678 * 679 * 680 * Side Effects: 681 * 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 690 Buffer buf;/* Buffer in which to store it */691 ClientData 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 698 699 700 701 702 703 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 707 708 709 710 711 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 * 721 * 722 * 723 * Results: 724 * 725 * 726 * 727 * Side Effects: 728 * 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 737 Buffer buf;/* Buffer in which to store it */738 ClientData 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 744 Buf_AddByte (buf, (Byte)' '); 744 745 } 745 746 746 747 slash = strrchr (word, '/'); 747 748 if (slash != (char *)NULL) { 748 749 750 749 *slash++ = '\0'; 750 Buf_AddBytes (buf, strlen(slash), (Byte *)slash); 751 slash[-1] = '/'; 751 752 } else { 752 753 Buf_AddBytes (buf, strlen(word), (Byte *)word); 753 754 } 754 755 return (dummy ? TRUE : TRUE); … … 758 759 *----------------------------------------------------------------------- 759 760 * VarSuffix -- 760 * 761 * 762 * Results: 763 * 764 * 765 * 766 * Side Effects: 767 * 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 776 Buffer buf;/* Buffer in which to store it */777 ClientData 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 784 785 786 787 788 789 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 * 798 * 799 * 800 * Results: 801 * 802 * 803 * 804 * Side Effects: 805 * 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 814 Buffer buf;/* Buffer in which to store it */815 ClientData 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 821 Buf_AddByte (buf, (Byte)' '); 821 822 } 822 823 823 824 dot = strrchr (word, '.'); 824 825 if (dot != (char *)NULL) { 825 826 827 826 *dot = '\0'; 827 Buf_AddBytes (buf, strlen (word), (Byte *)word); 828 *dot = '.'; 828 829 } else { 829 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 * 839 * 840 * 841 * Results: 842 * 843 * 844 * 845 * Side Effects: 846 * 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 855 Buffer buf;/* Buffer in which to store it */856 ClientData 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 862 Buf_AddByte (buf, (Byte)' '); 862 863 } 863 864 864 865 slash = strrchr (word, '/'); 865 866 if (slash != (char *)NULL) { 866 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 878 slash[-1] = '/'; 878 879 } else { 879 880 register char *dot; 880 881 dot = strrchr (slash, '.'); 881 882 if (dot) … … 896 897 *----------------------------------------------------------------------- 897 898 * VarMatch -- 898 * 899 * 900 * 901 * Results: 902 * 903 * 904 * 905 * Side Effects: 906 * 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 915 916 Buffer buf;/* Buffer in which to store it */917 ClientData pattern; 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 921 922 923 924 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 * 934 * 935 * 936 * 937 * Results: 938 * 939 * 940 * 941 * Side Effects: 942 * 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 951 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 958 VarPattern *pat = (VarPattern *) patp; 958 959 959 960 if (addSpace) 960 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 966 Str_SYSVSubst(buf, pat->rhs, ptr, len); 966 967 else 967 968 Buf_AddBytes(buf, strlen(word), (Byte *) word); 968 969 969 970 return(addSpace); … … 975 976 *----------------------------------------------------------------------- 976 977 * VarNoMatch -- 977 * 978 * 979 * 980 * Results: 981 * 982 * 983 * 984 * Side Effects: 985 * 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 994 995 Buffer buf;/* Buffer in which to store it */996 ClientData pattern; 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 1000 1001 1002 1003 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 * 1013 * 1014 * 1015 * Results: 1016 * 1017 * 1018 * Side Effects: 1019 * 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 1027 1028 Buffer buf;/* Buffer for result */1029 ClientData 1030 { 1031 register int 1032 register char *cp;/* General pointer */1033 VarPattern 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 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135 1136 1137 1138 1139 1140 1141 1142 1143 1144 1145 1146 1147 1148 1149 1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162 1163 1164 1165 1166 1167 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 1172 Buf_AddByte(buf, (Byte)' '); 1172 1173 } 1173 1174 Buf_AddBytes(buf, wordLen, (Byte *)word); … … 1178 1179 *----------------------------------------------------------------------- 1179 1180 * VarREError -- 1180 * 1181 * 1182 * Results: 1183 * 1184 * 1185 * Side Effects: 1186 * 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 * 1211 * 1212 * 1213 * Results: 1214 * 1215 * 1216 * Side Effects: 1217 * 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 1236 #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 1246 1246 (VAR_SUB_ONE|VAR_SUB_MATCHED)) 1247 xrv = REG_NOMATCH; 1247 1248 else { 1248 1249 tryagain: 1249 1250 xrv = regexec(&pat->re, wp, pat->nsub, pat->matches, flags); 1250 1251 } 1251 1252 1252 1253 switch (xrv) { 1253 1254 case 0: 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 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 1327 VarREError(xrv, &pat->re, "Unexpected regex error"); 1327 1328 /* fall through */ 1328 1329 case REG_NOMATCH: 1329 1330 1331 1332 1333 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 * 1343 * 1344 * 1345 * Results: 1346 * 1347 * 1348 * Side Effects: 1349 * 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 1357 Boolean 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 1363 1364 char **av; 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 1374 addSpace = (*modProc)(av[i], addSpace, buf, datum); 1374 1375 1375 1376 Buf_AddByte (buf, '\0'); … … 1382 1383 *----------------------------------------------------------------------- 1383 1384 * VarGetPattern -- 1384 * 1385 * 1386 * 1387 * 1388 * 1389 * 1390 * 1391 * 1392 * 1393 * Results: 1394 * 1395 * 1396 * 1397 * 1398 * 1399 * Side Effects: 1400 * 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 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 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446 intlen;1447 1448 1449 1450 1451 1452 1453 1454 1455 1456 1457 1458 1459 1460 1461 1462 1463 1464 1465 1466 1467 1468 1469 1470 1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481 1482 1483 1484 1485 1486 1487 1488 1489 1490 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 1497 1498 1497 *tstr = cp; 1498 *length = 0; 1499 return NULL; 1499 1500 } 1500 1501 else { 1501 1502 1503 *length -= 1;/* Don't count the NULL */1504 1505 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 * 1514 * 1515 * Results: 1516 * 1517 * 1518 * Side Effects: 1519 * 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 1526 { 1527 1528 Buffer 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 1535 1536 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 * 1548 * 1549 * 1550 * 1551 * Results: 1552 * 1553 * 1554 * 1555 * 1556 * 1557 * 1558 * 1559 * Side Effects: 1560 * 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; 1573 Var *v;/* Variable in invocation */1574 char *cp;/* Secondary pointer into str (place marker1575 1576 Boolean 1577 register char endc; 1578 1579 register char startc=0; 1580 1581 int cnt; 1582 1583 char 1584 char 1585 Boolean dynamic;/* TRUE if the variable is local and we're1586 1587 1588 1589 int vlen;/* length of variable name, after embedded variable1590 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 1600 1601 1602 1603 charname[2];1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 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 1634 1633 case '^': 1634 return("$(.PARENTS)"); 1635 1635 #endif 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 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 1649 Bufferbuf = Buf_Init(MAKE_BSIZE);1650 1651 1652 1653 1654 1655 1656 1657 1658 1659 1660 intrlen;1661 Booleanrfree;1662 char*rval = Var_Parse(tstr, ctxt, err, &rlen, &rfree);1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 #if defined(NMAKE) || defined(KMK)1695 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 1697 (vlen == 2) && (str[1] == 'F' || str[1] == 'D')) 1698 1698 #endif 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 #if defined(NMAKE) || defined(KMK)1731 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 1740 1741 1742 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 1767 str[1] == 'D')))) && 1769 1768 #endif 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 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 1786 case '^': 1788 1787 #endif 1789 1790 1791 1792 1793 1794 1795 1796 intlen;1797 1798 1799 1800 1801 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 1802 (strncmp(str, ".PARENTS", len) == 0) || 1804 1803 #endif 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 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 1845 1843 Fatal("Variable %s is recursive.", v->name); 1844 /*NOTREACHED*/ 1846 1845 } else { 1847 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 1861 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 * 1871 * 1872 * 1873 * 1874 * 1875 * 1876 * :HSubstitute the head of each word1877 * :TSubstitute the tail of each word1878 * :ESubstitute the extension (minus '.') of1879 * 1880 * :RSubstitute the root of each word1881 * 1882 * :lhs=rhsLike :S, but the rhs goes to the end of1883 * 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 1890 1891 1892 1893 char*newStr; /* New value to return */1894 char termc;/* Character which terminated scan */1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964 1965 1966 1967 1968 1969 1970 1971 1972 1973 1974 1975 1976 1977 1978 1979 1980 1981 1982 1983 1984 1985 1986 1987 VarPatternpattern;1988 1989 Buffer buf;/* Buffer for patterns */1990 1991 1992 1993 1994 1995 1996 1997 1998 1999 2000 2001 2002 2003 2004 2005 2006 2007 2008 2009 2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021 2022 2023 2024 2025 2026 2027 2028 char*cp2;2029 intlen;2030 BooleanfreeIt;2031 2032 2033 2034 2035 2036 2037 2038 2039 2040 2041 2042 2043 2044 2045 2046 2047 2048 2049 2050 2051 2052 2053 2054 2055 2056 2057 2058 2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071 2072 2073 2074 2075 2076 2077 2078 2079 2080 2081 2082 2083 2084 2085 2086 2087 2088 2089 2090 2091 2092 2093 2094 2095 2096 2097 2098 2099 intlen;2100 2101 2102 2103 2104 2105 2106 2107 2108 2109 2110 2111 2112 2113 2114 2115 2116 2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127 2128 2129 2130 2131 2132 2133 2134 2135 2136 2137 2138 2139 2140 2141 2142 2143 2144 2145 2146 2147 2148 2149 2150 2151 2152 2153 2154 2155 2156 2157 2158 2159 2160 char*re;2161 interror;2162 2163 2164 2165 2166 2167 2168 2169 2170 2171 2172 2173 2174 2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192 2193 2194 2195 2196 2197 2198 2199 2200 2201 2202 2203 2204 2205 2206 2207 2208 2209 2210 2211 if (error){2212 2213 2214 2215 2216 2217 2218 2219 2220 2221 2222 2223 2224 2225 2226 2227 2228 2229 2230 2231 2232 2233 2234 2235 2236 2237 2238 2239 2240 2241 2242 2243 2244 2245 2246 2247 2248 2249 2250 2251 2252 2253 2254 2255 2256 2257 2258 2259 2260 2261 2262 2263 2264 2265 2266 2267 2268 2269 2270 2271 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 2274 2275 2276 2277 2278 2279 2280 2281 2282 2283 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 2286 2284 default: 2285 { 2287 2286 #if defined(SYSVVARSUB) || defined(NMAKE) 2288 2289 2290 2291 2292 2293 2294 2295 2296 2297 2298 2299 2300 2301 2302 2303 2304 2305 2306 2307 2308 2309 2310 2311 2312 2313 2314 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 2318 2319 2320 2321 2322 2323 2324 2325 2326 2327 2328 2329 2330 2331 2332 2333 2334 2335 2336 2337 2338 2339 2340 2341 2342 2343 2344 2345 2346 2347 2348 2349 2350 2351 2352 2353 2354 2355 2316 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 2359 2360 2361 2362 2363 2364 2365 2366 2367 2368 2369 2370 2371 2372 2373 2374 2375 2376 2377 2378 2379 2380 2381 2382 2383 2384 2385 2386 2387 2388 2389 2390 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 2393 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 2400 2401 2402 2403 2404 2405 2406 2407 2408 2409 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 2413 2414 2415 2416 2417 2418 2419 2420 2421 2422 2423 2424 2425 2426 2427 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 * 2437 * 2438 * 2439 * 2440 * Results: 2441 * 2442 * 2443 * Side Effects: 2444 * 2435 * 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; 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 2460 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 2467 2468 2469 2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482 2483 2484 2485 2486 2487 2488 2489 2490 2491 2492 2493 2494 2495 2496 2497 2498 2499 2500 2501 2502 2503 2504 2505 2506 2507 2508 2509 2510 2511 2512 2513 2514 2515 2516 2517 2518 2519 2520 2521 2522 2523 2524 2525 2526 2527 2528 2529 2530 2531 2532 2533 2534 2535 2536 2537 2538 2539 2540 2541 2542 2543 2544 2545 2546 2547 2548 2549 2550 2551 2552 2553 2554 2555 2556 2557 2558 2559 2560 2561 2562 2563 2564 2565 2566 2567 2568 2569 2570 2571 2572 2573 2574 2575 2576 2577 2578 2579 2580 2581 2582 2583 2584 2585 2586 2587 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 * 2603 * 2604 * 2605 * Results: 2606 * 2607 * 2608 * Side Effects: 2609 * 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 * 2624 * 2625 * 2626 * 2627 * Results: 2628 * 2629 * 2630 * Side Effects: 2631 * 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 * 2646 * 2647 * Results: 2648 * 2649 * 2650 * Side Effects: 2651 * 2644 * 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 * 2684 * 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.