home *** CD-ROM | disk | FTP | other *** search
/ Frozen Fish 2: PC / frozenfish_august_1995.bin / bbs / d09xx / d0975.lha / PCal / pcallang.h < prev    next >
C/C++ Source or Header  |  1992-02-19  |  35KB  |  992 lines

  1. /*
  2.  * pcallang.h - language-dependent strings (month and day names, option file 
  3.  * keywords, preprocessor tokens, prepositions, etc.):
  4.  *
  5.  * Revision history:
  6.  *
  7.  *    4.3    AWR    12/03/91    support -s flag (override default
  8.  *                    shading of dates and fill boxes)
  9.  *
  10.  *            10/17/91    support -Z flag to generate debugging
  11.  *                    information
  12.  *
  13.  *    4.2    AWR    10/08/91    support -[kK] flags (select position
  14.  *                    of small calendars
  15.  *
  16.  *            10/03/91    support "note/<n>" (new message only)
  17.  *
  18.  *                    support -S flag (no small calendars)
  19.  *
  20.  *            10/02/91    support -N flag (user-specified notes
  21.  *                    heading)
  22.  *
  23.  *                    change message for -n to reflect
  24.  *                    optional notes font size
  25.  *
  26.  *            09/30/91    support "if" (synonym for "ifdef") and
  27.  *                    "elif" in date file
  28.  *
  29.  *            09/19/91    support -c flag (generate input file
  30.  *                    suitable for use with Un*x "calendar"
  31.  *                    utility and Pcal)
  32.  *
  33.  *                    support "elif" in "if{n}def" block
  34.  *
  35.  *    4.11    AWR    08/20/91    support "nearest" keyword as per
  36.  *                    Andy Fyfe
  37.  *
  38.  *                    changed MIN_ORD_LEN from 3 to 4 (to
  39.  *                    distinguish "even" from "every")
  40.  *
  41.  *                    add ABBR_DAY_LEN and ABBR_MONTH_LEN
  42.  *                    (cf. writefil.c) for length of
  43.  *                    abbreviated day/month names
  44.  *
  45.  *                    document %u and %w formats and number
  46.  *                    following %[+-] (cf. writefil.c)
  47.  *
  48.  *                    add DEF_WHOLE_YEAR (predefined when
  49.  *                    -w flag specified - cf. pcal.c)
  50.  *
  51.  *    4.1    AWR    08/16/91    support -G flag (outlined gray)
  52.  *
  53.  *    4.02    AWR    07/02/91    support -v flag (version number);
  54.  *                    add ordinal_suffix(); add format
  55.  *                    specifiers to help message
  56.  *
  57.  *    4.0    AWR    03/01/91    expand parameter message to explain
  58.  *                    parameter meaning when -w specified
  59.  *
  60.  *        AWR    02/19/91    revise ordinal definitions for
  61.  *                    support of negative ordinals
  62.  *
  63.  *        AWR    02/06/91    add text describing expression syntax
  64.  *
  65.  *        AWR    02/04/91    support "odd" and "even" ordinals
  66.  *
  67.  *        AWR    01/28/91    support -B (blank fill squares) flag
  68.  *                    and -O (outline "gray" dates) flag
  69.  *
  70.  *        AWR    01/16/91    added moon file support (tokens, help
  71.  *                    file text, error messages); define
  72.  *                    note block heading here
  73.  *
  74.  *        AWR    01/07/91    added support for -w (whole year) flag
  75.  *
  76.  *    3.0    AWR    12/10/90    added support for "workday", "weekday",
  77.  *                    "holiday", et. al.
  78.  *
  79.  *        AWR    11/15/90    extracted from pcal.c; revised
  80.  *                    to contain all language-dependent
  81.  *                    strings
  82.  */
  83.  
  84. #define ALL    "all"        /* command-line or date file keyword */
  85.  
  86. #ifdef MAIN_MODULE
  87.  
  88. char *months[12] = {
  89.     "January", "February", "March", "April", "May", "June",
  90.     "July", "August", "September", "October", "November", "December"
  91.     };
  92.  
  93. /* Must be a 2-D array so address within may be used as an initializer;
  94.  * wildcard names must be in same order as symbolic names in pcaldefs.h
  95.  */
  96. char days[14][12] = {
  97.         "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday",
  98.         "Saturday",         /* weekday names */
  99.     "day", "weekday", "workday", "holiday", "nonweekday", "nonworkday",
  100.     "nonholiday"        /* wildcards */
  101.     };
  102.  
  103. /* preprocessor tokens: token name, token code, dispatch routine; note that
  104.  * substring "if" must follow "ifdef" and "ifndef" for proper matching
  105.  */
  106.  
  107. KWD_F pp_info[] = {
  108.     "define",    PP_DEFINE,    do_define,
  109.     "elif",        PP_ELIF,    do_ifdef,
  110.     "else",        PP_ELSE,    NULL,
  111.     "endif",    PP_ENDIF,    NULL,
  112.     "ifdef",    PP_IFDEF,    do_ifdef,
  113.     "ifndef",    PP_IFNDEF,    do_ifndef,
  114.     "if",        PP_IFDEF,    do_ifdef,    /* "ifdef" synonym */
  115.     "include",    PP_INCLUDE,    NULL,        /* do_include */
  116.     "undef",    PP_UNDEF,    do_undef,
  117.     NULL,        PP_OTHER,    NULL };        /* must be last */
  118.  
  119. /* ordinal numbers - e.g. "first Monday in September": ordinal name,
  120.  * ordinal code, ordinal value; note that "all" is parsed as a keyword
  121.  * and (depending on context) may be subsequently treated as an ordinal
  122.  */
  123.  
  124. KWD_O ordinals[] = {
  125.     "first",    ORD_POSNUM,     1,
  126.     "second",    ORD_POSNUM,     2,
  127.     "third",    ORD_POSNUM,     3,
  128.     "fourth",    ORD_POSNUM,     4,
  129.     "fifth",    ORD_POSNUM,     5,
  130.     "last",        ORD_NEGNUM,    -1,
  131.     "odd",        ORD_ODD,     0,
  132.     "even",        ORD_EVEN,     0,
  133.     NULL,        ORD_OTHER,     0 };        /* must be last */
  134.  
  135. /* allowable suffixes for ordinal numbers - these must be in order 0, 1, 2...
  136.  * according to the rules of the target language; cf. ordinal_suffix() below
  137.  */
  138.  
  139. char *ord_suffix[] = { "th", "st", "nd", "rd", NULL };
  140.  
  141. /* prepositions - e.g., "Friday after fourth Thursday in November" */
  142.  
  143. KWD preps[] = {
  144.     "before",    PR_BEFORE,
  145.     "preceding",    PR_BEFORE,
  146.     "on_or_before",    PR_ON_BEFORE,
  147.     "oob",        PR_ON_BEFORE,
  148.     "after",    PR_AFTER,
  149.     "following",    PR_AFTER,
  150.     "on_or_after",    PR_ON_AFTER,
  151.     "ooa",        PR_ON_AFTER,
  152.     "nearest",    PR_NEAREST,
  153.     NULL,        PR_OTHER };    /* must be last */
  154.  
  155. /* other keywords */
  156.  
  157. KWD keywds[] = {
  158.     ALL,         DT_ALL,
  159.     "each",        DT_ALL,
  160.     "every",    DT_ALL,
  161.     "note",        DT_NOTE,
  162.     "opt",        DT_OPT,
  163.     "year",        DT_YEAR,
  164.     NULL,        DT_OTHER };    /* must be last */
  165.  
  166. /* moon phases (for moon file) */
  167.  
  168. KWD phases[] = {
  169.     "new_moon",    MOON_NM,    /* new moon */
  170.     "nm",        MOON_NM,    
  171.     "first_quarter",MOON_1Q,    /* first quarter */    
  172.     "1Q",        MOON_1Q,    
  173.     "FQ",        MOON_1Q,    
  174.     "full_moon",    MOON_FM,    /* full moon */
  175.     "FM",        MOON_FM,    
  176.     "last_quarter",    MOON_3Q,    /* last (third) quarter */
  177.     "LQ",        MOON_3Q,
  178.     "third_quarter",MOON_3Q,
  179.     "3Q",        MOON_3Q,
  180.     NULL,        MOON_OTHER };    /* must be last */
  181.  
  182. /* default notes box header */
  183.  
  184. char default_notes_hdr[] = "Notes";
  185.  
  186. #else
  187. extern char *months[];
  188. extern char days[14][12];
  189. extern KWD_F pp_info[];
  190. extern KWD preps[];
  191. extern KWD_O ordinals[];
  192. extern char *ord_suffix[];
  193. extern KWD keywds[];
  194. extern KWD phases[];
  195. extern char default_notes_hdr[];
  196. #endif
  197.  
  198. /* minimum size of abbreviations - adjust as appropriate for target language */
  199.  
  200. #define MIN_DAY_LEN    3    /* distinguish "Thursday" from "third" */
  201. #define ABBR_DAY_LEN    3    /* length of abbreviated day names */
  202. #define MIN_MONTH_LEN    3
  203. #define ABBR_MONTH_LEN    3    /* length of abbreviated month names */
  204. #define MIN_PPTOK_LEN    3
  205. #define MIN_PREP_LEN    7    /* distinguish "on_or_before", "on_or_after" */
  206. #define MIN_ORD_LEN    4    /* distinguish "every" from "even" */
  207.  
  208.  
  209. /*
  210.  * Symbolic names for command-line flags.  These may be changed
  211.  * as desired in order to be meaningful in languages other than
  212.  * English.
  213.  */
  214.  
  215. #define F_INITIALIZE    'I'        /* re-initialize program defaults */
  216. #define    F_BLACK_DAY    'b'        /* print day in black */
  217. #define F_GRAY_DAY    'g'        /* print day in gray */
  218.  
  219. #define F_DAY_FONT    'd'        /* select alternate day font */
  220. #define F_NOTES_FONT    'n'        /* select alternate notes font */
  221. #define F_TITLE_FONT    't'        /* select alternate title font */
  222.  
  223. #define F_EMPTY_CAL    'e'        /* print empty calendar */
  224. #define F_DATE_FILE    'f'        /* select alternate date file */
  225. #define F_OUT_FILE    'o'        /* select alternate output file */
  226.  
  227. #define F_LANDSCAPE    'l'        /* landscape mode */
  228. #define F_PORTRAIT    'p'        /* portrait mode */
  229.  
  230. #define F_HELP        'h'        /* generate full help message */
  231. #define F_USAGE        'u'        /* generate parameter usage message */
  232. #define F_VERSION    'v'        /* generate version ID */
  233.  
  234. #define F_MOON_4    'm'        /* print new/half/full moons */
  235. #define F_MOON_ALL    'M'        /* print all moons */
  236.  
  237. #define F_DEFINE    'D'        /* define preprocessor symbol */
  238. #define F_UNDEF        'U'        /* undefine preprocessor symbol */
  239.  
  240. #define F_L_FOOT    'L'        /* define left foot string */
  241. #define F_C_FOOT    'C'        /* define center foot string */
  242. #define F_R_FOOT    'R'        /* define right foot string */
  243.  
  244. #define F_NOTES_HDR    'N'        /* define heading for notes box */
  245.  
  246. #define F_FIRST_DAY    'F'        /* define alternate starting day */
  247.  
  248. #define F_USA_DATES    'A'        /* parse American date format */
  249. #define F_EUR_DATES    'E'        /* parse European date format */
  250.  
  251. #define F_X_TRANS    'X'        /* X-axis transformation */
  252. #define F_Y_TRANS    'Y'        /* Y-axis transformation */
  253. #define F_X_SCALE    'x'        /* X-axis scale factor */
  254. #define F_Y_SCALE    'y'        /* Y-axis scale factor */
  255.  
  256. #define F_JULIAN    'j'        /* print Julian day (day of year) */
  257. #define F_JULIAN_ALL    'J'        /* print Julian day and days left */
  258.  
  259. #define F_WHOLE_YEAR    'w'        /* print whole year per page */
  260.                     /* (cf. W_WYFLAG below) */
  261.  
  262. #define F_BLANK_BOXES    'B'        /* don't fill unused boxes */
  263.  
  264. #define F_SC_NONE    'S'        /* suppress small calendars */
  265. #define F_SC_FIRST    'k'        /* prev/next in first two boxes */
  266. #define F_SC_SPLIT    'K'        /* split between first and last boxes */
  267.  
  268. #define F_OUTLINE_GRAY    'G'        /* outline and fill "gray" dates */
  269. #define F_OUTLINE    'O'        /* draw "gray" dates as outlines */
  270.  
  271. #define F_SHADING    's'        /* define date/fill box shading */
  272.  
  273. #define F_CALENDAR    'c'        /* generate "calendar" utility input */
  274.  
  275. /* special "hidden" flag (and subflags) for debug info generation */
  276.  
  277. #define F_DEBUG        'Z'        /* generate debugging information */
  278.  
  279. #define D_DATES        'D'        /* debug dates as read */
  280. #define D_FILE_PATHS    'F'        /* debug date file paths */
  281. #define D_MOON        'M'        /* debug moon phases */
  282. #define D_TEXT        'T'        /* debug dates/text as written */
  283. #define D_OPT        'O'        /* debug option flags */
  284. #define D_PREPROCESSOR    'P'        /* debug "preprocessor" operation */
  285.  
  286. /*
  287.  * Flag usage information - not strictly language-dependent, but here anyway
  288.  * (N.B.: all flags must be represented by an entry in this table!)
  289.  *
  290.  * Flags may appear in any of three places: in environment variable
  291.  * PCAL_OPTS, on the command line, or in "opt" lines in the date file.
  292.  * The command line is actually parsed twice: once before reading the date
  293.  * file to get the flags needed in processing it (-[bcefgkwADEKSU]), and
  294.  * and again after reading the date file to give the user one last chance
  295.  * to override any of the other flags set earlier.  (Note, however, that
  296.  * the only way to turn off -J|-j [Julian dates], -M|-m [moons], -w [whole
  297.  * year], or -G|-O [outline "gray" dates] once selected is to use -I to
  298.  * reinitialize all program defaults.)
  299.  *
  300.  * The table below supplies the following information about each flag:
  301.  *
  302.  *    - Its name (cf. symbolic definitions above)
  303.  *
  304.  *    - Whether or not it can take an (optional) argument
  305.  *
  306.  *    - Which passes parse it - in order, they are: P_CMD0 ("pre-pass" of
  307.  *      command line to find debugging flags), P_ENV (environment variable),
  308.  *      P_CMD1 (first command line pass), P_OPT ("opt" lines in date file), 
  309.  *      and P_CMD2 (second command line pass)
  310.  *
  311.  */
  312.  
  313. #ifdef MAIN_MODULE
  314.  
  315. FLAG_USAGE flag_tbl[] = {
  316.  
  317. /*    flag name    arg?             passes where parsed    */
  318.  
  319.     F_INITIALIZE,    FALSE,             P_ENV | P_CMD1 | P_OPT | P_CMD2 ,
  320.  
  321.     F_BLACK_DAY,    TRUE,             P_ENV | P_CMD1 | P_OPT          ,
  322.     F_GRAY_DAY,    TRUE,             P_ENV | P_CMD1 | P_OPT          ,
  323.  
  324.     F_DAY_FONT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  325.     F_NOTES_FONT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  326.     F_TITLE_FONT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  327.  
  328.     F_EMPTY_CAL,    FALSE,             P_ENV | P_CMD1                  ,
  329.     F_DATE_FILE,    TRUE,             P_ENV | P_CMD1                  ,
  330.     F_OUT_FILE,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  331.  
  332.     F_LANDSCAPE,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  333.     F_PORTRAIT,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  334.  
  335.     F_HELP,        FALSE,                     P_CMD1                  ,
  336.     F_USAGE,    FALSE,                     P_CMD1                  ,
  337.     F_VERSION,    FALSE,                     P_CMD1                  ,
  338.  
  339.     F_MOON_4,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  340.     F_MOON_ALL,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  341.  
  342.     F_DEFINE,    TRUE,             P_ENV | P_CMD1                  ,
  343.     F_UNDEF,    TRUE,             P_ENV | P_CMD1                  ,
  344.  
  345.     F_L_FOOT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  346.     F_C_FOOT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  347.     F_R_FOOT,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  348.  
  349.     F_NOTES_HDR,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  350.  
  351.     F_FIRST_DAY,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  352.  
  353.     F_USA_DATES,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  354.     F_EUR_DATES,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  355.  
  356.     F_X_TRANS,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  357.     F_Y_TRANS,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  358.     F_X_SCALE,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  359.     F_Y_SCALE,    TRUE,             P_ENV          | P_OPT | P_CMD2 ,
  360.  
  361.     F_JULIAN,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  362.     F_JULIAN_ALL,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  363.  
  364.     F_WHOLE_YEAR,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  365.  
  366.     F_BLANK_BOXES,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  367.  
  368.     F_SC_NONE,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  369.     F_SC_FIRST,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  370.     F_SC_SPLIT,    FALSE,             P_ENV | P_CMD1 | P_OPT          ,
  371.  
  372.     F_OUTLINE_GRAY,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  373.     F_OUTLINE,    FALSE,             P_ENV          | P_OPT | P_CMD2 ,
  374.  
  375.     F_SHADING,    TRUE,            P_ENV          | P_OPT | P_CMD2 ,
  376.  
  377.     F_CALENDAR,    FALSE,             P_ENV | P_CMD1                  ,
  378.  
  379.     F_DEBUG,    TRUE,    P_CMD0 | P_ENV          | P_OPT          ,
  380.  
  381.     '-',        FALSE,             P_ENV | P_CMD1 | P_OPT | P_CMD2 ,
  382.     '\0',        FALSE,             P_ENV | P_CMD1 | P_OPT | P_CMD2        /* must be last */
  383.     };
  384.  
  385. /* subflags for debug info flag F_DEBUG */
  386.  
  387. DEBUG_INFO debug_info[] = {
  388.     D_DATES,    DEBUG_DATES,
  389.     D_FILE_PATHS,    DEBUG_PATHS,
  390.     D_MOON,        DEBUG_MOON,
  391.     D_OPT,        DEBUG_OPTS,
  392.     D_PREPROCESSOR,    DEBUG_PP,
  393.     D_TEXT,        DEBUG_TEXT,
  394.     '\0',        0        /* must be last */
  395.     };
  396.  
  397. #else
  398. extern FLAG_USAGE flag_tbl[];
  399. extern DEBUG_INFO debug_info[];
  400. #endif
  401.  
  402. /*
  403.  * Words used in usage() message - translate as necessary
  404.  */
  405.  
  406. #define W_DEFAULT    "default"        /* translate as required */
  407. #define W_USAGE        "Usage"
  408.  
  409. #define W_FONT        "<FONT>"        /* names of metavariables */
  410. #define W_FONT_SIZE    "<FONT>{/<n>}"
  411. #define W_DAY        "<DAY>"
  412. #define W_STRING    "<STRING>"
  413. #define W_FILE        "<FILE>"
  414. #define W_SYMBOL    "<SYMBOL>"
  415. #define W_VALUE        "<VALUE>"
  416. #define W_SHADING    "{<d>}{/<f>}"
  417.  
  418. #define W_MM        "MM"            /* abbrev. for month, year */
  419. #define W_YY        "YY"
  420.  
  421. #define W_WYFLAG    "-w"            /* must conform to F_WHOLE_YEAR */
  422.  
  423. #define W_BLACK        "black"            /* cf. color_msg() */
  424. #define W_GRAY        "gray"
  425.  
  426.  
  427. /* special flag_msg[] entries for end of option group, etc. */
  428.  
  429. #define END_GROUP    '\n', NULL, NULL, NULL        /* end of option group */
  430. #define END_LIST    '\0', NULL, NULL, NULL        /* end of list */
  431. #define GROUP_DEFAULT    ' ', NULL, " "            /* group default */
  432.  
  433. /*
  434.  * Message strings to be printed by usage() - translate as necessary
  435.  */
  436. #ifdef MAIN_MODULE
  437.  
  438. FLAG_MSG flag_msg[] = {
  439.  
  440. /*    flag name    metasyntax    description                        default */
  441.  
  442.     F_INITIALIZE,    NULL,        "initialize all parameters to program defaults",    NULL,
  443.     END_GROUP,
  444.  
  445.     F_BLACK_DAY,    W_DAY,        "print weekday in black",                NULL,
  446.     F_GRAY_DAY,    W_DAY,        "print weekday in gray (see below)",            NULL,
  447.     END_GROUP,
  448.  
  449.     F_OUTLINE_GRAY,    NULL,        "print \"gray\" dates as filled outlines",        NULL,
  450.     F_OUTLINE,    NULL,        "print \"gray\" dates as unfilled outlines",        NULL,
  451. #if NUM_STYLE == GRAY_NUMS
  452.     GROUP_DEFAULT,                                        "gray characters",
  453. #else
  454. #if NUM_STYLE == OUTLINE_NUMS
  455.     GROUP_DEFAULT,                                        "unfilled outlines",
  456. #else
  457.     GROUP_DEFAULT,                                        "filled outlines",
  458. #endif
  459. #endif
  460.  
  461.     END_GROUP,
  462.  
  463.     F_SHADING,    W_SHADING,    "specify date/fill box shading",            SHADING,
  464.     END_GROUP,
  465.  
  466.     F_DAY_FONT,    W_FONT,        "specify alternate day name font",            DAYFONT,
  467.     F_NOTES_FONT,    W_FONT_SIZE,    "specify alternate notes font and optional size <n>",    NULL,
  468.     ' ',        NULL,        " ",                            NOTESFONT,
  469.     F_TITLE_FONT,    W_FONT,        "specify alternate title font",                TITLEFONT,
  470.     END_GROUP,
  471.  
  472.     F_EMPTY_CAL,    NULL,        "generate empty calendar (ignore date file)",        NULL,
  473.     END_GROUP,
  474.  
  475.     F_DATE_FILE,    W_FILE,        "specify alternate date file",                DATEFILE,
  476.     END_GROUP,
  477.  
  478. #ifdef DEFAULT_OUTFILE
  479.     F_OUT_FILE,    W_FILE,        "specify alternate output file",            DEFAULT_OUTFILE,
  480. #else
  481.     F_OUT_FILE,    W_FILE,        "specify alternate output file",            "stdout",
  482. #endif
  483.     END_GROUP,
  484.  
  485.     F_LANDSCAPE,    NULL,        "generate landscape-style calendar",            NULL,
  486.     F_PORTRAIT,    NULL,        "generate portrait-style calendar",            NULL,
  487. #if ROTATE == LANDSCAPE
  488.     GROUP_DEFAULT,                                        "landscape",
  489. #else    
  490.     GROUP_DEFAULT,                                        "portrait",
  491. #endif
  492.     END_GROUP,
  493.  
  494.     F_HELP,        NULL,        "print this help message",                NULL,
  495.     F_USAGE,    NULL,        "print parameter usage message",            NULL,
  496.     F_VERSION,    NULL,        "print version information",                NULL,
  497.     END_GROUP,
  498.  
  499.     F_MOON_4,    NULL,        "draw a \"moon\" icon at full/new/half moons",        NULL,
  500.     F_MOON_ALL,    NULL,        "draw a \"moon\" icon every day",            NULL,
  501. #if DRAW_MOONS == NO_MOONS
  502.     GROUP_DEFAULT,                                        "no moons",
  503. #else
  504. #if DRAW_MOONS == SOME_MOONS
  505.     GROUP_DEFAULT,                                        "full/new/half moons",
  506. #else
  507.     GROUP_DEFAULT,                                        "every day",
  508. #endif
  509. #endif
  510.     END_GROUP,
  511.  
  512.     F_DEFINE,    W_SYMBOL,    "define preprocessor symbol",                NULL,
  513.     F_UNDEF,    W_SYMBOL,    "undefine preprocessor symbol",                NULL,
  514.     END_GROUP,
  515.  
  516.     F_L_FOOT,    W_STRING,    "specify left foot string",                LFOOT,
  517.     F_C_FOOT,    W_STRING,    "specify center foot string",                CFOOT,
  518.     F_R_FOOT,    W_STRING,    "specify right foot string",                RFOOT,
  519.     END_GROUP,
  520.  
  521.     F_NOTES_HDR,    W_STRING,    "specify header for notes box",                default_notes_hdr,
  522.     END_GROUP,
  523.  
  524.     F_FIRST_DAY,    W_DAY,        "specify starting day of week",                days[FIRST_DAY],
  525.     END_GROUP,
  526.  
  527.     F_USA_DATES,    NULL,        "parse American dates (\"mm/dd{/yy}\" and \"month dd\")", NULL,
  528.     F_EUR_DATES,    NULL,        "parse European dates (\"dd/mm{/yy}\" and \"dd month\")", NULL,
  529. #if DATE_STYLE == USA_DATES
  530.     GROUP_DEFAULT,                                        "American",
  531. #else
  532.     GROUP_DEFAULT,                                        "European",
  533. #endif
  534.     END_GROUP,
  535.  
  536.     F_X_TRANS,    W_VALUE,    "specify x-axis translation",                XTVAL,
  537.     F_Y_TRANS,    W_VALUE,    "specify y-axis translation",                YTVAL,
  538.     F_X_SCALE,    W_VALUE,    "specify x-axis scale factor",                XSVAL,
  539.     F_Y_SCALE,    W_VALUE,    "specify y-axis scale factor",                YSVAL,
  540.     END_GROUP,
  541.  
  542.     F_JULIAN,    NULL,        "print Julian day (day of year)",            NULL,
  543.     F_JULIAN_ALL,    NULL,        "print Julian day and days left in year",        NULL,
  544. #if JULIAN_DATES == NO_JULIANS
  545.     GROUP_DEFAULT,                                        "neither",
  546. #else
  547. #if JULIAN_DATES == SOME_JULIANS
  548.     GROUP_DEFAULT,                                        "Julian day",
  549. #else
  550.     GROUP_DEFAULT,                                        "both",
  551. #endif
  552. #endif
  553.     END_GROUP,
  554.  
  555.     F_WHOLE_YEAR,    NULL,        "print whole year (12 consecutive months) per page",    NULL,
  556.     END_GROUP,
  557.  
  558.     F_BLANK_BOXES,    NULL,        "leave unused boxes blank",                NULL,
  559.     END_GROUP,
  560.  
  561.     F_SC_NONE,    NULL,        "suppress generation of small calendars",        NULL,
  562.     F_SC_FIRST,    NULL,        "print small calendars in first two boxes",        NULL,
  563.     F_SC_SPLIT,    NULL,        "print previous month in first box, next in last",    NULL,
  564. #if SMALL_CAL_POS == SC_LAST
  565.     GROUP_DEFAULT,                                        "last two boxes",
  566. #else
  567. #if SMALL_CAL_POS == SC_FIRST
  568.     GROUP_DEFAULT,                                        "first two boxes",
  569. #else
  570. #if SMALL_CAL_POS == SC_SPLIT
  571.     GROUP_DEFAULT,                                        "first/last boxes",
  572. #else
  573.     GROUP_DEFAULT,                                        "suppress small calendars",
  574. #endif
  575. #endif
  576. #endif
  577.     END_GROUP,
  578.  
  579.     F_CALENDAR,    NULL,        "generate input for Un*x calendar(1) utility",        NULL,
  580.  
  581.     END_GROUP,            /* must precede END_LIST */
  582.  
  583.     END_LIST            /* must be last */
  584. };
  585.  
  586. #else
  587. extern FLAG_MSG flag_msg[];
  588. #endif
  589.  
  590. /* Numeric parameter descriptions and text */
  591.  
  592. #ifdef MAIN_MODULE
  593.  
  594. #if __STDC__
  595. PARAM_MSG param_msg[] = {
  596.     W_YY,            "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)",
  597.     W_MM " " W_YY,        "generate calendar for month " W_MM " (Jan = 1), year " W_YY,
  598.     W_MM " " W_YY " N",    "generate calendars for N months, starting at " W_MM "/" W_YY,
  599.     "(" W_DEFAULT ")",    "generate calendar for current month and/or year",
  600.     "",            "",
  601.     "if " W_WYFLAG " specified:",    "",
  602.     "",            "",
  603.     W_YY,            "generate calendar for year " W_YY " (19" W_YY " if " W_YY " < 100)",
  604.     W_MM " " W_YY,        "generate calendars for 12 months, starting at " W_MM "/" W_YY,
  605.     W_MM " " W_YY " N",    "generate calendars for N months, starting at " W_MM "/" W_YY,
  606.     "",            "  (N rounded up to next multiple of 12)",
  607.     "(" W_DEFAULT ")",    "generate calendar for current year",
  608.     NULL,        NULL        /* must be last */
  609. };
  610. #else
  611. PARAM_MSG param_msg[] = {
  612.     "YY",        "generate calendar for year YY (19YY if YY < 100)",
  613.     "MM YY",    "generate calendar for month MM (Jan = 1), year YY",
  614.     "MM YY N",    "generate calendars for N months, starting at MM/YY",
  615.     "(default)",    "generate calendar for current month and year",
  616.     "",        "",
  617.     "if -w specified:",    "",
  618.     "",        "",
  619.     "YY",        "generate calendar for year YY (19YY if YY < 100)",
  620.     "MM YY",    "generate calendar for 12 months, starting at MM/YY",
  621.     "MM YY N",    "generate calendars for N months, starting at MM/YY",
  622.     "",        "  (N rounded up to next multiple of 12)",
  623.     "(default)",    "generate calendar for current year",
  624.     NULL,        NULL        /* must be last */
  625. };
  626. #endif
  627.  
  628. #else
  629. extern PARAM_MSG param_msg[];
  630. #endif
  631.  
  632. #define PARAM_MSGS    3    /* number of above to print in command-line syntax message */
  633.  
  634. /* Date file syntax message - lines are copied intact */
  635.  
  636. #ifdef MAIN_MODULE
  637.  
  638. char *date_msg[] = {
  639.     "",
  640.     "Date file syntax:",
  641.     "",
  642.     "The following rules describe the syntax of date file entries:",
  643.     "",
  644.     "  year <year>",
  645.     "",
  646.     "  opt <options>",
  647.     "",
  648.     "  note{/<number>} <month_spec> <text>",
  649.     "  note{/<number>} <month> <text>",
  650.     "",
  651.     "  if -A flag (American date formats) specified:",
  652.     "    <month_name> <day>{*} {<text>}",
  653.     "    <month><sep><day>{<sep><year>}{*} {<text>}",
  654.     "",
  655.     "  if -E flag (European date formats) specified:",
  656.     "    <day> <month_name>{*} {<text>}",
  657.     "    <day><sep><month>{<sep><year>}{*} {<text>}",
  658.     "",
  659.     "  <ordinal> <day_name> in <month_spec>{*} {<text>}",
  660.     "  <day_name> <prep> <date_spec>",
  661.     "",
  662.     "where",
  663.     "",
  664.     "  {x}          means x is optional",
  665.     "",
  666.     "  <date_spec> := any of the above date specs (not year, note, or opt)",
  667.     "  <month_name> := first 3+ characters of name of month, or \"all\"",
  668.     "  <month_spec> := <month_name>, or \"year\"",
  669.     "  <day_name> := first 3+ characters of name of weekday, \"day\",",
  670.     "\t\t\"weekday\", \"workday\", \"holiday\", \"nonweekday\",",
  671.     "\t\t\"nonworkday\", \"nonholiday\", \"new_moon\",",
  672.     "\t\t\"first_quarter\", \"full_moon\", or \"last_quarter\"",
  673.     "  <ordinal> := ordinal number (\"1st\", \"2nd\", etc.), \"first\" .. \"fifth\",",
  674.     "\t\t\"last\", \"even\", \"odd\", or \"all\"",
  675.     "  <prep> := \"before\", \"preceding\", \"after\", \"following\", \"nearest\",",
  676.     "\t\t\"on_or_before\", or \"on_or_after\"",
  677.     "  <sep> := one or more non-numeric, non-space, non-'*' characters",
  678.     "  <month>, <day>, <year> are the numeric forms",
  679.     "",
  680.     "  <options> := any command-line option except -[cefhuvDU]",
  681.     "",
  682.     "Comments start with '#' and run through end-of-line.",
  683.     "",
  684.     "Holidays may be flagged by specifying '*' as the last character of",
  685.     "the date field(s), e.g. \"10/12* Columbus Day\", \"July 4* Independence",
  686.     "Day\", etc.  Any dates flagged as holidays will be printed in gray, and",
  687.     "any associated text will appear adjacent to the date.",
  688.     "",
  689.     "Note that the numeric date formats (mm/dd{/yy}, dd.mm{.yy}) support",
  690.     "an optional year, which will become the subsequent default year.  The",
  691.     "alphabetic date formats (month dd, dd month) do not support a year",
  692.     "field; the \"year yy\" command is provided to reset the default year.",
  693.     "",
  694.     "\"Floating\" days may be specified in the date file as \"first Mon in ",
  695.     "Sep\", \"last Mon in May\", \"4th Thu in Nov\", etc.; any word may be",
  696.     "used in place of \"in\".  \"Relative floating\" days (e.g. \"Fri after 4th ",
  697.     "Thu in Nov\") are also accepted; they may span month/year bounds.",
  698.     "Pcal also accepts date specs such as \"all Friday{s} in October\", \"last",
  699.     "Thursday in all\", etc., and produces the expected results; \"each\" and",
  700.     "\"every\" are accepted as synonyms for \"all\".  Negative ordinals are",
  701.     "allowed; \"-2nd\" means \"next to last\".",
  702.     "",
  703.     "The words \"day\", \"weekday\", \"workday\", and \"holiday\" may be used as",
  704.     "wildcards: \"day\" matches any day, \"weekday\" matches any day normally",
  705.     "printed in black, \"workday\" matches any day normally printed in black",
  706.     "and not explicitly flagged as a holiday, and \"holiday\" matches any",
  707.     "day explicitly flagged as a holiday.  \"Nonweekday\", \"nonworkday\",",
  708.     "and \"nonholiday\" are also supported and have the obvious meanings.",
  709.     "Moon phases may also appear as wildcards; \"nm\" is accepted as a",
  710.     "synonym for \"new_moon\", \"1q\" and \"fq\" for \"first_quarter\", \"fm\" for",
  711.     "\"full_moon\", and \"3q\", \"lq\", and \"third_quarter\" for \"last_quarter\". ",
  712.     "",
  713.     "\"Odd\" and \"even\" do not refer to the actual date; instead, \"odd\"",
  714.     "means \"alternate, starting with the first\"; \"even\" means \"alternate,",
  715.     "starting with the second\".  Thus, \"odd Fridays in March\" refers to",
  716.     "the first, third, and (if present) fifth Fridays in March - not to",
  717.     "those Fridays falling on odd dates.",
  718.     "",
  719.     "\"All\" refers to each individual month; \"year\" refers to the year",
  720.     "as an entity.  Thus \"odd Fridays in all\" refers to the first/third/",
  721.     "fifth Friday of each month, while \"odd Fridays in year\" refers to",
  722.     "the first Friday of January and every other Friday thereafter.",
  723.     "",
  724.     "Additional notes may be propagated to an empty calendar box by the",
  725.     "inclusion of one or more lines of the form \"note{/<number>} <month>",
  726.     "<text>\", where <month> may be numeric or alphabetic; \"note{/<number>}",
  727.     "all <text>\" propagates <text> to each month in the current year.",
  728.     "<number> is an optional positive or negative number specifying the",
  729.     "empty box where the associated text is to be placed: if positive,",
  730.     "Pcal counts forward from the first empty box; if negative, Pcal counts",
  731.     "backward from the last empty box.  Thus, \"note/1 ...\" places the",
  732.     "associated text in the first empty box, and \"note/-3 ...\" in the",
  733.     "third-to-last; the default is -1 (last empty box).  (Note that if the",
  734.     "-S option is used, it must be specified either on the command line or",
  735.     "prior to any \"note\" lines in the date file.)",
  736.     "",
  737.     "Pcal also allows format specifiers in the text (and foot strings -",
  738.     "cf. the -L, -C, -R, and -N options); each will be replaced by its",
  739.     "equivalent string as outlined in the table below.  (Most of these are",
  740.     "derived from the strftime() function; %[louwMD0+-] are Pcal-specific.)",
  741.     "",
  742.     "\t%a : abbreviated weekday",
  743.     "\t%A : full weekday",
  744.     "\t%b : abbreviated month name",
  745.     "\t%B : full month name",
  746.     "\t%d : day of month (1-31)",
  747.     "\t%j : day of year (1-366)",
  748.     "\t%l : days left in year (0-365)",
  749.     "\t%m : month (1-12)",
  750.     "\t%u : week number (1-54)",
  751.     "\t%U : week number (0-53)",
  752.     "\t%w : week number (1-54)",
  753.     "\t%W : week number (0-53)",
  754.     "\t%y : year w/o century (00-99)",
  755.     "\t%Y : year w/century",
  756.     "\t%% : '%' character",
  757.     "",
  758.     "\t%o : print number as ordinal",
  759.     "\t%0 : print number with leading zeroes",
  760.     "\t%+ : use following month or year",
  761.     "\t%- : use previous month or year",
  762.     "\t%{+N}[DWMY] : adjust date by +N days/weeks/months/years",
  763.     "\t%{-N}[DWMY] : adjust date by -N days/weeks/months/years",
  764.     "",
  765.     "%u considers the week containing 1/1 as week 1 and the following",
  766.     "logical Sunday (the first day of the week as printed; cf. the -F",
  767.     "flag) as the start of week 2; %U considers the first logical Sunday",
  768.     "as the first day of week 1.  %w and %W behave like %u and %U",
  769.     "respectively, but use the first logical Monday instead.  (Note that",
  770.     "%w has a different meaning to strftime().)",
  771.     "",
  772.     "%o prints a number as an ordinal, with the appropriate suffix (\"st\",",
  773.     "\"nd\", \"rd\", or \"th\" in English) appended; for example, \"%od\" prints",
  774.     "the day of the month as \"1st\", \"2nd\", \"3rd\", etc.",
  775.     "",
  776.     "Unlike strftime(), Pcal's default is to print numbers (except %y)",
  777.     "without leading zeroes.  If leading zeroes are desired, the '0'",
  778.     "prefix may be used; for example, \"%0j\" prints the day of year as",
  779.     "001-365.",
  780.     "",
  781.     "%+ and %- direct Pcal to substitute the following/previous month/year",
  782.     "in the following [bBmyY] specifier; for example, \"%+B\" prints the",
  783.     "name of the next month.",
  784.     "",
  785.     "%{[+-]N}[DWMY] do not print anything, but instead adjust the",
  786.     "working date by +-N days (D), weeks (W), months (M), or years (Y);",
  787.     "subsequent format specifiers use the adjusted date instead of the",
  788.     "current date.  For example, \"%+1M %B %Y\" adjusts the date forward by",
  789.     "one month and then prints the resulting month and year (\"January",
  790.     "1991\" in December, 1990); \"%-2W %b %d\" adjusts the date backward",
  791.     "by two weeks and prints the resulting month and day (\"Jul 26\" on",
  792.     "August 9).",
  793.     "",
  794.     "Such date adjustments are normally cumulative; for example,",
  795.     "\"%+1Y%-1D\" adjusts the date forward by one year and then backward",
  796.     "by one day.  If %D or %M is specified alone (or if N is zero), Pcal",
  797.     "restores the original date.  (Note that %M has a different meaning",
  798.     "to strftime().)",
  799.     "",
  800.     "The \"Notes\" box uses the first of the current month as the default",
  801.     "date.  All foot strings use the first of the current month in single-",
  802.     "month mode and the first of the starting month in whole-year mode.",
  803.     "",
  804.     "Simple cpp-like functionality is provided.  The date file may include",
  805.     "the following commands, which work like their cpp counterparts:",
  806.     "",
  807.     "\tdefine <sym>",
  808.     "\tundef <sym>",
  809.     "",
  810.     "\tif{{n}def} <expr>",
  811.     "\t   ...",
  812.     "\t{ elif <expr>",
  813.     "\t   ... }*",
  814.     "\t{ else",
  815.     "\t   ... }",
  816.     "\tendif",
  817.     "",
  818.     "\tinclude <file>",
  819.     "",
  820.     "Note that these do not start with '#', which is reserved as a comment",
  821.     "character.",
  822.     "",
  823.     "<sym> is a symbol name consisting of a letter followed by zero or",
  824.     "more letters, digits, or underscores ('_').  Symbol names are always",
  825.     "treated in a case-insensitive manner.",
  826.     "",
  827.     "<expr> is an expression consisting of symbol names joined by the logical",
  828.     "operators (in order of precedence, high to low) '!' (unary negate), '&'",
  829.     "(and), '^' (exclusive or), and '|' (inclusive or).  '&&' and '||' are",
  830.     "accepted as synonyms for '&' and '|' respectively; the order of",
  831.     "evaluation may be altered by the use of parentheses.  A symbol whose",
  832.     "name is currently defined evaluates to TRUE; one whose name is not",
  833.     "currently defined evaluates to FALSE.  Thus \"ifdef A | B | C\" is TRUE",
  834.     "if any of the symbols A, B, and C is currently defined, and",
  835.     "\"ifdef A & B & C\" is TRUE if all of them are.",
  836.     "",
  837.     "\"ifndef A | B | C\" is equivalent to \"ifdef !(A | B | C)\" (or, using",
  838.     "DeMorgan's Law, \"ifdef !A & !B & !C\") - in other words, TRUE if none of",
  839.     "the symbols A, B, and C is currently defined.",
  840.     "",
  841.     "\"if\" is accepted as a synonym for \"ifdef\".",
  842.     "",
  843.     "\"elif A\" is TRUE if A is defined.  Multiple \"elif\" clauses may appear;",
  844.     "at most one \"if{{n}def}\", \"elif\", or \"else\" clause in a given block",
  845.     "will be processed.",
  846.     "",
  847.     "\"define\" alone deletes all the current definitions; \"if{def}\" alone is",
  848.     "always false; \"ifndef\" alone is always true.",
  849.     "",
  850.     "The file name in the \"include\" directive may optionally be surrounded",
  851.     "by \"\" or <>; in any case, path names are taken to be relative to",
  852.     "the location of the file containing the \"include\" directive.  If the",
  853.     "string \"%y\" appears in the file name, it is replaced by the last two",
  854.     "digits of the current year.",
  855.     "",
  856.     "The \"-w\" flag defines the symbol \"whole_year\", which may be tested",
  857.     "in the same manner as any user-defined symbol.",
  858.     "",
  859.     "",
  860.     "Moon file syntax:",
  861.     "",
  862.     "The user may enter the dates and (optionally) times of quarter",
  863.     "moons (from a reliable source such as an almanac or astronomical",
  864.     "table) into a file called .moon%y (moon%y.dat on VMS), where %y is",
  865.     "the last two digits of the year.  If such a file exists (in the",
  866.     "same directory as the date file, or in the directory where Pcal",
  867.     "itself lives), Pcal will interpolate the phase of the moon from the",
  868.     "information in this file instead of using the default algorithm.",
  869.     "",
  870.     "(Pcal originally used an extremely simplistic moon phase algorithm;",
  871.     "the moon file was added to v4.0 to enable Pcal to interpolate the",
  872.     "phase of the moon from the [presumably more accurate] information",
  873.     "within.  More recently, the original moon phase algorithm was",
  874.     "superseded by an astronomer-strength version, largely obviating",
  875.     "the need for a moon file; however, it will continue to be",
  876.     "supported for the foreseeable future.)",
  877.     "",
  878.     "Entries in the moon file must conform to the following syntax:",
  879.     "",
  880.     "  if -A flag (American date formats) specified:",
  881.     "    <quarter> <month><sep><day> {<hour><sep><min>}",
  882.     "",
  883.     "  if -E flag (European date formats) specified:",
  884.     "    <quarter> <day><sep><month> {<hour><sep><min>}",
  885.     "",
  886.     "where",
  887.     "",
  888.     "  <quarter> := \"nm\", \"fq\" or \"1q\", \"fm\", \"lq\" or \"3q\" (new",
  889.     "\t\tmoon, first quarter, full moon, last quarter)",
  890.     "  <hour>    := number 0-23 (24-hour clock)",
  891.     "  <min>     := number 0-59",
  892.     "",
  893.     "This file must contain entries for all quarter moons in the year,",
  894.     "in chronological order; if any errors are encountered, Pcal will",
  895.     "revert to using its default algorithm.",
  896.     "",
  897.     "As in the date file, comments start with '#' and run through",
  898.     "end-of-line.  ",
  899.     NULL
  900.     };
  901. #else
  902. extern char *date_msg[];
  903. #endif
  904.  
  905. /* format strings for color_msg() - translate as necessary */
  906. #define COLOR_MSG_1    "all days in %s"
  907. #define COLOR_MSG_2    "in %s; others in %s"
  908.  
  909. /* format string for short usage() message */
  910. #define USAGE_MSG    "\"%s -%c\" prints full description of flags, parameters, and file formats\n"
  911.  
  912. /* format strings for comment in PostScript output file */
  913. #define VERSION_MSG    "Generated by %s %s"
  914. #define DATEFILE_MSG    " from %s"
  915.  
  916. #define LINE_SEP    ".p"        /* text line separator */
  917.  
  918. /* strings used in error messages */
  919. #define ENV_VAR        "environment variable "
  920. #define DATE_FILE    "date file "
  921.  
  922. /* Error and information messages - translate as necessary */
  923.  
  924. /* program error messages */
  925. #define    E_ALLOC_ERR    "%s: calloc() failed - out of memory\n"
  926. #define    E_FOPEN_ERR    "%s: can't open file %s\n"
  927. #define    E_ILL_LINE    "%s: %s in file %s, line %d\n"
  928. #define    E_ILL_MONTH    "%s: month %d not in range %d .. %d\n"
  929. #define    E_ILL_OPT    "%s: unrecognized flag %s"
  930. #define E_ILL_OPT2    " (%s\"%s\")"
  931. #define    E_ILL_YEAR    "%s: year %d not in range %d .. %d\n"
  932. #define    E_SYMFULL    "%s: symbol table full - can't define %s\n"
  933. #define    E_UNT_IFDEF    "%s: unterminated if{n}def..{else..}endif in file %s\n"
  934. #define E_FLAG_IGNORED    "%s: -%c flag ignored (%s\"%s\")\n"
  935.  
  936. /* preprocessor error strings */
  937. #define E_ELSE_ERR    "unmatched \"else\""
  938. #define E_ELIF_ERR    "unmatched \"elif\""
  939. #define E_END_ERR    "unmatched \"endif\""
  940. #define E_GARBAGE    "extraneous data on \"%s\" line"
  941. #define E_INV_DATE    "invalid date"
  942. #define E_NO_MATCH    "no match for wildcard"
  943. #define E_INV_LINE    "unrecognized line"
  944. #define E_FILE_NESTING    "maximum file nesting level exceeded"
  945. #define E_IF_NESTING    "maximum \"if{n}def\" nesting level exceeded"
  946. #define E_EXPR_SYNTAX    "syntax error in expression"
  947.  
  948. /* moon file error strings */
  949. #define E_DATE_SEQ    "date or phase out of sequence"
  950. #define E_PREM_EOF    "premature EOF"
  951.  
  952. /* information message (VMS, Amiga only) */
  953. #define    I_OUT_NAME    "%s: output is in file %s\n"
  954.  
  955. /* predefined macro names */
  956. #define DEF_WHOLE_YEAR    "whole_year"        /* defined when -w set */
  957.  
  958. /*
  959.  * Yes, some source code in a header file.  This is a language-dependent
  960.  * routine used by writefil.c to translate the %o (ordinal suffix) format
  961.  * specifier into the appropriate string for printing, and seemed to belong
  962.  * here with the other language dependencies.
  963.  */
  964. #ifdef WRITEFIL            /* include only in writefil.c */
  965. #ifdef PROTOS
  966. static char *ordinal_suffix(int num)
  967. #else
  968. static char *ordinal_suffix(num)
  969.     int num;        /* ordinal number - assumed positive */
  970. #endif
  971. {
  972.     static char buf[10];
  973.     int tens, units;
  974.  
  975.     /* Select suffix according to rules for target language.  In English,
  976.      * the rules are as follows:
  977.      *
  978.      *    tens digit    units digit    suffix
  979.      *      (any)          0, 4..9     "th"
  980.      *        1           (any)     "th"
  981.      *      != 1             1         "st"
  982.      *      != 1             2         "nd"
  983.      *      != 1             3         "rd"
  984.      */
  985.     tens = (num / 10) % 10;
  986.     units = num % 10;
  987.     strcpy(buf, ord_suffix[(units > 3 || tens == 1) ? 0 : units]);
  988.  
  989.     return buf;
  990. }
  991. #endif
  992.