1
0

makeshell.c 29 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100
  1. /*
  2. * $Id: makeshell.c,v 4.5 2005/03/13 19:51:58 bkorb Exp $
  3. * Time-stamp: "2005-02-20 14:06:03 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-2005 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. * 59 Temple Place - Suite 330,
  25. * Boston, MA 02111-1307, 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( const char* 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 | egrep %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. int nlHoldCt = 0;
  434. int pipeFd[2];
  435. FILE* fp;
  436. # define _TT_(n) tSCC z ## n [] = #n;
  437. TEXTTO_TABLE
  438. # undef _TT_
  439. # define _TT_(n) z ## n ,
  440. static const char* apzTTNames[] = { TEXTTO_TABLE };
  441. # undef _TT_
  442. printf( "%s_%s_TEXT='", pOpts->pzPROGNAME, apzTTNames[ whichVar ]);
  443. fflush( stdout );
  444. if (pipe( pipeFd ) != 0) {
  445. fprintf( stderr, zBadPipe, errno, strerror( errno ));
  446. exit( EXIT_FAILURE );
  447. }
  448. switch (fork()) {
  449. case -1:
  450. fprintf( stderr, zForkFail, errno, strerror(errno), pOpts->pzProgName);
  451. exit( EXIT_FAILURE );
  452. break;
  453. case 0:
  454. dup2( pipeFd[1], STDERR_FILENO );
  455. dup2( pipeFd[1], STDOUT_FILENO );
  456. close( pipeFd[0] );
  457. switch (whichVar) {
  458. case TT_LONGUSAGE:
  459. (*(pOpts->pUsageProc))( pOpts, EXIT_SUCCESS );
  460. /* NOTREACHED */
  461. exit( EXIT_FAILURE );
  462. case TT_USAGE:
  463. (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
  464. /* NOTREACHED */
  465. exit( EXIT_FAILURE );
  466. case TT_VERSION:
  467. pOD->pzLastArg = "c";
  468. optionPrintVersion( pOpts, pOD );
  469. /* NOTREACHED */
  470. default:
  471. exit( EXIT_FAILURE );
  472. }
  473. default:
  474. close( pipeFd[1] );
  475. fp = fdopen( pipeFd[0], "r" FOPEN_BINARY_FLAG );
  476. }
  477. for (;;) {
  478. int ch = fgetc( fp );
  479. switch (ch) {
  480. case '\n':
  481. nlHoldCt++;
  482. break;
  483. case '\'':
  484. while (nlHoldCt > 0) {
  485. fputc( '\n', stdout );
  486. nlHoldCt--;
  487. }
  488. fputs( "'\\''", stdout );
  489. break;
  490. case EOF:
  491. goto endCharLoop;
  492. default:
  493. while (nlHoldCt > 0) {
  494. fputc( '\n', stdout );
  495. nlHoldCt--;
  496. }
  497. fputc( ch, stdout );
  498. break;
  499. }
  500. } endCharLoop:;
  501. fputs( "'\n\n", stdout );
  502. close( pipeFd[0] );
  503. }
  504. static void
  505. emitUsage( tOptions* pOpts )
  506. {
  507. char zTimeBuf[ AO_NAME_SIZE ];
  508. /*
  509. * First, switch stdout to the output file name.
  510. * Then, change the program name to the one defined
  511. * by the definitions (rather than the current
  512. * executable name). Down case the upper cased name.
  513. */
  514. if (pzLeader != NULL)
  515. fputs( pzLeader, stdout );
  516. {
  517. tSCC zStdout[] = "stdout";
  518. tCC* pzOutName;
  519. {
  520. time_t curTime = time( NULL );
  521. struct tm* pTime = localtime( &curTime );
  522. strftime( zTimeBuf, AO_NAME_SIZE, "%A %B %e, %Y at %r %Z", pTime );
  523. }
  524. if (HAVE_OPT( SCRIPT ))
  525. pzOutName = OPT_ARG( SCRIPT );
  526. else pzOutName = zStdout;
  527. if ((pzLeader == NULL) && (pzShell != NULL))
  528. printf( "#! %s\n", pzShell );
  529. printf( zPreamble, zStartMarker, pzOutName, zTimeBuf );
  530. }
  531. /*
  532. * Get a copy of the original program name in lower case
  533. */
  534. {
  535. char* pzPN = zTimeBuf;
  536. tCC* pz = pOpts->pzPROGNAME;
  537. for (;;) {
  538. if ((*pzPN++ = tolower( *pz++ )) == '\0')
  539. break;
  540. }
  541. }
  542. printf( zEndPreamble, pOpts->pzPROGNAME );
  543. pOpts->pzProgPath = pOpts->pzProgName = zTimeBuf;
  544. textToVariable( pOpts, TT_LONGUSAGE, NULL );
  545. textToVariable( pOpts, TT_USAGE, NULL );
  546. {
  547. tOptDesc* pOptDesc = pOpts->pOptDesc;
  548. int optionCt = pOpts->optCt;
  549. for (;;) {
  550. if (pOptDesc->pOptProc == optionPrintVersion) {
  551. textToVariable( pOpts, TT_VERSION, pOptDesc );
  552. break;
  553. }
  554. if (--optionCt <= 0)
  555. break;
  556. pOptDesc++;
  557. }
  558. }
  559. }
  560. static void
  561. emitSetup( tOptions* pOpts )
  562. {
  563. tOptDesc* pOptDesc = pOpts->pOptDesc;
  564. int optionCt = pOpts->presetOptCt;
  565. const char* pzFmt;
  566. const char* pzDefault;
  567. for (;optionCt > 0; pOptDesc++, --optionCt) {
  568. char zVal[16];
  569. /*
  570. * Options that are either usage documentation or are compiled out
  571. * are not to be processed.
  572. */
  573. if (SKIP_OPT(pOptDesc) || (pOptDesc->pz_NAME == NULL))
  574. continue;
  575. if (pOptDesc->optMaxCt > 1)
  576. pzFmt = zMultiDef;
  577. else pzFmt = zSingleDef;
  578. /*
  579. * IF this is an enumeration/bitmask option, then convert the value
  580. * to a string before printing the default value.
  581. */
  582. switch (OPTST_GET_ARGTYPE(pOptDesc->fOptState)) {
  583. case OPARG_TYPE_ENUMERATION:
  584. (*(pOptDesc->pOptProc))( (tOptions*)2UL, pOptDesc );
  585. pzDefault = pOptDesc->pzLastArg;
  586. break;
  587. /*
  588. * Numeric and membership bit options are just printed as a number.
  589. */
  590. case OPARG_TYPE_NUMERIC:
  591. case OPARG_TYPE_MEMBERSHIP:
  592. snprintf( zVal, sizeof( zVal ), "%ld", (tUL)pOptDesc->pzLastArg );
  593. pzDefault = zVal;
  594. break;
  595. default:
  596. if (pOptDesc->pzLastArg == NULL) {
  597. if (pzFmt == zSingleDef)
  598. pzFmt = zSingleNoDef;
  599. pzDefault = NULL;
  600. }
  601. else
  602. pzDefault = pOptDesc->pzLastArg;
  603. }
  604. printf( pzFmt, pOpts->pzPROGNAME, pOptDesc->pz_NAME, pzDefault );
  605. }
  606. }
  607. static void
  608. printOptionAction( tOptions* pOpts, tOptDesc* pOptDesc )
  609. {
  610. if (pOptDesc->pOptProc == optionPrintVersion)
  611. printf( zTextExit, pOpts->pzPROGNAME, "VERSION" );
  612. else if (pOptDesc->pOptProc == optionPagedUsage)
  613. printf( zPagedUsageExit, pOpts->pzPROGNAME );
  614. else if (pOptDesc->pOptProc == optionLoadOpt) {
  615. printf( zCmdFmt, "echo 'Warning: Cannot load options files' >&2" );
  616. printf( zCmdFmt, "OPT_ARG_NEEDED=YES" );
  617. } else if (pOptDesc->pz_NAME == NULL) {
  618. if (pOptDesc->pOptProc == NULL) {
  619. printf( zCmdFmt, "echo 'Warning: Cannot save options files' "
  620. ">&2" );
  621. printf( zCmdFmt, "OPT_ARG_NEEDED=OK" );
  622. } else
  623. printf( zTextExit, pOpts->pzPROGNAME, "LONGUSAGE" );
  624. } else {
  625. if (pOptDesc->optMaxCt == 1)
  626. printf( zSingleArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  627. else {
  628. if ((unsigned)pOptDesc->optMaxCt < NOLIMIT)
  629. printf( zCountTest, pOpts->pzPROGNAME,
  630. pOptDesc->pz_NAME, pOptDesc->optMaxCt );
  631. printf( zMultiArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  632. }
  633. /*
  634. * Fix up the args.
  635. */
  636. if (OPTST_GET_ARGTYPE(pOptDesc->fOptState) == OPARG_TYPE_NONE) {
  637. printf( zCantArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  638. } else if (pOptDesc->fOptState & OPTST_ARG_OPTIONAL) {
  639. printf( zMayArg, pOpts->pzPROGNAME, pOptDesc->pz_NAME );
  640. } else {
  641. fputs( zMustArg, stdout );
  642. }
  643. }
  644. fputs( zOptionEndSelect, stdout );
  645. }
  646. static void
  647. printOptionInaction( tOptions* pOpts, tOptDesc* pOptDesc )
  648. {
  649. if (pOptDesc->pOptProc == optionLoadOpt) {
  650. printf( zCmdFmt, "echo 'Warning: Cannot suppress the loading of "
  651. "options files' >&2" );
  652. } else if (pOptDesc->optMaxCt == 1)
  653. printf( zNoSingleArg, pOpts->pzPROGNAME,
  654. pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
  655. else
  656. printf( zNoMultiArg, pOpts->pzPROGNAME,
  657. pOptDesc->pz_NAME, pOptDesc->pz_DisablePfx );
  658. printf( zCmdFmt, "OPT_ARG_NEEDED=NO" );
  659. fputs( zOptionEndSelect, stdout );
  660. }
  661. static void
  662. emitFlag( tOptions* pOpts )
  663. {
  664. tOptDesc* pOptDesc = pOpts->pOptDesc;
  665. int optionCt = pOpts->optCt;
  666. fputs( zOptionCase, stdout );
  667. for (;optionCt > 0; pOptDesc++, --optionCt) {
  668. if (SKIP_OPT(pOptDesc))
  669. continue;
  670. if (isprint( pOptDesc->optValue )) {
  671. printf( zOptionFlag, pOptDesc->optValue );
  672. printOptionAction( pOpts, pOptDesc );
  673. }
  674. }
  675. printf( zOptionUnknown, "flag", pOpts->pzPROGNAME );
  676. }
  677. /*
  678. * Emit the match text for a long option
  679. */
  680. static void
  681. emitMatchExpr( tCC* pzMatchName, tOptDesc* pCurOpt, tOptions* pOpts )
  682. {
  683. tOptDesc* pOD = pOpts->pOptDesc;
  684. int oCt = pOpts->optCt;
  685. int min = 1;
  686. char zName[ 256 ];
  687. char* pz = zName;
  688. for (;;) {
  689. int matchCt = 0;
  690. /*
  691. * Omit the current option, Documentation opts and compiled out opts.
  692. */
  693. if ((pOD == pCurOpt) || SKIP_OPT(pOD)){
  694. if (--oCt <= 0)
  695. break;
  696. pOD++;
  697. continue;
  698. }
  699. /*
  700. * Check each character of the name case insensitively.
  701. * They must not be the same. They cannot be, because it would
  702. * not compile correctly if they were.
  703. */
  704. while ( toupper( pOD->pz_Name[matchCt] )
  705. == toupper( pzMatchName[matchCt] ))
  706. matchCt++;
  707. if (matchCt > min)
  708. min = matchCt;
  709. /*
  710. * Check the disablement name, too.
  711. */
  712. if (pOD->pz_DisableName != NULL) {
  713. matchCt = 0;
  714. while ( toupper( pOD->pz_DisableName[matchCt] )
  715. == toupper( pzMatchName[matchCt] ))
  716. matchCt++;
  717. if (matchCt > min)
  718. min = matchCt;
  719. }
  720. if (--oCt <= 0)
  721. break;
  722. pOD++;
  723. }
  724. /*
  725. * IF the 'min' is all or one short of the name length,
  726. * THEN the entire string must be matched.
  727. */
  728. if ( (pzMatchName[min ] == NUL)
  729. || (pzMatchName[min+1] == NUL) )
  730. printf( zOptionFullName, pzMatchName );
  731. else {
  732. int matchCt = 0;
  733. for (; matchCt <= min; matchCt++)
  734. *pz++ = pzMatchName[matchCt];
  735. for (;;) {
  736. *pz = NUL;
  737. printf( zOptionPartName, zName );
  738. *pz++ = pzMatchName[matchCt++];
  739. if (pzMatchName[matchCt] == NUL) {
  740. *pz = NUL;
  741. printf( zOptionFullName, zName );
  742. break;
  743. }
  744. }
  745. }
  746. }
  747. /*
  748. * Emit GNU-standard long option handling code
  749. */
  750. static void
  751. emitLong( tOptions* pOpts )
  752. {
  753. tOptDesc* pOD = pOpts->pOptDesc;
  754. int ct = pOpts->optCt;
  755. fputs( zOptionCase, stdout );
  756. /*
  757. * do each option, ...
  758. */
  759. do {
  760. /*
  761. * Documentation & compiled-out options
  762. */
  763. if (SKIP_OPT(pOD))
  764. continue;
  765. emitMatchExpr( pOD->pz_Name, pOD, pOpts );
  766. printOptionAction( pOpts, pOD );
  767. /*
  768. * Now, do the same thing for the disablement version of the option.
  769. */
  770. if (pOD->pz_DisableName != NULL) {
  771. emitMatchExpr( pOD->pz_DisableName, pOD, pOpts );
  772. printOptionInaction( pOpts, pOD );
  773. }
  774. } while (pOD++, --ct > 0);
  775. printf( zOptionUnknown, "option", pOpts->pzPROGNAME );
  776. }
  777. static void
  778. openOutput( const char* pzFile )
  779. {
  780. FILE* fp;
  781. char* pzData = NULL;
  782. struct stat stbf;
  783. do {
  784. char* pzScan;
  785. int sizeLeft;
  786. /*
  787. * IF we cannot stat the file,
  788. * THEN assume we are creating a new file.
  789. * Skip the loading of the old data.
  790. */
  791. if (stat( pzFile, &stbf ) != 0)
  792. break;
  793. /*
  794. * The file must be a regular file
  795. */
  796. if (! S_ISREG( stbf.st_mode )) {
  797. fprintf( stderr, zNotFile, pzFile );
  798. exit( EXIT_FAILURE );
  799. }
  800. pzData = (char*)malloc( stbf.st_size + 1 );
  801. fp = fopen( pzFile, "r" FOPEN_BINARY_FLAG );
  802. sizeLeft = stbf.st_size;
  803. pzScan = pzData;
  804. /*
  805. * Read in all the data as fast as our OS will let us.
  806. */
  807. for (;;) {
  808. int inct = fread( (void*)pzScan, 1, sizeLeft, fp );
  809. if (inct == 0)
  810. break;
  811. pzScan += inct;
  812. sizeLeft -= inct;
  813. if (sizeLeft == 0)
  814. break;
  815. }
  816. /*
  817. * NUL-terminate the leader and look for the trailer
  818. */
  819. *pzScan = '\0';
  820. fclose( fp );
  821. pzScan = strstr( pzData, zStartMarker );
  822. if (pzScan == NULL) {
  823. pzTrailer = pzData;
  824. break;
  825. }
  826. *(pzScan++) = NUL;
  827. pzScan = strstr( pzScan, zTrailerMarker );
  828. if (pzScan == NULL) {
  829. pzTrailer = pzData;
  830. break;
  831. }
  832. /*
  833. * Check to see if the data contains
  834. * our marker. If it does, then we will skip over it
  835. */
  836. pzTrailer = pzScan + sizeof( zTrailerMarker ) - 1;
  837. pzLeader = pzData;
  838. } while (AG_FALSE);
  839. freopen( pzFile, "w" FOPEN_BINARY_FLAG, stdout );
  840. }
  841. /*=export_func genshelloptUsage
  842. * private:
  843. * what: The usage function for the genshellopt generated program
  844. *
  845. * arg: + tOptions* + pOpts + program options descriptor +
  846. * arg: + int + exitCode + usage text type to produce +
  847. *
  848. * doc:
  849. * This function is used to create the usage strings for the option
  850. * processing shell script code. Two child processes are spawned
  851. * each emitting the usage text in either the short (error exit)
  852. * style or the long style. The generated program will capture this
  853. * and create shell script variables containing the two types of text.
  854. =*/
  855. void
  856. genshelloptUsage( tOptions* pOpts, int exitCode )
  857. {
  858. /*
  859. * IF not EXIT_SUCCESS,
  860. * THEN emit the short form of usage.
  861. */
  862. if (exitCode != EXIT_SUCCESS)
  863. optionUsage( pOpts, exitCode );
  864. fflush( stderr );
  865. fflush( stdout );
  866. option_usage_fp = stdout;
  867. /*
  868. * First, print our usage
  869. */
  870. switch (fork()) {
  871. case -1:
  872. optionUsage( pOpts, EXIT_FAILURE );
  873. /*NOTREACHED*/
  874. _exit( EXIT_FAILURE );
  875. case 0:
  876. pagerState = PAGER_STATE_CHILD;
  877. optionUsage( pOpts, EXIT_SUCCESS );
  878. /*NOTREACHED*/
  879. _exit( EXIT_FAILURE );
  880. default:
  881. {
  882. int stat;
  883. wait( &stat );
  884. }
  885. }
  886. /*
  887. * Generate the pzProgName, since optionProcess() normally
  888. * gets it from the command line
  889. */
  890. {
  891. char* pz;
  892. AGDUPSTR( pz, pShellParseOptions->pzPROGNAME, "program name" );
  893. pShellParseOptions->pzProgName = pz;
  894. while (*pz != NUL) {
  895. *pz = tolower( *pz );
  896. pz++;
  897. }
  898. }
  899. /*
  900. * Separate the makeshell usage from the client usage
  901. */
  902. fprintf( option_usage_fp, zGenshell, pShellParseOptions->pzProgName );
  903. fflush( option_usage_fp );
  904. /*
  905. * Now, print the client usage.
  906. */
  907. switch (fork()) {
  908. case 0:
  909. pagerState = PAGER_STATE_CHILD;
  910. /*FALLTHROUGH*/
  911. case -1:
  912. optionUsage( pShellParseOptions, EXIT_FAILURE );
  913. default:
  914. {
  915. int stat;
  916. wait( &stat );
  917. }
  918. }
  919. exit( EXIT_SUCCESS );
  920. }
  921. /*
  922. * Local Variables:
  923. * mode: C
  924. * c-file-style: "stroustrup"
  925. * tab-width: 4
  926. * indent-tabs-mode: nil
  927. * End:
  928. * end of autoopts/makeshell.c */