Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

418 lines
11 KiB

  1. /*++
  2. HELP.C
  3. PrintHelp function
  4. split from options.c, 6/9/1997 by DavidCHR
  5. --*/
  6. #include "private.h"
  7. #include <malloc.h>
  8. PCHAR SlashVector = "[- /]"; /* These should all be the same */
  9. PCHAR BoolVector = "[- +]"; /* size-- for formatting reasons */
  10. PCHAR ColonVector = " : "; /* Separator */
  11. #ifdef DEBUG_OPTIONS
  12. VOID OptionHelpDebugPrint( PCHAR fmt, ... );
  13. #define HELPDEBUG OptionHelpDebugPrint
  14. #else
  15. #define HELPDEBUG
  16. #endif
  17. VOID
  18. FillBufferWithRepeatedString( IN PCHAR repeated_string,
  19. IN PCHAR buffer,
  20. IN ULONG bufferLength /* without null */ ){
  21. ULONG stringi, bufferj = 0;
  22. ULONG size;
  23. size = strlen( repeated_string );
  24. if ( size == 0 ) {
  25. memset( buffer, ' ', bufferLength );
  26. } else {
  27. for ( stringi = 0 ; stringi < bufferLength ; stringi++, bufferj++ ) {
  28. buffer[ bufferj ] = repeated_string[ bufferj % size ];
  29. }
  30. }
  31. buffer[ bufferLength ] = '\0';
  32. }
  33. /* PrintUsageEntry:
  34. formats a single line of text and sends it out.
  35. This is where all the output goes, so we can be assured that it all ends
  36. up formatted the same. It uses the following globals so that clients
  37. can adjust the values if needed. */
  38. ULONG OptMaxHeaderLength = 5;
  39. ULONG OptMaxCommandLength = 13;
  40. ULONG OptMaxSeparatorLength = 3;
  41. ULONG OptMaxDescriptionLength = 58;
  42. VOID
  43. PrintUsageEntry( FILE *out, // output file stream
  44. PCHAR aHeader, // usually SlashVector, BoolVector or NULL
  45. PCHAR aCommand, // command name or NULL
  46. PCHAR aSeparator, // between command and description
  47. PCHAR Description, // NULL-terminated string vector
  48. BOOL fRepeatSeparator ) {
  49. PCHAR output_line; // sick. see below
  50. PCHAR Separator;
  51. PCHAR Header;
  52. PCHAR Command;
  53. HELPDEBUG( "PrintUsageEntry( aHeader = \"%s\"\n"
  54. " aCommand = \"%s\"\n"
  55. " aSeparator = \"%s\"\n"
  56. " Description = \"%s\"\n"
  57. " fRepeat = %d )...\n",
  58. aHeader, aCommand, aSeparator, Description,
  59. fRepeatSeparator );
  60. ASSERT( aSeparator != NULL );
  61. if ( fRepeatSeparator ) {
  62. #define EXPAND_TO_SEPARATOR( arg ) { \
  63. PCHAR local_arg; \
  64. arg = aSeparator; \
  65. ASSERT( arg != NULL ); \
  66. if ( strlen( arg ) < OptMax##arg##Length ) { \
  67. arg = (PCHAR) alloca( ( OptMax##arg##Length+1 ) * sizeof( CHAR ) ); \
  68. if ( arg ) { \
  69. HELPDEBUG( "filling " #arg " with \"%s\"...", aSeparator ); \
  70. FillBufferWithRepeatedString( aSeparator, arg, \
  71. OptMax##arg##Length ); \
  72. HELPDEBUG( "results in \"%s\".\n", arg ); \
  73. } else { \
  74. arg = a##arg; \
  75. } \
  76. } else { \
  77. arg = a##arg; \
  78. } \
  79. }
  80. /* BEWARE:
  81. if you are using emacs, this next statement may not automatically
  82. format correctly. Set it manually and the other lines will fix
  83. themselves.
  84. This is a bug in emacs's macro-handling code. :-) */
  85. EXPAND_TO_SEPARATOR( Separator ); // separator may need expanding anyway
  86. if ( !aHeader) {
  87. EXPAND_TO_SEPARATOR( Header );
  88. } else {
  89. Header = aHeader;
  90. }
  91. if ( !aCommand ) {
  92. EXPAND_TO_SEPARATOR( Command );
  93. } else {
  94. Command = aCommand;
  95. }
  96. } else {
  97. Separator = aSeparator;
  98. Header = aHeader;
  99. Command = aCommand;
  100. ASSERT( Separator != NULL );
  101. ASSERT( Header != NULL );
  102. ASSERT( Command != NULL );
  103. }
  104. /* before we try to do all this sick string manipulation, try to
  105. allocate the buffer. If this fails, well... it'll save us the
  106. trouble. :-) */
  107. output_line = (PCHAR) alloca( ( OptMaxHeaderLength +
  108. OptMaxCommandLength +
  109. OptMaxSeparatorLength +
  110. OptMaxDescriptionLength +
  111. 2 /* NULL-termination */ ) *
  112. sizeof( CHAR ) );
  113. if ( output_line ) {
  114. PCHAR index;
  115. CHAR outputFormatter[ 10 ] = { 0 }; // "%50hs" and the like
  116. #ifdef WINNT // ugh. Why can't we support this function? I can't find it...
  117. #define snprintf _snprintf
  118. #endif
  119. #define FORMAT_FORMAT( arg ) { \
  120. snprintf( outputFormatter, sizeof( outputFormatter), \
  121. "%%%ds", OptMax##arg##Length ); \
  122. HELPDEBUG( #arg ": formatter = \"%s\"\n ", outputFormatter ); \
  123. HELPDEBUG( "input value = \"%s\"\n", arg ); \
  124. snprintf( index, OptMax##arg##Length, \
  125. outputFormatter, arg ); \
  126. index[ OptMax##arg##Length ] = '\0'; \
  127. HELPDEBUG( "output = \"%s\"\n", index ); \
  128. index += OptMax##arg##Length; \
  129. }
  130. index = output_line;
  131. FORMAT_FORMAT( Header );
  132. FORMAT_FORMAT( Command );
  133. FORMAT_FORMAT( Separator );
  134. // the description does not want to be right-justified.
  135. snprintf( index, OptMaxDescriptionLength, "%s", Description );
  136. index[OptMaxDescriptionLength] = '\0';
  137. #undef FORMAT_FORMAT
  138. fprintf( out, "%s\n", output_line );
  139. } else {
  140. fprintf( stderr,
  141. "ERROR: cannot format for %s %s %s -- "
  142. "STACK SPACE EXHAUSTED\n",
  143. Header, Command, Description );
  144. fprintf( out, "%s%s%s%s\n", Header, Command,
  145. aSeparator, Description );
  146. }
  147. }
  148. VOID
  149. PrintUsage( FILE *out,
  150. ULONG flags,
  151. optionStruct *options,
  152. PCHAR prefix /* can be NULL */) {
  153. ULONG i;
  154. BOOL PrintAnything = TRUE;
  155. PCHAR Syntax = NULL;
  156. PCHAR CommandName = NULL;
  157. PCHAR Description = NULL;
  158. PCHAR Separator = NULL;
  159. fprintf(out, "Command line options:\n\n");
  160. for (i = 0 ; !ARRAY_TERMINATED( options+i ); i++ ) {
  161. Description = options[i].helpMsg;
  162. HELPDEBUG("option %d has flags 0x%x\n", i, options[i].flags );
  163. if ( options[i].flags & OPT_HIDDEN ) {
  164. continue;
  165. }
  166. if ( options[i].flags & OPT_NOSWITCH ) {
  167. Syntax = "";
  168. } else {
  169. Syntax = SlashVector;
  170. }
  171. if ( options[i].flags & OPT_NOCOMMAND ) {
  172. CommandName = "";
  173. } else {
  174. CommandName = options[i].cmd;
  175. }
  176. if ( options[i].flags & OPT_NOSEPARATOR ) {
  177. Separator = "";
  178. } else {
  179. Separator = ColonVector;
  180. }
  181. switch (options[i].flags & OPT_MUTEX_MASK) {
  182. case OPT_ENUMERATED:
  183. {
  184. // special case.
  185. CHAR HeaderBuffer[ 22 ]; // formatting = 21 chars wide + null
  186. HELPDEBUG("[OPT_ENUM]");
  187. PrintAnything = FALSE;
  188. sprintf( HeaderBuffer, "%5hs%13hs%3hs", SlashVector,
  189. CommandName, Separator );
  190. fprintf( out, "%hs%hs\n", HeaderBuffer, Description );
  191. fprintf( out, "%hs is one of: \n", HeaderBuffer );
  192. PrintEnumValues( out, HeaderBuffer,
  193. ( optEnumStruct * ) options[i].optData );
  194. break;
  195. }
  196. case OPT_PAUSE:
  197. HELPDEBUG("[OPT_PAUSE]");
  198. PrintAnything = FALSE;
  199. if ( !Description ) {
  200. Description = "Press [ENTER] to continue";
  201. }
  202. fprintf( stderr, "%hs\n", Description );
  203. getchar();
  204. break;
  205. case OPT_DUMMY:
  206. PrintUsageEntry( out,
  207. ( options[i].flags & OPT_NOSWITCH ) ?
  208. "" : NULL,
  209. ( options[i].flags & OPT_NOCOMMAND ) ?
  210. "" : NULL,
  211. ( options[i].flags & OPT_NOSEPARATOR ) ?
  212. "" : "-" ,
  213. Description, TRUE );
  214. break;
  215. case OPT_CONTINUE:
  216. PrintUsageEntry( out, "", "", "", Description, FALSE );
  217. break;
  218. case OPT_HELP:
  219. if ( !Description ) {
  220. Description = "Prints this message.";
  221. }
  222. PrintUsageEntry( out, Syntax, CommandName,
  223. ColonVector, Description, FALSE );
  224. break;
  225. case OPT_SUBOPTION:
  226. if ( !Description ) {
  227. Description = "[ undocumented suboption ]";
  228. }
  229. PrintUsageEntry( out, Syntax, CommandName,
  230. ColonVector, Description, FALSE );
  231. break;
  232. case OPT_BOOL:
  233. PrintUsageEntry( out,
  234. ( ( options[i].flags & OPT_NOSWITCH ) ?
  235. Syntax : BoolVector ), CommandName,
  236. ColonVector, Description, FALSE );
  237. break;
  238. case OPT_STOP_PARSING:
  239. if ( !Description ) {
  240. Description = "Terminates optionlist.";
  241. }
  242. goto defaulted;
  243. case OPT_FUNC2:
  244. if ( !Description ) {
  245. OPT_FUNC_PARAMETER_DATA optFuncData = { 0 };
  246. optFuncData.argv = &( options[i].cmd );
  247. HELPDEBUG("Jumping to OPT_FUNC2 0x%x...",
  248. ((POPTU) &options[i].data)->raw_data );
  249. ( (POPTU)&options[i].data)->func2( TRUE, &optFuncData );
  250. break;
  251. }
  252. /* fallthrough-- if this one has no description,
  253. they both will, so the next if will not be taken. */
  254. case OPT_FUNC:
  255. if ( !Description ) {
  256. HELPDEBUG("Jumping to OPTFUNC 0x%x...",
  257. ((POPTU) &options[i].data)->raw_data );
  258. ( (POPTU) &options[i].data )->func( 0, NULL );
  259. break;
  260. }
  261. // fallthrough
  262. #ifdef WINNT
  263. case OPT_WSTRING:
  264. case OPT_USTRING:
  265. #endif
  266. case OPT_STRING:
  267. case OPT_INT:
  268. case OPT_FLOAT:
  269. // fallthrough
  270. default: // this is the default means.
  271. defaulted:
  272. #if (HIGHEST_OPTION_SUPPORTED != OPT_STOP_PARSING )
  273. #error "new options? update this switch statement or bad things will happen."
  274. #endif
  275. PrintUsageEntry( out, Syntax, CommandName,
  276. ColonVector, Description, FALSE );
  277. }
  278. if ( options[i].flags & OPT_ENVIRONMENT ) {
  279. CHAR buffer[ MAX_PATH ];
  280. sprintf( buffer, " (or set environment variable \"%hs\")",
  281. options[i].optData );
  282. PrintUsageEntry( out, "", CommandName, ColonVector,
  283. buffer, FALSE );
  284. }
  285. } // for-loop
  286. } // function