mamake.c 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464
  1. /***********************************************************************
  2. * *
  3. * This software is part of the ast package *
  4. * Copyright (c) 1990-2013 AT&T Intellectual Property *
  5. * Copyright (c) 2020-2022 Contributors to ksh 93u+m *
  6. * and is licensed under the *
  7. * Eclipse Public License, Version 2.0 *
  8. * *
  9. * A copy of the License is available at *
  10. * https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html *
  11. * (with md5 checksum 84283fa8859daf213bdda5a9f8d1be1d) *
  12. * *
  13. * Glenn Fowler <gsf@research.att.com> *
  14. * Martijn Dekker <martijn@inlv.org> *
  15. * *
  16. ***********************************************************************/
  17. #pragma clang diagnostic ignored "-Wdeprecated-register"
  18. #pragma clang diagnostic ignored "-Wparentheses"
  19. /*
  20. * mamake -- MAM make
  21. *
  22. * coded for portability
  23. */
  24. #define RELEASE_DATE "2022-07-15"
  25. static char id[] = "\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\0\n";
  26. #if _PACKAGE_ast
  27. #include <ast.h>
  28. #include <error.h>
  29. static const char usage[] =
  30. "[-?\n@(#)$Id: mamake (ksh 93u+m) " RELEASE_DATE " $\n]"
  31. "[-author?Glenn Fowler <gsf@research.att.com>]"
  32. "[-author?Contributors to https://github.com/ksh93/ksh]"
  33. "[-copyright?(c) 1994-2012 AT&T Intellectual Property]"
  34. "[-copyright?(c) 2020-2022 Contributors to ksh 93u+m]"
  35. "[-license?https://www.eclipse.org/org/documents/epl-2.0/EPL-2.0.html]"
  36. "[+NAME?mamake - make abstract machine make]"
  37. "[+DESCRIPTION?\bmamake\b reads \amake abstract machine\a target and"
  38. " prerequisite file descriptions from a mamfile (see \b-f\b) and executes"
  39. " actions to update targets that are older than their prerequisites."
  40. " Mamfiles are portable to environments that only have"
  41. " \bsh\b(1) and \bcc\b(1).]"
  42. "[+?Mamfiles are used rather than"
  43. " old-\bmake\b makefiles because some features are not reliably supported"
  44. " across all \bmake\b variants:]{"
  45. " [+action execution?Multi-line actions are executed as a"
  46. " unit by \b$SHELL\b. There are some shell constructs"
  47. " that cannot be expressed in an old-\bmake\b makefile.]"
  48. " [+viewpathing?\bVPATH\b is properly interpreted. This allows"
  49. " source to be separate from generated files.]"
  50. " [+recursion?Ordered subdirectory recursion over unrelated"
  51. " makefiles.]"
  52. " }"
  53. "[+?\bmamprobe\b(1) is called to probe and generate system specific variable"
  54. " definitions. The probe information is regenerated when it is older"
  55. " than the \bmamprobe\b command.]"
  56. "[+?For compatibility with \bnmake\b(1) the \b-K\b option and the"
  57. " \brecurse\b and \bcc-*\b command line targets are ignored.]"
  58. "[e:?Explain reason for triggering action. Ignored if -F is on.]"
  59. "[f:?Read \afile\a instead of the default.]:[file:=Mamfile]"
  60. "[i:?Ignore action errors.]"
  61. "[k:?Continue after error with sibling prerequisites.]"
  62. "[n:?Print actions but do not execute. Recursion actions (see \b-r\b) are still"
  63. " executed. Use \b-N\b to disable recursion actions too.]"
  64. "[r:?Recursively make leaf directories matching \apattern\a. Only leaf"
  65. " directories containing a file named \bMamfile\b"
  66. " are considered.]:[pattern]"
  67. "[C:?Do all work in \adirectory\a. All messages will mention"
  68. " \adirectory\a.]:[directory]"
  69. "[D:?Set the debug trace level to \alevel\a. Higher levels produce more"
  70. " output.]#[level]"
  71. "[F:?Force all targets to be out of date.]"
  72. "[K:?Ignored.]"
  73. "[N:?Like \b-n\b but recursion actions (see \b-r\b) are also disabled.]"
  74. "[V:?Print the program version and exit.]"
  75. "[G:debug-symbols?Compile and link with debugging symbol options enabled.]"
  76. "[S:strip-symbols?Strip link-time static symbols from executables.]"
  77. "\n"
  78. "\n[ target ... ] [ name=value ... ]\n"
  79. "\n"
  80. "[+SEE ALSO?\bgmake\b(1), \bmake\b(1), \bmamprobe\b(1),"
  81. " \bnmake\b(1), \bsh\b(1)]"
  82. ;
  83. #else
  84. #define elementsof(x) (sizeof(x)/sizeof(x[0]))
  85. #define newof(p,t,n,x) ((p)?(t*)realloc((char*)(p),sizeof(t)*(n)+(x)):(t*)calloc(1,sizeof(t)*(n)+(x)))
  86. #define NiL 0
  87. #endif
  88. #include <stdio.h>
  89. #include <unistd.h>
  90. #include <ctype.h>
  91. #include <sys/types.h>
  92. #include <sys/stat.h>
  93. #include <time.h>
  94. #if !_PACKAGE_ast
  95. #include <stdlib.h>
  96. #include <string.h>
  97. #endif
  98. #define delimiter(c) ((c)==' '||(c)=='\t'||(c)=='\n'||(c)==';'||(c)=='('||(c)==')'||(c)=='`'||(c)=='|'||(c)=='&'||(c)=='=')
  99. #define add(b,c) (((b)->nxt >= (b)->end) ? append(b, "") : NiL, *(b)->nxt++ = (c))
  100. #define get(b) ((b)->nxt-(b)->buf)
  101. #define set(b,o) ((b)->nxt=(b)->buf+(o))
  102. #define use(b) (*(b)->nxt=0,(b)->nxt=(b)->buf)
  103. #define CHUNK 4096
  104. #define KEY(a,b,c,d) ((((unsigned long)(a))<<15)|(((unsigned long)(b))<<10)|(((unsigned long)(c))<<5)|(((unsigned long)(d))))
  105. #define NOW ((unsigned long)time((time_t*)0))
  106. #define ROTATE(p,l,r,t) ((t)=(p)->l,(p)->l=(t)->r,(t)->r=(p),(p)=(t))
  107. #define RULE_active 0x0001 /* active target */
  108. #define RULE_dontcare 0x0002 /* ok if not found */
  109. #define RULE_error 0x0004 /* not found or not generated */
  110. #define RULE_exists 0x0008 /* target file exists */
  111. #define RULE_generated 0x0010 /* generated target */
  112. #define RULE_ignore 0x0020 /* ignore time */
  113. #define RULE_implicit 0x0040 /* implicit prerequisite */
  114. #define RULE_made 0x0080 /* already made */
  115. #define RULE_virtual 0x0100 /* not a file */
  116. #define STREAM_KEEP 0x0001 /* don't fclose() on pop() */
  117. #define STREAM_MUST 0x0002 /* push() file must exist */
  118. #define STREAM_PIPE 0x0004 /* pclose() on pop() */
  119. #ifndef S_IXUSR
  120. #define S_IXUSR 0100 /* owner execute permission */
  121. #endif
  122. #ifndef S_IXGRP
  123. #define S_IXGRP 0010 /* group execute permission */
  124. #endif
  125. #ifndef S_IXOTH
  126. #define S_IXOTH 0001 /* other execute permission */
  127. #endif
  128. struct Rule_s;
  129. typedef struct stat Stat_t;
  130. typedef FILE Stdio_t;
  131. typedef struct Buf_s /* buffer stream */
  132. {
  133. struct Buf_s* old; /* next dropped buffer */
  134. char* end; /* 1 past end of buffer */
  135. char* nxt; /* next char to add */
  136. char* buf; /* buffer space */
  137. } Buf_t;
  138. typedef struct Dict_item_s /* dictionary item */
  139. {
  140. struct Dict_item_s* left; /* left child */
  141. struct Dict_item_s* right; /* right child */
  142. void* value; /* user defined value */
  143. char name[1];/* 0 terminated name */
  144. } Dict_item_t;
  145. typedef struct Dict_s /* dictionary handle */
  146. {
  147. Dict_item_t* root; /* root item */
  148. } Dict_t;
  149. typedef struct List_s /* Rule_t list */
  150. {
  151. struct List_s* next; /* next in list */
  152. struct Rule_s* rule; /* list item */
  153. } List_t;
  154. typedef struct Rule_s /* rule item */
  155. {
  156. char* name; /* unbound name */
  157. char* path; /* bound path */
  158. List_t* prereqs; /* prerequisites */
  159. struct Rule_s* leaf; /* recursion leaf alias */
  160. int flags; /* RULE_* flags */
  161. int making; /* currently make()ing */
  162. unsigned long time; /* modification time */
  163. } Rule_t;
  164. typedef struct Stream_s /* input file stream stack */
  165. {
  166. Stdio_t* fp; /* read stream */
  167. char* file; /* stream path */
  168. unsigned long line; /* stream line */
  169. int flags; /* stream flags */
  170. } Stream_t;
  171. typedef struct View_s /* viewpath level */
  172. {
  173. struct View_s* next; /* next level in viewpath */
  174. int node; /* viewpath node path length */
  175. char dir[1]; /* viewpath level dir prefix */
  176. } View_t;
  177. static struct /* program state */
  178. {
  179. Buf_t* buf; /* work buffer */
  180. Buf_t* old; /* dropped buffers */
  181. Buf_t* opt; /* option buffer */
  182. Dict_t* leaf; /* recursion leaf dictionary */
  183. Dict_t* libs; /* library dictionary */
  184. Dict_t* rules; /* rule dictionary */
  185. Dict_t* vars; /* variable dictionary */
  186. View_t* view; /* viewpath levels */
  187. char* directory; /* work in this directory */
  188. char* id; /* command name */
  189. char* file; /* first input file */
  190. char* pwd; /* current directory */
  191. char* recurse; /* recursion pattern */
  192. char* shell; /* ${SHELL} */
  193. int active; /* targets currently active */
  194. int debug; /* negative of debug level */
  195. int errors; /* some error(s) occurred */
  196. int exec; /* execute actions */
  197. int explain; /* explain actions */
  198. int force; /* all targets out of date */
  199. int ignore; /* ignore command errors */
  200. int indent; /* debug indent */
  201. int keepgoing; /* do siblings on error */
  202. int never; /* never execute */
  203. int peek; /* next line already in input */
  204. int probed; /* probe already done */
  205. int verified; /* don't bother with verify() */
  206. Stream_t streams[4]; /* input file stream stack */
  207. Stream_t* sp; /* input stream stack pointer */
  208. char input[8*CHUNK]; /* input buffer */
  209. } state;
  210. static unsigned long make(Rule_t*);
  211. static char mamfile[] = "Mamfile";
  212. static char sh[] = "/bin/sh";
  213. extern char** environ;
  214. #if !_PACKAGE_ast
  215. #if defined(NeXT) || defined(__NeXT)
  216. #define getcwd(a,b) getwd(a)
  217. #endif
  218. /*
  219. * emit usage message and exit
  220. */
  221. static void
  222. usage()
  223. {
  224. fprintf(stderr, "Usage: %s"
  225. " [-iknFKNV]"
  226. " [-f Mamfile]"
  227. " [-r pattern]"
  228. " [-C directory]"
  229. " [-D level]"
  230. " [target ...]"
  231. " [name=value ...]"
  232. "\n", state.id);
  233. exit(2);
  234. }
  235. #endif
  236. /*
  237. * output error message identification
  238. */
  239. static void
  240. identify(Stdio_t* sp)
  241. {
  242. if (state.directory)
  243. fprintf(sp, "%s [%s]: ", state.id, state.directory);
  244. else
  245. fprintf(sp, "%s: ", state.id);
  246. }
  247. /*
  248. * emit error message
  249. * level:
  250. * <0 debug
  251. * 0 info
  252. * 1 warning
  253. * 2 error
  254. * >2 exit(level-2)
  255. */
  256. static void
  257. report(int level, char* text, char* item, unsigned long stamp)
  258. {
  259. int i;
  260. if (level >= state.debug)
  261. {
  262. if (level)
  263. identify(stderr);
  264. if (level < 0)
  265. {
  266. fprintf(stderr, "debug%d: ", level);
  267. for (i = 1; i < state.indent; i++)
  268. fprintf(stderr, " ");
  269. }
  270. else
  271. {
  272. if (state.sp && state.sp->line)
  273. {
  274. if (state.sp->file)
  275. fprintf(stderr, "%s: ", state.sp->file);
  276. fprintf(stderr, "%ld: ", state.sp->line);
  277. }
  278. if (level == 1)
  279. fprintf(stderr, "warning: ");
  280. else if (level > 1)
  281. state.errors = 1;
  282. }
  283. if (item)
  284. fprintf(stderr, "%s: ", item);
  285. fprintf(stderr, "%s", text);
  286. if (stamp && state.debug <= -2)
  287. fprintf(stderr, " %10lu", stamp);
  288. fprintf(stderr, "\n");
  289. if (level > 2)
  290. exit(level - 2);
  291. }
  292. }
  293. /*
  294. * don't know how to make or exit code making
  295. */
  296. static void
  297. dont(Rule_t* r, int code, int keepgoing)
  298. {
  299. identify(stderr);
  300. if (!code)
  301. fprintf(stderr, "don't know how to make %s\n", r->name);
  302. else
  303. {
  304. fprintf(stderr, "*** exit code %d making %s%s\n", code, r->name, state.ignore ? " ignored" : "");
  305. unlink(r->name);
  306. if (state.ignore)
  307. return;
  308. }
  309. if (!keepgoing)
  310. exit(1);
  311. state.errors++;
  312. r->flags |= RULE_error;
  313. }
  314. /*
  315. * local strrchr()
  316. */
  317. static char*
  318. last(register char* s, register int c)
  319. {
  320. register char* r = 0;
  321. for (r = 0; *s; s++)
  322. if (*s == c)
  323. r = s;
  324. return r;
  325. }
  326. /*
  327. * open a buffer stream
  328. */
  329. static Buf_t*
  330. buffer(void)
  331. {
  332. register Buf_t* buf;
  333. if (buf = state.old)
  334. state.old = state.old->old;
  335. else if (!(buf = newof(0, Buf_t, 1, 0)) || !(buf->buf = newof(0, char, CHUNK, 0)))
  336. report(3, "out of memory [buffer]", NiL, (unsigned long)0);
  337. buf->end = buf->buf + CHUNK;
  338. buf->nxt = buf->buf;
  339. return buf;
  340. }
  341. /*
  342. * close a buffer stream
  343. */
  344. static void
  345. drop(Buf_t* buf)
  346. {
  347. buf->old = state.old;
  348. state.old = buf;
  349. }
  350. /*
  351. * append str length n to buffer and return the buffer base
  352. */
  353. static char*
  354. appendn(Buf_t* buf, char* str, int n)
  355. {
  356. int m;
  357. int i;
  358. if ((n + 1) >= (buf->end - buf->nxt))
  359. {
  360. i = buf->nxt - buf->buf;
  361. m = (((buf->end - buf->buf) + n + CHUNK + 1) / CHUNK) * CHUNK;
  362. if (!(buf->buf = newof(buf->buf, char, m, 0)))
  363. report(3, "out of memory [buffer resize]", NiL, (unsigned long)0);
  364. buf->end = buf->buf + m;
  365. buf->nxt = buf->buf + i;
  366. }
  367. memcpy(buf->nxt, str, n + 1);
  368. buf->nxt += n;
  369. return buf->buf;
  370. }
  371. /*
  372. * append str to buffer and return the buffer base
  373. * if str==0 then next pointer reset to base
  374. */
  375. static char*
  376. append(Buf_t* buf, char* str)
  377. {
  378. if (str)
  379. return appendn(buf, str, strlen(str));
  380. buf->nxt = buf->buf;
  381. return buf->buf;
  382. }
  383. /*
  384. * allocate space for s and return the copy
  385. */
  386. static char*
  387. duplicate(char* s)
  388. {
  389. char* t;
  390. int n;
  391. n = strlen(s);
  392. if (!(t = newof(0, char, n, 1)))
  393. report(3, "out of memory [duplicate]", s, (unsigned long)0);
  394. strcpy(t, s);
  395. return t;
  396. }
  397. /*
  398. * open a new dictionary
  399. */
  400. static Dict_t*
  401. dictionary(void)
  402. {
  403. Dict_t* dict;
  404. if (!(dict = newof(0, Dict_t, 1, 0)))
  405. report(3, "out of memory [dictionary]", NiL, (unsigned long)0);
  406. return dict;
  407. }
  408. /*
  409. * return the value for item name in dictionary dict
  410. * if value!=0 then name entry value is created if necessary and set
  411. * uses top-down splaying (ala Tarjan and Sleator)
  412. */
  413. static void*
  414. search(register Dict_t* dict, char* name, void* value)
  415. {
  416. register int cmp;
  417. register Dict_item_t* root;
  418. register Dict_item_t* t;
  419. register Dict_item_t* left;
  420. register Dict_item_t* right;
  421. register Dict_item_t* lroot;
  422. register Dict_item_t* rroot;
  423. root = dict->root;
  424. left = right = lroot = rroot = 0;
  425. while (root)
  426. {
  427. if (!(cmp = strcmp(name, root->name)))
  428. break;
  429. else if (cmp < 0)
  430. {
  431. if (root->left && (cmp = strcmp(name, root->left->name)) <= 0)
  432. {
  433. ROTATE(root, left, right, t);
  434. if (!cmp)
  435. break;
  436. }
  437. if (right)
  438. right->left = root;
  439. else
  440. rroot = root;
  441. right = root;
  442. root = root->left;
  443. right->left = 0;
  444. }
  445. else
  446. {
  447. if (root->right && (cmp = strcmp(name, root->right->name)) >= 0)
  448. {
  449. ROTATE(root, right, left, t);
  450. if (!cmp)
  451. break;
  452. }
  453. if (left)
  454. left->right = root;
  455. else
  456. lroot = root;
  457. left = root;
  458. root = root->right;
  459. left->right = 0;
  460. }
  461. }
  462. if (root)
  463. {
  464. if (right)
  465. right->left = root->right;
  466. else
  467. rroot = root->right;
  468. if (left)
  469. left->right = root->left;
  470. else
  471. lroot = root->left;
  472. }
  473. else if (value)
  474. {
  475. if (!(root = newof(0, Dict_item_t, 1, strlen(name))))
  476. report(3, "out of memory [dictionary]", name, (unsigned long)0);
  477. strcpy(root->name, name);
  478. }
  479. if (root)
  480. {
  481. if (value)
  482. root->value = value;
  483. root->left = lroot;
  484. root->right = rroot;
  485. dict->root = root;
  486. return value ? (void*)root->name : root->value;
  487. }
  488. if (left)
  489. {
  490. left->right = rroot;
  491. dict->root = lroot;
  492. }
  493. else if (right)
  494. {
  495. right->left = lroot;
  496. dict->root = rroot;
  497. }
  498. return 0;
  499. }
  500. /*
  501. * low level for walk()
  502. */
  503. static int
  504. apply(Dict_t* dict, Dict_item_t* item, int (*func)(Dict_item_t*, void*), void* handle)
  505. {
  506. register Dict_item_t* right;
  507. do
  508. {
  509. right = item->right;
  510. if (item->left && apply(dict, item->left, func, handle))
  511. return -1;
  512. if ((*func)(item, handle))
  513. return -1;
  514. } while (item = right);
  515. return 0;
  516. }
  517. /*
  518. * apply func to each dictionary item
  519. */
  520. static int
  521. walk(Dict_t* dict, int (*func)(Dict_item_t*, void*), void* handle)
  522. {
  523. return dict->root ? apply(dict, dict->root, func, handle) : 0;
  524. }
  525. /*
  526. * return a rule pointer for name
  527. */
  528. static Rule_t*
  529. rule(char* name)
  530. {
  531. Rule_t* r;
  532. if (!(r = (Rule_t*)search(state.rules, name, NiL)))
  533. {
  534. if (!(r = newof(0, Rule_t, 1, 0)))
  535. report(3, "out of memory [rule]", name, (unsigned long)0);
  536. r->name = (char*)search(state.rules, name, (void*)r);
  537. }
  538. return r;
  539. }
  540. /*
  541. * prepend p onto rule r prereqs
  542. */
  543. static void
  544. cons(Rule_t* r, Rule_t* p)
  545. {
  546. register List_t* x;
  547. for (x = r->prereqs; x && x->rule != p; x = x->next);
  548. if (!x)
  549. {
  550. if (!(x = newof(0, List_t, 1, 0)))
  551. report(3, "out of memory [list]", r->name, (unsigned long)0);
  552. x->rule = p;
  553. x->next = r->prereqs;
  554. r->prereqs = x;
  555. }
  556. }
  557. /*
  558. * initialize the viewpath
  559. */
  560. static void
  561. view(void)
  562. {
  563. register char* s;
  564. register char* t;
  565. register char* p;
  566. register View_t* vp;
  567. View_t* zp;
  568. int c;
  569. int n;
  570. Stat_t st;
  571. Stat_t ts;
  572. char buf[CHUNK];
  573. if (stat(".", &st))
  574. report(3, "cannot stat", ".", (unsigned long)0);
  575. if ((s = (char*)search(state.vars, "PWD", NiL)) && !stat(s, &ts) &&
  576. ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
  577. state.pwd = s;
  578. if (!state.pwd)
  579. {
  580. if (!getcwd(buf, sizeof(buf) - 1))
  581. report(3, "cannot determine PWD", NiL, (unsigned long)0);
  582. state.pwd = duplicate(buf);
  583. search(state.vars, "PWD", state.pwd);
  584. }
  585. if ((s = (char*)search(state.vars, "VPATH", NiL)) && *s)
  586. {
  587. zp = 0;
  588. for (;;)
  589. {
  590. for (t = s; *t && *t != ':'; t++);
  591. if (c = *t)
  592. *t = 0;
  593. if (!state.view)
  594. {
  595. /*
  596. * determine the viewpath offset
  597. */
  598. if (stat(s, &st))
  599. report(3, "cannot stat top view", s, (unsigned long)0);
  600. if (stat(state.pwd, &ts))
  601. report(3, "cannot stat", state.pwd, (unsigned long)0);
  602. if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
  603. p = ".";
  604. else
  605. {
  606. p = state.pwd + strlen(state.pwd);
  607. while (p > state.pwd)
  608. {
  609. if (*--p == '/')
  610. {
  611. if (p == state.pwd)
  612. report(3, ". not under VPATH", s, (unsigned long)0);
  613. *p = 0;
  614. if (stat(state.pwd, &ts))
  615. report(3, "cannot stat", state.pwd, (unsigned long)0);
  616. *p = '/';
  617. if (ts.st_dev == st.st_dev && ts.st_ino == st.st_ino)
  618. {
  619. p++;
  620. break;
  621. }
  622. }
  623. }
  624. if (p <= state.pwd)
  625. report(3, "cannot determine viewpath offset", s, (unsigned long)0);
  626. }
  627. }
  628. n = strlen(s);
  629. if (!(vp = newof(0, View_t, 1, strlen(p) + n + 1)))
  630. report(3, "out of memory [view]", s, (unsigned long)0);
  631. vp->node = n + 1;
  632. strcpy(vp->dir, s);
  633. *(vp->dir + n) = '/';
  634. strcpy(vp->dir + n + 1, p);
  635. report(-4, vp->dir, "view", (unsigned long)0);
  636. if (!state.view)
  637. state.view = zp = vp;
  638. else
  639. zp = zp->next = vp;
  640. if (!c)
  641. break;
  642. *t++ = c;
  643. s = t;
  644. }
  645. }
  646. }
  647. /*
  648. * return next '?' or '}' in nested '}'
  649. */
  650. static char*
  651. cond(register char* s)
  652. {
  653. register int n;
  654. if (*s == '?')
  655. s++;
  656. n = 0;
  657. for (;;)
  658. {
  659. switch (*s++)
  660. {
  661. case 0:
  662. break;
  663. case '{':
  664. n++;
  665. continue;
  666. case '}':
  667. if (!n--)
  668. break;
  669. continue;
  670. case '?':
  671. if (!n)
  672. break;
  673. continue;
  674. default:
  675. continue;
  676. }
  677. break;
  678. }
  679. return s - 1;
  680. }
  681. /*
  682. * expand var refs from s into buf
  683. */
  684. static void
  685. substitute(Buf_t* buf, register char* s)
  686. {
  687. register char* t;
  688. register char* v;
  689. register char* q;
  690. register char* b;
  691. register int c;
  692. register int n;
  693. int a = 0;
  694. int i;
  695. while (c = *s++)
  696. {
  697. if (c == '$' && *s == '{')
  698. {
  699. b = s - 1;
  700. i = 1;
  701. for (n = *(t = ++s) == '-' ? 0 : '-'; (c = *s) && c != '?' && c != '+' && c != n && c != ':' && c != '=' && c != '[' && c != '}'; s++)
  702. if (!isalnum(c) && c != '_')
  703. i = 0;
  704. *s = 0;
  705. if (c == '[')
  706. {
  707. append(buf, b);
  708. *s = c;
  709. continue;
  710. }
  711. v = (char*)search(state.vars, t, NiL);
  712. if ((c == ':' || c == '=') && (!v || c == ':' && !*v))
  713. {
  714. append(buf, b);
  715. *s = c;
  716. continue;
  717. }
  718. if (t[0] == 'A' && t[1] == 'R' && t[2] == 0)
  719. a = 1;
  720. *s = c;
  721. if (c && c != '}')
  722. {
  723. n = 1;
  724. for (t = ++s; *s; s++)
  725. if (*s == '{')
  726. n++;
  727. else if (*s == '}' && !--n)
  728. break;
  729. }
  730. switch (c)
  731. {
  732. case '?':
  733. q = cond(t - 1);
  734. if (v)
  735. {
  736. if (((q - t) != 1 || *t != '*') && strncmp(v, t, q - t))
  737. v = 0;
  738. }
  739. else if (q == t)
  740. v = s;
  741. t = cond(q);
  742. if (v)
  743. {
  744. if (t > q)
  745. {
  746. c = *t;
  747. *t = 0;
  748. substitute(buf, q + 1);
  749. *t = c;
  750. }
  751. }
  752. else
  753. {
  754. q = cond(t);
  755. if (q > t)
  756. {
  757. c = *q;
  758. *q = 0;
  759. substitute(buf, t + 1);
  760. *q = c;
  761. }
  762. }
  763. break;
  764. case '+':
  765. case '-':
  766. if ((v == 0 || *v == 0) == (c == '-'))
  767. {
  768. c = *s;
  769. *s = 0;
  770. substitute(buf, t);
  771. *s = c;
  772. break;
  773. }
  774. if (c != '-')
  775. break;
  776. /* FALLTHROUGH */
  777. case 0:
  778. case '=':
  779. case '}':
  780. if (v)
  781. {
  782. if (a && t[0] == 'm' && t[1] == 'a' && t[2] == 'm' && t[3] == '_' && t[4] == 'l' && t[5] == 'i' && t[6] == 'b')
  783. {
  784. for (t = v; isspace(*t); t++);
  785. for (; *t && !isspace(*t); t++);
  786. if (*t)
  787. *t = 0;
  788. else
  789. t = 0;
  790. substitute(buf, v);
  791. if (t)
  792. *t = ' ';
  793. }
  794. else
  795. substitute(buf, v);
  796. }
  797. else if (i)
  798. {
  799. c = *s;
  800. *s = 0;
  801. append(buf, b);
  802. *s = c;
  803. continue;
  804. }
  805. break;
  806. }
  807. if (*s)
  808. s++;
  809. }
  810. else
  811. add(buf, c);
  812. }
  813. }
  814. /*
  815. * expand var refs from s into buf and return buf base
  816. */
  817. static char*
  818. expand(Buf_t* buf, char* s)
  819. {
  820. substitute(buf, s);
  821. return use(buf);
  822. }
  823. /*
  824. * stat() with .exe check
  825. */
  826. static char*
  827. status(Buf_t* buf, int off, char* path, struct stat* st)
  828. {
  829. int r;
  830. char* s;
  831. Buf_t* tmp;
  832. if (!stat(path, st))
  833. return path;
  834. if (!(tmp = buf))
  835. {
  836. tmp = buffer();
  837. off = 0;
  838. }
  839. if (off)
  840. set(tmp, off);
  841. else
  842. append(tmp, path);
  843. append(tmp, ".exe");
  844. s = use(tmp);
  845. r = stat(s, st);
  846. if (!buf)
  847. {
  848. drop(tmp);
  849. s = path;
  850. }
  851. if (r)
  852. {
  853. if (off)
  854. s[off] = 0;
  855. s = 0;
  856. }
  857. return s;
  858. }
  859. /*
  860. * return path to file
  861. */
  862. static char*
  863. find(Buf_t* buf, char* file, struct stat* st)
  864. {
  865. char* s;
  866. View_t* vp;
  867. int node;
  868. int c;
  869. int o;
  870. if (s = status(buf, 0, file, st))
  871. {
  872. report(-3, s, "find", (unsigned long)0);
  873. return s;
  874. }
  875. if (vp = state.view)
  876. {
  877. node = 0;
  878. if (*file == '/')
  879. {
  880. do
  881. {
  882. if (!strncmp(file, vp->dir, vp->node))
  883. {
  884. file += vp->node;
  885. node = 2;
  886. break;
  887. }
  888. } while (vp = vp->next);
  889. }
  890. else
  891. vp = vp->next;
  892. if (vp)
  893. {
  894. do
  895. {
  896. if (node)
  897. {
  898. c = vp->dir[vp->node];
  899. vp->dir[vp->node] = 0;
  900. append(buf, vp->dir);
  901. vp->dir[vp->node] = c;
  902. }
  903. else
  904. {
  905. append(buf, vp->dir);
  906. append(buf, "/");
  907. }
  908. append(buf, file);
  909. o = get(buf);
  910. s = use(buf);
  911. if (s = status(buf, o, s, st))
  912. {
  913. report(-3, s, "find", (unsigned long)0);
  914. return s;
  915. }
  916. } while (vp = vp->next);
  917. }
  918. }
  919. return 0;
  920. }
  921. /*
  922. * bind r to a file and return the modify time
  923. */
  924. static unsigned long
  925. bindfile(Rule_t* r)
  926. {
  927. char* s;
  928. Buf_t* buf;
  929. struct stat st;
  930. buf = buffer();
  931. if (s = find(buf, r->name, &st))
  932. {
  933. if (s != r->name)
  934. r->path = duplicate(s);
  935. r->time = st.st_mtime;
  936. r->flags |= RULE_exists;
  937. }
  938. drop(buf);
  939. return r->time;
  940. }
  941. /*
  942. * pop the current input file
  943. */
  944. static int
  945. pop(void)
  946. {
  947. int r;
  948. if (!state.sp)
  949. report(3, "input stack underflow", NiL, (unsigned long)0);
  950. if (!state.sp->fp || (state.sp->flags & STREAM_KEEP))
  951. r = 0;
  952. else if (state.sp->flags & STREAM_PIPE)
  953. r = pclose(state.sp->fp);
  954. else
  955. r = fclose(state.sp->fp);
  956. if (state.sp == state.streams)
  957. state.sp = 0;
  958. else
  959. state.sp--;
  960. return r;
  961. }
  962. /*
  963. * push file onto the input stack
  964. */
  965. static int
  966. push(char* file, Stdio_t* fp, int flags)
  967. {
  968. char* path;
  969. Buf_t* buf;
  970. struct stat st;
  971. if (!state.sp)
  972. state.sp = state.streams;
  973. else if (++state.sp >= &state.streams[elementsof(state.streams)])
  974. report(3, "input stream stack overflow", NiL, (unsigned long)0);
  975. if (state.sp->fp = fp)
  976. {
  977. if(state.sp->file)
  978. free(state.sp->file);
  979. state.sp->file = strdup("pipeline");
  980. if(!state.sp->file)
  981. report(3, "out of memory [push]", NiL, (unsigned long)0);
  982. }
  983. else if (flags & STREAM_PIPE)
  984. report(3, "pipe error", file, (unsigned long)0);
  985. else if (!file || !strcmp(file, "-") || !strcmp(file, "/dev/stdin"))
  986. {
  987. flags |= STREAM_KEEP;
  988. if(state.sp->file)
  989. free(state.sp->file);
  990. state.sp->file = strdup("/dev/stdin");
  991. if(!state.sp->file)
  992. report(3, "out of memory [push]", NiL, (unsigned long)0);
  993. state.sp->fp = stdin;
  994. }
  995. else
  996. {
  997. buf = buffer();
  998. if (path = find(buf, file, &st))
  999. {
  1000. if (!(state.sp->fp = fopen(path, "r")))
  1001. report(3, "cannot read", path, (unsigned long)0);
  1002. if(state.sp->file)
  1003. free(state.sp->file);
  1004. state.sp->file = duplicate(path);
  1005. drop(buf);
  1006. }
  1007. else
  1008. {
  1009. drop(buf);
  1010. pop();
  1011. if (flags & STREAM_MUST)
  1012. report(3, "not found", file, (unsigned long)0);
  1013. return 0;
  1014. }
  1015. }
  1016. state.sp->flags = flags;
  1017. state.sp->line = 0;
  1018. return 1;
  1019. }
  1020. /*
  1021. * return the next input line
  1022. */
  1023. static char*
  1024. input(void)
  1025. {
  1026. char* e;
  1027. if (!state.sp)
  1028. report(3, "no input file stream", NiL, (unsigned long)0);
  1029. if (state.peek)
  1030. state.peek = 0;
  1031. else if (!fgets(state.input, sizeof(state.input), state.sp->fp))
  1032. return 0;
  1033. else if (*state.input && *(e = state.input + strlen(state.input) - 1) == '\n')
  1034. *e = 0;
  1035. state.sp->line++;
  1036. return state.input;
  1037. }
  1038. /*
  1039. * pass shell action s to ${SHELL:-/bin/sh}
  1040. * the -c wrapper ensures that scripts are run in the selected shell
  1041. * even on systems that otherwise demand #! magic (can you say Cygwin)
  1042. */
  1043. static int
  1044. execute(register char* s)
  1045. {
  1046. register int c;
  1047. Buf_t* buf;
  1048. if (!state.shell && (!(state.shell = (char*)search(state.vars, "SHELL", NiL)) || !strcmp(state.shell, sh)))
  1049. state.shell = sh;
  1050. buf = buffer();
  1051. append(buf, state.shell);
  1052. append(buf, " -c '");
  1053. while (c = *s++)
  1054. {
  1055. if (c == '\'')
  1056. {
  1057. add(buf, c);
  1058. for (s--; *s == c; s++)
  1059. {
  1060. add(buf, '\\');
  1061. add(buf, c);
  1062. }
  1063. }
  1064. add(buf, c);
  1065. }
  1066. add(buf, '\'');
  1067. s = use(buf);
  1068. report(-5, s, "exec", (unsigned long)0);
  1069. if ((c = system(s)) > 255)
  1070. c >>= 8;
  1071. drop(buf);
  1072. return c;
  1073. }
  1074. /*
  1075. * run action s to update r
  1076. */
  1077. static unsigned long
  1078. run(Rule_t* r, register char* s)
  1079. {
  1080. register Rule_t* q;
  1081. register char* t;
  1082. register int c;
  1083. register View_t* v;
  1084. int i;
  1085. int j;
  1086. int x;
  1087. Stat_t st;
  1088. Buf_t* buf;
  1089. if (r->flags & RULE_error)
  1090. return r->time;
  1091. buf = buffer();
  1092. if (!strncmp(s, "mamake -r ", 10))
  1093. {
  1094. state.verified = 1;
  1095. x = !state.never;
  1096. }
  1097. else
  1098. x = state.exec;
  1099. if (x)
  1100. append(buf, "trap - 1 2 3 15\nPATH=.:$PATH\nset -x\n");
  1101. if (state.view)
  1102. {
  1103. do
  1104. {
  1105. for (; delimiter(*s); s++)
  1106. add(buf, *s);
  1107. for (t = s; *s && !delimiter(*s); s++);
  1108. c = *s;
  1109. *s = 0;
  1110. if (c == '=')
  1111. {
  1112. append(buf, t);
  1113. continue;
  1114. }
  1115. if ((q = (Rule_t*)search(state.rules, t, NiL)) && q->path && !(q->flags & RULE_generated))
  1116. append(buf, q->path);
  1117. else
  1118. {
  1119. append(buf, t);
  1120. if (*t == '-' && *(t + 1) == 'I' && (*(t + 2) || c))
  1121. {
  1122. if (*(t + 2))
  1123. i = 2;
  1124. else
  1125. {
  1126. for (i = 3; isspace(*(t + i)); i++);
  1127. *s = c;
  1128. for (s = t + i; *s && !isspace(*s); s++);
  1129. c = *s;
  1130. *s = 0;
  1131. append(buf, t + 2);
  1132. }
  1133. if (*(t + i) && *(t + i) != '/')
  1134. {
  1135. v = state.view;
  1136. while (v = v->next)
  1137. {
  1138. add(buf, ' ');
  1139. for (j = 0; j < i; j++)
  1140. add(buf, *(t + j));
  1141. append(buf, v->dir);
  1142. if (*(t + i) != '.' || *(t + i + 1))
  1143. {
  1144. add(buf, '/');
  1145. append(buf, t + i);
  1146. }
  1147. }
  1148. }
  1149. }
  1150. }
  1151. } while (*s = c);
  1152. s = use(buf);
  1153. }
  1154. else if (x)
  1155. {
  1156. append(buf, s);
  1157. s = use(buf);
  1158. }
  1159. if (x)
  1160. {
  1161. if (c = execute(s))
  1162. dont(r, c, state.keepgoing);
  1163. if (status((Buf_t*)0, 0, r->name, &st))
  1164. {
  1165. r->time = st.st_mtime;
  1166. r->flags |= RULE_exists;
  1167. }
  1168. else
  1169. r->time = NOW;
  1170. }
  1171. else
  1172. {
  1173. fprintf(stdout, "%s\n", s);
  1174. if (state.debug)
  1175. fflush(stdout);
  1176. r->time = NOW;
  1177. r->flags |= RULE_exists;
  1178. }
  1179. drop(buf);
  1180. return r->time;
  1181. }
  1182. /*
  1183. * return the full path for s using buf workspace
  1184. */
  1185. static char*
  1186. path(Buf_t* buf, char* s, int must)
  1187. {
  1188. register char* p;
  1189. register char* d;
  1190. register char* x;
  1191. char* e;
  1192. register int c;
  1193. int t;
  1194. int o;
  1195. Stat_t st;
  1196. for (e = s; *e && !isspace(*e); e++);
  1197. t = *e;
  1198. if ((x = status(buf, 0, s, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
  1199. return x;
  1200. if (!(p = (char*)search(state.vars, "PATH", NiL)))
  1201. report(3, "variable not defined", "PATH", (unsigned long)0);
  1202. do
  1203. {
  1204. for (d = p; *p && *p != ':'; p++);
  1205. c = *p;
  1206. *p = 0;
  1207. if (*d && (*d != '.' || *(d + 1)))
  1208. {
  1209. append(buf, d);
  1210. add(buf, '/');
  1211. }
  1212. *p = c;
  1213. if (t)
  1214. *e = 0;
  1215. append(buf, s);
  1216. if (t)
  1217. *e = t;
  1218. o = get(buf);
  1219. x = use(buf);
  1220. if ((x = status(buf, o, x, &st)) && (st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
  1221. return x;
  1222. } while (*p++);
  1223. if (must)
  1224. report(3, "command not found", s, (unsigned long)0);
  1225. return 0;
  1226. }
  1227. /*
  1228. * generate (if necessary) and read the MAM probe information
  1229. * done on the first `setv CC ...'
  1230. */
  1231. static void
  1232. probe(void)
  1233. {
  1234. register char* cc;
  1235. register char* s;
  1236. unsigned long h;
  1237. unsigned long q;
  1238. Buf_t* buf;
  1239. Buf_t* pro;
  1240. Buf_t* tmp;
  1241. struct stat st;
  1242. static char let[] = "ABCDEFGHIJKLMNOP";
  1243. static char cmd[] = "mamprobe";
  1244. if (!(cc = (char*)search(state.vars, "CC", NiL)))
  1245. cc = "cc";
  1246. buf = buffer();
  1247. s = path(buf, cmd, 1);
  1248. q = stat(s, &st) ? (unsigned long)0 : (unsigned long)st.st_mtime;
  1249. pro = buffer();
  1250. s = cc = path(pro, cc, 1);
  1251. for (h = 0; *s; s++)
  1252. h = h * 0x63c63cd9L + *s + 0x9c39c33dL;
  1253. if (!(s = (char*)search(state.vars, "INSTALLROOT", NiL)))
  1254. report(3, "variable must be defined", "INSTALLROOT", (unsigned long)0);
  1255. append(buf, s);
  1256. append(buf, "/lib/probe/C/mam/");
  1257. for (h &= 0xffffffffL; h; h >>= 4)
  1258. add(buf, let[h & 0xf]);
  1259. s = use(buf);
  1260. h = stat(s, &st) ? (unsigned long)0 : (unsigned long)st.st_mtime;
  1261. if (h < q || !push(s, (Stdio_t*)0, 0))
  1262. {
  1263. tmp = buffer();
  1264. append(tmp, cmd);
  1265. add(tmp, ' ');
  1266. append(tmp, s);
  1267. add(tmp, ' ');
  1268. append(tmp, cc);
  1269. if (execute(use(tmp)))
  1270. report(3, "cannot generate probe info", s, (unsigned long)0);
  1271. drop(tmp);
  1272. if (!push(s, (Stdio_t*)0, 0))
  1273. report(3, "cannot read probe info", s, (unsigned long)0);
  1274. }
  1275. drop(pro);
  1276. drop(buf);
  1277. make(rule(""));
  1278. pop();
  1279. }
  1280. /*
  1281. * add attributes in s to r
  1282. */
  1283. static void
  1284. attributes(register Rule_t* r, register char* s)
  1285. {
  1286. register char* t;
  1287. register int n;
  1288. for (;;)
  1289. {
  1290. int flag = 0;
  1291. for (; isspace(*s); s++);
  1292. for (t = s; *s && !isspace(*s); s++);
  1293. if (!(n = s - t))
  1294. break;
  1295. switch (*t)
  1296. {
  1297. case 'd':
  1298. if (n == 8 && !strncmp(t, "dontcare", n))
  1299. flag = RULE_dontcare;
  1300. break;
  1301. case 'g':
  1302. if (n == 9 && !strncmp(t, "generated", n))
  1303. flag = RULE_generated;
  1304. break;
  1305. case 'i':
  1306. if (n == 6 && !strncmp(t, "ignore", n))
  1307. flag = RULE_ignore;
  1308. else if (n == 8 && !strncmp(t, "implicit", n))
  1309. flag = RULE_implicit;
  1310. break;
  1311. case 'v':
  1312. if (n == 7 && !strncmp(t, "virtual", n))
  1313. flag = RULE_virtual;
  1314. break;
  1315. case 'a':
  1316. if (n == 7 && !strncmp(t, "archive", n))
  1317. flag = -1; /* ignore (not implemented) */
  1318. break;
  1319. case 'j':
  1320. if (n == 5 && !strncmp(t, "joint", n))
  1321. flag = -1; /* ignore (not implemented) */
  1322. break;
  1323. }
  1324. if(flag > 0)
  1325. r->flags |= flag;
  1326. else if(flag == 0)
  1327. {
  1328. t[n] = '\0';
  1329. report(3, "unknown attribute", t, (unsigned long)0);
  1330. }
  1331. }
  1332. }
  1333. /*
  1334. * define ${mam_libX} for library reference lib
  1335. */
  1336. static char*
  1337. require(char* lib, int dontcare)
  1338. {
  1339. register int c;
  1340. char* s;
  1341. char* r;
  1342. FILE* f;
  1343. Buf_t* buf;
  1344. Buf_t* tmp;
  1345. struct stat st;
  1346. int tofree = 0;
  1347. static int dynamic = -1;
  1348. if (dynamic < 0)
  1349. dynamic = (s = search(state.vars, "mam_cc_L", NiL)) ? atoi(s) : 0;
  1350. if (!(r = search(state.vars, lib, NiL)))
  1351. {
  1352. buf = buffer();
  1353. tmp = buffer();
  1354. s = 0;
  1355. for (;;)
  1356. {
  1357. if (s)
  1358. append(buf, s);
  1359. if (r = search(state.vars, "mam_cc_PREFIX_ARCHIVE", NiL))
  1360. append(buf, r);
  1361. append(buf, lib + 2);
  1362. if (r = search(state.vars, "mam_cc_SUFFIX_ARCHIVE", NiL))
  1363. append(buf, r);
  1364. r = expand(tmp, use(buf));
  1365. if (!stat(r, &st))
  1366. break;
  1367. if (s)
  1368. {
  1369. r = lib;
  1370. break;
  1371. }
  1372. s = "${INSTALLROOT}/lib/";
  1373. if (dynamic)
  1374. {
  1375. append(buf, s);
  1376. if (r = search(state.vars, "mam_cc_PREFIX_SHARED", NiL))
  1377. append(buf, r);
  1378. append(buf, lib + 2);
  1379. if (r = search(state.vars, "mam_cc_SUFFIX_SHARED", NiL))
  1380. append(buf, r);
  1381. r = expand(tmp, use(buf));
  1382. if (!stat(r, &st))
  1383. {
  1384. r = lib;
  1385. break;
  1386. }
  1387. }
  1388. }
  1389. if (r != lib)
  1390. {
  1391. tofree = 1;
  1392. r = duplicate(r);
  1393. }
  1394. search(state.vars, lib, r);
  1395. append(tmp, lib + 2);
  1396. append(tmp, ".req");
  1397. if (!(f = fopen(use(tmp), "r")))
  1398. {
  1399. append(tmp, "${INSTALLROOT}/lib/lib/");
  1400. append(tmp, lib + 2);
  1401. f = fopen(expand(buf, use(tmp)), "r");
  1402. }
  1403. if (f)
  1404. {
  1405. for (;;)
  1406. {
  1407. while (isspace(c = fgetc(f)));
  1408. if (c == EOF)
  1409. break;
  1410. do
  1411. {
  1412. add(tmp, c);
  1413. } while ((c = fgetc(f)) != EOF && !isspace(c));
  1414. s = use(tmp);
  1415. if (s[0] && (s[0] != '-' || s[1]))
  1416. {
  1417. add(buf, ' ');
  1418. append(buf, require(s, 0));
  1419. }
  1420. }
  1421. fclose(f);
  1422. if(tofree)
  1423. free(r);
  1424. r = use(buf);
  1425. }
  1426. else if (dontcare)
  1427. {
  1428. append(tmp, "set -\n");
  1429. append(tmp, "cd \"${TMPDIR:-/tmp}\"\n");
  1430. append(tmp, "echo 'int main(){return 0;}' > x.${!-$$}.c\n");
  1431. append(tmp, "${CC} ${CCFLAGS} -o x.${!-$$}.x x.${!-$$}.c ");
  1432. append(tmp, r);
  1433. append(tmp, " >/dev/null 2>&1\n");
  1434. append(tmp, "c=$?\n");
  1435. append(tmp, "rm -f x.${!-$$}.[cox]\n");
  1436. append(tmp, "exit $c\n");
  1437. if (execute(expand(buf, use(tmp))))
  1438. {
  1439. if(tofree)
  1440. free(r);
  1441. r = "";
  1442. }
  1443. }
  1444. r = duplicate(r);
  1445. search(state.vars, lib, r);
  1446. append(tmp, "mam_lib");
  1447. append(tmp, lib + 2);
  1448. search(state.vars, use(tmp), r);
  1449. drop(tmp);
  1450. drop(buf);
  1451. }
  1452. return r;
  1453. }
  1454. /*
  1455. * input() until `done r'
  1456. */
  1457. static unsigned long
  1458. make(Rule_t* r)
  1459. {
  1460. register char* s;
  1461. register char* t;
  1462. register char* u;
  1463. register char* v;
  1464. register Rule_t* q;
  1465. unsigned long z;
  1466. unsigned long x;
  1467. Buf_t* buf;
  1468. Buf_t* cmd;
  1469. r->making++;
  1470. if (r->flags & RULE_active)
  1471. state.active++;
  1472. if (*r->name)
  1473. {
  1474. z = bindfile(r);
  1475. state.indent++;
  1476. report(-1, r->name, "make", r->time);
  1477. }
  1478. else
  1479. z = 0;
  1480. buf = buffer();
  1481. cmd = 0;
  1482. /*
  1483. * Parse lines
  1484. */
  1485. while (s = input())
  1486. {
  1487. /* skip initial whitespace and empty line */
  1488. for (; isspace(*s); s++);
  1489. if (!*s)
  1490. continue;
  1491. /* isolate command name (u), argument word (t), and the operand string (v) */
  1492. for (u = s; *s && !isspace(*s); s++);
  1493. if (*s)
  1494. {
  1495. for (*s++ = 0; isspace(*s); s++);
  1496. for (t = s; *s && !isspace(*s); s++);
  1497. if (*s)
  1498. for (*s++ = 0; isspace(*s); s++);
  1499. v = s;
  1500. }
  1501. else
  1502. t = v = s;
  1503. /* enforce 4-letter lowercase command name */
  1504. if(u[0]<'a' || u[0]>'z' || u[1]<'a' || u[1]>'z' || u[2]<'a' || u[2]>'z' || u[3]<'a' || u[3]>'z' || u[4] && !isspace(u[4]))
  1505. report(3, "not a command name", u, (unsigned long)0);
  1506. switch (KEY(u[0], u[1], u[2], u[3]))
  1507. {
  1508. case KEY('b','i','n','d'):
  1509. if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && (s = require(t, !strcmp(v, "dontcare"))) && strncmp(r->name, "FEATURE/", 8) && strcmp(r->name, "configure.h"))
  1510. {
  1511. for (;;)
  1512. {
  1513. for (t = s; *s && !isspace(*s); s++);
  1514. if (*s)
  1515. *s = 0;
  1516. else
  1517. s = 0;
  1518. if (*t)
  1519. {
  1520. q = rule(expand(buf, t));
  1521. attributes(q, v);
  1522. x = bindfile(q);
  1523. if (z < x)
  1524. z = x;
  1525. if (q->flags & RULE_error)
  1526. r->flags |= RULE_error;
  1527. }
  1528. if (!s)
  1529. break;
  1530. for (*s++ = ' '; isspace(*s); s++);
  1531. }
  1532. }
  1533. continue;
  1534. case KEY('d','o','n','e'):
  1535. q = rule(expand(buf, t));
  1536. if (q != r && t[0] != '$')
  1537. report(2, "improper done statement", t, (unsigned long)0);
  1538. attributes(r, v);
  1539. if (cmd && state.active && (state.force || r->time < z || !r->time && !z))
  1540. {
  1541. if (state.explain && !state.force)
  1542. {
  1543. if (!r->time)
  1544. fprintf(stderr, "%s [not found]\n", r->name);
  1545. else
  1546. fprintf(stderr, "%s [%lu] older than prerequisites [%lu]\n", r->name, r->time, z);
  1547. }
  1548. substitute(buf, use(cmd));
  1549. x = run(r, use(buf));
  1550. if (z < x)
  1551. z = x;
  1552. }
  1553. r->flags |= RULE_made;
  1554. if (!(r->flags & (RULE_dontcare|RULE_error|RULE_exists|RULE_generated|RULE_implicit|RULE_virtual)))
  1555. dont(r, 0, state.keepgoing);
  1556. break;
  1557. case KEY('e','x','e','c'):
  1558. r->flags |= RULE_generated;
  1559. if (r->path)
  1560. {
  1561. free(r->path);
  1562. r->path = 0;
  1563. r->time = 0;
  1564. }
  1565. if (state.active)
  1566. {
  1567. if (cmd)
  1568. add(cmd, '\n');
  1569. else
  1570. cmd = buffer();
  1571. append(cmd, v);
  1572. }
  1573. continue;
  1574. case KEY('m','a','k','e'):
  1575. q = rule(expand(buf, t));
  1576. if (!q->making)
  1577. {
  1578. attributes(q, v);
  1579. x = make(q);
  1580. if (!(q->flags & RULE_ignore) && z < x)
  1581. z = x;
  1582. if (q->flags & RULE_error)
  1583. r->flags |= RULE_error;
  1584. }
  1585. continue;
  1586. case KEY('p','r','e','v'):
  1587. q = rule(expand(buf, t));
  1588. if (!q->making)
  1589. {
  1590. if (!(q->flags & RULE_ignore) && z < q->time)
  1591. z = q->time;
  1592. if (q->flags & RULE_error)
  1593. r->flags |= RULE_error;
  1594. state.indent++;
  1595. report(-2, q->name, "prev", q->time);
  1596. state.indent--;
  1597. }
  1598. continue;
  1599. case KEY('s','e','t','v'):
  1600. if (!search(state.vars, t, NiL))
  1601. {
  1602. if (*v == '"')
  1603. {
  1604. s = v + strlen(v) - 1;
  1605. if (*s == '"')
  1606. {
  1607. *s = 0;
  1608. v++;
  1609. }
  1610. }
  1611. search(state.vars, t, duplicate(expand(buf, v)));
  1612. }
  1613. if (!state.probed && t[0] == 'C' && t[1] == 'C' && !t[2])
  1614. {
  1615. state.probed = 1;
  1616. probe();
  1617. }
  1618. continue;
  1619. case KEY('i','n','f','o'):
  1620. case KEY('n','o','t','e'):
  1621. case KEY('m','e','t','a'):
  1622. /* comment command */
  1623. continue;
  1624. default:
  1625. report(3, "unknown command", u, (unsigned long)0);
  1626. }
  1627. break;
  1628. }
  1629. drop(buf);
  1630. if (cmd)
  1631. drop(cmd);
  1632. if (*r->name)
  1633. {
  1634. report(-1, r->name, "done", z);
  1635. state.indent--;
  1636. }
  1637. if (r->flags & RULE_active)
  1638. state.active--;
  1639. r->making--;
  1640. return r->time = z;
  1641. }
  1642. /*
  1643. * verify that active targets were made
  1644. */
  1645. static int
  1646. verify(Dict_item_t* item, void* handle)
  1647. {
  1648. Rule_t* r = (Rule_t*)item->value;
  1649. if ((r->flags & (RULE_active|RULE_error|RULE_made)) == RULE_active)
  1650. dont(r, 0, 1);
  1651. return 0;
  1652. }
  1653. /*
  1654. * return 1 if name is an initializer
  1655. */
  1656. static int
  1657. initializer(char* name)
  1658. {
  1659. register char* s;
  1660. if (s = last(name, '/'))
  1661. s++;
  1662. else
  1663. s = name;
  1664. return s[0] == 'I' && s[1] == 'N' && s[2] == 'I' && s[3] == 'T';
  1665. }
  1666. /*
  1667. * update recursion leaf r and its prerequisites
  1668. */
  1669. static int
  1670. update(register Rule_t* r)
  1671. {
  1672. register List_t* x;
  1673. Buf_t* buf;
  1674. static char cmd[] = "${MAMAKE} -C ";
  1675. static char arg[] = " ${MAMAKEARGS}";
  1676. r->flags |= RULE_made;
  1677. if (r->leaf)
  1678. r->leaf->flags |= RULE_made;
  1679. for (x = r->prereqs; x; x = x->next)
  1680. if (x->rule->leaf && !(x->rule->flags & RULE_made))
  1681. update(x->rule);
  1682. buf = buffer();
  1683. substitute(buf, cmd);
  1684. append(buf, r->name);
  1685. substitute(buf, arg);
  1686. run(r, use(buf));
  1687. drop(buf);
  1688. return 0;
  1689. }
  1690. /*
  1691. * scan Mamfile prereqs
  1692. */
  1693. static int
  1694. scan(Dict_item_t* item, void* handle)
  1695. {
  1696. register Rule_t* r = (Rule_t*)item->value;
  1697. register char* s;
  1698. register char* t;
  1699. register char* u;
  1700. register char* w;
  1701. Rule_t* q;
  1702. int i;
  1703. int j;
  1704. int k;
  1705. int p;
  1706. Buf_t* buf;
  1707. static char* files[] =
  1708. {
  1709. "Mamfile"
  1710. /* ksh 93u+m no longer uses these:
  1711. * "Nmakefile",
  1712. * "nmakefile",
  1713. * "Makefile",
  1714. * "makefile"
  1715. */
  1716. };
  1717. /*
  1718. * drop non-leaf rules
  1719. */
  1720. if (!r->leaf)
  1721. return 0;
  1722. /*
  1723. * always make initializers
  1724. */
  1725. if (initializer(r->name))
  1726. {
  1727. if (!(r->flags & RULE_made))
  1728. update(r);
  1729. return 0;
  1730. }
  1731. buf = buffer();
  1732. for (i = 0; i < elementsof(files); i++)
  1733. {
  1734. append(buf, r->name);
  1735. add(buf, '/');
  1736. append(buf, files[i]);
  1737. if (push(use(buf), (Stdio_t*)0, 0))
  1738. {
  1739. while (s = input())
  1740. {
  1741. j = p = 0;
  1742. while (*s)
  1743. {
  1744. for (k = 1; isspace(i = *s) || i == '"' || i == '\''; s++);
  1745. for (t = s; (i = *s) && !isspace(i) && i != '"' && i != '\'' && i != '\\' && i != ':'; s++)
  1746. if (i == '/')
  1747. t = s + 1;
  1748. else if (i == '.' && *(s + 1) != 'c' && *(s + 1) != 'C' && *(s + 1) != 'h' && *(s + 1) != 'H' && t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
  1749. *s = 0;
  1750. if (*s)
  1751. *s++ = 0;
  1752. if (!t[0])
  1753. k = 0;
  1754. else if ((t[0] == '-' || t[0] == '+') && t[1] == 'l' && t[2])
  1755. {
  1756. append(buf, "lib");
  1757. append(buf, t + 2);
  1758. t = use(buf);
  1759. }
  1760. else if (p)
  1761. {
  1762. if (t[0] == '+' && !t[1])
  1763. p = 2;
  1764. else if (p == 1)
  1765. {
  1766. if (i != ':' || strncmp(s, "command", 7))
  1767. {
  1768. append(buf, "lib");
  1769. append(buf, t);
  1770. t = use(buf);
  1771. }
  1772. if (i == ':')
  1773. while (*s && isspace(*s))
  1774. s++;
  1775. }
  1776. }
  1777. else if (i == ':')
  1778. {
  1779. if (j != ':' || !isupper(*t))
  1780. k = 0;
  1781. else if (!strcmp(t, "PACKAGE"))
  1782. {
  1783. p = 1;
  1784. k = 0;
  1785. }
  1786. else
  1787. {
  1788. for (u = t; *u; u++)
  1789. {
  1790. if (isupper(*u))
  1791. *u = tolower(*u);
  1792. else if (!isalnum(*u))
  1793. {
  1794. k = 0;
  1795. break;
  1796. }
  1797. }
  1798. }
  1799. }
  1800. else if (t[0] != 'l' || t[1] != 'i' || t[2] != 'b')
  1801. k = 0;
  1802. else
  1803. {
  1804. for (u = t + 3; *u; u++)
  1805. {
  1806. if (!isalnum(*u))
  1807. {
  1808. k = 0;
  1809. break;
  1810. }
  1811. }
  1812. }
  1813. if (k && ((q = (Rule_t*)search(state.leaf, t, NiL)) && q != r || *t++ == 'l' && *t++ == 'i' && *t++ == 'b' && *t && (q = (Rule_t*)search(state.leaf, t, NiL)) && q != r))
  1814. {
  1815. for (t = w = r->name; *w; w++)
  1816. if (*w == '/')
  1817. t = w + 1;
  1818. if (t[0] == 'l' && t[1] == 'i' && t[2] == 'b')
  1819. t += 3;
  1820. for (u = w = q->name; *w; w++)
  1821. if (*w == '/')
  1822. u = w + 1;
  1823. if (strcmp(t, u))
  1824. cons(r, q);
  1825. }
  1826. j = i;
  1827. }
  1828. }
  1829. pop();
  1830. for (s = 0, w = r->name; *w; w++)
  1831. if (*w == '/')
  1832. s = w;
  1833. if (s)
  1834. {
  1835. if ((s - r->name) > 3 && *(s - 1) == 'b' && *(s - 2) == 'i' && *(s - 3) == 'l' && *(s - 4) != '/')
  1836. {
  1837. /*
  1838. * foolib : foo : libfoo
  1839. */
  1840. *(s - 3) = 0;
  1841. q = (Rule_t*)search(state.leaf, r->name, NiL);
  1842. if (q && q != r)
  1843. cons(r, q);
  1844. for (t = w = r->name; *w; w++)
  1845. if (*w == '/')
  1846. t = w + 1;
  1847. append(buf, "lib");
  1848. append(buf, t);
  1849. q = (Rule_t*)search(state.leaf, use(buf), NiL);
  1850. if (q && q != r)
  1851. cons(r, q);
  1852. *(s - 3) = 'l';
  1853. }
  1854. else if (((s - r->name) != 3 || *(s - 1) != 'b' || *(s - 2) != 'i' || *(s - 3) != 'l') && (*(s + 1) != 'l' || *(s + 2) != 'i' || *(s + 3) != 'b'))
  1855. {
  1856. /*
  1857. * huh/foobar : lib/libfoo
  1858. */
  1859. s++;
  1860. t = s + strlen(s);
  1861. while (--t > s)
  1862. {
  1863. append(buf, "lib/lib");
  1864. appendn(buf, s, t - s);
  1865. q = (Rule_t*)search(state.leaf, use(buf), NiL);
  1866. if (q && q != r)
  1867. cons(r, q);
  1868. }
  1869. }
  1870. }
  1871. break;
  1872. }
  1873. }
  1874. drop(buf);
  1875. return 0;
  1876. }
  1877. /*
  1878. * descend into op and its prereqs
  1879. */
  1880. static int
  1881. descend(Dict_item_t* item, void* handle)
  1882. {
  1883. Rule_t* r = (Rule_t*)item->value;
  1884. if (!state.active && (!(r->flags & RULE_active) || !(r = (Rule_t*)search(state.leaf, r->name, NiL))))
  1885. return 0;
  1886. return r->leaf && !(r->flags & RULE_made) ? update(r) : 0;
  1887. }
  1888. /*
  1889. * append the non-leaf active targets to state.opt
  1890. */
  1891. static int
  1892. active(Dict_item_t* item, void* handle)
  1893. {
  1894. Rule_t* r = (Rule_t*)item->value;
  1895. if (r->flags & RULE_active)
  1896. {
  1897. if (r->leaf || search(state.leaf, r->name, NiL))
  1898. state.active = 0;
  1899. else
  1900. {
  1901. add(state.opt, ' ');
  1902. append(state.opt, r->name);
  1903. }
  1904. }
  1905. return 0;
  1906. }
  1907. /*
  1908. * recurse on mamfiles in subdirs matching pattern
  1909. */
  1910. static int
  1911. recurse(char* pattern)
  1912. {
  1913. register char* s;
  1914. register char* t;
  1915. Rule_t* r;
  1916. Buf_t* buf;
  1917. Buf_t* tmp;
  1918. struct stat st;
  1919. /*
  1920. * first determine the MAM subdirs
  1921. */
  1922. tmp = buffer();
  1923. buf = buffer();
  1924. state.exec = !state.never;
  1925. state.leaf = dictionary();
  1926. append(buf, "ls -d ");
  1927. append(buf, pattern);
  1928. s = use(buf);
  1929. push("recurse", popen(s, "r"), STREAM_PIPE);
  1930. while (s = input())
  1931. {
  1932. append(buf, s);
  1933. add(buf, '/');
  1934. append(buf, mamfile);
  1935. if (find(tmp, use(buf), &st))
  1936. {
  1937. r = rule(s);
  1938. if (t = last(r->name, '/'))
  1939. t++;
  1940. else
  1941. t = r->name;
  1942. r->leaf = rule(t);
  1943. search(state.leaf, t, r);
  1944. }
  1945. }
  1946. pop();
  1947. drop(buf);
  1948. drop(tmp);
  1949. /*
  1950. * grab the non-leaf active targets
  1951. */
  1952. if (!state.active)
  1953. {
  1954. state.active = 1;
  1955. walk(state.rules, active, NiL);
  1956. }
  1957. search(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1));
  1958. /*
  1959. * scan the Mamfile and descend
  1960. */
  1961. walk(state.rules, scan, NiL);
  1962. while (state.view)
  1963. {
  1964. View_t *prev = state.view;
  1965. state.view = state.view->next;
  1966. free(prev);
  1967. }
  1968. walk(state.rules, descend, NiL);
  1969. return 0;
  1970. }
  1971. int
  1972. main(int argc, char** argv)
  1973. {
  1974. register char** e;
  1975. register char* s;
  1976. register char* t;
  1977. register char* v;
  1978. Buf_t* tmp;
  1979. int c;
  1980. /*
  1981. * initialize the state
  1982. */
  1983. state.id = "mamake";
  1984. state.active = 1;
  1985. state.exec = 1;
  1986. state.file = mamfile;
  1987. state.opt = buffer();
  1988. state.rules = dictionary();
  1989. state.vars = dictionary();
  1990. search(state.vars, "MAMAKE", *argv);
  1991. /*
  1992. * parse the options
  1993. */
  1994. #if _PACKAGE_ast
  1995. error_info.id = state.id;
  1996. for (;;)
  1997. {
  1998. switch (optget(argv, usage))
  1999. {
  2000. case 'e':
  2001. append(state.opt, " -e");
  2002. state.explain = 1;
  2003. continue;
  2004. case 'i':
  2005. append(state.opt, " -i");
  2006. state.ignore = 1;
  2007. continue;
  2008. case 'k':
  2009. append(state.opt, " -k");
  2010. state.keepgoing = 1;
  2011. continue;
  2012. case 'N':
  2013. state.never = 1;
  2014. /* FALLTHROUGH */
  2015. case 'n':
  2016. append(state.opt, " -n");
  2017. state.exec = 0;
  2018. continue;
  2019. case 'F':
  2020. append(state.opt, " -F");
  2021. state.force = 1;
  2022. continue;
  2023. case 'K':
  2024. continue;
  2025. case 'V':
  2026. fprintf(stdout, "%s\n", id + 10);
  2027. exit(0);
  2028. case 'f':
  2029. append(state.opt, " -f ");
  2030. append(state.opt, opt_info.arg);
  2031. state.file = opt_info.arg;
  2032. continue;
  2033. case 'r':
  2034. state.recurse = opt_info.arg;
  2035. continue;
  2036. case 'C':
  2037. state.directory = opt_info.arg;
  2038. continue;
  2039. case 'D':
  2040. append(state.opt, " -D");
  2041. append(state.opt, opt_info.arg);
  2042. state.debug = -opt_info.num;
  2043. continue;
  2044. case 'G':
  2045. append(state.opt, " -G");
  2046. search(state.vars, "-debug-symbols", "1");
  2047. continue;
  2048. case 'S':
  2049. append(state.opt, " -S");
  2050. search(state.vars, "-strip-symbols", "1");
  2051. continue;
  2052. case '?':
  2053. error(ERROR_usage(2), "%s", opt_info.arg);
  2054. UNREACHABLE();
  2055. case ':':
  2056. error(2, "%s", opt_info.arg);
  2057. continue;
  2058. }
  2059. break;
  2060. }
  2061. if (error_info.errors)
  2062. {
  2063. error(ERROR_usage(2), "%s", optusage(NiL));
  2064. UNREACHABLE();
  2065. }
  2066. argv += opt_info.index;
  2067. #else
  2068. while ((s = *++argv) && *s == '-')
  2069. {
  2070. if (*(s + 1) == '-')
  2071. {
  2072. if (!*(s + 2))
  2073. {
  2074. append(state.opt, " --");
  2075. argv++;
  2076. break;
  2077. }
  2078. for (t = s += 2; *t && *t != '='; t++);
  2079. if (!strncmp(s, "debug-symbols", t - s) && append(state.opt, " -G") || !strncmp(s, "strip-symbols", t - s) && append(state.opt, " -S"))
  2080. {
  2081. if (*t)
  2082. {
  2083. v = t + 1;
  2084. if (t > s && *(t - 1) == '+')
  2085. t--;
  2086. c = *t;
  2087. *t = 0;
  2088. }
  2089. else
  2090. {
  2091. c = 0;
  2092. v = "1";
  2093. }
  2094. search(state.vars, s - 1, v);
  2095. if (c)
  2096. *t = c;
  2097. continue;
  2098. }
  2099. usage();
  2100. break;
  2101. }
  2102. for (;;)
  2103. {
  2104. switch (*++s)
  2105. {
  2106. case 0:
  2107. break;
  2108. case 'e':
  2109. append(state.opt, " -e");
  2110. state.explain = 1;
  2111. continue;
  2112. case 'i':
  2113. append(state.opt, " -i");
  2114. state.ignore = 1;
  2115. continue;
  2116. case 'k':
  2117. append(state.opt, " -k");
  2118. state.keepgoing = 1;
  2119. continue;
  2120. case 'N':
  2121. state.never = 1;
  2122. /* FALLTHROUGH */
  2123. case 'n':
  2124. append(state.opt, " -n");
  2125. state.exec = 0;
  2126. continue;
  2127. case 'F':
  2128. append(state.opt, " -F");
  2129. state.force = 1;
  2130. continue;
  2131. case 'G':
  2132. append(state.opt, " -G");
  2133. search(state.vars, "-debug-symbols", "1");
  2134. continue;
  2135. case 'K':
  2136. continue;
  2137. case 'S':
  2138. append(state.opt, " -S");
  2139. search(state.vars, "-strip-symbols", "1");
  2140. continue;
  2141. case 'V':
  2142. fprintf(stdout, "%s\n", id + 10);
  2143. exit(0);
  2144. case 'f':
  2145. case 'r':
  2146. case 'C':
  2147. case 'D':
  2148. t = s;
  2149. if (!*++s && !(s = *++argv))
  2150. {
  2151. report(2, "option value expected", t, (unsigned long)0);
  2152. usage();
  2153. }
  2154. else
  2155. switch (*t)
  2156. {
  2157. case 'f':
  2158. append(state.opt, " -f ");
  2159. append(state.opt, s);
  2160. state.file = s;
  2161. break;
  2162. case 'r':
  2163. state.recurse = s;
  2164. break;
  2165. case 'C':
  2166. state.directory = s;
  2167. break;
  2168. case 'D':
  2169. append(state.opt, " -D");
  2170. append(state.opt, s);
  2171. state.debug = -atoi(s);
  2172. break;
  2173. }
  2174. break;
  2175. default:
  2176. report(2, "unknown option", s, (unsigned long)0);
  2177. /* FALLTHROUGH */
  2178. case '?':
  2179. usage();
  2180. break;
  2181. }
  2182. break;
  2183. }
  2184. }
  2185. #endif
  2186. /*
  2187. * load the environment
  2188. */
  2189. for (e = environ; s = *e; e++)
  2190. {
  2191. for (t = s; *t; t++)
  2192. {
  2193. if (*t == '=')
  2194. {
  2195. *t = 0;
  2196. search(state.vars, s, t + 1);
  2197. *t = '=';
  2198. break;
  2199. }
  2200. }
  2201. }
  2202. /*
  2203. * grab the command line targets and variable definitions
  2204. */
  2205. while (s = *argv++)
  2206. {
  2207. for (t = s; *t; t++)
  2208. {
  2209. if (*t == '=')
  2210. {
  2211. v = t + 1;
  2212. if (t > s && *(t - 1) == '+')
  2213. t--;
  2214. c = *t;
  2215. *t = 0;
  2216. search(state.vars, s, v);
  2217. tmp = buffer();
  2218. append(tmp, s);
  2219. append(tmp, ".FORCE");
  2220. search(state.vars, use(tmp), v);
  2221. drop(tmp);
  2222. *t = c;
  2223. break;
  2224. }
  2225. }
  2226. if (!*t)
  2227. {
  2228. /*
  2229. * handle a few targets for nmake compatibility
  2230. */
  2231. if (*s == 'e' && !strncmp(s, "error 0 $(MAKEVERSION:", 22))
  2232. exit(1);
  2233. if (*s == 'r' && !strcmp(s, "recurse") || *s == 'c' && !strncmp(s, "cc-", 3))
  2234. continue;
  2235. rule(s)->flags |= RULE_active;
  2236. state.active = 0;
  2237. if (state.recurse)
  2238. continue;
  2239. }
  2240. add(state.opt, ' ');
  2241. add(state.opt, '\'');
  2242. append(state.opt, s);
  2243. add(state.opt, '\'');
  2244. }
  2245. /*
  2246. * initialize the views
  2247. */
  2248. if (state.directory && chdir(state.directory))
  2249. report(3, "cannot change working directory", NiL, (unsigned long)0);
  2250. view();
  2251. /*
  2252. * recursion drops out here
  2253. */
  2254. if (state.recurse)
  2255. return recurse(state.recurse);
  2256. /*
  2257. * read the mamfile(s) and bring the targets up to date
  2258. */
  2259. search(state.vars, "MAMAKEARGS", duplicate(use(state.opt) + 1));
  2260. push(state.file, (Stdio_t*)0, STREAM_MUST);
  2261. make(rule(""));
  2262. pop();
  2263. /*
  2264. * verify that active targets were made
  2265. */
  2266. if (!state.active && !state.verified)
  2267. walk(state.rules, verify, NiL);
  2268. /*
  2269. * done
  2270. */
  2271. return state.errors != 0;
  2272. }