makeshell.c 28 KB

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