makeshell.c 29 KB

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