GnuCOBOL  2.0
A free COBOL compiler
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
cobgetopt.c File Reference
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <string.h>
#include <ctype.h>
#include "libcob.h"
#include "cobgetopt.h"
Include dependency graph for cobgetopt.c:

Macros

#define _(s)   s
 
#define N_(s)   s
 
#define COB_LIB_EXPIMP
 
#define NONOPTION_P   (argv[cob_optind][0] != '-' || argv[cob_optind][1] == '\0')
 

Enumerations

enum  { REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER }
 

Functions

static void exchange (char **argv)
 
static const char * _getopt_initialize (const char *optstring)
 
int cob_getopt_long_long (const int argc, char *const *argv, const char *optstring, const struct option *longopts, int *longind, const int long_only)
 

Variables

char * cob_optarg = NULL
 
int cob_optind = 1
 
static int cob_getopt_initialized = 0
 
static char * nextchar = NULL
 
int cob_opterr = 1
 
int cob_optopt = '?'
 
static enum { ... }  ordering
 
static int first_nonopt
 
static int last_nonopt
 
static int seen_short = 0
 

Macro Definition Documentation

#define _ (   s)    s
#define COB_LIB_EXPIMP
#define N_ (   s)    s
#define NONOPTION_P   (argv[cob_optind][0] != '-' || argv[cob_optind][1] == '\0')

Referenced by cob_getopt_long_long().

Enumeration Type Documentation

anonymous enum
Enumerator
REQUIRE_ORDER 
PERMUTE 
RETURN_IN_ORDER 
151  {
153 } ordering;

Function Documentation

static const char* _getopt_initialize ( const char *  optstring)
static

References cob_optind, first_nonopt, last_nonopt, nextchar, NULL, ordering, and PERMUTE.

Referenced by cob_getopt_long_long().

239 {
240  /* Start processing options with ARGV-element 1 (since ARGV-element 0
241  is the program name); the sequence of previously skipped
242  non-option ARGV-elements is empty. */
243 
245 
246  nextchar = NULL;
247 
248  /* Determine how to handle the ordering of options and nonoptions. */
249 
250  if (optstring[0] == '-')
251  {
252  ++optstring;
253  }
254  else if (optstring[0] == '+')
255  {
256  ++optstring;
257  }
258  ordering = PERMUTE;
259 
260  return optstring;
261 }
int cob_getopt_long_long ( const int  argc,
char *const *  argv,
const char *  optstring,
const struct option longopts,
int *  longind,
const int  long_only 
)

References _, _getopt_initialize(), cob_getopt_initialized, cob_optarg, cob_opterr, cob_optind, cob_optopt, exchange(), first_nonopt, option::flag, option::has_arg, last_nonopt, option::name, nextchar, NONOPTION_P, NULL, ordering, p, PERMUTE, REQUIRE_ORDER, seen_short, and option::val.

Referenced by cob_sys_getopt_long_long(), and process_command_line().

323 {
324  if (argc < 1)
325  return -1;
326 
327  cob_optarg = NULL;
328 
329  if (cob_optind == 0 || !cob_getopt_initialized)
330  {
331  if (cob_optind == 0)
332  cob_optind = 1; /* Don't scan ARGV[0], the program name. */
333  optstring = _getopt_initialize (optstring);
335  }
336 
337  /* Test whether ARGV[optind] points to a non-option argument.
338  Either it does not have option syntax, or there is an environment flag
339  from the shell indicating it is not an option. The later information
340  is only used when the used in the GNU libc. */
341 
342  if (nextchar == NULL || *nextchar == '\0')
343  {
344  /* Advance to the next ARGV-element. */
345 
346  seen_short = 0;
347  /* Give FIRST_NONOPT & LAST_NONOPT rational values if OPTIND has been
348  moved back by the user (who may also have changed the arguments). */
349  if (last_nonopt > cob_optind)
351  if (first_nonopt > cob_optind)
353 
354  if (ordering == PERMUTE)
355  {
356  /* If we have just processed some options following some non-options,
357  exchange them so that the options come first. */
358 
360  exchange ((char **) argv);
361  else if (last_nonopt != cob_optind)
363 
364  /* Skip any additional non-options
365  and extend the range of non-options previously skipped. */
366 
367  while (cob_optind < argc && NONOPTION_P)
368  cob_optind++;
370  }
371 
372  /* The special ARGV-element `--' means premature end of options.
373  Skip it like a null option,
374  then exchange with previous non-options as if it were an option,
375  then skip everything else like a non-option. */
376 
377  if (cob_optind != argc && !strcmp (argv[cob_optind], "--"))
378  {
379  cob_optind++;
380 
381  if (first_nonopt != last_nonopt && last_nonopt != cob_optind)
382  exchange ((char **) argv);
383  else if (first_nonopt == last_nonopt)
385  last_nonopt = argc;
386 
387  cob_optind = argc;
388  }
389 
390  /* If we have done all the ARGV-elements, stop the scan
391  and back over any non-options that we skipped and permuted. */
392 
393  if (cob_optind == argc)
394  {
395  /* Set the next-arg-index to point at the non-options
396  that we previously skipped, so the caller will digest them. */
397  if (first_nonopt != last_nonopt)
398  cob_optind = first_nonopt;
399  return -1;
400  }
401 
402  /* If we have come to a non-option and did not permute it,
403  either stop the scan or describe it to the caller and pass it by. */
404 
405  if (NONOPTION_P)
406  {
407  if (ordering == REQUIRE_ORDER)
408  return -1;
409  cob_optarg = argv[cob_optind++];
410  return 1;
411  }
412 
413  /* We have found another option-ARGV-element.
414  Skip the initial punctuation. */
415 
416  nextchar = (argv[cob_optind] + 1
417  + (longopts != NULL && argv[cob_optind][1] == '-'));
418  }
419 
420  /* Decode the current option-ARGV-element. */
421 
422  /* Check whether the ARGV-element is a long option.
423 
424  If long_only and the ARGV-element has the form "-f", where f is
425  a valid short option, don't consider it an abbreviated form of
426  a long option that starts with f. Otherwise there would be no
427  way to give the -f short option.
428 
429  On the other hand, if there's a long option "fubar" and
430  the ARGV-element is "-fu", do consider that an abbreviation of
431  the long option, just like "--fu", and not "-f" with arg "u".
432 
433  This distinction seems to be the most useful approach. */
434 
435  if (longopts != NULL && (argv[cob_optind][1] == '-'
436  || (long_only && !seen_short && (argv[cob_optind][2] || !strchr (optstring, argv[cob_optind][1])))))
437  {
438  char *nameend;
439  const struct option *p;
440  const struct option *pfound = NULL;
441  int exact = 0;
442  int ambig = 0;
443  int indfound = -1;
444  int option_index;
445 
446  for (nameend = nextchar; *nameend && *nameend != '='; nameend++)
447  /* Do nothing. */ ;
448 
449  /* Test all long options for either exact match
450  or abbreviated matches. */
451  for (p = longopts, option_index = 0; p->name; p++, option_index++)
452  if (!strncmp (p->name, nextchar, (size_t)(nameend - nextchar)))
453  {
454  if ((unsigned int) (nameend - nextchar)
455  == (unsigned int) strlen (p->name))
456  {
457  /* Exact match found. */
458  pfound = p;
459  indfound = option_index;
460  exact = 1;
461  break;
462  }
463  else if (pfound == NULL)
464  {
465  /* First nonexact match found. */
466  pfound = p;
467  indfound = option_index;
468  }
469 #if 0 /* RXWRXW - ambig */
470  else if (long_only
471  || pfound->has_arg != p->has_arg
472  || pfound->flag != p->flag
473  || pfound->val != p->val)
474 #else
475  else
476 #endif
477  /* Second or later nonexact match found. */
478  ambig = 1;
479  }
480 
481  if (ambig && !exact)
482  {
483  if (cob_opterr)
484  {
485  fprintf (stderr, _("%s: option `%s' is ambiguous\n"),
486  argv[0], argv[cob_optind]);
487  }
488  nextchar += strlen (nextchar);
489  cob_optind++;
490  cob_optopt = 0;
491  return '?';
492  }
493 
494  if (pfound != NULL)
495  {
496  option_index = indfound;
497  cob_optind++;
498  if (*nameend)
499  {
500  /* Don't test has_arg with >, because some C compilers don't
501  allow it to be used on enums. */
502  if (pfound->has_arg)
503  cob_optarg = nameend + 1;
504  else
505  {
506  if (cob_opterr)
507  {
508  if (argv[cob_optind - 1][1] == '-')
509  {
510  /* --option */
511  fprintf (stderr,
512  _("%s: option `--%s' doesn't allow an argument\n"),
513  argv[0], pfound->name);
514  }
515  else
516  {
517  /* +option or -option */
518  fprintf (stderr,
519  _("%s: option `%c%s' doesn't allow an argument\n"),
520  argv[0], argv[cob_optind - 1][0], pfound->name);
521  }
522  }
523 
524  nextchar += strlen (nextchar);
525 
526  cob_optopt = pfound->val;
527  return '?';
528  }
529  }
530  else if (pfound->has_arg == 1)
531  {
532  if (cob_optind < argc)
533  cob_optarg = argv[cob_optind++];
534  else
535  {
536  if (cob_opterr)
537  {
538  fprintf (stderr,
539  _("%s: option `%s' requires an argument\n"),
540  argv[0], argv[cob_optind - 1]);
541  }
542  nextchar += strlen (nextchar);
543  cob_optopt = pfound->val;
544  return optstring[0] == ':' ? ':' : '?';
545  }
546  }
547  nextchar += strlen (nextchar);
548  if (longind != NULL)
549  *longind = option_index;
550  if (pfound->flag)
551  {
552  *(pfound->flag) = pfound->val;
553  return 0;
554  }
555  return pfound->val;
556  }
557 
558  /* Can't find it as a long option. If this is not getopt_long_only,
559  or the option starts with '--' or is not a valid short
560  option, then it's an error.
561  Otherwise interpret it as a short option. */
562  if (!long_only || argv[cob_optind][1] == '-'
563  || strchr (optstring, *nextchar) == NULL)
564  {
565  if (cob_opterr)
566  {
567  if (argv[cob_optind][1] == '-')
568  {
569  /* --option */
570  fprintf (stderr, _("%s: unrecognized option `--%s'\n"),
571  argv[0], nextchar);
572  }
573  else
574  {
575  /* +option or -option */
576  fprintf (stderr, _("%s: unrecognized option `%c%s'\n"),
577  argv[0], argv[cob_optind][0], nextchar);
578  }
579  }
580  nextchar = (char *) "";
581  cob_optind++;
582  cob_optopt = 0;
583  return '?';
584  }
585  }
586 
587  /* Look at and handle the next short option-character. */
588 
589  {
590  char c = *nextchar++;
591  char *temp = strchr (optstring, c);
592 
593  /* Increment `cob_optind' when we start to process its last character. */
594  if (*nextchar == '\0')
595  {
596  ++cob_optind;
597  seen_short = 0;
598  }
599 
600  if (temp == NULL || c == ':')
601  {
602  if (cob_opterr)
603  {
604  fprintf (stderr, _("%s: invalid option -- %c\n"), argv[0], c);
605  }
606  cob_optopt = c;
607  seen_short = 0;
608  return '?';
609  }
610  /* Convenience. Treat POSIX -W foo same as long option --foo */
611  if (temp[0] == 'W' && temp[1] == ';')
612  {
613  char *nameend;
614  const struct option *p;
615  const struct option *pfound = NULL;
616  int exact = 0;
617  int ambig = 0;
618  int indfound = 0;
619  int option_index;
620 
621  /* This is an option that requires an argument. */
622  if (*nextchar != '\0')
623  {
625  /* If we end this ARGV-element by taking the rest as an arg,
626  we must advance to the next element now. */
627  cob_optind++;
628  }
629  else if (cob_optind == argc)
630  {
631  if (cob_opterr)
632  {
633  /* 1003.2 specifies the format of this message. */
634  fprintf (stderr, _("%s: option requires an argument -- %c\n"),
635  argv[0], c);
636  }
637  cob_optopt = c;
638  if (optstring[0] == ':')
639  c = ':';
640  else
641  c = '?';
642  seen_short = 0;
643  return c;
644  }
645  else
646  /* We already incremented `cob_optind' once;
647  increment it again when taking next ARGV-elt as argument. */
648  cob_optarg = argv[cob_optind++];
649 
650  /* cob_optarg is now the argument, see if it's in the
651  table of longopts. */
652 
653  for (nextchar = nameend = cob_optarg; *nameend && *nameend != '='; nameend++)
654  /* Do nothing. */ ;
655 
656  /* Test all long options for either exact match
657  or abbreviated matches. */
658  for (p = longopts, option_index = 0; p->name; p++, option_index++)
659  if (!strncmp (p->name, nextchar, (size_t)(nameend - nextchar)))
660  {
661  if ((unsigned int) (nameend - nextchar) == strlen (p->name))
662  {
663  /* Exact match found. */
664  pfound = p;
665  indfound = option_index;
666  exact = 1;
667  break;
668  }
669  else if (pfound == NULL)
670  {
671  /* First nonexact match found. */
672  pfound = p;
673  indfound = option_index;
674  }
675  else
676  /* Second or later nonexact match found. */
677  ambig = 1;
678  }
679  if (ambig && !exact)
680  {
681  if (cob_opterr)
682  {
683  fprintf (stderr, _("%s: option `-W %s' is ambiguous\n"),
684  argv[0], argv[cob_optind]);
685  }
686  nextchar += strlen (nextchar);
687  cob_optind++;
688  seen_short = 0;
689  return '?';
690  }
691  if (pfound != NULL)
692  {
693  option_index = indfound;
694  if (*nameend)
695  {
696  /* Don't test has_arg with >, because some C compilers don't
697  allow it to be used on enums. */
698  if (pfound->has_arg)
699  cob_optarg = nameend + 1;
700  else
701  {
702  if (cob_opterr)
703  {
704  fprintf (stderr, _("\
705 %s: option `-W %s' doesn't allow an argument\n"),
706  argv[0], pfound->name);
707  }
708 
709  nextchar += strlen (nextchar);
710  seen_short = 0;
711  return '?';
712  }
713  }
714  else if (pfound->has_arg == 1)
715  {
716  if (cob_optind < argc)
717  cob_optarg = argv[cob_optind++];
718  else
719  {
720  if (cob_opterr)
721  {
722  fprintf (stderr,
723  _("%s: option `%s' requires an argument\n"),
724  argv[0], argv[cob_optind - 1]);
725  }
726  nextchar += strlen (nextchar);
727  seen_short = 0;
728  return optstring[0] == ':' ? ':' : '?';
729  }
730  }
731  nextchar += strlen (nextchar);
732  if (longind != NULL)
733  *longind = option_index;
734  if (pfound->flag)
735  {
736  *(pfound->flag) = pfound->val;
737  return 0;
738  }
739  return pfound->val;
740  }
741  nextchar = NULL;
742  return 'W'; /* Let the application handle it. */
743  }
744  if (temp[1] == ':')
745  {
746  if (temp[2] == ':')
747  {
748  /* This is an option that accepts an argument optionally. */
749  if (*nextchar != '\0')
750  {
752  cob_optind++;
753  }
754  else
755  cob_optarg = NULL;
756  nextchar = NULL;
757  }
758  else
759  {
760  /* This is an option that requires an argument. */
761  if (*nextchar != '\0')
762  {
764  /* If we end this ARGV-element by taking the rest as an arg,
765  we must advance to the next element now. */
766  cob_optind++;
767  }
768  else if (cob_optind == argc)
769  {
770  if (cob_opterr)
771  {
772  /* 1003.2 specifies the format of this message. */
773  fprintf (stderr,
774  _("%s: option requires an argument -- %c\n"),
775  argv[0], c);
776  }
777  cob_optopt = c;
778  seen_short = 0;
779  if (optstring[0] == ':')
780  c = ':';
781  else
782  c = '?';
783  }
784  else
785  /* We already incremented `cob_optind' once;
786  increment it again when taking next ARGV-elt as argument. */
787  cob_optarg = argv[cob_optind++];
788  nextchar = NULL;
789  }
790  }
791  seen_short = 1;
792  return c;
793  }
794 }
static void exchange ( char **  argv)
static

References cob_optind, first_nonopt, and last_nonopt.

Referenced by cob_getopt_long_long().

177 {
178  int bottom = first_nonopt;
179  int middle = last_nonopt;
180  int top = cob_optind;
181  char *tem;
182 
183  /* Exchange the shorter segment with the far end of the longer segment.
184  That puts the shorter segment into the right place.
185  It leaves the longer segment in the right place overall,
186  but it consists of two parts that need to be swapped next. */
187 
188  while (top > middle && middle > bottom)
189  {
190  if (top - middle > middle - bottom)
191  {
192  /* Bottom segment is the short one. */
193  int len = middle - bottom;
194  register int i;
195 
196  /* Swap it with the top part of the top segment. */
197  for (i = 0; i < len; i++)
198  {
199  tem = argv[bottom + i];
200  argv[bottom + i] = argv[top - (middle - bottom) + i];
201  argv[top - (middle - bottom) + i] = tem;
202 #if 0 /* RXWRXW - swap flags */
203  SWAP_FLAGS (bottom + i, top - (middle - bottom) + i);
204 #endif
205  }
206  /* Exclude the moved bottom segment from further swapping. */
207  top -= len;
208  }
209  else
210  {
211  /* Top segment is the short one. */
212  int len = top - middle;
213  register int i;
214 
215  /* Swap it with the bottom part of the bottom segment. */
216  for (i = 0; i < len; i++)
217  {
218  tem = argv[bottom + i];
219  argv[bottom + i] = argv[middle + i];
220  argv[middle + i] = tem;
221 #if 0 /* RXWRXW - swap flags */
222  SWAP_FLAGS (bottom + i, middle + i);
223 #endif
224  }
225  /* Exclude the moved top segment from further swapping. */
226  bottom += len;
227  }
228  }
229 
230  /* Update records for the slots the non-options now occupy. */
231 
234 }

Variable Documentation

int cob_getopt_initialized = 0
static

Referenced by cob_getopt_long_long().

int cob_opterr = 1

Referenced by cob_getopt_long_long().

int cob_optopt = '?'

Referenced by cob_getopt_long_long().

int first_nonopt
static
int last_nonopt
static
char* nextchar = NULL
static
enum { ... } ordering
int seen_short = 0
static

Referenced by cob_getopt_long_long().