"Fossies" - the Fresh Open Source Software Archive

Member "dateutils-0.4.6/src/dconv.yucc" (19 Mar 2019, 13757 Bytes) of package /linux/privat/dateutils-0.4.6.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. See also the latest Fossies "Diffs" side-by-side code changes report for "dconv.yucc": 0.4.5_vs_0.4.6.

    1 /* -*- c -*- */
    2 #if !defined INCLUDED_yuck_h_
    3 #define INCLUDED_yuck_h_
    4 
    5 #include <stddef.h>
    6 
    7 #define YUCK_OPTARG_NONE    ((void*)0x1U)
    8 
    9 enum yuck_cmds_e {
   10     /* value used when no command was specified */
   11     DATECONV_CMD_NONE = 0U,
   12 
   13     /* actual commands */
   14     
   15     /* convenience identifiers */
   16     YUCK_NOCMD = DATECONV_CMD_NONE,
   17     YUCK_NCMDS = DATECONV_CMD_NONE
   18 };
   19 
   20 
   21 
   22 typedef struct yuck_s yuck_t;
   23 
   24 
   25 
   26 /* generic struct */
   27 struct yuck_s {
   28     enum yuck_cmds_e cmd;
   29 
   30     /* left-over arguments,
   31      * the command string is never a part of this */
   32     size_t nargs;
   33     char **args;
   34 
   35     /* slots common to all commands */
   36 
   37     /* help is handled automatically */
   38     /* version is handled automatically */
   39     unsigned int quiet_flag;
   40     char *format_arg;
   41     size_t input_format_nargs; char **input_format_args;
   42     char *base_arg;
   43     unsigned int backslash_escapes_flag;
   44     unsigned int sed_mode_flag;
   45     unsigned int empty_mode_flag;
   46     char *locale_arg;
   47     char *from_locale_arg;
   48     char *from_zone_arg;
   49     char *zone_arg;
   50 };
   51 
   52 
   53 static __attribute__((nonnull(1))) int
   54 yuck_parse(yuck_t*, int argc, char *argv[]);
   55 static __attribute__((nonnull(1))) void yuck_free(yuck_t*);
   56 
   57 static __attribute__((nonnull(1))) void yuck_auto_help(const yuck_t*);
   58 static __attribute__((nonnull(1))) void yuck_auto_usage(const yuck_t*);
   59 static __attribute__((nonnull(1))) void yuck_auto_version(const yuck_t*);
   60 
   61 /* some hooks */
   62 #if defined yuck_post_help
   63 static __attribute__((nonnull(1))) void yuck_post_help(const yuck_t*);
   64 #endif  /* yuck_post_help */
   65 
   66 #if defined yuck_post_usage
   67 static __attribute__((nonnull(1))) void yuck_post_usage(const yuck_t*);
   68 #endif  /* yuck_post_usage */
   69 
   70 #if defined yuck_post_version
   71 static __attribute__((nonnull(1))) void yuck_post_version(const yuck_t*);
   72 #endif  /* yuck_post_version */
   73 
   74 #endif  /* INCLUDED_yuck_h_ */
   75 /* -*- c -*- */
   76 #if defined HAVE_CONFIG_H
   77 # include "config.h"
   78 #endif  /* HAVE_CONFIG_H */
   79 #if defined HAVE_VERSION_H
   80 # include "version.h"
   81 #endif  /* HAVE_VERSION_H */
   82 #include <stdlib.h>
   83 #include <stdbool.h>
   84 #include <string.h>
   85 #include <stdio.h>
   86 #include <limits.h>
   87 
   88 #if defined __INTEL_COMPILER
   89 # pragma warning (push)
   90 # pragma warning (disable:177)
   91 # pragma warning (disable:111)
   92 # pragma warning (disable:3280)
   93 #elif defined __GNUC__
   94 # if __GNUC__ > 4 || __GNUC__ == 4 &&  __GNUC_MINOR__ >= 6
   95 #  pragma GCC diagnostic push
   96 # endif  /* GCC version */
   97 # pragma GCC diagnostic ignored "-Wunused-label"
   98 # pragma GCC diagnostic ignored "-Wunused-variable"
   99 # pragma GCC diagnostic ignored "-Wunused-function"
  100 # pragma GCC diagnostic ignored "-Wshadow"
  101 #endif  /* __INTEL_COMPILER */
  102 
  103 
  104 static inline bool
  105 yuck_streqp(const char *s1, const char *s2)
  106 {
  107     return !strcmp(s1, s2);
  108 }
  109 
  110 /* for multi-args */
  111 static inline char**
  112 yuck_append(char **array, size_t n, char *val)
  113 {
  114     if (!(n % 16U)) {
  115         /* resize */
  116         void *tmp = realloc(array, (n + 16U) * sizeof(*array));
  117         if (tmp == NULL) {
  118             free(array);
  119             return NULL;
  120         }
  121         /* otherwise make it persistent */
  122         array = tmp;
  123     }
  124     array[n] = val;
  125     return array;
  126 }
  127 
  128 static enum yuck_cmds_e yuck_parse_cmd(const char *cmd)
  129 {
  130     if (0) {
  131         ;
  132     } else {
  133         /* error here? */
  134         fprintf(stderr, "dateconv: invalid command `%s'\n\
  135 Try `--help' for a list of commands.\n", cmd);
  136     }
  137     return (enum yuck_cmds_e)-1;
  138 }
  139 
  140 
  141 static int yuck_parse(yuck_t tgt[static 1U], int argc, char *argv[])
  142 {
  143     char *op;
  144     int i;
  145 
  146     /* we'll have at most this many args */
  147     memset(tgt, 0, sizeof(*tgt));
  148     if ((tgt->args = calloc(argc, sizeof(*tgt->args))) == NULL) {
  149         return -1;
  150     }
  151     for (i = 1; i < argc && tgt->nargs < (size_t)-1; i++) {
  152         op = argv[i];
  153 
  154         switch (*op) {
  155         case '-':
  156             /* could be an option */
  157             switch (*++op) {
  158             default:
  159                 /* could be glued into one */
  160                 for (; *op; op++) {
  161                     goto shortopt; back_from_shortopt:;
  162                 }
  163                 break;
  164             case '-':
  165                 if (*++op == '\0') {
  166                     i++;
  167                     goto dashdash; back_from_dashdash:;
  168                     break;
  169                 }
  170                 goto longopt; back_from_longopt:;
  171                 break;
  172             case '\0':
  173                 goto plain_dash;
  174             }
  175             break;
  176         default:
  177         plain_dash:
  178             goto arg; back_from_arg:;
  179             break;
  180         }
  181     }
  182     if (i < argc) {
  183         op = argv[i];
  184 
  185         if (*op++ == '-' && *op++ == '-' && !*op) {
  186             /* another dashdash, filter out */
  187             i++;
  188         }
  189     }
  190     /* has to be here as the max_pargs condition might drive us here */
  191     dashdash:
  192     {
  193         /* dashdash loop, pile everything on tgt->args
  194          * don't check for subcommands either, this is in accordance to
  195          * the git tool which won't accept commands after -- */
  196         for (; i < argc; i++) {
  197             tgt->args[tgt->nargs++] = argv[i];
  198         }
  199     }
  200     return 0;
  201 
  202     longopt:
  203     {
  204         /* split into option and arg part */
  205         char *arg;
  206 
  207         if ((arg = strchr(op, '=')) != NULL) {
  208             /* \nul this one out */
  209             *arg++ = '\0';
  210         }
  211 
  212         switch (tgt->cmd) {
  213         default:
  214             goto DATECONV_CMD_NONE_longopt; back_from_DATECONV_CMD_NONE_longopt:;
  215             break;
  216         }
  217         goto back_from_longopt;
  218 
  219 
  220         DATECONV_CMD_NONE_longopt:
  221         {
  222             if (0) {
  223                 ;
  224             } else if (yuck_streqp(op, "help")) {
  225                 /* invoke auto action and exit */
  226                 yuck_auto_help(tgt);
  227                 goto success;
  228             } else if (yuck_streqp(op, "version")) {
  229                 /* invoke auto action and exit */
  230                 yuck_auto_version(tgt);
  231                 goto success;
  232             } else if (yuck_streqp(op, "quiet")) {
  233                 tgt->quiet_flag++; goto xtra_chk;
  234             } else if (yuck_streqp(op, "format")) {
  235                 tgt->format_arg = arg ?: argv[++i];
  236             } else if (yuck_streqp(op, "input-format")) {
  237                 tgt->input_format_args =
  238                     yuck_append(
  239                         tgt->input_format_args, tgt->input_format_nargs++,
  240                         arg ?: argv[++i]);
  241                 if (tgt->input_format_args == NULL) {
  242                     return -1;
  243                 };
  244             } else if (yuck_streqp(op, "base")) {
  245                 tgt->base_arg = arg ?: argv[++i];
  246             } else if (yuck_streqp(op, "backslash-escapes")) {
  247                 tgt->backslash_escapes_flag++; goto xtra_chk;
  248             } else if (yuck_streqp(op, "sed-mode")) {
  249                 tgt->sed_mode_flag++; goto xtra_chk;
  250             } else if (yuck_streqp(op, "empty-mode")) {
  251                 tgt->empty_mode_flag++; goto xtra_chk;
  252             } else if (yuck_streqp(op, "locale")) {
  253                 tgt->locale_arg = arg ?: argv[++i];
  254             } else if (yuck_streqp(op, "from-locale")) {
  255                 tgt->from_locale_arg = arg ?: argv[++i];
  256             } else if (yuck_streqp(op, "from-zone")) {
  257                 tgt->from_zone_arg = arg ?: argv[++i];
  258             } else if (yuck_streqp(op, "zone")) {
  259                 tgt->zone_arg = arg ?: argv[++i];
  260             } else {
  261                 /* grml */
  262                 fprintf(stderr, "dateconv: unrecognized option `--%s'\n", op);
  263                 goto failure;
  264             xtra_chk:
  265                 if (arg != NULL) {
  266                     fprintf(stderr, "dateconv: option `--%s' doesn't allow an argument\n", op);
  267                     goto failure;
  268                 }
  269             }
  270             if (i >= argc) {
  271                 fprintf(stderr, "dateconv: option `--%s' requires an argument\n", op);
  272                 goto failure;
  273             }
  274             goto back_from_DATECONV_CMD_NONE_longopt;
  275         }
  276         
  277     }
  278 
  279     shortopt:
  280     {
  281         char *arg = op + 1U;
  282 
  283         switch (tgt->cmd) {
  284         default:
  285             goto DATECONV_CMD_NONE_shortopt; back_from_DATECONV_CMD_NONE_shortopt:;
  286             break;
  287         }
  288         goto back_from_shortopt;
  289 
  290 
  291         DATECONV_CMD_NONE_shortopt:
  292         {
  293             switch (*op) {
  294             default:
  295                 /* again for clarity */
  296                 switch (*op) {
  297                 case '0':
  298                 case '1':
  299                 case '2':
  300                 case '3':
  301                 case '4':
  302                 case '5':
  303                 case '6':
  304                 case '7':
  305                 case '8':
  306                 case '9':
  307                     if (op[-1] == '-') {
  308                         /* literal treatment of numeral */
  309                         goto arg;
  310                     }
  311                     /* fallthrough */
  312                 default:
  313                     break;
  314                 }
  315                 ;
  316                 ;
  317                 fprintf(stderr, "dateconv: unrecognized option -%c\n", *op);
  318                 goto failure;
  319 
  320 
  321 
  322                 
  323             case 'h':
  324                 /* invoke auto action and exit */
  325                 yuck_auto_help(tgt);
  326                 goto success;
  327                 break;
  328             case 'V':
  329                 /* invoke auto action and exit */
  330                 yuck_auto_version(tgt);
  331                 goto success;
  332                 break;
  333             case 'q':
  334                 tgt->quiet_flag++;
  335                 break;
  336             case 'f':
  337                 tgt->format_arg = *arg
  338                     ? (op += strlen(arg), arg)
  339                     : argv[++i];
  340                 break;
  341             case 'i':
  342                 tgt->input_format_args =
  343                     yuck_append(
  344                         tgt->input_format_args,
  345                         tgt->input_format_nargs++,
  346                         *arg ? (op += strlen(arg), arg) : argv[++i]);
  347                 if (tgt->input_format_args == NULL) {
  348                     return -1;
  349                 };
  350                 break;
  351             case 'b':
  352                 tgt->base_arg = *arg
  353                     ? (op += strlen(arg), arg)
  354                     : argv[++i];
  355                 break;
  356             case 'e':
  357                 tgt->backslash_escapes_flag++;
  358                 break;
  359             case 'S':
  360                 tgt->sed_mode_flag++;
  361                 break;
  362             case 'E':
  363                 tgt->empty_mode_flag++;
  364                 break;
  365             case 'z':
  366                 tgt->zone_arg = *arg
  367                     ? (op += strlen(arg), arg)
  368                     : argv[++i];
  369                 break;
  370             }
  371             if (i >= argc) {
  372                 fprintf(stderr, "dateconv: option `--%s' requires an argument\n", op);
  373                 goto failure;
  374             }
  375             goto back_from_DATECONV_CMD_NONE_shortopt;
  376         }
  377         
  378     }
  379 
  380     arg:
  381     {
  382         if (tgt->cmd || YUCK_NCMDS == 0U) {
  383             tgt->args[tgt->nargs++] = argv[i];
  384         } else {
  385             /* ah, might be an arg then */
  386             if ((tgt->cmd = yuck_parse_cmd(op)) > YUCK_NCMDS) {
  387                 return -1;
  388             }
  389         }
  390         goto back_from_arg;
  391     }
  392 
  393     failure:
  394     {
  395         exit(EXIT_FAILURE);
  396     }
  397 
  398     success:
  399     {
  400         exit(EXIT_SUCCESS);
  401     }
  402 }
  403 
  404 static void yuck_free(yuck_t tgt[static 1U])
  405 {
  406     if (tgt->args != NULL) {
  407         /* free despite const qualifier */
  408         free(tgt->args);
  409     }
  410     /* free mulargs */
  411     switch (tgt->cmd) {
  412         void *ptr;
  413     default:
  414         break;
  415     case DATECONV_CMD_NONE:
  416 ;
  417 ;
  418 ;
  419 ;
  420         ptr = tgt->input_format_args;
  421         if (ptr != NULL) {
  422             free(ptr);
  423         }
  424 ;
  425 ;
  426 ;
  427 ;
  428 ;
  429 ;
  430 ;
  431 ;
  432 ;
  433         break;
  434     }
  435     return;
  436 }
  437 
  438 static void yuck_auto_usage(const yuck_t src[static 1U])
  439 {
  440     switch (src->cmd) {
  441     default:
  442     YUCK_NOCMD:
  443         puts("Usage: dateconv [OPTION]... [DATE/TIME]...\n\
  444 \n\
  445 Convert DATE/TIMEs between calendrical systems.\n\
  446 If DATE/TIME is omitted date/times are read from stdin.\n\
  447 \n\
  448 DATE/TIME can also be one of the following specials\n\
  449   - `now'           interpreted as the current (UTC) time stamp\n\
  450   - `time'          the time part of the current (UTC) time stamp\n\
  451   - `today'         the current date (according to UTC)\n\
  452   - `tomo[rrow]'    tomorrow's date (according to UTC)\n\
  453   - `y[ester]day'   yesterday's date (according to UTC)\n\
  454 ");
  455         break;
  456 
  457     }
  458 
  459 #if defined yuck_post_usage
  460     yuck_post_usage(src);
  461 #endif  /* yuck_post_usage */
  462     return;
  463 }
  464 
  465 static void yuck_auto_help(const yuck_t src[static 1U])
  466 {
  467     yuck_auto_usage(src);
  468 
  469 
  470     /* leave a not about common options */
  471     if (src->cmd == YUCK_NOCMD) {
  472         ;
  473     }
  474 
  475     switch (src->cmd) {
  476     default:
  477     case DATECONV_CMD_NONE:
  478         puts("\
  479   -h, --help            Print help and exit\n\
  480   -V, --version         Print version and exit\n\
  481   -q, --quiet           Suppress message about date/time and duration\n\
  482                         parser errors and fix-ups.\n\
  483                         The default is to print a warning or the\n\
  484                         fixed up value and return error code 2.\n\
  485   -f, --format=STRING   Output format.  This can either be a specifier\n\
  486                         string (similar to strftime()'s FMT) or the name\n\
  487                         of a calendar.\n\
  488   -i, --input-format=STRING...\n\
  489                         Input format, can be used multiple times.\n\
  490                         Each date/time will be passed to the input\n\
  491                         format parsers in the order they are given, if a\n\
  492                         date/time can be read successfully with a given\n\
  493                         input format specifier string, that value will\n\
  494                         be used.\n\
  495   -b, --base=DT         For underspecified input use DT as a fallback to\n\
  496                         fill in missing fields.  Also used for ambiguous\n\
  497                         format specifiers to position their range on the\n\
  498                         absolute time line.\n\
  499                         Must be a date/time in ISO8601 format.\n\
  500                         If omitted defaults to the current date/time.\n\
  501   -e, --backslash-escapes\n\
  502                         Enable interpretation of backslash escapes in the\n\
  503                         output and input format specifier strings.\n\
  504   -S, --sed-mode        Copy parts from the input before and after a\n\
  505                         matching date/time.\n\
  506                         Note that all occurrences of date/times within a\n\
  507                         line will be processed.\n\
  508   -E, --empty-mode      Empty lines that cannot be parsed.\n\
  509       --locale=LOCALE   Format results according to LOCALE, this would only\n\
  510                         affect month and weekday names.\n\
  511       --from-locale=LOCALE\n\
  512                         Interpret dates on stdin or the command line as\n\
  513                         coming from the locale LOCALE, this would only\n\
  514                         affect month and weekday names as input formats\n\
  515                         have to be specified explicitly.\n\
  516       --from-zone=ZONE  Interpret dates on stdin or the command line as\n\
  517                         coming from the time zone ZONE.\n\
  518   -z, --zone=ZONE       Convert dates printed on stdout to time zone ZONE,\n\
  519                         default: UTC.\n\
  520 ");
  521         break;
  522 
  523     }
  524 
  525 #if defined yuck_post_help
  526     yuck_post_help(src);
  527 #endif  /* yuck_post_help */
  528 
  529 #if defined PACKAGE_BUGREPORT
  530     puts("\n\
  531 Report bugs to " PACKAGE_BUGREPORT);
  532 #endif  /* PACKAGE_BUGREPORT */
  533     return;
  534 }
  535 
  536 static void yuck_auto_version(const yuck_t src[static 1U])
  537 {
  538     switch (src->cmd) {
  539     default:
  540 #if 0
  541 
  542 #elif defined package_string
  543         puts(package_string);
  544 #elif defined package_version
  545         printf("dateconv %s\n", package_version);
  546 #elif defined PACKAGE_STRING
  547         puts(PACKAGE_STRING);
  548 #elif defined PACKAGE_VERSION
  549         puts("dateconv " PACKAGE_VERSION);
  550 #elif defined VERSION
  551         puts("dateconv " VERSION);
  552 #else  /* !PACKAGE_VERSION, !VERSION */
  553         puts("dateconv unknown version");
  554 #endif  /* PACKAGE_VERSION */
  555         break;
  556     }
  557 
  558 #if defined yuck_post_version
  559     yuck_post_version(src);
  560 #endif  /* yuck_post_version */
  561     return;
  562 }
  563 
  564 #if defined __INTEL_COMPILER
  565 # pragma warning (pop)
  566 #elif defined __GNUC__
  567 # if __GNUC__ > 4 || __GNUC__ == 4 &&  __GNUC_MINOR__ >= 6
  568 #  pragma GCC diagnostic pop
  569 # endif  /* GCC version */
  570 #endif  /* __INTEL_COMPILER */