Upload Tizen:Base source
[framework/base/util-linux-ng.git] / misc-utils / ddate.c
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    and I'm not responsible if this program messes anything up (except your 
22    mind, I'm responsible for that) (and that goes for me as well --lhos)
23
24    Version history:
25    Bureflux 3161:      First release of enhanced ddate with format strings
26    59 Bcy, 3161:       PRAISE_BOB and KILL_BOB options split, other minor
27                        changes.
28
29    1999-02-22 Arkadiusz Mi¶kiewicz <misiek@pld.ORG.PL>
30    - added Native Language Support
31
32    2000-03-17 Burt Holzman <bnh@iname.com>
33    - added range checks for dates
34 */
35
36 /* configuration options  VVVVV   READ THIS!!! */
37
38 /* If you wish ddate(1) to print the date in the same format as Druel's 
39  * original ddate when called in immediate mode, define OLD_IMMEDIATE_FMT 
40  */
41
42 #define OLD_IMMEDIATE_FMT
43
44 /* If you wish to use the US format for aneristic dates (m-d-y), as opposed to
45  * the Commonwealth format, define US_FORMAT.
46  */
47
48 /* #define US_FORMAT */
49
50 /* If you are ideologically, theologically or otherwise opposed to the 
51  * Church of the SubGenius and do not wish your copy of ddate(1) to contain
52  * code for counting down to X-Day, undefine KILL_BOB */
53
54 #define KILL_BOB 13013
55
56 /* If you wish ddate(1) to contain SubGenius slogans, define PRAISE_BOB */
57
58 /*#define PRAISE_BOB 13013*/
59
60 #include <stdlib.h>
61 #include <string.h>
62 #include <time.h>
63 #include <stdio.h>
64 #include "nls.h"
65
66 #ifndef __GNUC__
67 #define inline /* foo */
68 #endif
69
70 #ifdef KILL_BOB
71 int xday_countdown(int yday, int year);
72 #endif
73
74
75 /* string constants */
76
77 char *day_long[5] = { 
78     "Sweetmorn", "Boomtime", "Pungenday", "Prickle-Prickle", "Setting Orange"
79 };
80
81 char *day_short[5] = {"SM","BT","PD","PP","SO"};
82
83 char *season_long[5] = { 
84     "Chaos", "Discord", "Confusion", "Bureaucracy", "The Aftermath"
85 };
86
87 char *season_short[5] = {"Chs", "Dsc", "Cfn", "Bcy", "Afm"};
88
89 char *holyday[5][2] = { 
90     { "Mungday", "Chaoflux" },
91     { "Mojoday", "Discoflux" },
92     { "Syaday",  "Confuflux" },
93     { "Zaraday", "Bureflux" },
94     { "Maladay", "Afflux" }
95 };
96
97 struct disc_time {
98     int season; /* 0-4 */
99     int day; /* 0-72 */
100     int yday; /* 0-365 */
101     int year; /* 3066- */
102 };
103
104 char *excl[] = {
105     "Hail Eris!", "All Hail Discordia!", "Kallisti!", "Fnord.", "Or not.",
106     "Wibble.", "Pzat!", "P'tang!", "Frink!", 
107 #ifdef PRAISE_BOB
108     "Slack!", "Praise \"Bob\"!", "Or kill me.",
109 #endif /* PRAISE_BOB */
110     /* randomness, from the Net and other places. Feel free to add (after
111        checking with the relevant authorities, of course). */
112     "Grudnuk demand sustenance!", "Keep the Lasagna flying!", 
113     "Umlaut Zebra über alles!", "You are what you see.",
114     "Or is it?", "This statement is false.",
115 #if defined(linux) || defined (__linux__) || defined (__linux)
116     "Hail Eris, Hack Linux!",
117 #endif
118     ""
119 };
120
121 char default_fmt[] = "%{%A, %B %d%}, %Y YOLD";
122 char *default_immediate_fmt=
123 #ifdef OLD_IMMEDIATE_FMT
124 "Today is %{%A, the %e day of %B%} in the YOLD %Y%N%nCelebrate %H"
125 #else
126 default_fmt
127 #endif
128 ;
129
130 #define DY(y) (y+1166)
131
132 static inline char *ending(int i) {
133         return i/10==1?"th":(i%10==1?"st":(i%10==2?"nd":(i%10==3?"rd":"th")));
134 }
135
136 static inline int leapp(int i) {
137         return (!(DY(i)%4))&&((DY(i)%100)||(!(DY(i)%400)));
138 }
139
140 /* select a random string */
141 static inline char *sel(char **strings, int num) {
142         return(strings[random()%num]);
143 }
144
145 void print(struct disc_time,char **); /* old */
146 void format(char *buf, const char* fmt, struct disc_time dt);
147 /* read a fortune file */
148 int load_fortunes(char *fn, char *delim, char** result);
149
150 struct disc_time convert(int,int);
151 struct disc_time makeday(int,int,int);
152
153 int
154 main (int argc, char *argv[]) {
155     long t;
156     struct tm *eris;
157     int bob,raw;
158     struct disc_time hastur;
159     char schwa[23*17], *fnord=0;
160     int pi;
161     char *progname, *p;
162
163     progname = argv[0];
164     if ((p = strrchr(progname, '/')) != NULL)
165         progname = p+1;
166
167     setlocale(LC_ALL, "");
168     bindtextdomain(PACKAGE, LOCALEDIR);
169     textdomain(PACKAGE);
170
171     srandom(time(NULL));
172     /* do args here */
173     for(pi=1; pi<argc; pi++) {
174         switch(argv[pi][0]) {
175         case '+': fnord=argv[pi]+1; break;
176         case '-': 
177             switch(argv[pi][1]) {
178             case 'V':
179                 printf(_("%s (%s)\n"), progname, PACKAGE_STRING);
180             default: goto usage;
181             }
182         default: goto thud;
183         }
184     }
185
186   thud:
187     if (argc-pi==3){ 
188         int moe=atoi(argv[pi]), larry=atoi(argv[pi+1]), curly=atoi(argv[pi+2]);
189         hastur=makeday(
190 #ifdef US_FORMAT
191             moe,larry,
192 #else
193             larry,moe,
194 #endif
195             curly);
196         if (hastur.season == -1) {
197                 printf("Invalid date -- out of range\n");
198                 return -1;
199         }
200         fnord=fnord?fnord:default_fmt;
201     } else if (argc!=pi) { 
202       usage:
203         fprintf(stderr,_("usage: %s [+format] [day month year]\n"), argv[0]);
204         exit(1);
205     } else {
206         t= time(NULL);
207         eris=localtime(&t);
208         bob=eris->tm_yday; /* days since Jan 1. */
209         raw=eris->tm_year; /* years since 1980 */
210         hastur=convert(bob,raw);
211         fnord=fnord?fnord:default_immediate_fmt;
212     }
213     format(schwa, fnord, hastur);
214     printf("%s\n", schwa);
215    
216     return 0;
217 }
218
219 void format(char *buf, const char* fmt, struct disc_time dt)
220 {
221     int tib_start=-1, tib_end=0;
222     int i, fmtlen=strlen(fmt);
223     char *bufptr=buf;
224
225 /*    fprintf(stderr, "format(%p, \"%s\", dt)\n", buf, fmt);*/
226
227     /* first, find extents of St. Tib's Day area, if defined */
228     for(i=0; i<fmtlen; i++) {
229         if(fmt[i]=='%') {
230             switch(fmt[i+1]) {
231             case 'A':
232             case 'a':
233             case 'd':
234             case 'e':
235                 if(tib_start>0)     tib_end=i+1;
236                 else                tib_start=i;
237                 break;
238             case '{': tib_start=i; break;
239             case '}': tib_end=i+1; break;
240             }
241         }
242     }
243
244     /* now do the formatting */
245     buf[0]=0;
246
247     for(i=0; i<fmtlen; i++) {
248         if((i==tib_start) && (dt.day==-1)) {
249             /* handle St. Tib's Day */
250             strcpy(bufptr, _("St. Tib's Day")); bufptr += 13;
251             i=tib_end;
252         } else {
253             if(fmt[i]=='%') {
254                 char *wibble=0, snarf[23];
255                 switch(fmt[++i]) {
256                 case 'A': wibble=day_long[dt.yday%5]; break;
257                 case 'a': wibble=day_short[dt.yday%5]; break;
258                 case 'B': wibble=season_long[dt.season]; break;
259                 case 'b': wibble=season_short[dt.season]; break;
260                 case 'd': sprintf(snarf, "%d", dt.day+1); wibble=snarf; break;
261                 case 'e': sprintf(snarf, "%d%s", dt.day+1, ending(dt.day+1)); 
262                     wibble=snarf; break;
263                 case 'H': if(dt.day==4||dt.day==49)
264                     wibble=holyday[dt.season][dt.day==49]; break;
265                 case 'N': if(dt.day!=4&&dt.day!=49) goto eschaton; break;
266                 case 'n': *(bufptr++)='\n'; break;
267                 case 't': *(bufptr++)='\t'; break;
268                     
269                 case 'Y': sprintf(snarf, "%d", dt.year); wibble=snarf; break;
270                 case '.': wibble=sel(excl, sizeof(excl)/sizeof(excl[0]));
271                     break;
272 #ifdef KILL_BOB
273                 case 'X': sprintf(snarf, "%d", 
274                                   xday_countdown(dt.yday, dt.year));
275                                   wibble = snarf; break;
276 #endif /* KILL_BOB */
277                 }
278                 if(wibble) {
279 /*                  fprintf(stderr, "wibble = (%s)\n", wibble);*/
280                     strcpy(bufptr, wibble); bufptr+=strlen(wibble);
281                 }
282             } else {
283                 *(bufptr++) = fmt[i];
284             }
285         }
286     }
287   eschaton:
288     *(bufptr)=0;
289 }
290
291 struct disc_time makeday(int imonth,int iday,int iyear) /*i for input */
292
293     struct disc_time funkychickens;
294     
295     int cal[12] = { 31,28,31,30,31,30,31,31,30,31,30,31 };
296     int dayspast=0;
297
298     memset(&funkychickens,0,sizeof(funkychickens));
299     /* basic range checks */
300     if (imonth < 1 || imonth > 12) {
301             funkychickens.season = -1;
302             return funkychickens;
303     }
304     if (iday < 1 || iday > cal[imonth-1]) {
305             if (!(imonth == 2 && iday == 29 && iyear%4 == 0 &&
306                   (iyear%100 != 0 || iyear%400 == 0))) {
307                     funkychickens.season = -1;
308                     return funkychickens;
309             }
310     }
311     
312     imonth--;
313     funkychickens.year= iyear+1166;
314     while(imonth>0) { dayspast+=cal[--imonth]; }
315     funkychickens.day=dayspast+iday-1;
316     funkychickens.season=0;
317     if((funkychickens.year%4)==2) {
318         if (funkychickens.day==59 && iday==29)  funkychickens.day=-1;
319     }
320     funkychickens.yday=funkychickens.day;
321 /*               note: EQUAL SIGN...hopefully that fixes it */
322     while(funkychickens.day>=73) {
323         funkychickens.season++;
324         funkychickens.day-=73;
325     }
326     return funkychickens;
327 }
328
329 struct disc_time convert(int nday, int nyear)
330 {  struct disc_time funkychickens;
331    
332    funkychickens.year = nyear+3066;
333    funkychickens.day=nday;
334    funkychickens.season=0;
335    if ((funkychickens.year%4)==2)
336      {if (funkychickens.day==59)
337         funkychickens.day=-1;
338      else if (funkychickens.day >59)
339        funkychickens.day-=1;
340     }
341    funkychickens.yday=funkychickens.day;
342    while (funkychickens.day>=73)
343      { funkychickens.season++;
344        funkychickens.day-=73;
345      }
346    return funkychickens;
347   
348  }
349
350 #ifdef KILL_BOB
351
352 /* Code for counting down to X-Day, X-Day being Cfn 40, 3164 
353  *
354  * After `X-Day' passed without incident, the CoSG declared that it had 
355  * got the year upside down --- X-Day is actually in 8661 AD rather than 
356  * 1998 AD.
357  *
358  * Thus, the True X-Day is Cfn 40, 9827.
359  *
360  */
361
362 int xday_countdown(int yday, int year) {
363     int r=(185-yday)+(((yday<59)&&(leapp(year)))?1:0);
364     while(year<9827) r+=(leapp(++year)?366:365);
365     while(year>9827) r-=(leapp(year--)?366:365);
366     return r;
367 }
368
369 #endif