GnuCOBOL  2.0
A free COBOL compiler
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:

Go to the source code of this file.

Macros

#define _(msgid)   msgid
 
#define N_(msgid)   msgid
 
#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 = ((void*)0)
 
int cob_optind = 1
 
static int cob_getopt_initialized = 0
 
static char * nextchar = ((void*)0)
 
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 _ (   msgid)    msgid

Definition at line 44 of file cobgetopt.c.

Referenced by cob_getopt_long_long().

#define COB_LIB_EXPIMP

Definition at line 49 of file cobgetopt.c.

#define N_ (   msgid)    msgid

Definition at line 45 of file cobgetopt.c.

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

Definition at line 52 of file cobgetopt.c.

Referenced by cob_getopt_long_long().

Enumeration Type Documentation

anonymous enum
Enumerator
REQUIRE_ORDER 
PERMUTE 
RETURN_IN_ORDER 

Definition at line 149 of file cobgetopt.c.

149  {
151 } ordering;
static enum @0 ordering

Function Documentation

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

Definition at line 236 of file cobgetopt.c.

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

Referenced by cob_getopt_long_long().

237 {
238  /* Start processing options with ARGV-element 1 (since ARGV-element 0
239  is the program name); the sequence of previously skipped
240  non-option ARGV-elements is empty. */
241 
243 
244  nextchar = NULL;
245 
246  /* Determine how to handle the ordering of options and nonoptions. */
247 
248  if (optstring[0] == '-')
249  {
251  ++optstring;
252  }
253  else if (optstring[0] == '+')
254  {
256  ++optstring;
257  }
258  else
259  ordering = PERMUTE;
260 
261  return optstring;
262 }
static int last_nonopt
Definition: cobgetopt.c:160
int cob_optind
Definition: cobgetopt.c:92
static char * nextchar
Definition: cobgetopt.c:107
EC ARGUMENT EC EC BOUND EC BOUND EC BOUND EC BOUND TABLE EC DATA EC DATA EC DATA PTR NULL
Definition: exception.def:95
static enum @0 ordering
static int first_nonopt
Definition: cobgetopt.c:159

Here is the caller graph for this function:

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

Definition at line 321 of file cobgetopt.c.

References _, _getopt_initialize(), cob_fast_malloc(), cob_free(), 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, PERMUTE, REQUIRE_ORDER, seen_short, and option::val.

Referenced by cob_sys_getopt_long_long(), and process_command_line().

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

Here is the call graph for this function:

Here is the caller graph for this function:

static void exchange ( char **  argv)
static

Definition at line 174 of file cobgetopt.c.

References cob_optind, first_nonopt, and last_nonopt.

Referenced by cob_getopt_long_long().

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

Here is the caller graph for this function:

Variable Documentation

int cob_getopt_initialized = 0
static

Definition at line 98 of file cobgetopt.c.

Referenced by cob_getopt_long_long().

char* cob_optarg = ((void*)0)
int cob_opterr = 1

Definition at line 112 of file cobgetopt.c.

Referenced by cob_getopt_long_long().

int cob_optind = 1
int cob_optopt = '?'

Definition at line 118 of file cobgetopt.c.

Referenced by cob_getopt_long_long().

int first_nonopt
static

Definition at line 159 of file cobgetopt.c.

Referenced by _getopt_initialize(), cob_getopt_long_long(), and exchange().

int last_nonopt
static

Definition at line 160 of file cobgetopt.c.

Referenced by _getopt_initialize(), cob_getopt_long_long(), and exchange().

char* nextchar = ((void*)0)
static

Definition at line 107 of file cobgetopt.c.

Referenced by _getopt_initialize(), and cob_getopt_long_long().

enum { ... } ordering
int seen_short = 0
static

Definition at line 162 of file cobgetopt.c.

Referenced by cob_getopt_long_long().