"Fossies" - the Fresh Open Source Software Archive

Member "dateutils-0.4.6/src/dadd.yucc" (19 Mar 2019, 13938 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 "dadd.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     DATEADD_CMD_NONE = 0U,
   12 
   13     /* actual commands */
   14     
   15     /* convenience identifiers */
   16     YUCK_NOCMD = DATEADD_CMD_NONE,
   17     YUCK_NCMDS = DATEADD_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, "dateadd: 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 DATEADD_CMD_NONE_longopt; back_from_DATEADD_CMD_NONE_longopt:;
  215             break;
  216         }
  217         goto back_from_longopt;
  218 
  219 
  220         DATEADD_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, "dateadd: unrecognized option `--%s'\n", op);
  263                 goto failure;
  264             xtra_chk:
  265                 if (arg != NULL) {
  266                     fprintf(stderr, "dateadd: option `--%s' doesn't allow an argument\n", op);
  267                     goto failure;
  268                 }
  269             }
  270             if (i >= argc) {
  271                 fprintf(stderr, "dateadd: option `--%s' requires an argument\n", op);
  272                 goto failure;
  273             }
  274             goto back_from_DATEADD_CMD_NONE_longopt;
  275         }
  276         
  277     }
  278 
  279     shortopt:
  280     {
  281         char *arg = op + 1U;
  282 
  283         switch (tgt->cmd) {
  284         default:
  285             goto DATEADD_CMD_NONE_shortopt; back_from_DATEADD_CMD_NONE_shortopt:;
  286             break;
  287         }
  288         goto back_from_shortopt;
  289 
  290 
  291         DATEADD_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, "dateadd: 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, "dateadd: option `--%s' requires an argument\n", op);
  373                 goto failure;
  374             }
  375             goto back_from_DATEADD_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 DATEADD_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: dateadd [OPTION]... [DATE/TIME] [DURATION]\n\
  444 \n\
  445 Add DURATION to DATE/TIME and print the result.\n\
  446 If DATE/TIME is omitted but DURATION is given, read a list of DATE/TIMEs from\n\
  447 stdin.\n\
  448 If DURATION is omitted but DATE/TIME is given, read a list of DURATIONs from\n\
  449 stdin.\n\
  450 \n\
  451 Durations are specified as nY, nMO, nW, or nD for years, months, weeks, or days\n\
  452 respectively, or nH, nM, nS for hours, minutes, and seconds, where N is a\n\
  453 (possibly negative) number.  The unit symbols can be written lower-case as well\n\
  454 (y, mo, w, d, h, m, s) and the unit symbol `d' can be omitted.\n\
  455 \n\
  456 Note that duration addition is not commutative!\n\
  457   2000-03-30 +1mo +1d -> 2000-05-01\n\
  458   2000-03-30 +1d +1mo -> 2000-04-30\n\
  459 ");
  460         break;
  461 
  462     }
  463 
  464 #if defined yuck_post_usage
  465     yuck_post_usage(src);
  466 #endif  /* yuck_post_usage */
  467     return;
  468 }
  469 
  470 static void yuck_auto_help(const yuck_t src[static 1U])
  471 {
  472     yuck_auto_usage(src);
  473 
  474 
  475     /* leave a not about common options */
  476     if (src->cmd == YUCK_NOCMD) {
  477         ;
  478     }
  479 
  480     switch (src->cmd) {
  481     default:
  482     case DATEADD_CMD_NONE:
  483         puts("\
  484   -h, --help            Print help and exit\n\
  485   -V, --version         Print version and exit\n\
  486   -q, --quiet           Suppress message about date/time and duration\n\
  487                         parser errors and fix-ups.\n\
  488                         The default is to print a warning or the\n\
  489                         fixed up value and return error code 2.\n\
  490   -f, --format=STRING   Output format.  This can either be a specifier\n\
  491                         string (similar to strftime()'s FMT) or the name\n\
  492                         of a calendar.\n\
  493   -i, --input-format=STRING...\n\
  494                         Input format, can be used multiple times.\n\
  495                         Each date/time will be passed to the input\n\
  496                         format parsers in the order they are given, if a\n\
  497                         date/time can be read successfully with a given\n\
  498                         input format specifier string, that value will\n\
  499                         be used.\n\
  500   -b, --base=DT         For underspecified input use DT as a fallback to\n\
  501                         fill in missing fields.  Also used for ambiguous\n\
  502                         format specifiers to position their range on the\n\
  503                         absolute time line.\n\
  504                         Must be a date/time in ISO8601 format.\n\
  505                         If omitted defaults to the current date/time.\n\
  506   -e, --backslash-escapes\n\
  507                         Enable interpretation of backslash escapes in the\n\
  508                         output and input format specifier strings.\n\
  509   -S, --sed-mode        Copy parts from the input before and after a\n\
  510                         matching date/time.\n\
  511                         Note that all occurrences of date/times within a\n\
  512                         line will be processed.\n\
  513   -E, --empty-mode      Empty lines that cannot be parsed.\n\
  514       --locale=LOCALE   Format results according to LOCALE, this would only\n\
  515                         affect month and weekday names.\n\
  516       --from-locale=LOCALE\n\
  517                         Interpret dates on stdin or the command line as\n\
  518                         coming from the locale LOCALE, this would only\n\
  519                         affect month and weekday names as input formats\n\
  520                         have to be specified explicitly.\n\
  521       --from-zone=ZONE  Interpret dates on stdin or the command line as\n\
  522                         coming from the time zone ZONE.\n\
  523   -z, --zone=ZONE       Convert dates printed on stdout to time zone ZONE,\n\
  524                         default: UTC.\n\
  525 ");
  526         break;
  527 
  528     }
  529 
  530 #if defined yuck_post_help
  531     yuck_post_help(src);
  532 #endif  /* yuck_post_help */
  533 
  534 #if defined PACKAGE_BUGREPORT
  535     puts("\n\
  536 Report bugs to " PACKAGE_BUGREPORT);
  537 #endif  /* PACKAGE_BUGREPORT */
  538     return;
  539 }
  540 
  541 static void yuck_auto_version(const yuck_t src[static 1U])
  542 {
  543     switch (src->cmd) {
  544     default:
  545 #if 0
  546 
  547 #elif defined package_string
  548         puts(package_string);
  549 #elif defined package_version
  550         printf("dateadd %s\n", package_version);
  551 #elif defined PACKAGE_STRING
  552         puts(PACKAGE_STRING);
  553 #elif defined PACKAGE_VERSION
  554         puts("dateadd " PACKAGE_VERSION);
  555 #elif defined VERSION
  556         puts("dateadd " VERSION);
  557 #else  /* !PACKAGE_VERSION, !VERSION */
  558         puts("dateadd unknown version");
  559 #endif  /* PACKAGE_VERSION */
  560         break;
  561     }
  562 
  563 #if defined yuck_post_version
  564     yuck_post_version(src);
  565 #endif  /* yuck_post_version */
  566     return;
  567 }
  568 
  569 #if defined __INTEL_COMPILER
  570 # pragma warning (pop)
  571 #elif defined __GNUC__
  572 # if __GNUC__ > 4 || __GNUC__ == 4 &&  __GNUC_MINOR__ >= 6
  573 #  pragma GCC diagnostic pop
  574 # endif  /* GCC version */
  575 #endif  /* __INTEL_COMPILER */