📄 datemath.c
字号:
/* * $Id: //pentools/main/datemath/datemath.c#5 $ * * written by: Stephen J. Friedl * Software Consultant * Tustin, California USA * steve@unixwiz.net * * This tool's home page is * * http://www.unixwiz.net/tools/datemath.html * * This is the main driver for the datemath program. The very * large bulk of the code is in the lex scanner specifiction * file "lex.l" and in the yacc grammer file "gram.y", so this * file is little more than a wrapper. It will, however, serve * as an anchor for the documentation. * * This program performs various operations on mm/dd/yy, mm/yy, * and YYMM dates, and it sends the results to the standard * output. This function will most often be used in shell * scripts surrounded by `` characters: * * END_DATE=`datemath $YYMM + 3` # add three months * * Datemath is fairly smart about converting from one kind * of date to another when it makes sense, and most operations * can apply to any kind of date. mm/yy and yymm dates are * both converted to yymm internally, and are used synonymously. * * The most common usage will be: * * datemath date + num * datemath date - num * datemath date - date * * The first two add or subtract the specified number of days/months * for mm/dd/yy or mm/yy dates, and output the same kind of date. * The third form outputs the number of days/months between the * two specified dates in integer form. * * This program also supports functions that operate on dates, and * they are: * * fday(date) return mm/dd/yy of first day of month * lday(date) return mm/dd/yy of last day of month * ndays(date) return # of days in this month * year(date) return year (19YY format) * month(date) return month of this date * day(date) return day of this date (mm/dd/yy only) * yymm(date) convert mm/dd/yy to mm/yy * * All expressions have a type: mm/dd/yy, yymm, and integer, and they * can be nested arbitrarily and grouped with parenthesis. For example * we want to run program "foo" with two mm/dd/yy dates, but all we * have is a mm/yy date in $YYMM. We would do this with: * * foo `datemath fday(yymm)` `datemath lday(yymm+2)` * * If we needed to see how many days is in this span, we would do: * * datemath '( lday(yymm+2) - fday(yymm) ) + 1' * * The string can be separate arguments or a single arg, but * the user must take care to quote characters special to the * shell. * * Dates themselves can be in any of the following formats: * * mm/yy * yymm * mmddyy * mmddyyyy * mm/dd/yy * mm/dd/yyyy * * and full range checking is done on them to make sure the * dates given are plausible. * * Currently, "syntax error" is the only indication of most failures, * although some semantic errors (such as the wrong date type) will * be identified. Exit value is 0 if all is OK and nonzero on error. * * COMMAND LINE * * Other than the expression parsed, a few command-line params * are allowed with the traditional "dash" notation. * * -L This runs only the lexer, not the parser: it's used * for testing the flex code by reading and printing * one token at a time. It does no date math. * * -V print the version of this program. * * -9 yy two-digit years from yy..99 are 1900, and all * else is 2000. Default = 40 * * -2 output two-digit years * * -4 output four-digit years (default) * * -C output dates in Y/M/D format * * BUGS * > limited error checking of plausible dates * > very poor syntax error recovery * > should be a way to output yymm dates as mm/yy * > no way to do collated date *input* */#include <stdio.h>#include <stdlib.h>#include <unistd.h>#include <string.h>#include <malloc.h>#include "defs.h"static const char Version[] = "datemath 2.0.10 - 2003-06-20 - steve@unixwiz.net";const char *ProgName = NULL;int year_digits = 4, collate_order = FALSE;static void usage(const char *argv0) __attribute__((noreturn));int main(int argc, char **argv){int c, i, len;char *exprbuf;int lextest = FALSE; ProgName = argv[0]; setbuf(stdout, (char *)0); while ( (c = getopt(argc, argv, "VL9:24C")) != EOF ) { switch (c) { default: usage(argv[0]); case '4': year_digits = 4; break; case '2': year_digits = 2; break; case 'C': collate_order = TRUE; break; case '9': century19_year = atoi(optarg); break; case 'L': lextest = TRUE; break; case 'V': /* version */ fprintf(stderr, "%s\n", Version); exit(EXIT_SUCCESS); } } /*---------------------------------------------------------------- * BUILD EXPRESSION STRING * * Figure out how much space we need for the whole string, * allocate it, then fill the buffer with it. */ len = 0; for (i = optind; i < argc; i++ ) { len += strlen(argv[i]) + 1; } if ( len == 0 ) { fprintf(stderr, "ERROR: missing datemath expression\n"); usage(argv[0]); } len += 2; /* good measure */ if ( (exprbuf = malloc(len)) == 0 ) die("ERROR: cannot get %d bytes of memory", len); for ( ; optind < argc; ) { strcat(exprbuf, argv[optind++]); strcat(exprbuf, " "); } init_scan(exprbuf); if ( lextest ) { int tok; while ( (tok = yylex()) != 0 ) printf("got token %d [%s]\n", tok, yytext); exit(EXIT_SUCCESS); } else { exit( yyparse() == 0 ? EXIT_SUCCESS : EXIT_FAILURE); }}void yyerror(const char *msg){ die("syntax error in command line: %s", msg);}static void usage(const char *argv0){const char *const *p;static const char * const text[] = {""," -V Report version information to stderr and exit"," -4 Output dates with four-digit years (default)"," -2 Output dates with two-digit years"," -9 ## Two-digit years starting with ## are 19xx, else 20xx"," -C Collate mode: output dates in year/month/day format","","Expression keywords:","""today tomorrow yesterday -- the obvious dates","fday(date) - the first day of the month","lday(date) - the last day of the month","ndays(date) - number of days in the month",0}; fprintf(stderr, "%s\n\n", Version); fprintf(stderr, "usage: %s [options] date-expression\n", argv0); for (p = text; *p; p++) { fprintf(stderr, "%s\n", *p); } exit(EXIT_FAILURE);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -