1 | /* $Id: CoinParamUtils.cpp 1469 2011-09-03 18:49:33Z stefan $ */ |
2 | // Copyright (C) 2007, International Business Machines |
3 | // Corporation and others. All Rights Reserved. |
4 | // This code is licensed under the terms of the Eclipse Public License (EPL). |
5 | |
6 | #include <cassert> |
7 | #include <cerrno> |
8 | #include <iostream> |
9 | |
10 | #include "CoinUtilsConfig.h" |
11 | #include "CoinParam.hpp" |
12 | #include <cstdlib> |
13 | #include <cstring> |
14 | #include <cstdio> |
15 | |
16 | #ifdef COIN_HAS_READLINE |
17 | #include <readline/readline.h> |
18 | #include <readline/history.h> |
19 | #endif |
20 | |
21 | /* Unnamed local namespace */ |
22 | namespace |
23 | { |
24 | |
25 | /* |
26 | cmdField: The index of the current command line field. Forced to -1 when |
27 | accepting commands from stdin (interactive) or a command file. |
28 | readSrc: Current input source. |
29 | |
30 | pendingVal: When the form param=value is encountered, both keyword and value |
31 | form one command line field. We need to return `param' as the |
32 | field and somehow keep the value around for the upcoming call |
33 | that'll request it. That's the purpose of pendingVal. |
34 | */ |
35 | |
36 | int cmdField = 1 ; |
37 | FILE *readSrc = stdin ; |
38 | std::string pendingVal = "" ; |
39 | |
40 | |
41 | /* |
42 | Get next command or field in command. When in interactive mode, prompt the |
43 | user and read the resulting line of input. |
44 | */ |
45 | std::string nextField (const char *prompt) |
46 | { |
47 | static char line[1000] ; |
48 | static char *where = NULL ; |
49 | std::string field ; |
50 | const char *dflt_prompt = "Eh? " ; |
51 | |
52 | if (prompt == 0) |
53 | { prompt = dflt_prompt ; } |
54 | /* |
55 | Do we have a line at the moment? If not, acquire one. When we're done, |
56 | line holds the input line and where points to the start of the line. If we're |
57 | using the readline library, add non-empty lines to the history list. |
58 | */ |
59 | if (!where) { |
60 | #ifdef COIN_HAS_READLINE |
61 | if (readSrc == stdin) |
62 | { where = readline(prompt) ; |
63 | if (where) |
64 | { if (*where) |
65 | add_history (where) ; |
66 | strcpy(line,where) ; |
67 | free(where) ; |
68 | where = line ; } } |
69 | else |
70 | { where = fgets(line,1000,readSrc) ; } |
71 | #else |
72 | if (readSrc == stdin) |
73 | { fprintf(stdout,"%s" ,prompt) ; |
74 | fflush(stdout) ; } |
75 | where = fgets(line,1000,readSrc) ; |
76 | #endif |
77 | /* |
78 | If where is NULL, we have EOF. Return a null string. |
79 | */ |
80 | if (!where) |
81 | return field ; |
82 | /* |
83 | Clean the image. Trailing junk first. The line will be cut off at the last |
84 | non-whitespace character, but we need to scan until we find the end of the |
85 | string or some other non-printing character to make sure we don't miss a |
86 | printing character after whitespace. |
87 | */ |
88 | char *lastNonBlank = line-1 ; |
89 | for (where = line ; *where != '\0' ; where++) |
90 | { if (*where != '\t' && *where < ' ') |
91 | { break ; } |
92 | if (*where != '\t' && *where != ' ') |
93 | { lastNonBlank = where ; } } |
94 | *(lastNonBlank+1) = '\0' ; |
95 | where = line ; } |
96 | /* |
97 | Munch through leading white space. |
98 | */ |
99 | while (*where == ' ' || *where == '\t') |
100 | where++ ; |
101 | /* |
102 | See if we can separate a field; if so, copy it over into field for return. |
103 | If we're out of line, return the string "EOL". |
104 | */ |
105 | char *saveWhere = where ; |
106 | while (*where != ' ' && *where != '\t' && *where!='\0') |
107 | where++ ; |
108 | if (where != saveWhere) |
109 | { char save = *where ; |
110 | *where = '\0' ; |
111 | field = saveWhere ; |
112 | *where = save ; } |
113 | else |
114 | { where = NULL ; |
115 | field = "EOL" ; } |
116 | |
117 | return (field) ; } |
118 | |
119 | } |
120 | |
121 | |
122 | /* Visible functions */ |
123 | |
124 | namespace CoinParamUtils |
125 | { |
126 | |
127 | /* |
128 | As mentioned above, cmdField set to -1 is the indication that we're reading |
129 | from stdin or a file. |
130 | */ |
131 | void setInputSrc (FILE *src) |
132 | |
133 | { if (src != 0) |
134 | { cmdField = -1 ; |
135 | readSrc = src ; } } |
136 | |
137 | /* |
138 | A utility to allow clients to determine if we're processing parameters from |
139 | the comand line or otherwise. |
140 | */ |
141 | bool isCommandLine () |
142 | |
143 | { assert(cmdField != 0) ; |
144 | |
145 | if (cmdField > 0) |
146 | { return (true) ; } |
147 | else |
148 | { return (false) ; } } |
149 | |
150 | /* |
151 | A utility to allow clients to determine if we're accepting parameters |
152 | interactively. |
153 | */ |
154 | bool isInteractive () |
155 | |
156 | { assert(cmdField != 0) ; |
157 | |
158 | if (cmdField < 0 && readSrc == stdin) |
159 | { return (true) ; } |
160 | else |
161 | { return (false) ; } } |
162 | |
163 | /* |
164 | Utility functions for acquiring input. |
165 | */ |
166 | |
167 | |
168 | /* |
169 | Return the next field (word) from the current command line. Generally, this |
170 | is expected to be of the form `-param' or `--param', with special cases as |
171 | set out below. |
172 | |
173 | If we're in interactive mode (cmdField == -1), nextField does all the work |
174 | to prompt the user and return the next field from the resulting input. It is |
175 | assumed that the user knows not to use `-' or `--' prefixes in interactive |
176 | mode. |
177 | |
178 | If we're in command line mode (cmdField > 0), cmdField indicates the |
179 | current command line word. The order of processing goes like this: |
180 | * A stand-alone `-' is converted to `stdin' |
181 | * A stand-alone '--' is returned as a word; interpretation is up to the |
182 | client. |
183 | * A prefix of '-' or '--' is stripped from the field. |
184 | If the result is `stdin', it's assumed we're switching to interactive mode |
185 | and the user is prompted for another command. |
186 | |
187 | Whatever results from the above sequence is returned to the client as the |
188 | next field. An empty string indicates end of input. |
189 | |
190 | Prompt will be used by nextField if it's necessary to prompt the user for |
191 | a command (only when reading from stdin). |
192 | |
193 | If provided, pfx is set to the prefix ("-", "--", or "") stripped from the |
194 | field. Lack of prefix is not necessarily an error because of the following |
195 | scenario: To read a file, the verbose command might be "foo -import |
196 | myfile". But we might want to allow a short form, "foo myfile". And we'd |
197 | like "foo import" to be interpreted as "foo -import import" (i.e., import the |
198 | file named `import'). |
199 | */ |
200 | |
201 | std::string getCommand (int argc, const char *argv[], |
202 | const std::string prompt, std::string *pfx) |
203 | |
204 | { std::string field = "EOL" ; |
205 | pendingVal = "" ; |
206 | int pfxlen ; |
207 | |
208 | if (pfx != 0) |
209 | { (*pfx) = "" ; } |
210 | /* |
211 | Acquire the next field, and convert as outlined above if we're processing |
212 | command line parameters. |
213 | */ |
214 | while (field == "EOL" ) |
215 | { pfxlen = 0 ; |
216 | if (cmdField > 0) |
217 | { if (cmdField < argc) |
218 | { field = argv[cmdField++] ; |
219 | if (field == "-" ) |
220 | { field = "stdin" ; } |
221 | else |
222 | if (field == "--" ) |
223 | { /* Prevent `--' from being eaten by next case. */ } |
224 | else |
225 | { if (field[0] == '-') |
226 | { pfxlen = 1 ; |
227 | if (field[1] == '-') |
228 | pfxlen = 2 ; |
229 | if (pfx != 0) |
230 | (*pfx) = field.substr(0,pfxlen) ; |
231 | field = field.substr(pfxlen) ; } } } |
232 | else |
233 | { field = "" ; } } |
234 | else |
235 | { field = nextField(prompt.c_str()) ; } |
236 | if (field == "stdin" ) |
237 | { std::cout << "Switching to line mode" << std::endl ; |
238 | cmdField = -1 ; |
239 | field = nextField(prompt.c_str()) ; } } |
240 | /* |
241 | Are we left with something of the form param=value? If so, separate the |
242 | pieces, returning `param' and saving `value' for later use as per comments |
243 | at the head of the file. |
244 | */ |
245 | std::string::size_type found = field.find('='); |
246 | if (found != std::string::npos) |
247 | { pendingVal = field.substr(found+1) ; |
248 | field = field.substr(0,found) ; } |
249 | |
250 | return (field) ; } |
251 | |
252 | |
253 | /* |
254 | Function to look up a parameter keyword (name) in the parameter vector and |
255 | deal with the result. The keyword may end in one or more `?' characters; |
256 | this is a query for information about matching parameters. |
257 | |
258 | If we have a single match satisfying the minimal match requirements, and |
259 | there's no query, we simply return the index of the matching parameter in |
260 | the parameter vector. If there are no matches, and no query, the return |
261 | value will be -3. No matches on a query returns -1. |
262 | |
263 | A single short match, or a single match of any length with a query, will |
264 | result in a short help message |
265 | |
266 | If present, these values are set as follows: |
267 | * matchCntp is set to the number of parameters that matched. |
268 | * shortCntp is set to the number of matches that failed to meet the minimum |
269 | match requirement. |
270 | * queryCntp is set to the number of trailing `?' characters at the end |
271 | of name. |
272 | |
273 | Return values: |
274 | >0: index of the single unique match for the name |
275 | -1: query present |
276 | -2: no query, one or more short matches |
277 | -3: no query, no match |
278 | -4: multiple full matches (indicates configuration error) |
279 | |
280 | The final three parameters (matchCnt, shortCnt, queryCnt) are optional and |
281 | default to null. Use them if you want more detail on the match. |
282 | */ |
283 | |
284 | int lookupParam (std::string name, CoinParamVec ¶mVec, |
285 | int *matchCntp, int *shortCntp, int *queryCntp) |
286 | |
287 | { |
288 | int retval = -3 ; |
289 | |
290 | if (matchCntp != 0) |
291 | { *matchCntp = 0 ; } |
292 | if (shortCntp != 0) |
293 | { *shortCntp = 0 ; } |
294 | if (queryCntp != 0) |
295 | { *queryCntp = 0 ; } |
296 | /* |
297 | Is there anything here at all? |
298 | */ |
299 | if (name.length() == 0) |
300 | { return (retval) ; } |
301 | /* |
302 | Scan the parameter name to see if it ends in one or more `?' characters. If |
303 | so, take it as a request to return a list of parameters that match name up |
304 | to the first `?'. The strings '?' and '???' are considered to be valid |
305 | parameter names (short and long help, respectively) and are handled as |
306 | special cases: If the whole string is `?'s, one and three are commands as |
307 | is, while 2 and 4 or more are queries about `?' or `???'. |
308 | */ |
309 | int numQuery = 0 ; |
310 | { int length = static_cast<int>(name.length()) ; |
311 | int i ; |
312 | for (i = length-1 ; i >= 0 && name[i] == '?' ; i--) |
313 | { numQuery++ ; } |
314 | if (numQuery == length) |
315 | { switch (length) |
316 | { case 1: |
317 | case 3: |
318 | { numQuery = 0 ; |
319 | break ; } |
320 | case 2: |
321 | { numQuery -= 1 ; |
322 | break ; } |
323 | default: |
324 | { numQuery -= 3 ; |
325 | break ; } } } |
326 | name = name.substr(0,length-numQuery) ; |
327 | if (queryCntp != 0) |
328 | { *queryCntp = numQuery ; } } |
329 | /* |
330 | See if we can match the parameter name. On return, matchNdx is set to the |
331 | last match satisfying the minimal match criteria, or -1 if there's no |
332 | match. matchCnt is the number of matches satisfying the minimum match |
333 | length, and shortCnt is possible matches that were short of the minimum |
334 | match length, |
335 | */ |
336 | int matchNdx = -1 ; |
337 | int shortCnt = 0 ; |
338 | int matchCnt = CoinParamUtils::matchParam(paramVec,name,matchNdx,shortCnt) ; |
339 | /* |
340 | Set up return values before we get into further processing. |
341 | */ |
342 | if (matchCntp != 0) |
343 | { *matchCntp = matchCnt ; } |
344 | if (shortCntp != 0) |
345 | { *shortCntp = shortCnt ; } |
346 | if (numQuery > 0) |
347 | { retval = -1 ; } |
348 | else |
349 | { if (matchCnt+shortCnt == 0) |
350 | { retval = -3 ; } |
351 | else |
352 | if (matchCnt > 1) |
353 | { retval = -4 ; } |
354 | else |
355 | { retval = -2 ; } } |
356 | /* |
357 | No matches? Nothing more to be done here. |
358 | */ |
359 | if (matchCnt+shortCnt == 0) |
360 | { return (retval) ; } |
361 | /* |
362 | A unique match and no `?' in the name says we have our parameter. Return |
363 | the result. |
364 | */ |
365 | if (matchCnt == 1 && shortCnt == 0 && numQuery == 0) |
366 | { assert (matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ; |
367 | return (matchNdx) ; } |
368 | /* |
369 | A single match? There are two possibilities: |
370 | * The string specified is shorter than the match length requested by the |
371 | parameter. (Useful for avoiding inadvertent execution of commands that |
372 | the client might regret.) |
373 | * The string specified contained a `?', in which case we print the help. |
374 | The match may or may not be short. |
375 | */ |
376 | if (matchCnt+shortCnt == 1) |
377 | { CoinParamUtils::shortOrHelpOne(paramVec,matchNdx,name,numQuery) ; |
378 | return (retval) ; } |
379 | /* |
380 | The final case: multiple matches. Most commonly this will be multiple short |
381 | matches. If we have multiple matches satisfying the minimal length |
382 | criteria, we have a configuration problem. The other question is whether |
383 | the user wanted help information. Two question marks gets short help. |
384 | */ |
385 | if (matchCnt > 1) |
386 | { std::cout |
387 | << "Configuration error! `" << name |
388 | <<"' was fully matched " << matchCnt << " times!" |
389 | << std::endl ; } |
390 | std::cout |
391 | << "Multiple matches for `" << name << "'; possible completions:" |
392 | << std::endl ; |
393 | CoinParamUtils::shortOrHelpMany(paramVec,name,numQuery) ; |
394 | |
395 | return (retval) ; } |
396 | |
397 | |
398 | /* |
399 | Utility functions to acquire parameter values from the command line. For |
400 | all of these, a pendingVal is consumed if it exists. |
401 | */ |
402 | |
403 | |
404 | /* |
405 | Read a string and return a pointer to the string. Set valid to indicate the |
406 | result of parsing: 0: okay, 1: <unused>, 2: not present. |
407 | */ |
408 | |
409 | std::string getStringField (int argc, const char *argv[], int *valid) |
410 | |
411 | { std::string field ; |
412 | |
413 | if (pendingVal != "" ) |
414 | { field = pendingVal ; |
415 | pendingVal = "" ; } |
416 | else |
417 | { field = "EOL" ; |
418 | if (cmdField > 0) |
419 | { if (cmdField < argc) |
420 | { field = argv[cmdField++] ; } } |
421 | else |
422 | { field = nextField(0) ; } } |
423 | |
424 | if (valid != 0) |
425 | { if (field != "EOL" ) |
426 | { *valid = 0 ; } |
427 | else |
428 | { *valid = 2 ; } } |
429 | |
430 | return (field) ; } |
431 | |
432 | /* |
433 | Read an int and return the value. Set valid to indicate the result of |
434 | parsing: 0: okay, 1: parse error, 2: not present. |
435 | */ |
436 | |
437 | int getIntField (int argc, const char *argv[], int *valid) |
438 | |
439 | { std::string field ; |
440 | |
441 | if (pendingVal != "" ) |
442 | { field = pendingVal ; |
443 | pendingVal = "" ; } |
444 | else |
445 | { field = "EOL" ; |
446 | if (cmdField > 0) |
447 | { if (cmdField < argc) |
448 | { field = argv[cmdField++] ; } } |
449 | else |
450 | { field = nextField(0) ; } } |
451 | /* |
452 | The only way to check for parse error here is to set the system variable |
453 | errno to 0 and then see if it's nonzero after we try to convert the string |
454 | to integer. |
455 | */ |
456 | int value = 0 ; |
457 | errno = 0 ; |
458 | if (field != "EOL" ) |
459 | { value = atoi(field.c_str()) ; } |
460 | |
461 | if (valid != 0) |
462 | { if (field != "EOL" ) |
463 | { if (errno == 0) |
464 | { *valid = 0 ; } |
465 | else |
466 | { *valid = 1 ; } } |
467 | else |
468 | { *valid = 2 ; } } |
469 | |
470 | return (value) ; } |
471 | |
472 | |
473 | /* |
474 | Read a double and return the value. Set valid to indicate the result of |
475 | parsing: 0: okay, 1: bad parse, 2: not present. But we'll never return |
476 | valid == 1 because atof gives us no way to tell.) |
477 | */ |
478 | |
479 | double getDoubleField (int argc, const char *argv[], int *valid) |
480 | |
481 | { std::string field ; |
482 | |
483 | if (pendingVal != "" ) |
484 | { field = pendingVal ; |
485 | pendingVal = "" ; } |
486 | else |
487 | { field = "EOL" ; |
488 | if (cmdField > 0) |
489 | { if (cmdField < argc) |
490 | { field = argv[cmdField++] ; } } |
491 | else |
492 | { field = nextField(0) ; } } |
493 | /* |
494 | The only way to check for parse error here is to set the system variable |
495 | errno to 0 and then see if it's nonzero after we try to convert the string |
496 | to integer. |
497 | */ |
498 | double value = 0.0 ; |
499 | errno = 0 ; |
500 | if (field != "EOL" ) |
501 | { value = atof(field.c_str()) ; } |
502 | |
503 | if (valid != 0) |
504 | { if (field != "EOL" ) |
505 | { if (errno == 0) |
506 | { *valid = 0 ; } |
507 | else |
508 | { *valid = 1 ; } } |
509 | else |
510 | { *valid = 2 ; } } |
511 | |
512 | return (value) ; } |
513 | |
514 | |
515 | /* |
516 | Utility function to scan a parameter vector for matches. Sets matchNdx to |
517 | the index of the last parameter that meets the minimal match criteria (but |
518 | note there should be at most one such parameter if the parameter vector is |
519 | properly configured). Sets shortCnt to the number of short matches (should |
520 | be zero in a properly configured vector if a minimal match is found). |
521 | Returns the number of matches satisfying the minimal match requirement |
522 | (should be 0 or 1 in a properly configured vector). |
523 | |
524 | The routine allows for the possibility of null entries in the parameter |
525 | vector. |
526 | |
527 | In order to handle `?' and `???', there's nothing to it but to force a |
528 | unique match if we match `?' exactly. (This is another quirk of clp/cbc |
529 | parameter parsing, which we need to match for historical reasons.) |
530 | */ |
531 | |
532 | int matchParam (const CoinParamVec ¶mVec, std::string name, |
533 | int &matchNdx, int &shortCnt) |
534 | |
535 | { |
536 | int vecLen = static_cast<int>(paramVec.size()) ; |
537 | int matchCnt = 0 ; |
538 | |
539 | matchNdx = -1 ; |
540 | shortCnt = 0 ; |
541 | |
542 | for (int i = 0 ; i < vecLen ; i++) |
543 | { CoinParam *param = paramVec[i] ; |
544 | if (param == 0) continue ; |
545 | int match = paramVec[i]->matches(name) ; |
546 | if (match == 1) |
547 | { matchNdx = i ; |
548 | matchCnt++ ; |
549 | if (name == "?" ) |
550 | { matchCnt = 1 ; |
551 | break ; } } |
552 | else |
553 | { shortCnt += match>>1 ; } } |
554 | |
555 | return (matchCnt) ; |
556 | } |
557 | |
558 | /* |
559 | Now a bunch of routines that are useful in the context of generating help |
560 | messages. |
561 | */ |
562 | |
563 | /* |
564 | Simple formatting routine for long messages. Used to print long help for |
565 | parameters. Lines are broken at the first white space after 65 characters, |
566 | or when an explicit return (`\n') character is scanned. Leading spaces are |
567 | suppressed. |
568 | */ |
569 | |
570 | void printIt (const char *msg) |
571 | |
572 | { int length = static_cast<int>(strlen(msg)) ; |
573 | char temp[101] ; |
574 | int i ; |
575 | int n = 0 ; |
576 | for (i = 0 ; i < length ; i++) |
577 | { if (msg[i] == '\n' || |
578 | (n >= 65 && (msg[i] == ' ' || msg[i] == '\t'))) |
579 | { temp[n] = '\0' ; |
580 | std::cout << temp << std::endl ; |
581 | n = 0 ; } |
582 | else |
583 | if (n || msg[i] != ' ') |
584 | { temp[n++] = msg[i] ; } } |
585 | if (n > 0) |
586 | { temp[n] = '\0' ; |
587 | std::cout << temp << std::endl ; } |
588 | |
589 | return ; } |
590 | |
591 | |
592 | /* |
593 | Utility function for the case where a name matches a single parameter, but |
594 | either it's short, or the user wanted help, or both. |
595 | |
596 | The routine allows for the possibility that there are null entries in the |
597 | parameter vector, but matchNdx should point to a valid entry if it's >= 0. |
598 | */ |
599 | |
600 | void shortOrHelpOne (CoinParamVec ¶mVec, |
601 | int matchNdx, std::string name, int numQuery) |
602 | |
603 | { int i ; |
604 | int numParams = static_cast<int>(paramVec.size()) ; |
605 | int lclNdx = -1 ; |
606 | /* |
607 | For a short match, we need to look up the parameter again. This should find |
608 | a short match, given the conditions where this routine is called. But be |
609 | prepared to find a full match. |
610 | |
611 | If matchNdx >= 0, just use the index we're handed. |
612 | */ |
613 | if (matchNdx < 0) |
614 | { int match = 0 ; |
615 | for (i = 0 ; i < numParams ; i++) |
616 | { CoinParam *param = paramVec[i] ; |
617 | if (param == 0) continue ; |
618 | int match = param->matches(name) ; |
619 | if (match != 0) |
620 | { lclNdx = i ; |
621 | break ; } } |
622 | |
623 | assert (lclNdx >= 0) ; |
624 | |
625 | if (match == 1) |
626 | { std::cout |
627 | << "Match for '" << name << "': " |
628 | << paramVec[matchNdx]->matchName() << "." ; } |
629 | else |
630 | { std::cout |
631 | << "Short match for '" << name << "'; possible completion: " |
632 | << paramVec[lclNdx]->matchName() << "." ; } } |
633 | else |
634 | { assert(matchNdx >= 0 && matchNdx < static_cast<int>(paramVec.size())) ; |
635 | std::cout << "Match for `" << name << "': " |
636 | << paramVec[matchNdx]->matchName() ; |
637 | lclNdx = matchNdx ; } |
638 | /* |
639 | Print some help, if there was a `?' in the name. `??' gets the long help. |
640 | */ |
641 | if (numQuery > 0) |
642 | { std::cout << std::endl ; |
643 | if (numQuery == 1) |
644 | { std::cout << paramVec[lclNdx]->shortHelp() ; } |
645 | else |
646 | { paramVec[lclNdx]->printLongHelp() ; } } |
647 | std::cout << std::endl ; |
648 | |
649 | return ; } |
650 | |
651 | /* |
652 | Utility function for the case where a name matches multiple parameters. |
653 | Zero or one `?' gets just the matching names, while `??' gets short help |
654 | with each match. |
655 | |
656 | The routine allows for the possibility that there are null entries in the |
657 | parameter vector. |
658 | */ |
659 | |
660 | void shortOrHelpMany (CoinParamVec ¶mVec, std::string name, int numQuery) |
661 | |
662 | { int numParams = static_cast<int>(paramVec.size()) ; |
663 | /* |
664 | Scan the parameter list. For each match, print just the name, or the name |
665 | and short help. |
666 | */ |
667 | int lineLen = 0 ; |
668 | bool printed = false ; |
669 | for (int i = 0 ; i < numParams ; i++) |
670 | { CoinParam *param = paramVec[i] ; |
671 | if (param == 0) continue ; |
672 | int match = param->matches(name) ; |
673 | if (match > 0) |
674 | { std::string nme = param->matchName() ; |
675 | int len = static_cast<int>(nme.length()) ; |
676 | if (numQuery >= 2) |
677 | { std::cout << nme << " : " << param->shortHelp() ; |
678 | std::cout << std::endl ; } |
679 | else |
680 | { lineLen += 2+len ; |
681 | if (lineLen > 80) |
682 | { std::cout << std::endl ; |
683 | lineLen = 2+len ; } |
684 | std::cout << " " << nme ; |
685 | printed = true ; } } } |
686 | |
687 | if (printed) |
688 | { std::cout << std::endl ; } |
689 | |
690 | return ; } |
691 | |
692 | |
693 | /* |
694 | A generic help message that explains the basic operation of parameter |
695 | parsing. |
696 | */ |
697 | |
698 | void printGenericHelp () |
699 | |
700 | { std::cout << std::endl ; |
701 | std::cout |
702 | << "For command line arguments, keywords have a leading `-' or '--'; " |
703 | << std::endl ; |
704 | std::cout |
705 | << "-stdin or just - switches to stdin with a prompt." |
706 | << std::endl ; |
707 | std::cout |
708 | << "When prompted, one command per line, without the leading `-'." |
709 | << std::endl ; |
710 | std::cout |
711 | << "abcd value sets abcd to value." |
712 | << std::endl ; |
713 | std::cout |
714 | << "abcd without a value (where one is expected) gives the current value." |
715 | << std::endl ; |
716 | std::cout |
717 | << "abcd? gives a list of possible matches; if there's only one, a short" |
718 | << std::endl ; |
719 | std::cout |
720 | << "help message is printed." |
721 | << std::endl ; |
722 | std::cout |
723 | << "abcd?? prints the short help for all matches; if there's only one" |
724 | << std::endl ; |
725 | std::cout |
726 | << "match, a longer help message and current value are printed." |
727 | << std::endl ; |
728 | |
729 | return ; } |
730 | |
731 | |
732 | /* |
733 | Utility function for various levels of `help' command. The entries between |
734 | paramVec[firstParam] and paramVec[lastParam], inclusive, will be printed. |
735 | If shortHelp is true, the short help message will be printed for each |
736 | parameter. If longHelp is true, the long help message will be printed for |
737 | each parameter. If hidden is true, even parameters with display = false |
738 | will be printed. Each line is prefaced with the specified prefix. |
739 | |
740 | The routine allows for the possibility that there are null entries in the |
741 | parameter vector. |
742 | */ |
743 | |
744 | void printHelp (CoinParamVec ¶mVec, int firstParam, int lastParam, |
745 | std::string prefix, |
746 | bool shortHelp, bool longHelp, bool hidden) |
747 | |
748 | { bool noHelp = !(shortHelp || longHelp) ; |
749 | int i ; |
750 | int pfxLen = static_cast<int>(prefix.length()) ; |
751 | bool printed = false ; |
752 | |
753 | if (noHelp) |
754 | { int lineLen = 0 ; |
755 | for (i = firstParam ; i <= lastParam ; i++) |
756 | { CoinParam *param = paramVec[i] ; |
757 | if (param == 0) continue ; |
758 | if (param->display() || hidden) |
759 | { std::string nme = param->matchName() ; |
760 | int len = static_cast<int>(nme.length()) ; |
761 | if (!printed) |
762 | { std::cout << std::endl << prefix ; |
763 | lineLen += pfxLen ; |
764 | printed = true ; } |
765 | lineLen += 2+len ; |
766 | if (lineLen > 80) |
767 | { std::cout << std::endl << prefix ; |
768 | lineLen = pfxLen+2+len ; } |
769 | std::cout << " " << nme ; } } |
770 | if (printed) |
771 | { std::cout << std::endl ; } } |
772 | else |
773 | if (shortHelp) |
774 | { for (i = firstParam ; i <= lastParam ; i++) |
775 | { CoinParam *param = paramVec[i] ; |
776 | if (param == 0) continue ; |
777 | if (param->display() || hidden) |
778 | { std::cout << std::endl << prefix ; |
779 | std::cout << param->matchName() ; |
780 | std::cout << ": " ; |
781 | std::cout << param->shortHelp() ; } } |
782 | std::cout << std::endl ; } |
783 | else |
784 | if (longHelp) |
785 | { for (i = firstParam ; i <= lastParam ; i++) |
786 | { CoinParam *param = paramVec[i] ; |
787 | if (param == 0) continue ; |
788 | if (param->display() || hidden) |
789 | { std::cout << std::endl << prefix ; |
790 | std::cout << "Command: " << param->matchName() ; |
791 | std::cout << std::endl << prefix ; |
792 | std::cout << "---- description" << std::endl ; |
793 | printIt(param->longHelp().c_str()) ; |
794 | std::cout << prefix << "----" << std::endl ; } } } |
795 | |
796 | std::cout << std::endl ; |
797 | |
798 | return ; } |
799 | |
800 | } // end namespace CoinParamUtils |
801 | |