~ chicken-core (master) /chicken-do.c
Trap1/* chicken-do2;3; Execute command if dependency changed or target is out of date.4;5; Copyright (c) 2017-2022, The CHICKEN Team6; All rights reserved.7;8; Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following9; conditions are met:10;11; Redistributions of source code must retain the above copyright notice, this list of conditions and the following12; disclaimer.13; Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following14; disclaimer in the documentation and/or other materials provided with the distribution.15; Neither the name of the author nor the names of its contributors may be used to endorse or promote16; products derived from this software without specific prior written permission.17;18; THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS19; OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY20; AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR21; CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR22; CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR23; SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY24; THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR25; OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE26; POSSIBILITY OF SUCH DAMAGE.27*/282930#include "chicken.h"3132#ifdef WIN3233# include <windows.h>34# include <sys/types.h>35#else36# include <sys/wait.h>37#endif3839#include <sys/stat.h>40#include <errno.h>4142#define MAX_TARGETS 25643#define MAX_DEPENDS 10244445#ifdef WIN3246# define MAX_COMMAND_LEN 3276747#endif4849static char *targets[ MAX_TARGETS ];50static char *depends[ MAX_DEPENDS ];51static struct stat tstats[ MAX_TARGETS ];52static char **cmd;53static int opts = 1;54static int quiet = 0;555657static void usage(int code)58{59 fputs("usage: chicken-do [-q] [-h] [--] TARGET ... : DEPENDENCY ... : COMMAND ...\n", stderr);60 exit(code);61}626364static void cleanup()65{66 char **t;6768 for(t = targets; *t != NULL; ++t)69#ifdef WIN3270 DeleteFile(*t);71#else72 unlink(*t);73#endif74}757677static int execute(char **argv)78{79#ifdef WIN3280 static PROCESS_INFORMATION process_info;81 static STARTUPINFO startup_info;82 static TCHAR cmdline[ MAX_COMMAND_LEN ];83 static int len;8485 ZeroMemory(&process_info, sizeof(PROCESS_INFORMATION));86 ZeroMemory(&startup_info, sizeof(STARTUPINFO));87 startup_info.cb = sizeof(STARTUPINFO);8889 /* quote command arguments */90 while(*argv != NULL) {91 len += snprintf(cmdline + len, sizeof(cmdline) - len, "%s ", *(argv++));92 if(len > sizeof(cmdline)) {93 fprintf(stderr, "argument list too long\n");94 exit(1);95 }96 }9798 if(!CreateProcess(NULL, cmdline, NULL, NULL, TRUE,99 NORMAL_PRIORITY_CLASS, NULL, NULL, &startup_info,100 &process_info)) {101 fprintf(stderr, "creating subprocess failed (%ld)\n", GetLastError());102 exit(1);103 }104105 WaitForSingleObject(process_info.hProcess, INFINITE);106 DWORD code;107108 if(!GetExitCodeProcess(process_info.hProcess, &code)) {109 fprintf(stderr, "unable to obtain exit status of subprocess\n");110 exit(1);111 }112 CloseHandle(process_info.hProcess);113 CloseHandle(process_info.hThread);114115116 return code;117#else118 pid_t child = fork();119120 if(child == -1) {121 perror("forking subprocess failed");122 exit(1);123 }124125 if(child == 0) {126 execvp(argv[ 0 ], argv);127 /* returns only in case of error */128 perror("executing command failed");129 cleanup();130 exit(1);131 }132133 for(;;) {134 int status;135 pid_t w = waitpid(child, &status, 0);136137 if(w == -1) {138 perror("waiting for subprocess failed");139 cleanup();140 exit(1);141 }142143 if(WIFEXITED(status))144 return WEXITSTATUS(status);145146 if(WIFSIGNALED(status)) {147 fprintf(stderr, "subprocess killed by signal %d\n", WTERMSIG(status));148 cleanup();149 exit(1);150 }151 }152#endif153}154155156int main(int argc, char *argv[])157{158 int i, a = 0;159 struct stat *st, sd;160 char **t = targets;161 char **d = depends;162163 if(argc < 3) usage(1);164165 for(i = 1; i < argc; ++i) {166 if(!strcmp(argv[ i ], ":")) {167 *t = NULL;168 break;169 }170171 if(opts && *argv[ i ] == '-') {172 switch(argv[ i ][ 1 ]) {173 case 'q': quiet = 1; break;174 case 'h': usage(0);175 case '-': opts = 0; break;176 default: usage(1);177 }178 }179 else if(t >= targets + MAX_TARGETS) {180 fprintf(stderr, "too many targets\n");181 exit(1);182 }183 else *(t++) = argv[ i ];184 }185186 if(i == argc) usage(1);187188 while(++i < argc) {189 if(!strcmp(argv[ i ], ":")) {190 *d = NULL;191 break;192 }193194 if(d >= depends + MAX_DEPENDS) {195 fprintf(stderr, "too many dependencies\n");196 exit(1);197 }198199 *(d++) = argv[ i ];200 }201202 if(i == argc) usage(1);203204 cmd = argv + i + 1;205 st = tstats;206207 for(t = targets; *t != NULL; ++t) {208 if(stat(*t, st++) == -1) {209 if(errno == ENOENT) goto build;210211 fprintf(stderr, "%s: %s\n", *t, strerror(errno));212 exit(1);213 }214 }215216 for(d = depends; *d != NULL; ++d) {217 if(stat(*d, &sd) == -1) {218 fprintf(stderr, "%s: %s\n", *d, strerror(errno));219 exit(1);220 }221222 st = tstats;223224 for(t = targets; *t != NULL; ++t) {225 if(sd.st_mtime > (st++)->st_mtime) goto build;226 }227 }228229 return 0;230231build:232 if(!quiet) {233 fputs(" ", stdout);234235 for(t = cmd; *t != NULL; ++t)236 printf(" %s", *t);237238 putchar('\n');239 fflush(stdout);240 }241242 int s = execute(cmd);243244 if(s != 0) cleanup();245246 return s;247}