~ubuntu-branches/ubuntu/oneiric/valkyrie/oneiric

« back to all changes in this revision

Viewing changes to valkyrie/options/vk_popt.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Hai Zaar
  • Date: 2009-05-06 14:48:00 UTC
  • Revision ID: james.westby@ubuntu.com-20090506144800-vw617m4d4qa2pam3
Tags: upstream-1.4.0
ImportĀ upstreamĀ versionĀ 1.4.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* --------------------------------------------------------------------- 
 
2
 * Implementation of Popt functions                          vk_popt.cpp
 
3
 * This is a seriously hacked version of the popt libraries.
 
4
 * No credit to me, all thanks and many apologies to the Red Hat team
 
5
 * ---------------------------------------------------------------------
 
6
 * popt is Copyright (c) 1998 Red Hat Software and distributed under
 
7
 * an X11-style license, which is in turn compatible the GNU GPL v.2.
 
8
 * See the file COPYING for the full license details.
 
9
*/
 
10
 
 
11
#include "vk_popt.h"
 
12
#include "vk_option.h"           /* namespace VkOPTION */
 
13
#include "vk_utils.h"
 
14
 
 
15
 
 
16
/* return a vkPoptOption initialised to null */
 
17
vkPoptOption nullOpt()
 
18
{
 
19
   vkPoptOption _nullOpt = TABLE_END;
 
20
   return _nullOpt;
 
21
}
 
22
 
 
23
const char * vkPoptPeekArg( vkPoptContext con )
 
24
{
 
25
   const char * ret = NULL;
 
26
   if ( con && con->leftovers != NULL && 
 
27
        con->nextLeftover < con->numLeftovers )
 
28
      ret = con->leftovers[con->nextLeftover];
 
29
   return ret;
 
30
}
 
31
 
 
32
 
 
33
const char * vkPoptGetArg( vkPoptContext con )
 
34
{
 
35
   const char * ret = NULL;
 
36
   if ( con && con->leftovers != NULL && 
 
37
        con->nextLeftover < con->numLeftovers ) {
 
38
      ret = con->leftovers[con->nextLeftover++];
 
39
   }
 
40
   return ret;
 
41
}
 
42
 
 
43
 
 
44
const char ** vkPoptGetArgs( vkPoptContext con )
 
45
{
 
46
   if ( con == NULL || con->leftovers == NULL || 
 
47
        con->numLeftovers == con->nextLeftover )
 
48
      return NULL;
 
49
 
 
50
   /* some apps like [like RPM ;-) ] need this NULL terminated */
 
51
   con->leftovers[con->numLeftovers] = NULL;
 
52
   return (con->leftovers + con->nextLeftover);
 
53
}
 
54
 
 
55
 
 
56
vkPoptContext vkPoptGetContext( int argc, const char ** argv,
 
57
                                const vkPoptOption * options )
 
58
{
 
59
   vkPoptContext con = (vkPoptContext)malloc( sizeof(*con) );
 
60
 
 
61
   if ( con == NULL ) {
 
62
      return NULL;
 
63
   }
 
64
 
 
65
   memset( con, 0, sizeof(*con) );
 
66
 
 
67
   con->os = con->optionStack;
 
68
   con->os->argc  = argc;
 
69
   con->os->argv  = argv;
 
70
   con->os->next  = 1;      /* skip argv[0] */
 
71
   con->leftovers = (const char**)calloc( (argc + 1), sizeof(*con->leftovers) );
 
72
   con->options   = options;
 
73
   con->flags     = PCONTEXT_POSIXMEHARDER;
 
74
   con->finalArgvAlloced = argc * 2;
 
75
   con->finalArgv = (const char**)calloc( con->finalArgvAlloced, 
 
76
                                          sizeof(*con->finalArgv) );
 
77
 
 
78
   return con;
 
79
}
 
80
 
 
81
 
 
82
static void vkCleanOSE( struct optionStackEntry *os )
 
83
{
 
84
   os->nextArg = (const char*)_free( os->nextArg );
 
85
   os->argv    = (const char**)_free( os->argv );
 
86
}
 
87
 
 
88
 
 
89
const vkPoptOption * vkFindOption( const vkPoptOption * opt, 
 
90
                                   const char * longFlag,  
 
91
                                   char shortFlag, 
 
92
                                   int singleDash )
 
93
{
 
94
   /* this happens when a single - is given */
 
95
   if ( singleDash && !shortFlag && (longFlag && *longFlag == '\0') )
 
96
      shortFlag = '-';
 
97
 
 
98
   for (; opt->longFlag || opt->shortFlag || opt->arg; opt++) {
 
99
 
 
100
      if ( opt->arg != NULL ) {     /* is-a table */
 
101
         /* recurse on included sub-tables. */
 
102
         const vkPoptOption* opt2 = vkFindOption( opt->arg, longFlag, shortFlag, singleDash );
 
103
         if ( opt2 == NULL )
 
104
            continue;     /* no match in sub-table */
 
105
         /* found match: return option */
 
106
         return opt2;
 
107
      }
 
108
      else {                        /* is-a leaf */
 
109
         if ( longFlag && opt->longFlag && !singleDash &&
 
110
              !strcmp( longFlag, opt->longFlag ) )
 
111
            break; /* longFlag match */
 
112
         if (shortFlag && shortFlag == opt->shortFlag)
 
113
            break; /* shortFlag match */
 
114
      }
 
115
   }
 
116
 
 
117
   if ( !opt->longFlag && !opt->shortFlag )
 
118
      return NULL;    /* end of optArr: no match found */
 
119
 
 
120
   /* found match */
 
121
   return opt;
 
122
}
 
123
 
 
124
 
 
125
static const char * vkExpandNextArg( const char * s )
 
126
{
 
127
   char *t, *te;
 
128
   size_t tn = strlen(s) + 1;
 
129
   char c;
 
130
 
 
131
   te = t = (char*)malloc(tn);;
 
132
   if ( t == NULL ) 
 
133
      return NULL;
 
134
   while ((c = *s++) != '\0') {
 
135
      *te++ = c;
 
136
   }
 
137
 
 
138
   *te = '\0';
 
139
   /* memory leak, hard to plug */
 
140
   t = (char*)realloc(t, strlen(t) + 1);
 
141
   return t;
 
142
}
 
143
 
 
144
 
 
145
/* get next option opt_ret
 
146
   returns 0 on success, 1 on last item, PERROR_* on error */
 
147
int vkPoptGetNextOpt( vkPoptContext con,
 
148
                      char *arg_val/*OUT*/,
 
149
                      const vkPoptOption** opt_ret/*OUT*/ )
 
150
{
 
151
   const vkPoptOption * opt = NULL;
 
152
   int done = 0;
 
153
 
 
154
   if ( con == NULL ) {
 
155
      return 1;
 
156
   }
 
157
 
 
158
   while ( !done ) {
 
159
      const char * origOptString = NULL;
 
160
      const char * longArg = NULL;
 
161
      int shorty = 0;
 
162
 
 
163
      while ( !con->os->nextCharArg && 
 
164
              con->os->next == con->os->argc && 
 
165
              con->os > con->optionStack ) {
 
166
         vkCleanOSE( con->os-- );
 
167
      }
 
168
 
 
169
      if ( !con->os->nextCharArg && 
 
170
           con->os->next == con->os->argc ) {
 
171
         return 1;
 
172
      }
 
173
 
 
174
      /* process next long option */
 
175
      if ( !con->os->nextCharArg ) {
 
176
         char * localOptString, * optString;
 
177
         int thisopt;
 
178
         thisopt = con->os->next;
 
179
         if ( con->os->argv != NULL )
 
180
            origOptString = con->os->argv[con->os->next++];
 
181
 
 
182
         if ( origOptString == NULL ) {
 
183
            return PERROR_BADOPT;
 
184
         }
 
185
         if ( strcmp(origOptString, "--") == 0 ) {
 
186
            return PERROR_BADQUOTE;
 
187
         }
 
188
 
 
189
         if ( con->restLeftover || *origOptString != '-' ) {
 
190
            if ( con->flags & PCONTEXT_POSIXMEHARDER )
 
191
               con->restLeftover = 1;
 
192
            if ( con->leftovers != NULL )
 
193
               con->leftovers[con->numLeftovers++] = origOptString;
 
194
            continue;
 
195
         }
 
196
 
 
197
         /* make a copy we can hack at */
 
198
         localOptString = optString = 
 
199
            strcpy((char*)alloca(strlen(origOptString) + 1), origOptString);
 
200
 
 
201
         if ( optString[0] == '\0' )
 
202
            return PERROR_BADOPT;
 
203
 
 
204
         if ( optString[1] == '-' && !optString[2] ) {
 
205
            con->restLeftover = 1;
 
206
            continue;
 
207
         } else {
 
208
            char *oe;
 
209
            int singleDash;
 
210
            optString++;
 
211
            if ( *optString == '-' )
 
212
               singleDash = 0, optString++;
 
213
            else
 
214
               singleDash = 1;
 
215
 
 
216
            /* Check for "--long=arg" option. */
 
217
            for ( oe = optString; *oe && *oe != '='; oe++ )
 
218
               { };
 
219
            if ( *oe == '=' ) {
 
220
               /* FIX: don't use '=' for shortopts */
 
221
               if ( singleDash )
 
222
                  return PERROR_NODASH;
 
223
               *oe++ = '\0';
 
224
               /* longArg is mapped back to persistent storage. */
 
225
               longArg = origOptString + (oe - localOptString);
 
226
               /* FIX: catch cases where --longarg=<no-arg> */
 
227
               if ( strlen(longArg) == 0 ) {
 
228
                  //printf("1: returning PERROR_NOARG\n");
 
229
                  return PERROR_NOARG;
 
230
               }
 
231
            } 
 
232
#if 0
 
233
            else if ( singleDash == 0 ) {
 
234
               /* FIX: catch cases where we didn't find an '=', 
 
235
                  and this is a --longarg option */
 
236
               //printf("2: returning PERROR_NOARG\n");
 
237
               return PERROR_NOARG;
 
238
            } 
 
239
#endif
 
240
 
 
241
            opt = vkFindOption( con->options, optString, 
 
242
                                '\0', singleDash );
 
243
            if ( !opt && !singleDash ) {
 
244
               //printf("returning PERROR_BADOPT\n");
 
245
               return PERROR_BADOPT;
 
246
            }
 
247
         }
 
248
 
 
249
         if ( !opt ) {
 
250
            con->os->nextCharArg = origOptString + 1;
 
251
         } else {
 
252
            shorty = 0;
 
253
         }
 
254
      }
 
255
 
 
256
      /* process next short option */
 
257
      if ( con->os->nextCharArg ) {
 
258
         origOptString = con->os->nextCharArg;
 
259
         con->os->nextCharArg = NULL;
 
260
 
 
261
         opt = vkFindOption( con->options, NULL, *origOptString, 0 );
 
262
         if ( !opt ) {
 
263
            return PERROR_BADOPT;
 
264
         }
 
265
         shorty = 1;
 
266
      
 
267
         origOptString++;
 
268
         if ( *origOptString != '\0' )
 
269
            con->os->nextCharArg = origOptString;
 
270
      }
 
271
 
 
272
      if ( opt == NULL ) 
 
273
         return PERROR_BADOPT;
 
274
 
 
275
      if ( opt->argType != VkOPTION::ARG_NONE ) {
 
276
         con->os->nextArg = (const char*)_free(con->os->nextArg);
 
277
         if ( longArg ) {
 
278
            longArg = vkExpandNextArg( longArg );
 
279
            con->os->nextArg = longArg;
 
280
         } else if ( con->os->nextCharArg ) {
 
281
            longArg = vkExpandNextArg( con->os->nextCharArg);
 
282
            con->os->nextArg = longArg;
 
283
            con->os->nextCharArg = NULL;
 
284
         } else {
 
285
            while ( con->os->next == con->os->argc &&
 
286
                    con->os > con->optionStack ) {
 
287
               vkCleanOSE( con->os-- );
 
288
            }
 
289
            if ( con->os->next == con->os->argc ) {
 
290
               /* FIX: con->os->argv not defined */
 
291
               return PERROR_NOARG;
 
292
               con->os->nextArg = NULL;
 
293
            } else {
 
294
               if ( con->os->argv != NULL ) {
 
295
                  /* watch out: subtle side-effects live here. */
 
296
                  longArg = con->os->argv[con->os->next++];
 
297
                  longArg = vkExpandNextArg( longArg );
 
298
                  con->os->nextArg = longArg;
 
299
               }
 
300
            }
 
301
         }
 
302
         longArg = NULL;
 
303
 
 
304
         /* store the argument value for checking */
 
305
         if ( con->os->nextArg ) {
 
306
            sprintf( arg_val, "%s", con->os->nextArg );
 
307
         }
 
308
      }     /* end if ! VkOPTION::ARG_NONE */
 
309
 
 
310
      if ( opt->optKey >= 0 ) {  /* is-a leaf */
 
311
         done = 1;
 
312
      }
 
313
 
 
314
      if ( (con->finalArgvCount + 2) >= (con->finalArgvAlloced) ) {
 
315
         con->finalArgvAlloced += 10;
 
316
         con->finalArgv = (const char**)realloc(con->finalArgv,
 
317
                                                sizeof(*con->finalArgv) * con->finalArgvAlloced);
 
318
      }
 
319
 
 
320
      if ( con->finalArgv != NULL ) {
 
321
         char *s = (char*)malloc((opt->longFlag ? strlen(opt->longFlag) : 0) + 3);
 
322
         if ( s != NULL ) {
 
323
            if ( opt->longFlag ) {
 
324
               sprintf(s, "--%s", opt->longFlag);
 
325
            } else {
 
326
               sprintf(s, "-%c", opt->shortFlag);
 
327
            }
 
328
            con->finalArgv[con->finalArgvCount++] = s;
 
329
         } else
 
330
            con->finalArgv[con->finalArgvCount++] = NULL;
 
331
      }
 
332
 
 
333
      if ((opt->arg == NULL/* leaf */) &&
 
334
          (opt->argType != VkOPTION::ARG_NONE)) {
 
335
         if (con->finalArgv != NULL && con->os->nextArg) {
 
336
            char* s = (char*)malloc( strlen(con->os->nextArg)+1 );
 
337
            if (s == NULL) {
 
338
               vkPrintErr("virtual memory exhausted.");
 
339
               exit(EXIT_FAILURE);
 
340
            } else {
 
341
               con->finalArgv[con->finalArgvCount++] =
 
342
                  strcpy( s, con->os->nextArg );
 
343
            }
 
344
         }
 
345
      }
 
346
   }  /* end while ( !done ) */
 
347
 
 
348
   //  vk_assert( opt != NULL );
 
349
   *opt_ret = opt;
 
350
   return PARSED_OK;
 
351
}
 
352
 
 
353
 
 
354
vkPoptContext vkPoptFreeContext( vkPoptContext con )
 
355
{
 
356
   if ( con == NULL ) 
 
357
      return con;
 
358
 
 
359
   /* poptResetContext( con ); */
 
360
   int i;
 
361
   while ( con->os > con->optionStack ) {
 
362
      vkCleanOSE(con->os--);
 
363
   }
 
364
   con->os->nextCharArg = NULL;
 
365
   con->os->nextArg  = NULL;
 
366
   con->os->next     = 1;      /* skip argv[0] */
 
367
   con->numLeftovers = 0;
 
368
   con->nextLeftover = 0;
 
369
   con->restLeftover = 0;
 
370
 
 
371
   if ( con->finalArgv != NULL )
 
372
      for (i = 0; i < con->finalArgvCount; i++)
 
373
         con->finalArgv[i] = (const char*)_free(con->finalArgv[i]);
 
374
   con->finalArgvCount = 0;
 
375
 
 
376
   con->leftovers = (const char**)_free( con->leftovers );
 
377
   con->finalArgv = (const char**)_free( con->finalArgv );
 
378
 
 
379
   con = (vkPoptContext)_free( con );
 
380
   return con;
 
381
}
 
382
 
 
383
 
 
384
const char * vkPoptBadOption( vkPoptContext con )
 
385
{
 
386
   struct optionStackEntry * os = NULL;
 
387
 
 
388
   if ( con != NULL )
 
389
      os = con->optionStack;
 
390
 
 
391
   return ( os && os->argv ? os->argv[os->next - 1] : NULL );
 
392
}
 
393
 
 
394
 
 
395
 
 
396
/*------ help printing stuff --------------------------------*/
 
397
/* set in poptPrintHelp */
 
398
static int leftColWidth = -1;
 
399
 
 
400
static const char * vkGetHelpDesc( const vkPoptOption * opt )
 
401
{
 
402
   /* if ARG_NONE: no arguments to describe */
 
403
   if ( opt->argType == VkOPTION::ARG_NONE )
 
404
      return NULL;
 
405
 
 
406
   if ( opt->helpdesc )
 
407
      return opt->helpdesc;
 
408
 
 
409
   return NULL;
 
410
}
 
411
 
 
412
 
 
413
/* called from vkTableHelp() for leaf table */
 
414
static void vkSingleOptionHelp( FILE * fp, 
 
415
                                const vkPoptOption * opt )
 
416
{
 
417
   int indentLength  = leftColWidth + 2;
 
418
   int lineLength    = 80 - indentLength;
 
419
   const char * help = opt->helptxt;
 
420
   const char * helpdesc = vkGetHelpDesc( opt );
 
421
   int helpLength;
 
422
   char * defs = NULL;
 
423
   char * left;
 
424
   int nb = leftColWidth + 1;
 
425
 
 
426
   /* make sure there's more than enough room in target buffer. */
 
427
   if ( opt->longFlag )  
 
428
      nb += strlen( opt->longFlag );
 
429
   if ( helpdesc )  
 
430
      nb += strlen( helpdesc );
 
431
 
 
432
   left = (char*)malloc( nb );
 
433
   if ( left == NULL ) 
 
434
      return;
 
435
   left[0] = '\0';
 
436
   left[leftColWidth] = '\0';
 
437
 
 
438
   if ( opt->longFlag && opt->shortFlag ) {
 
439
      sprintf( left, "-%c, --%s", opt->shortFlag, opt->longFlag);
 
440
   } else if (opt->shortFlag != '\0') {
 
441
      sprintf( left, "-%c", opt->shortFlag);
 
442
   } else if (opt->longFlag) {
 
443
      sprintf( left, "--%s", opt->longFlag );
 
444
   }
 
445
 
 
446
   if ( !*left ) {
 
447
      goto out;
 
448
   }
 
449
 
 
450
   if ( helpdesc ) {
 
451
      char * le = left + strlen( left );
 
452
      *le++ = ' ';
 
453
      strcpy( le, helpdesc );
 
454
      le += strlen(le);
 
455
      *le = '\0';
 
456
   }
 
457
 
 
458
   if ( help ) {
 
459
      fprintf( fp,"  %-*s", leftColWidth, left );
 
460
   } else {
 
461
      fprintf( fp,"  %s\n", left ); 
 
462
      goto out;
 
463
   }
 
464
 
 
465
   left = (char*)_free(left);
 
466
   if ( defs ) {
 
467
      help = defs;
 
468
      defs = NULL;
 
469
   }
 
470
  
 
471
   helpLength = strlen( help );
 
472
   while ( helpLength > lineLength ) {
 
473
      const char * ch;
 
474
      char format[100];
 
475
 
 
476
      ch = help + lineLength - 1;
 
477
      while ( ch > help && !isspace(*ch) ) 
 
478
         ch--;
 
479
      if ( ch == help ) 
 
480
         break;    /* give up */
 
481
      while ( ch > (help + 1) && isspace(*ch) )
 
482
         ch--;
 
483
      ch++;
 
484
    
 
485
      sprintf( format, "%%.%ds\n%%%ds", 
 
486
               (int) (ch - help), indentLength );
 
487
      fprintf( fp, format, help, " " );
 
488
      help = ch;
 
489
      while ( isspace(*help) && *help ) 
 
490
         help++;
 
491
      helpLength = strlen( help );
 
492
   }
 
493
 
 
494
   if ( helpLength ) 
 
495
      fprintf( fp, "%s\n", help );
 
496
 
 
497
 out:
 
498
   defs = (char*)_free(defs);
 
499
   left = (char*)_free(left);
 
500
}
 
501
 
 
502
 
 
503
static int vkMaxArgWidth( const vkPoptOption * opt )
 
504
{
 
505
   int max = 0;
 
506
   int len = 0;
 
507
   const char * s;
 
508
 
 
509
   if ( opt == NULL )
 
510
      return 0;
 
511
 
 
512
   for (; opt->longFlag || opt->shortFlag || opt->arg; opt++ ) {
 
513
 
 
514
      if ( opt->arg != NULL ) {     /* is-a table */
 
515
         /* recurse on included sub-tables. */
 
516
         len = vkMaxArgWidth( opt->arg );
 
517
         if ( len > max ) 
 
518
            max = len;
 
519
      }
 
520
      else {                        /* is-a leaf */
 
521
         len = sizeof("  ") - 1;
 
522
         if ( opt->shortFlag != '\0' )
 
523
            len += sizeof("-X")-1;
 
524
         if ( opt->shortFlag != '\0' && opt->longFlag ) 
 
525
            len += sizeof(", ")-1;
 
526
         if (opt->longFlag) {
 
527
            len += sizeof("--") - 1;
 
528
            len += strlen( opt->longFlag );
 
529
         }
 
530
 
 
531
         s = vkGetHelpDesc( opt );
 
532
         if ( s )
 
533
            len += sizeof("=") - 1 + strlen( s );
 
534
         if ( len > max ) 
 
535
            max = len;
 
536
      }
 
537
   }
 
538
   return max;
 
539
}
 
540
 
 
541
 
 
542
/* this version prints nested tables first. swap 'em over if this
 
543
   isn't the behaviour you want. */
 
544
static void vkTableHelp( FILE * fp, const vkPoptOption * opt )
 
545
{
 
546
   if ( opt == NULL )
 
547
      return;
 
548
 
 
549
   /* recurse over all tables */
 
550
   for (; opt->longFlag || opt->shortFlag || opt->arg; opt++) {
 
551
      if ( opt->arg != NULL ) {     /* is-a table */
 
552
         /* print table title */
 
553
         fprintf( fp, "\n%s options:\n", opt->helptxt );
 
554
         /* recurse on included sub-tables. */
 
555
         vkTableHelp( fp, opt->arg );
 
556
      }
 
557
      else {                        /* is-a leaf */
 
558
         /* print options */
 
559
         vkSingleOptionHelp( fp, opt );
 
560
      }
 
561
   }
 
562
}
 
563
 
 
564
 
 
565
/* if tableName == NULL, recurses over all tables;
 
566
   else just prints contents of the specified table. */
 
567
void vkPoptPrintHelp( vkPoptContext con, FILE * fp,
 
568
                      const char * tableName )
 
569
{
 
570
   const char * fn;
 
571
 
 
572
   fprintf( fp, "\nUsage:" );
 
573
   fn = con->optionStack->argv[0];
 
574
   if ( fn != NULL ) {
 
575
      if ( strchr(fn, '/') ) 
 
576
         fn = strrchr( fn, '/' ) + 1;
 
577
      fprintf( fp, " %s", fn );
 
578
   }
 
579
 
 
580
   fprintf( fp, " %s", 
 
581
            "[valkyrie-opts] [valgrind-opts] [prog-and-args]\n" );
 
582
 
 
583
   leftColWidth = vkMaxArgWidth( con->options );
 
584
 
 
585
   if ( tableName == NULL ) {
 
586
      /* print all tables */
 
587
      vkTableHelp( fp, con->options );
 
588
   } else {
 
589
      /* trawl through con->options till we find the right table */
 
590
      const vkPoptOption * opt;
 
591
      for ( opt = con->options; (opt != NULL) &&
 
592
               (opt->helptxt != NULL); opt++ ) {
 
593
         if ( strcmp( opt->helptxt, tableName ) == 0 ) {
 
594
            break;
 
595
         }
 
596
      }
 
597
      if ( (opt != NULL) && (opt->helptxt) != NULL ) {
 
598
         if ( opt->helptxt )
 
599
            fprintf( fp, "\n%s options:\n", opt->helptxt );
 
600
         else
 
601
            vkPrintErr("Error: vkPoptPrintHelp(): No match found for table '%s'.", tableName);
 
602
         vkTableHelp( fp, opt->arg );
 
603
      }
 
604
   }
 
605
 
 
606
}