enumeration.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475
  1. /*
  2. * $Id: enumeration.c,v 4.19 2007/07/04 21:36:37 bkorb Exp $
  3. * Time-stamp: "2007-07-04 11:33:42 bkorb"
  4. *
  5. * Automated Options Paged Usage module.
  6. *
  7. * This routine will run run-on options through a pager so the
  8. * user may examine, print or edit them at their leisure.
  9. *
  10. * This file is part of AutoOpts, a companion to AutoGen.
  11. * AutoOpts is free software.
  12. * AutoOpts is copyright (c) 1992-2007 by Bruce Korb - all rights reserved
  13. *
  14. * AutoOpts is available under any one of two licenses. The license
  15. * in use must be one of these two and the choice is under the control
  16. * of the user of the license.
  17. *
  18. * The GNU Lesser General Public License, version 3 or later
  19. * See the files "COPYING.lgplv3" and "COPYING.gplv3"
  20. *
  21. * The Modified Berkeley Software Distribution License
  22. * See the file "COPYING.mbsd"
  23. *
  24. * These files have the following md5sums:
  25. *
  26. * 239588c55c22c60ffe159946a760a33e pkg/libopts/COPYING.gplv3
  27. * fa82ca978890795162346e661b47161a pkg/libopts/COPYING.lgplv3
  28. * 66a5cedaf62c4b2637025f049f9b826f pkg/libopts/COPYING.mbsd
  29. */
  30. tSCC* pz_enum_err_fmt;
  31. /* = = = START-STATIC-FORWARD = = = */
  32. /* static forward declarations maintained by :mkfwd */
  33. static void
  34. enumError(
  35. tOptions* pOpts,
  36. tOptDesc* pOD,
  37. tCC* const * paz_names,
  38. int name_ct );
  39. static uintptr_t
  40. findName(
  41. tCC* pzName,
  42. tOptions* pOpts,
  43. tOptDesc* pOD,
  44. tCC* const * paz_names,
  45. unsigned int name_ct );
  46. /* = = = END-STATIC-FORWARD = = = */
  47. static void
  48. enumError(
  49. tOptions* pOpts,
  50. tOptDesc* pOD,
  51. tCC* const * paz_names,
  52. int name_ct )
  53. {
  54. size_t max_len = 0;
  55. size_t ttl_len = 0;
  56. if (pOpts != NULL)
  57. fprintf( option_usage_fp, pz_enum_err_fmt, pOpts->pzProgName,
  58. pOD->optArg.argString, pOD->pz_Name );
  59. fprintf( option_usage_fp, zValidKeys, pOD->pz_Name );
  60. if (**paz_names == 0x7F) {
  61. paz_names++;
  62. name_ct--;
  63. }
  64. /*
  65. * Figure out the maximum length of any name, plus the total length
  66. * of all the names.
  67. */
  68. {
  69. tCC * const * paz = paz_names;
  70. int ct = name_ct;
  71. do {
  72. size_t len = strlen( *(paz++) ) + 1;
  73. if (len > max_len)
  74. max_len = len;
  75. ttl_len += len;
  76. } while (--ct > 0);
  77. }
  78. /*
  79. * IF any one entry is about 1/2 line or longer, print one per line
  80. */
  81. if (max_len > 35) {
  82. do {
  83. fprintf( option_usage_fp, " %s\n", *(paz_names++) );
  84. } while (--name_ct > 0);
  85. }
  86. /*
  87. * ELSE IF they all fit on one line, then do so.
  88. */
  89. else if (ttl_len < 76) {
  90. fputc( ' ', option_usage_fp );
  91. do {
  92. fputc( ' ', option_usage_fp );
  93. fputs( *(paz_names++), option_usage_fp );
  94. } while (--name_ct > 0);
  95. fputc( '\n', option_usage_fp );
  96. }
  97. /*
  98. * Otherwise, columnize the output
  99. */
  100. else {
  101. int ent_no = 0;
  102. char zFmt[16]; /* format for all-but-last entries on a line */
  103. sprintf( zFmt, "%%-%ds", (int)max_len );
  104. max_len = 78 / max_len; /* max_len is now max entries on a line */
  105. fputs( " ", option_usage_fp );
  106. /*
  107. * Loop through all but the last entry
  108. */
  109. while (--name_ct > 0) {
  110. if (++ent_no == max_len) {
  111. /*
  112. * Last entry on a line. Start next line, too.
  113. */
  114. fprintf( option_usage_fp, "%s\n ", *(paz_names++) );
  115. ent_no = 0;
  116. }
  117. else
  118. fprintf( option_usage_fp, zFmt, *(paz_names++) );
  119. }
  120. fprintf( option_usage_fp, "%s\n", *paz_names );
  121. }
  122. /*
  123. * IF we do not have a pOpts pointer, then this output is being requested
  124. * by the usage procedure. Let's not re-invoke it recursively.
  125. */
  126. if (pOpts != NULL)
  127. (*(pOpts->pUsageProc))( pOpts, EXIT_FAILURE );
  128. if (OPTST_GET_ARGTYPE(pOD->fOptState) == OPARG_TYPE_MEMBERSHIP)
  129. fputs( zSetMemberSettings, option_usage_fp );
  130. }
  131. static uintptr_t
  132. findName(
  133. tCC* pzName,
  134. tOptions* pOpts,
  135. tOptDesc* pOD,
  136. tCC* const * paz_names,
  137. unsigned int name_ct )
  138. {
  139. uintptr_t res = name_ct;
  140. size_t len = strlen( (char*)pzName );
  141. uintptr_t idx;
  142. /*
  143. * Look for an exact match, but remember any partial matches.
  144. * Multiple partial matches means we have an ambiguous match.
  145. */
  146. for (idx = 0; idx < name_ct; idx++) {
  147. if (strncmp( (char*)paz_names[idx], (char*)pzName, len) == 0) {
  148. if (paz_names[idx][len] == NUL)
  149. return idx; /* full match */
  150. if (res != name_ct) {
  151. pz_enum_err_fmt = zAmbigKey;
  152. option_usage_fp = stderr;
  153. enumError( pOpts, pOD, paz_names, (int)name_ct );
  154. }
  155. res = idx; /* save partial match */
  156. }
  157. }
  158. /*
  159. * no partial match -> error
  160. */
  161. if (res == name_ct) {
  162. pz_enum_err_fmt = zNoKey;
  163. option_usage_fp = stderr;
  164. enumError( pOpts, pOD, paz_names, (int)name_ct );
  165. }
  166. /*
  167. * Return the matching index as a char* pointer.
  168. * The result gets stashed in a char* pointer, so it will have to fit.
  169. */
  170. return res;
  171. }
  172. /*=export_func optionKeywordName
  173. * what: Convert between enumeration values and strings
  174. * private:
  175. *
  176. * arg: tOptDesc*, pOD, enumeration option description
  177. * arg: unsigned int, enum_val, the enumeration value to map
  178. *
  179. * ret_type: char const*
  180. * ret_desc: the enumeration name from const memory
  181. *
  182. * doc: This converts an enumeration value into the matching string.
  183. =*/
  184. char const*
  185. optionKeywordName(
  186. tOptDesc* pOD,
  187. unsigned int enum_val )
  188. {
  189. tOptDesc od;
  190. od.optArg.argEnum = enum_val;
  191. (*(pOD->pOptProc))( (void*)(2UL), &od );
  192. return od.optArg.argString;
  193. }
  194. /*=export_func optionEnumerationVal
  195. * what: Convert from a string to an enumeration value
  196. * private:
  197. *
  198. * arg: tOptions*, pOpts, the program options descriptor
  199. * arg: tOptDesc*, pOD, enumeration option description
  200. * arg: char const * const *, paz_names, list of enumeration names
  201. * arg: unsigned int, name_ct, number of names in list
  202. *
  203. * ret_type: uintptr_t
  204. * ret_desc: the enumeration value
  205. *
  206. * doc: This converts the optArg.argString string from the option description
  207. * into the index corresponding to an entry in the name list.
  208. * This will match the generated enumeration value.
  209. * Full matches are always accepted. Partial matches are accepted
  210. * if there is only one partial match.
  211. =*/
  212. uintptr_t
  213. optionEnumerationVal(
  214. tOptions* pOpts,
  215. tOptDesc* pOD,
  216. tCC * const * paz_names,
  217. unsigned int name_ct )
  218. {
  219. uintptr_t res = 0UL;
  220. /*
  221. * IF the program option descriptor pointer is invalid,
  222. * then it is some sort of special request.
  223. */
  224. switch ((uintptr_t)pOpts) {
  225. case 0UL:
  226. /*
  227. * print the list of enumeration names.
  228. */
  229. enumError( pOpts, pOD, paz_names, (int)name_ct );
  230. break;
  231. case 1UL:
  232. {
  233. unsigned int ix = pOD->optArg.argEnum;
  234. /*
  235. * print the name string.
  236. */
  237. if (ix >= name_ct)
  238. printf( "INVALID-%d", ix );
  239. else
  240. fputs( paz_names[ ix ], stdout );
  241. break;
  242. }
  243. case 2UL:
  244. {
  245. tSCC zInval[] = "*INVALID*";
  246. unsigned int ix = pOD->optArg.argEnum;
  247. /*
  248. * Replace the enumeration value with the name string.
  249. */
  250. if (ix >= name_ct)
  251. return (uintptr_t)zInval;
  252. res = (uintptr_t)paz_names[ ix ];
  253. break;
  254. }
  255. default:
  256. res = findName( pOD->optArg.argString, pOpts, pOD, paz_names, name_ct );
  257. if (pOD->fOptState & OPTST_ALLOC_ARG) {
  258. AGFREE(pOD->optArg.argString);
  259. pOD->fOptState &= ~OPTST_ALLOC_ARG;
  260. pOD->optArg.argString = NULL;
  261. }
  262. }
  263. return res;
  264. }
  265. /*=export_func optionSetMembers
  266. * what: Convert between bit flag values and strings
  267. * private:
  268. *
  269. * arg: tOptions*, pOpts, the program options descriptor
  270. * arg: tOptDesc*, pOD, enumeration option description
  271. * arg: char const * const *,
  272. * paz_names, list of enumeration names
  273. * arg: unsigned int, name_ct, number of names in list
  274. *
  275. * doc: This converts the optArg.argString string from the option description
  276. * into the index corresponding to an entry in the name list.
  277. * This will match the generated enumeration value.
  278. * Full matches are always accepted. Partial matches are accepted
  279. * if there is only one partial match.
  280. =*/
  281. void
  282. optionSetMembers(
  283. tOptions* pOpts,
  284. tOptDesc* pOD,
  285. tCC* const * paz_names,
  286. unsigned int name_ct )
  287. {
  288. /*
  289. * IF the program option descriptor pointer is invalid,
  290. * then it is some sort of special request.
  291. */
  292. switch ((uintptr_t)pOpts) {
  293. case 0UL:
  294. /*
  295. * print the list of enumeration names.
  296. */
  297. enumError( pOpts, pOD, paz_names, (int)name_ct );
  298. return;
  299. case 1UL:
  300. {
  301. /*
  302. * print the name string.
  303. */
  304. uintptr_t bits = (uintptr_t)pOD->optCookie;
  305. uintptr_t res = 0;
  306. size_t len = 0;
  307. while (bits != 0) {
  308. if (bits & 1) {
  309. if (len++ > 0) fputs( " | ", stdout );
  310. fputs( paz_names[ res ], stdout );
  311. }
  312. if (++res >= name_ct) break;
  313. bits >>= 1;
  314. }
  315. return;
  316. }
  317. case 2UL:
  318. {
  319. char* pz;
  320. uintptr_t bits = (uintptr_t)pOD->optCookie;
  321. uintptr_t res = 0;
  322. size_t len = 0;
  323. /*
  324. * Replace the enumeration value with the name string.
  325. * First, determine the needed length, then allocate and fill in.
  326. */
  327. while (bits != 0) {
  328. if (bits & 1)
  329. len += strlen( paz_names[ res ]) + 8;
  330. if (++res >= name_ct) break;
  331. bits >>= 1;
  332. }
  333. pOD->optArg.argString = pz = AGALOC( len, "enum name" );
  334. /*
  335. * Start by clearing all the bits. We want to turn off any defaults
  336. * because we will be restoring to current state, not adding to
  337. * the default set of bits.
  338. */
  339. strcpy( pz, "none" );
  340. pz += 4;
  341. bits = (uintptr_t)pOD->optCookie;
  342. res = 0;
  343. while (bits != 0) {
  344. if (bits & 1) {
  345. strcpy( pz, " + " );
  346. strcpy( pz+3, paz_names[ res ]);
  347. pz += strlen( paz_names[ res ]) + 3;
  348. }
  349. if (++res >= name_ct) break;
  350. bits >>= 1;
  351. }
  352. return;
  353. }
  354. default:
  355. break;
  356. }
  357. {
  358. tCC* pzArg = pOD->optArg.argString;
  359. uintptr_t res;
  360. if ((pzArg == NULL) || (*pzArg == NUL)) {
  361. pOD->optCookie = (void*)0;
  362. return;
  363. }
  364. res = (uintptr_t)pOD->optCookie;
  365. for (;;) {
  366. tSCC zSpn[] = " ,|+\t\r\f\n";
  367. int iv, len;
  368. pzArg += strspn( pzArg, zSpn );
  369. iv = (*pzArg == '!');
  370. if (iv)
  371. pzArg += strspn( pzArg+1, zSpn ) + 1;
  372. len = strcspn( pzArg, zSpn );
  373. if (len == 0)
  374. break;
  375. if ((len == 3) && (strncmp(pzArg, zAll, (size_t)3) == 0)) {
  376. if (iv)
  377. res = 0;
  378. else res = ~0UL;
  379. }
  380. else if ((len == 4) && (strncmp(pzArg, zNone, (size_t)4) == 0)) {
  381. if (! iv)
  382. res = 0;
  383. }
  384. else do {
  385. char* pz;
  386. uintptr_t bit = strtoul( pzArg, &pz, 0 );
  387. if (pz != pzArg + len) {
  388. char z[ AO_NAME_SIZE ];
  389. tCC* p;
  390. if (*pz != NUL) {
  391. if (len >= AO_NAME_LIMIT)
  392. break;
  393. strncpy( z, pzArg, (size_t)len );
  394. z[len] = NUL;
  395. p = z;
  396. } else {
  397. p = pzArg;
  398. }
  399. bit = 1UL << findName(p, pOpts, pOD, paz_names, name_ct);
  400. }
  401. if (iv)
  402. res &= ~bit;
  403. else res |= bit;
  404. } while (0);
  405. if (pzArg[len] == NUL)
  406. break;
  407. pzArg += len + 1;
  408. }
  409. if (name_ct < (8 * sizeof( uintptr_t ))) {
  410. res &= (1UL << name_ct) - 1UL;
  411. }
  412. pOD->optCookie = (void*)res;
  413. }
  414. }
  415. /*
  416. * Local Variables:
  417. * mode: C
  418. * c-file-style: "stroustrup"
  419. * indent-tabs-mode: nil
  420. * End:
  421. * end of autoopts/enumeration.c */