"Fossies" - the Fresh Open Source Software Archive

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