"Fossies" - the Fresh Open Source Software Archive

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