1
0

makeshell.c 28 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099
  1. /*
  2. * $Id: makeshell.c,v 4.22 2007/07/04 21:36:37 bkorb Exp $
  3. * Time-stamp: "2007-07-04 10:22:32 bkorb"
  4. *
  5. * This module will interpret the options set in the tOptions
  6. * structure and create a Bourne shell script capable of parsing them.
  7. *
  8. * This file is part of AutoOpts, a companion to AutoGen.
  9. * AutoOpts is free software.
  10. * AutoOpts is copyright (c) 1992-2007 by Bruce Korb - all rights reserved
  11. *
  12. * AutoOpts is available under any one of two licenses. The license
  13. * in use must be one of these two and the choice is under the control
  14. * of the user of the license.
  15. *
  16. * The GNU Lesser General Public License, version 3 or later
  17. * See the files "COPYING.lgplv3" and "COPYING.gplv3"
  18. *
  19. * The Modified Berkeley Software Distribution License
  20. * See the file "COPYING.mbsd"
  21. *
  22. * These files have the following md5sums:
  23. *
  24. * 239588c55c22c60ffe159946a760a33e pkg/libopts/COPYING.gplv3
  25. * fa82ca978890795162346e661b47161a pkg/libopts/COPYING.lgplv3
  26. * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
  27. */
  28. tOptions* pShellParseOptions = NULL;
  29. /* * * * * * * * * * * * * * * * * * * * *
  30. *
  31. * Setup Format Strings
  32. */
  33. tSCC zStartMarker[] =
  34. "# # # # # # # # # # -- do not modify this marker --\n#\n"
  35. "# DO NOT EDIT THIS SECTION";
  36. tSCC zPreamble[] =
  37. "%s OF %s\n#\n"
  38. "# From here to the next `-- do not modify this marker --',\n"
  39. "# the text has been generated %s\n";
  40. tSCC zEndPreamble[] =
  41. "# From the %s option definitions\n#\n";
  42. tSCC zMultiDef[] = "\n"
  43. "if test -z \"${%1$s_%2$s}\"\n"
  44. "then\n"
  45. " %1$s_%2$s_CT=0\n"
  46. "else\n"
  47. " %1$s_%2$s_CT=1\n"
  48. " %1$s_%2$s_1=\"${%1$s_%2$s}\"\n"
  49. "fi\n"
  50. "export %1$s_%2$s_CT";
  51. tSCC zSingleDef[] = "\n"
  52. "%1$s_%2$s=\"${%1$s_%2$s-'%3$s'}\"\n"
  53. "%1$s_%2$s_set=false\n"
  54. "export %1$s_%2$s\n";
  55. tSCC zSingleNoDef[] = "\n"
  56. "%1$s_%2$s=\"${%1$s_%2$s}\"\n"
  57. "%1$s_%2$s_set=false\n"
  58. "export %1$s_%2$s\n";
  59. /* * * * * * * * * * * * * * * * * * * * *
  60. *
  61. * LOOP START
  62. *
  63. * The loop may run in either of two modes:
  64. * all options are named options (loop only)
  65. * regular, marked option processing.
  66. */
  67. tSCC zLoopCase[] = "\n"
  68. "OPT_PROCESS=true\n"
  69. "OPT_ARG=\"$1\"\n\n"
  70. "while ${OPT_PROCESS} && [ $# -gt 0 ]\ndo\n"
  71. " OPT_ELEMENT=''\n"
  72. " OPT_ARG_VAL=''\n\n"
  73. /*
  74. * 'OPT_ARG' may or may not match the current $1
  75. */
  76. " case \"${OPT_ARG}\" in\n"
  77. " -- )\n"
  78. " OPT_PROCESS=false\n"
  79. " shift\n"
  80. " ;;\n\n";
  81. tSCC zLoopOnly[] = "\n"
  82. "OPT_ARG=\"$1\"\n\n"
  83. "while [ $# -gt 0 ]\ndo\n"
  84. " OPT_ELEMENT=''\n"
  85. " OPT_ARG_VAL=''\n\n"
  86. " OPT_ARG=\"${1}\"\n";
  87. /* * * * * * * * * * * * * * * *
  88. *
  89. * CASE SELECTORS
  90. *
  91. * If the loop runs as a regular option loop,
  92. * then we must have selectors for each acceptable option
  93. * type (long option, flag character and non-option)
  94. */
  95. tSCC zLongSelection[] =
  96. " --* )\n";
  97. tSCC zFlagSelection[] =
  98. " -* )\n";
  99. tSCC zEndSelection[] =
  100. " ;;\n\n";
  101. tSCC zNoSelection[] =
  102. " * )\n"
  103. " OPT_PROCESS=false\n"
  104. " ;;\n"
  105. " esac\n\n";
  106. /* * * * * * * * * * * * * * * *
  107. *
  108. * LOOP END
  109. */
  110. tSCC zLoopEnd[] =
  111. " if [ -n \"${OPT_ARG_VAL}\" ]\n"
  112. " then\n"
  113. " eval %1$s_${OPT_NAME}${OPT_ELEMENT}=\"'${OPT_ARG_VAL}'\"\n"
  114. " export %1$s_${OPT_NAME}${OPT_ELEMENT}\n"
  115. " fi\n"
  116. "done\n\n"
  117. "unset OPT_PROCESS || :\n"
  118. "unset OPT_ELEMENT || :\n"
  119. "unset OPT_ARG || :\n"
  120. "unset OPT_ARG_NEEDED || :\n"
  121. "unset OPT_NAME || :\n"
  122. "unset OPT_CODE || :\n"
  123. "unset OPT_ARG_VAL || :\n%2$s";
  124. tSCC zTrailerMarker[] = "\n"
  125. "# # # # # # # # # #\n#\n"
  126. "# END OF AUTOMATED OPTION PROCESSING\n"
  127. "#\n# # # # # # # # # # -- do not modify this marker --\n";
  128. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  129. *
  130. * OPTION SELECTION
  131. */
  132. tSCC zOptionCase[] =
  133. " case \"${OPT_CODE}\" in\n";
  134. tSCC zOptionPartName[] =
  135. " '%s' | \\\n";
  136. tSCC zOptionFullName[] =
  137. " '%s' )\n";
  138. tSCC zOptionFlag[] =
  139. " '%c' )\n";
  140. tSCC zOptionEndSelect[] =
  141. " ;;\n\n";
  142. tSCC zOptionUnknown[] =
  143. " * )\n"
  144. " echo Unknown %s: \"${OPT_CODE}\" >&2\n"
  145. " echo \"$%s_USAGE_TEXT\"\n"
  146. " exit 1\n"
  147. " ;;\n"
  148. " esac\n\n";
  149. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  150. *
  151. * OPTION PROCESSING
  152. *
  153. * Formats for emitting the text for handling particular options
  154. */
  155. tSCC zTextExit[] =
  156. " echo \"$%s_%s_TEXT\"\n"
  157. " exit 0\n";
  158. tSCC zPagedUsageExit[] =
  159. " echo \"$%s_LONGUSAGE_TEXT\" | ${PAGER-more}\n"
  160. " exit 0\n";
  161. tSCC zCmdFmt[] =
  162. " %s\n";
  163. tSCC zCountTest[] =
  164. " if [ $%1$s_%2$s_CT -ge %3$d ] ; then\n"
  165. " echo Error: more than %3$d %2$s options >&2\n"
  166. " echo \"$%1$s_USAGE_TEXT\"\n"
  167. " exit 1 ; fi\n";
  168. tSCC zMultiArg[] =
  169. " %1$s_%2$s_CT=`expr ${%1$s_%2$s_CT} + 1`\n"
  170. " OPT_ELEMENT=\"_${%1$s_%2$s_CT}\"\n"
  171. " OPT_NAME='%2$s'\n";
  172. tSCC zSingleArg[] =
  173. " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
  174. " echo Error: duplicate %2$s option >&2\n"
  175. " echo \"$%1$s_USAGE_TEXT\"\n"
  176. " exit 1 ; fi\n"
  177. " %1$s_%2$s_set=true\n"
  178. " OPT_NAME='%2$s'\n";
  179. tSCC zNoMultiArg[] =
  180. " %1$s_%2$s_CT=0\n"
  181. " OPT_ELEMENT=''\n"
  182. " %1$s_%2$s='%3$s'\n"
  183. " export %1$s_%2$s\n"
  184. " OPT_NAME='%2$s'\n";
  185. tSCC zNoSingleArg[] =
  186. " if [ -n \"${%1$s_%2$s}\" ] && ${%1$s_%2$s_set} ; then\n"
  187. " echo Error: duplicate %2$s option >&2\n"
  188. " echo \"$%1$s_USAGE_TEXT\"\n"
  189. " exit 1 ; fi\n"
  190. " %1$s_%2$s_set=true\n"
  191. " %1$s_%2$s='%3$s'\n"
  192. " export %1$s_%2$s\n"
  193. " OPT_NAME='%2$s'\n";
  194. tSCC zMayArg[] =
  195. " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
  196. " export %1$s_%2$s${OPT_ELEMENT}\n"
  197. " OPT_ARG_NEEDED=OK\n";
  198. tSCC zMustArg[] =
  199. " OPT_ARG_NEEDED=YES\n";
  200. tSCC zCantArg[] =
  201. " eval %1$s_%2$s${OPT_ELEMENT}=true\n"
  202. " export %1$s_%2$s${OPT_ELEMENT}\n"
  203. " OPT_ARG_NEEDED=NO\n";
  204. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  205. *
  206. * LONG OPTION PROCESSING
  207. *
  208. * Formats for emitting the text for handling long option types
  209. */
  210. tSCC zLongOptInit[] =
  211. " OPT_CODE=`echo \"X${OPT_ARG}\"|sed 's/^X-*//'`\n"
  212. " shift\n"
  213. " OPT_ARG=\"$1\"\n\n"
  214. " case \"${OPT_CODE}\" in *=* )\n"
  215. " OPT_ARG_VAL=`echo \"${OPT_CODE}\"|sed 's/^[^=]*=//'`\n"
  216. " OPT_CODE=`echo \"${OPT_CODE}\"|sed 's/=.*$//'` ;; esac\n\n";
  217. tSCC zLongOptArg[] =
  218. " case \"${OPT_ARG_NEEDED}\" in\n"
  219. " NO )\n"
  220. " OPT_ARG_VAL=''\n"
  221. " ;;\n\n"
  222. " YES )\n"
  223. " if [ -z \"${OPT_ARG_VAL}\" ]\n"
  224. " then\n"
  225. " if [ $# -eq 0 ]\n"
  226. " then\n"
  227. " echo No argument provided for ${OPT_NAME} option >&2\n"
  228. " echo \"$%s_USAGE_TEXT\"\n"
  229. " exit 1\n"
  230. " fi\n\n"
  231. " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  232. " shift\n"
  233. " OPT_ARG=\"$1\"\n"
  234. " fi\n"
  235. " ;;\n\n"
  236. " OK )\n"
  237. " if [ -z \"${OPT_ARG_VAL}\" ] && [ $# -gt 0 ]\n"
  238. " then\n"
  239. " case \"${OPT_ARG}\" in -* ) ;; * )\n"
  240. " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  241. " shift\n"
  242. " OPT_ARG=\"$1\" ;; esac\n"
  243. " fi\n"
  244. " ;;\n"
  245. " esac\n";
  246. /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  247. *
  248. * FLAG OPTION PROCESSING
  249. *
  250. * Formats for emitting the text for handling flag option types
  251. */
  252. tSCC zFlagOptInit[] =
  253. " OPT_CODE=`echo \"X${OPT_ARG}\" | sed 's/X-\\(.\\).*/\\1/'`\n"
  254. " OPT_ARG=` echo \"X${OPT_ARG}\" | sed 's/X-.//'`\n\n";
  255. tSCC zFlagOptArg[] =
  256. " case \"${OPT_ARG_NEEDED}\" in\n"
  257. " NO )\n"
  258. " if [ -n \"${OPT_ARG}\" ]\n"
  259. " then\n"
  260. " OPT_ARG=-\"${OPT_ARG}\"\n"
  261. " else\n"
  262. " shift\n"
  263. " OPT_ARG=\"$1\"\n"
  264. " fi\n"
  265. " ;;\n\n"
  266. " YES )\n"
  267. " if [ -n \"${OPT_ARG}\" ]\n"
  268. " then\n"
  269. " OPT_ARG_VAL=\"${OPT_ARG}\"\n\n"
  270. " else\n"
  271. " if [ $# -eq 0 ]\n"
  272. " then\n"
  273. " echo No argument provided for ${OPT_NAME} option >&2\n"
  274. " echo \"$%s_USAGE_TEXT\"\n"
  275. " exit 1\n"
  276. " fi\n"
  277. " shift\n"
  278. " OPT_ARG_VAL=\"$1\"\n"
  279. " fi\n\n"
  280. " shift\n"
  281. " OPT_ARG=\"$1\"\n"
  282. " ;;\n\n"
  283. " OK )\n"
  284. " if [ -n \"${OPT_ARG}\" ]\n"
  285. " then\n"
  286. " OPT_ARG_VAL=\"${OPT_ARG}\"\n"
  287. " shift\n"
  288. " OPT_ARG=\"$1\"\n\n"
  289. " else\n"
  290. " shift\n"
  291. " if [ $# -gt 0 ]\n"
  292. " then\n"
  293. " case \"$1\" in -* ) ;; * )\n"
  294. " OPT_ARG_VAL=\"$1\"\n"
  295. " shift ;; esac\n"
  296. " OPT_ARG=\"$1\"\n"
  297. " fi\n"
  298. " fi\n"
  299. " ;;\n"
  300. " esac\n";
  301. tSCC* pzShell = NULL;
  302. static char* pzLeader = NULL;
  303. static char* pzTrailer = NULL;
  304. /* = = = START-STATIC-FORWARD = = = */
  305. /* static forward declarations maintained by :mkfwd */
  306. static void
  307. textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD );
  308. static void
  309. emitUsage( tOptions* pOpts );
  310. static void
  311. emitSetup( tOptions* pOpts );
  312. static void
  313. printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc );
  314. static void
  315. printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc );
  316. static void
  317. emitFlag( tOptions* pOpts );
  318. static void
  319. emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts );
  320. static void
  321. emitLong( tOptions* pOpts );
  322. static void
  323. openOutput( char const* pzFile );
  324. /* = = = END-STATIC-FORWARD = = = */
  325. /*=export_func optionParseShell
  326. * private:
  327. *
  328. * what: Decipher a boolean value
  329. * arg: + tOptions* + pOpts + program options descriptor +
  330. *
  331. * doc:
  332. * Emit a shell script that will parse the command line options.
  333. =*/
  334. void
  335. optionParseShell( tOptions* pOpts )
  336. {
  337. /*
  338. * Check for our SHELL option now.
  339. * IF the output file contains the "#!" magic marker,
  340. * it will override anything we do here.
  341. */
  342. if (HAVE_OPT( SHELL ))
  343. pzShell = OPT_ARG( SHELL );
  344. else if (! ENABLED_OPT( SHELL ))
  345. pzShell = NULL;
  346. else if ((pzShell = getenv( "SHELL" )),
  347. pzShell == NULL)
  348. pzShell = "/bin/sh";
  349. /*
  350. * Check for a specified output file
  351. */
  352. if (HAVE_OPT( SCRIPT ))
  353. openOutput( OPT_ARG( SCRIPT ));
  354. emitUsage( pOpts );
  355. emitSetup( pOpts );
  356. /*
  357. * There are four modes of option processing.
  358. */
  359. switch (pOpts->fOptSet & (OPTPROC_LONGOPT|OPTPROC_SHORTOPT)) {
  360. case OPTPROC_LONGOPT:
  361. fputs( zLoopCase, stdout );
  362. fputs( zLongSelection, stdout );
  363. fputs( zLongOptInit, stdout );
  364. emitLong( pOpts );
  365. printf( zLongOptArg, pOpts->pzPROGNAME );
  366. fputs( zEndSelection, stdout );
  367. fputs( zNoSelection, stdout );
  368. break;
  369. case 0:
  370. fputs( zLoopOnly, stdout );
  371. fputs( zLongOptInit, stdout );
  372. emitLong( pOpts );
  373. printf( zLongOptArg, pOpts->pzPROGNAME );
  374. break;
  375. case OPTPROC_SHORTOPT:
  376. fputs( zLoopCase, stdout );
  377. fputs( zFlagSelection, stdout );
  378. fputs( zFlagOptInit, stdout );
  379. emitFlag( pOpts );
  380. printf( zFlagOptArg, pOpts->pzPROGNAME );
  381. fputs( zEndSelection, stdout );
  382. fputs( zNoSelection, stdout );
  383. break;
  384. case OPTPROC_LONGOPT|OPTPROC_SHORTOPT:
  385. fputs( zLoopCase, stdout );
  386. fputs( zLongSelection, stdout );
  387. fputs( zLongOptInit, stdout );
  388. emitLong( pOpts );
  389. printf( zLongOptArg, pOpts->pzPROGNAME );
  390. fputs( zEndSelection, stdout );
  391. fputs( zFlagSelection, stdout );
  392. fputs( zFlagOptInit, stdout );
  393. emitFlag( pOpts );
  394. printf( zFlagOptArg, pOpts->pzPROGNAME );
  395. fputs( zEndSelection, stdout );
  396. fputs( zNoSelection, stdout );
  397. break;
  398. }
  399. printf( zLoopEnd, pOpts->pzPROGNAME, zTrailerMarker );
  400. if ((pzTrailer != NULL) && (*pzTrailer != '\0'))
  401. fputs( pzTrailer, stdout );
  402. else if (ENABLED_OPT( SHELL ))
  403. printf( "\nenv | grep '^%s_'\n", pOpts->pzPROGNAME );
  404. fflush( stdout );
  405. fchmod( STDOUT_FILENO, 0755 );
  406. fclose( stdout );
  407. }
  408. static void
  409. textToVariable( tOptions* pOpts, teTextTo whichVar, tOptDesc* pOD )
  410. {
  411. # define _TT_(n) tSCC z ## n [] = #n;
  412. TEXTTO_TABLE
  413. # undef _TT_
  414. # define _TT_(n) z ## n ,
  415. static char const* apzTTNames[] = { TEXTTO_TABLE };
  416. # undef _TT_
  417. #if defined(__windows__) && !defined(__CYGWIN__)
  418. printf( "%1$s_%2$s_TEXT='no %2$s text'\n",
  419. pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
  420. #else
  421. int nlHoldCt = 0;
  422. int pipeFd[2];
  423. FILE* fp;
  424. printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
  425. fflush( stdout );
  426. if (pipe( pipeFd ) != 0) {
  427. fprintf( stderr, zBadPipe, errno, strerror( errno ));
  428. exit( EXIT_FAILURE );
  429. }
  430. switch (fork()) {
  431. case -1:
  432. fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
  433. exit( EXIT_FAILURE );
  434. break;
  435. case 0:
  436. dup2( pipeFd[1], STDERR_FILENO );
  437. dup2( pipeFd[1], STDOUT_FILENO );
  438. close( pipeFd[0] );
  439. switch (whichVar) {
  440. case TT_LONGUSAGE:
  441. (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
  442. /* NOTREACHED */
  443. exit( EXIT_FAILURE );
  444. case TT_USAGE:
  445. (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
  446. /* NOTREACHED */
  447. exit( EXIT_FAILURE );
  448. case TT_VERSION:
  449. if (pOD->fOptState & OPTST_ALLOC_ARG) {
  450. AGFREE(pOD->optArg.argString);
  451. pOD->fOptState &= ~OPTST_ALLOC_ARG;
  452. }
  453. pOD->optArg.argString = "c";
  454. optionPrintVersion( pOpts, pOD );
  455. /* NOTREACHED */
  456. default:
  457. exit( EXIT_FAILURE );
  458. }
  459. default:
  460. close( pipeFd[1] );
  461. fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
  462. }
  463. for (;;) {
  464. int ch = fgetc( fp );
  465. switch (ch) {
  466. case '\n':
  467. nlHoldCt++;
  468. break;
  469. case '\'':
  470. while (nlHoldCt > 0) {
  471. fputc( '\n', stdout );
  472. nlHoldCt--;
  473. }
  474. fputs( "'\\''", stdout );
  475. break;
  476. case EOF:
  477. goto endCharLoop;
  478. default:
  479. while (nlHoldCt > 0) {
  480. fputc( '\n', stdout );
  481. nlHoldCt--;
  482. }
  483. fputc( ch, stdout );
  484. break;
  485. }
  486. } endCharLoop:;
  487. fputs( "'\n\n", stdout );
  488. close( pipeFd[0] );
  489. #endif
  490. }
  491. static void
  492. emitUsage( tOptions* pOpts )
  493. {
  494. char zTimeBuf[ AO_NAME_SIZE ];
  495. /*
  496. * First, switch stdout to the output file name.
  497. * Then, change the program name to the one defined
  498. * by the definitions (rather than the current
  499. * executable name). Down case the upper cased name.
  500. */
  501. if (pzLeader != NULL)
  502. fputs( pzLeader, stdout );
  503. {
  504. tSCC zStdout[] = "stdout";
  505. tCC* pzOutName;
  506. {
  507. time_t curTime = time( NULL );
  508. struct tm* pTime = localtime( &curTime );
  509. strftime(zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
  510. }
  511. if (HAVE_OPT( SCRIPT ))
  512. pzOutName = OPT_ARG( SCRIPT );
  513. else pzOutName = zStdout;
  514. if ((pzLeader == NULL) && (pzShell != NULL))
  515. printf( "#! %s\n", pzShell );
  516. printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
  517. }
  518. /*
  519. * Get a copy of the original program name in lower case
  520. */
  521. {
  522. char* pzPN = zTimeBuf;
  523. tCC* pz = pOpts->pzPROGNAME;
  524. for (;;) {
  525. if ((*pzPN++ = tolower( *pz++ )) == '\0')
  526. break;
  527. }
  528. }
  529. printf( zEndPreamble, pOpts->pzPROGNAME );
  530. pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
  531. textToVariable( pOpts, TT_LONGUSAGE, NULL );
  532. textToVariable( pOpts, TT_USAGE, NULL );
  533. {
  534. tOptDesc* pOptDesc = pOpts->pOptDesc;
  535. int optionCt = pOpts->optCt;
  536. for (;;) {
  537. if (pOptDesc->pOptProc == optionPrintVersion) {
  538. textToVariable( pOpts, TT_VERSION, pOptDesc );
  539. break;
  540. }
  541. if (--optionCt <= 0)
  542. break;
  543. pOptDesc++;
  544. }
  545. }
  546. }
  547. static void
  548. emitSetup( tOptions* pOpts )
  549. {
  550. tOptDesc* pOptDesc = pOpts->pOptDesc;
  551. int optionCt = pOpts->presetOptCt;
  552. char const* pzFmt;
  553. char const* pzDefault;
  554. for (;optionCt > 0; pOptDesc++, --optionCt) {
  555. char zVal[16];
  556. /*
  557. * Options that are either usage documentation or are compiled out
  558. * are not to be processed.
  559. */
  560. if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
  561. continue;
  562. if (pOptDesc->optMaxCt > 1)
  563. pzFmt = zMultiDef;
  564. else pzFmt = zSingleDef;
  565. /*
  566. * IF this is an enumeration/bitmask option, then convert the value
  567. * to a string before printing the default value.
  568. */
  569. switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
  570. case OPARG_TYPE_ENUMERATION:
  571. (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc );
  572. pzDefault = pOptDesc->optArg.argString;
  573. break;
  574. /*
  575. * Numeric and membership bit options are just printed as a number.
  576. */
  577. case OPARG_TYPE_NUMERIC:
  578. snprintf( zVal, sizeof( zVal ), "%d",
  579. (int)pOptDesc->optArg.argInt );
  580. pzDefault = zVal;
  581. break;
  582. case OPARG_TYPE_MEMBERSHIP:
  583. snprintf( zVal, sizeof( zVal ), "%lu",
  584. (unsigned long)pOptDesc->optArg.argIntptr );
  585. pzDefault = zVal;
  586. break;
  587. case OPARG_TYPE_BOOLEAN:
  588. pzDefault = (pOptDesc->optArg.argBool) ? "true" : "false";
  589. break;
  590. default:
  591. if (pOptDesc->optArg.argString == NULL) {
  592. if (pzFmt == zSingleDef)
  593. pzFmt = zSingleNoDef;
  594. pzDefault = NULL;
  595. }
  596. else
  597. pzDefault = pOptDesc->optArg.argString;
  598. }
  599. printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
  600. }
  601. }
  602. static void
  603. printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
  604. {
  605. if (pOptDesc->pOptProc == optionPrintVersion)
  606. printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
  607. else if (pOptDesc->pOptProc == optionPagedUsage)
  608. printf( zPagedUsageExit, pOpts->pzPROGNAME );
  609. else if (pOptDesc->pOptProc == optionLoadOpt) {
  610. printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
  611. printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
  612. } else if (pOptDesc->pz_NAME == NULL) {
  613. if (pOptDesc->pOptProc == NULL) {
  614. printf( zCmdFmt, "echo 'Warning: Cannot save options files' "
  615. ">&2" );
  616. printf( zCmdFmt, "OPT_ARG_NEEDED=OK" );
  617. } else
  618. printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" );
  619. } else {
  620. if (pOptDesc->optMaxCt == 1)
  621. printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  622. else {
  623. if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
  624. printf( zCountTest, pOpts->pzPROGNAME,
  625. pOptDesc->pz_NAME, pOptDesc->optMaxCt );
  626. printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  627. }
  628. /*
  629. * Fix up the args.
  630. */
  631. if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
  632. printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  633. } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
  634. printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  635. } else {
  636. fputs( zMustArg, stdout );
  637. }
  638. }
  639. fputs( zOptionEndSelect, stdout );
  640. }
  641. static void
  642. printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
  643. {
  644. if (pOptDesc->pOptProc == optionLoadOpt) {
  645. printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
  646. "options files' >&2" );
  647. } else if (pOptDesc->optMaxCt == 1)
  648. printf( zNoSingleArg, pOpts->pzPROGNAME,
  649. pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
  650. else
  651. printf( zNoMultiArg, pOpts->pzPROGNAME,
  652. pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
  653. printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
  654. fputs( zOptionEndSelect, stdout );
  655. }
  656. static void
  657. emitFlag( tOptions* pOpts )
  658. {
  659. tOptDesc* pOptDesc = pOpts->pOptDesc;
  660. int optionCt = pOpts->optCt;
  661. fputs( zOptionCase, stdout );
  662. for (;optionCt > 0; pOptDesc++, --optionCt) {
  663. if (SKIP_OPT(pOptDesc))
  664. continue;
  665. if (isprint( pOptDesc->optValue )) {
  666. printf( zOptionFlag, pOptDesc->optValue );
  667. printOptionAction( pOpts, pOptDesc );
  668. }
  669. }
  670. printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
  671. }
  672. /*
  673. * Emit the match text for a long option
  674. */
  675. static void
  676. emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
  677. {
  678. tOptDesc* pOD = pOpts->pOptDesc;
  679. int oCt = pOpts->optCt;
  680. int min = 1;
  681. char zName[ 256 ];
  682. char* pz = zName;
  683. for (;;) {
  684. int matchCt = 0;
  685. /*
  686. * Omit the current option, Documentation opts and compiled out opts.
  687. */
  688. if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
  689. if (--oCt <= 0)
  690. break;
  691. pOD++;
  692. continue;
  693. }
  694. /*
  695. * Check each character of the name case insensitively.
  696. * They must not be the same. They cannot be, because it would
  697. * not compile correctly if they were.
  698. */
  699. while ( toupper( pOD->pz_Name[matchCt] )
  700. == toupper( pzMatchName[matchCt] ))
  701. matchCt++;
  702. if (matchCt > min)
  703. min = matchCt;
  704. /*
  705. * Check the disablement name, too.
  706. */
  707. if (pOD->pz_DisableName != NULL) {
  708. matchCt = 0;
  709. while ( toupper( pOD->pz_DisableName[matchCt] )
  710. == toupper( pzMatchName[matchCt] ))
  711. matchCt++;
  712. if (matchCt > min)
  713. min = matchCt;
  714. }
  715. if (--oCt <= 0)
  716. break;
  717. pOD++;
  718. }
  719. /*
  720. * IF the 'min' is all or one short of the name length,
  721. * THEN the entire string must be matched.
  722. */
  723. if ( (pzMatchName[min ] == NUL)
  724. || (pzMatchName[min+1] == NUL) )
  725. printf( zOptionFullName, pzMatchName );
  726. else {
  727. int matchCt = 0;
  728. for (; matchCt <= min; matchCt++)
  729. *pz++ = pzMatchName[matchCt];
  730. for (;;) {
  731. *pz = NUL;
  732. printf( zOptionPartName, zName );
  733. *pz++ = pzMatchName[matchCt++];
  734. if (pzMatchName[matchCt] == NUL) {
  735. *pz = NUL;
  736. printf( zOptionFullName, zName );
  737. break;
  738. }
  739. }
  740. }
  741. }
  742. /*
  743. * Emit GNU-standard long option handling code
  744. */
  745. static void
  746. emitLong( tOptions* pOpts )
  747. {
  748. tOptDesc* pOD = pOpts->pOptDesc;
  749. int ct = pOpts->optCt;
  750. fputs( zOptionCase, stdout );
  751. /*
  752. * do each option, ...
  753. */
  754. do {
  755. /*
  756. * Documentation & compiled-out options
  757. */
  758. if (SKIP_OPT(pOD))
  759. continue;
  760. emitMatchExpr( pOD->pz_Name, pOD, pOpts );
  761. printOptionAction( pOpts, pOD );
  762. /*
  763. * Now, do the same thing for the disablement version of the option.
  764. */
  765. if (pOD->pz_DisableName != NULL) {
  766. emitMatchExpr( pOD->pz_DisableName, pOD, pOpts );
  767. printOptionInaction( pOpts, pOD );
  768. }
  769. } while (pOD++, --ct > 0);
  770. printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
  771. }
  772. static void
  773. openOutput( char const* pzFile )
  774. {
  775. FILE* fp;
  776. char* pzData = NULL;
  777. struct stat stbf;
  778. do {
  779. char* pzScan;
  780. size_t sizeLeft;
  781. /*
  782. * IF we cannot stat the file,
  783. * THEN assume we are creating a new file.
  784. * Skip the loading of the old data.
  785. */
  786. if (stat( pzFile, &stbf ) != 0)
  787. break;
  788. /*
  789. * The file must be a regular file
  790. */
  791. if (! S_ISREG( stbf.st_mode )) {
  792. fprintf( stderr, zNotFile, pzFile );
  793. exit( EXIT_FAILURE );
  794. }
  795. pzData = AGALOC(stbf.st_size + 1, "file data");
  796. fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
  797. sizeLeft = (unsigned)stbf.st_size;
  798. pzScan = pzData;
  799. /*
  800. * Read in all the data as fast as our OS will let us.
  801. */
  802. for (;;) {
  803. int inct = fread( (void*)pzScan, (size_t)1, sizeLeft, fp);
  804. if (inct == 0)
  805. break;
  806. pzScan += inct;
  807. sizeLeft -= inct;
  808. if (sizeLeft == 0)
  809. break;
  810. }
  811. /*
  812. * NUL-terminate the leader and look for the trailer
  813. */
  814. *pzScan = '\0';
  815. fclose( fp );
  816. pzScan = strstr( pzData, zStartMarker );
  817. if (pzScan == NULL) {
  818. pzTrailer = pzData;
  819. break;
  820. }
  821. *(pzScan++) = NUL;
  822. pzScan = strstr( pzScan, zTrailerMarker );
  823. if (pzScan == NULL) {
  824. pzTrailer = pzData;
  825. break;
  826. }
  827. /*
  828. * Check to see if the data contains
  829. * our marker. If it does, then we will skip over it
  830. */
  831. pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1;
  832. pzLeader = pzData;
  833. } while (AG_FALSE);
  834. freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
  835. }
  836. /*=export_func genshelloptUsage
  837. * private:
  838. * what: The usage function for the genshellopt generated program
  839. *
  840. * arg: + tOptions* + pOpts + program options descriptor +
  841. * arg: + int + exitCode + usage text type to produce +
  842. *
  843. * doc:
  844. * This function is used to create the usage strings for the option
  845. * processing shell script code. Two child processes are spawned
  846. * each emitting the usage text in either the short (error exit)
  847. * style or the long style. The generated program will capture this
  848. * and create shell script variables containing the two types of text.
  849. =*/
  850. void
  851. genshelloptUsage( tOptions* pOpts, int exitCode )
  852. {
  853. #if defined(__windows__) && !defined(__CYGWIN__)
  854. optionUsage( pOpts, exitCode );
  855. #else
  856. /*
  857. * IF not EXIT_SUCCESS,
  858. * THEN emit the short form of usage.
  859. */
  860. if (exitCode != EXIT_SUCCESS)
  861. optionUsage( pOpts, exitCode );
  862. fflush( stderr );
  863. fflush( stdout );
  864. option_usage_fp = stdout;
  865. /*
  866. * First, print our usage
  867. */
  868. switch (fork()) {
  869. case -1:
  870. optionUsage( pOpts, EXIT_FAILURE );
  871. /*NOTREACHED*/
  872. _exit( EXIT_FAILURE );
  873. case 0:
  874. pagerState = PAGER_STATE_CHILD;
  875. optionUsage( pOpts, EXIT_SUCCESS );
  876. /*NOTREACHED*/
  877. _exit( EXIT_FAILURE );
  878. default:
  879. {
  880. int sts;
  881. wait( &sts );
  882. }
  883. }
  884. /*
  885. * Generate the pzProgName, since optionProcess() normally
  886. * gets it from the command line
  887. */
  888. {
  889. char* pz;
  890. AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
  891. pShellParseOptions->pzProgName = pz;
  892. while (*pz != NUL) {
  893. *pz = tolower( *pz );
  894. pz++;
  895. }
  896. }
  897. /*
  898. * Separate the makeshell usage from the client usage
  899. */
  900. fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
  901. fflush( option_usage_fp );
  902. /*
  903. * Now, print the client usage.
  904. */
  905. switch (fork()) {
  906. case 0:
  907. pagerState = PAGER_STATE_CHILD;
  908. /*FALLTHROUGH*/
  909. case -1:
  910. optionUsage( pShellParseOptions, EXIT_FAILURE );
  911. default:
  912. {
  913. int sts;
  914. wait( &sts );
  915. }
  916. }
  917. exit( EXIT_SUCCESS );
  918. #endif
  919. }
  920. /*
  921. * Local Variables:
  922. * mode: C
  923. * c-file-style: "stroustrup"
  924. * indent-tabs-mode: nil
  925. * End:
  926. * end of autoopts/makeshell.c */