source: npl/overig/util-linux/ddate.c @ dd7f574

gcc484perl-5.22
Last change on this file since dd7f574 was c5c522c, checked in by Edwin Eefting <edwin@datux.nl>, 8 years ago

initial commit, transferred from cleaned syn3 svn tree

  • Property mode set to 100644
File size: 10.7 KB
Line 
1/* $ DVCS ID: $jer|,523/lhos,KYTP!41023161\b"?" <<= DO NOT DELETE! */
2
3/* ddate.c .. converts boring normal dates to fun Discordian Date -><-
4   written  the 65th day of The Aftermath in the Year of Our Lady of
5   Discord 3157 by Druel the Chaotic aka Jeremy Johnson aka
6   mpython@gnu.ai.mit.edu 
7      28 Sever St Apt #3
8      Worcester MA 01609
9
10   and I'm not responsible if this program messes anything up (except your
11   mind, I'm responsible for that)
12
13   (k) YOLD 3161 and all time before and after.
14   Reprint, reuse, and recycle what you wish.
15   This program is in the public domain.  Distribute freely.  Or not.
16
17   Majorly hacked, extended and bogotified/debogotified on
18   Sweetmorn, Bureaucracy 42, 3161 YOLD, by Lee H:. O:. Smith, KYTP,
19   aka Andrew Bulhak, aka acb@dev.null.org
20
21   Slightly hackled and crackled by a sweet firey stove on
22   Boomtime, the 53rd day of Bureaucracy in the YOLD 3179,
23   by Chaplain Nyan the Wiser, aka Dan Dart, aka ntw@dandart.co.uk
24
25   and I'm not responsible if this program messes anything up (except your
26   mind, I'm responsible for that) (and that goes for me as well --lhos)
27
28   Version history:
29   Bureflux 3161:      First release of enhanced ddate with format strings
30   59 Bcy, 3161:       PRAISE_BOB and KILL_BOB options split, other minor
31                       changes.
32   53 Bcy, 3179:       Fixed gregorian date conversions less than YOLD 1167
33
34   1999-02-22 Arkadiusz Miskiewicz <misiek@pld.ORG.PL>
35   - added Native Language Support
36
37   2000-03-17 Burt Holzman <holzman+ddate@gmail.com>
38   - added range checks for dates
39
40   2014-06-07 William Woodruff <william@tuffbizz.com>
41   - removed gettext dependent locale code
42
43   15th of Confusion, 3180:
44   - call out adherents of the wrong fruit
45
46   FIVE TONS OF FLAX
47*/
48
49/* configuration options  VVVVV   READ THIS!!! */
50
51/* If you wish ddate(1) to print the date in the same format as Druel's
52 * original ddate when called in immediate mode, define OLD_IMMEDIATE_FMT
53 */
54
55#define OLD_IMMEDIATE_FMT
56
57/* If you wish to use the US format for aneristic dates (m-d-y), as opposed to
58 * the Commonwealth format, define US_FORMAT.
59 */
60
61/* #define US_FORMAT */
62
63/* If you are ideologically, theologically or otherwise opposed to the
64 * Church of the SubGenius and do not wish your copy of ddate(1) to contain
65 * code for counting down to X-Day, undefine KILL_BOB */
66
67#define KILL_BOB 13013
68
69/* If you wish ddate(1) to contain SubGenius slogans, define PRAISE_BOB */
70
71/*#define PRAISE_BOB 13013*/
72
73#include <stdlib.h>
74#include <string.h>
75#include <time.h>
76#include <stdio.h>
77
78
79// work around includes and defines from formerly c.h
80#ifndef ARRAY_SIZE
81# define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]) + __must_be_array(arr))
82#endif
83
84/* &a[0] degrades to a pointer: a different type from an array */
85# define __must_be_array(a) \
86        BUILD_BUG_ON_ZERO(__builtin_types_compatible_p(__typeof__(a), __typeof__(&a[0])))
87
88#define BUILD_BUG_ON_ZERO(e) (sizeof(struct { int:-!!(e); }))
89
90/* work around hacks for standalone package */
91#define PACKAGE "ddate"
92#define PACKAGE_STRING "Stand Alone"
93
94#ifndef __GNUC__
95#define inline /* foo */
96#endif
97
98#ifdef KILL_BOB
99int xday_countdown(int yday, int year);
100#endif
101
102
103/* string constants */
104
105char *day_long[5] = {
106    "Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"
107};
108
109char *day_short[5] = {"SM","BT","PD","PP","SO"};
110
111char *season_long[5] = {
112    "Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"
113};
114
115char *season_short[5] = {"Chs", "Dsc", "Cfn", "Bcy", "Afm"};
116
117char *holyday[5][2] = {
118    { "Mungday", "Chaoflux" },
119    { "Mojoday", "Discoflux" },
120    { "Syaday",  "Confuflux" },
121    { "Zaraday", "Bureflux" },
122    { "Maladay", "Afflux" }
123};
124
125struct disc_time {
126    int season; /* 0-4 */
127    int day; /* 0-72 */
128    int yday; /* 0-365 */
129    int year; /* 3066- */
130};
131
132char *excl[] = {
133    "Hail Eris!", "All Hail Discordia!", "Kallisti!", "Fnord.", "Or not.",
134    "Wibble.", "Pzat!", "P'tang!", "Frink!",
135#ifdef PRAISE_BOB
136    "Slack!", "Praise \"Bob\"!", "Or kill me.",
137#endif /* PRAISE_BOB */
138    /* randomness, from the Net and other places. Feel free to add (after
139       checking with the relevant authorities, of course). */
140    "Grudnuk demand sustenance!", "Keep the Lasagna flying!",
141    "You are what you see.",
142    "Or is it?", "This statement is false.",
143    "Lies and slander, sire!", "Hee hee hee!",
144#if defined(linux) || defined (__linux__) || defined (__linux)
145    "Hail Eris, Hack Linux!",
146#elif defined(__APPLE__)
147    "This Fruit is not the True Fruit of Discord.",
148#endif
149    ""
150};
151
152char default_fmt[] = "%{%A, %B %d%}, %Y YOLD";
153char *default_immediate_fmt=
154#ifdef OLD_IMMEDIATE_FMT
155"Today is %{%A, the %e day of %B%} in the YOLD %Y%N%nCelebrate %H"
156#else
157default_fmt
158#endif
159;
160
161#define DY(y) (y+1166)
162
163static inline char *ending(int i) {
164        return i/10==1?"th":(i%10==1?"st":(i%10==2?"nd":(i%10==3?"rd":"th")));
165}
166
167static inline int leapp(int i) {
168        return (!(DY(i)%4))&&((DY(i)%100)||(!(DY(i)%400)));
169}
170
171/* select a random string */
172static inline char *sel(char **strings, int num) {
173        return(strings[random()%num]);
174}
175
176void print(struct disc_time,char **); /* old */
177void format(char *buf, const char* fmt, struct disc_time dt);
178/* read a fortune file */
179int load_fortunes(char *fn, char *delim, char** result);
180
181struct disc_time convert(int,int);
182struct disc_time makeday(int,int,int);
183
184int
185main (int argc, char *argv[]) {
186    long t;
187    struct tm *eris;
188    int bob,raw;
189    struct disc_time hastur;
190    char schwa[23*17], *fnord=0;
191    int pi;
192    char *progname, *p;
193
194    progname = argv[0];
195    if ((p = strrchr(progname, '/')) != NULL)
196        progname = p+1;
197
198    srandom(time(NULL));
199    /* do args here */
200    for(pi=1; pi<argc; pi++) {
201        switch(argv[pi][0]) {
202        case '+': fnord=argv[pi]+1; break;
203        case '-':
204            switch(argv[pi][1]) {
205            case 'V':
206                printf(("%s (%s)\n"), progname, PACKAGE_STRING);
207            default: goto usage;
208            }
209        default: goto thud;
210        }
211    }
212
213  thud:
214    if (argc-pi==3){
215        int moe=atoi(argv[pi]), larry=atoi(argv[pi+1]), curly=atoi(argv[pi+2]);
216        hastur=makeday(
217#ifdef US_FORMAT
218            moe,larry,
219#else
220            larry,moe,
221#endif
222            curly);
223        if (hastur.season == -1) {
224                printf("Invalid date -- out of range\n");
225                return -1;
226        }
227        fnord=fnord?fnord:default_fmt;
228    } else if (argc!=pi) {
229      usage:
230        fprintf(stderr,("usage: %s [+format] [day month year]\n"), argv[0]);
231        exit(1);
232    } else {
233        t= time(NULL);
234        eris=localtime(&t);
235        bob=eris->tm_yday; /* days since Jan 1. */
236        raw=eris->tm_year; /* years since 1980 */
237        hastur=convert(bob,raw);
238        fnord=fnord?fnord:default_immediate_fmt;
239    }
240    format(schwa, fnord, hastur);
241    printf("%s\n", schwa);
242   
243    return 0;
244}
245
246void format(char *buf, const char* fmt, struct disc_time dt)
247{
248    int tib_start=-1, tib_end=0;
249    int i, fmtlen=strlen(fmt);
250    char *bufptr=buf;
251
252/*    fprintf(stderr, "format(%p, \"%s\", dt)\n", buf, fmt);*/
253
254    /* first, find extents of St. Tib's Day area, if defined */
255    for(i=0; i<fmtlen; i++) {
256        if(fmt[i]=='%') {
257            switch(fmt[i+1]) {
258            case 'A':
259            case 'a':
260            case 'd':
261            case 'e':
262                if(tib_start>0)     tib_end=i+1;
263                else                tib_start=i;
264                break;
265            case '{': tib_start=i; break;
266            case '}': tib_end=i+1; break;
267            }
268        }
269    }
270
271    /* now do the formatting */
272    buf[0]=0;
273
274    for(i=0; i<fmtlen; i++) {
275        if((i==tib_start) && (dt.day==-1)) {
276            /* handle St. Tib's Day */
277            strcpy(bufptr, ("St. Tib's Day"));
278            bufptr += strlen(bufptr);
279            i=tib_end;
280        } else {
281            if(fmt[i]=='%') {
282                char *wibble=0, snarf[23];
283                switch(fmt[++i]) {
284                case 'A': wibble=day_long[dt.yday%5]; break;
285                case 'a': wibble=day_short[dt.yday%5]; break;
286                case 'B': wibble=season_long[dt.season]; break;
287                case 'b': wibble=season_short[dt.season]; break;
288                case 'd': sprintf(snarf, "%d", dt.day+1); wibble=snarf; break;
289                case 'e': sprintf(snarf, "%d%s", dt.day+1, ending(dt.day+1));
290                    wibble=snarf; break;
291                case 'H': if(dt.day==4||dt.day==49)
292                    wibble=holyday[dt.season][dt.day==49]; break;
293                case 'N': if(dt.day!=4&&dt.day!=49) goto eschaton; break;
294                case 'n': *(bufptr++)='\n'; break;
295                case 't': *(bufptr++)='\t'; break;
296
297                case 'Y': sprintf(snarf, "%d", dt.year); wibble=snarf; break;
298                case '.': wibble=sel(excl, ARRAY_SIZE(excl));
299                    break;
300#ifdef KILL_BOB
301                case 'X': sprintf(snarf, "%d",
302                                  xday_countdown(dt.yday, dt.year));
303                                  wibble = snarf; break;
304#endif /* KILL_BOB */
305                }
306                if(wibble) {
307/*                  fprintf(stderr, "wibble = (%s)\n", wibble);*/
308                    strcpy(bufptr, wibble); bufptr+=strlen(wibble);
309                }
310            } else {
311                *(bufptr++) = fmt[i];
312            }
313        }
314    }
315  eschaton:
316    *(bufptr)=0;
317}
318
319struct disc_time makeday(int imonth,int iday,int iyear) /*i for input */
320{
321    struct disc_time funkychickens;
322   
323    int cal[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
324    int dayspast=0;
325
326    memset(&funkychickens,0,sizeof(funkychickens));
327    /* basic range checks */
328    if (imonth < 1 || imonth > 12 || iyear == 0) {
329            funkychickens.season = -1;
330            return funkychickens;
331    }
332    if (iday < 1 || iday > cal[imonth-1]) {
333            if (!(imonth == 2 && iday == 29 && iyear%4 == 0 &&
334                  (iyear%100 != 0 || iyear%400 == 0))) {
335                    funkychickens.season = -1;
336                    return funkychickens;
337            }
338    }
339   
340    imonth--;
341    /*  note: gregorian year 0 doesn't exist so
342     *  add one if user specifies a year less than 0 */
343    funkychickens.year= iyear+1166 + ((0 > iyear)?1:0);
344    while(imonth>0) { dayspast+=cal[--imonth]; }
345    funkychickens.day=dayspast+iday-1;
346    funkychickens.season=0;
347    if((funkychickens.year%4)==2) {
348        if (funkychickens.day==59 && iday==29)  funkychickens.day=-1;
349    }
350    funkychickens.yday=funkychickens.day;
351/*               note: EQUAL SIGN...hopefully that fixes it */
352    while(funkychickens.day>=73) {
353        funkychickens.season++;
354        funkychickens.day-=73;
355    }
356    return funkychickens;
357}
358
359struct disc_time convert(int nday, int nyear)
360{  struct disc_time funkychickens;
361   
362   funkychickens.year = nyear+3066;
363   funkychickens.day=nday;
364   funkychickens.season=0;
365   if ((funkychickens.year%4)==2)
366     {if (funkychickens.day==59)
367        funkychickens.day=-1;
368     else if (funkychickens.day >59)
369       funkychickens.day-=1;
370    }
371   funkychickens.yday=funkychickens.day;
372   while (funkychickens.day>=73)
373     { funkychickens.season++;
374       funkychickens.day-=73;
375     }
376   return funkychickens;
377 
378 }
379
380#ifdef KILL_BOB
381
382/* Code for counting down to X-Day, X-Day being Cfn 40, 3164
383 *
384 * After `X-Day' passed without incident, the CoSG declared that it had
385 * got the year upside down --- X-Day is actually in 8661 AD rather than
386 * 1998 AD.
387 *
388 * Thus, the True X-Day is Cfn 40, 9827.
389 *
390 */
391
392int xday_countdown(int yday, int year) {
393    int r=(185-yday)+(((yday<59)&&(leapp(year)))?1:0);
394    while(year<9827) r+=(leapp(++year)?366:365);
395    while(year>9827) r-=(leapp(year--)?366:365);
396    return r;
397}
398
399#endif
Note: See TracBrowser for help on using the repository browser.