1
/***************************************************************/
5
/* This file contains the built-in functions used in */
8
/* This file is part of REMIND. */
9
/* Copyright (C) 1992-1998 by David F. Skoll */
10
/* Copyright (C) 1999-2000 by Roaring Penguin Software Inc. */
12
/***************************************************************/
15
static char const RCSID[] = "$Id: funcs.c,v 1.9 2000/02/18 03:45:55 dfs Exp $";
35
#ifdef HAVE_SYS_FILE_H
39
#ifdef HAVE_SYS_TYPES_H
40
#include <sys/types.h>
51
#if defined(__MSDOS__) || defined(__OS2__)
71
/* Function prototypes */
72
PRIVATE int FAbs ARGS ((void));
73
PRIVATE int FAccess ARGS ((void));
74
PRIVATE int FArgs ARGS ((void));
75
PRIVATE int FAsc ARGS ((void));
76
PRIVATE int FBaseyr ARGS ((void));
77
PRIVATE int FChar ARGS ((void));
78
PRIVATE int FChoose ARGS ((void));
79
PRIVATE int FCoerce ARGS ((void));
80
PRIVATE int FDate ARGS ((void));
81
PRIVATE int FDay ARGS ((void));
82
PRIVATE int FDaysinmon ARGS ((void));
83
PRIVATE int FDefined ARGS ((void));
84
PRIVATE int FDosubst ARGS ((void));
85
PRIVATE int FEasterdate ARGS ((void));
86
PRIVATE int FFiledate ARGS ((void));
87
PRIVATE int FFiledir ARGS ((void));
88
PRIVATE int FFilename ARGS ((void));
89
PRIVATE int FGetenv ARGS ((void));
90
PRIVATE int FHebdate ARGS ((void));
91
PRIVATE int FHebday ARGS ((void));
92
PRIVATE int FHebmon ARGS ((void));
93
PRIVATE int FHebyear ARGS ((void));
94
PRIVATE int FHour ARGS ((void));
95
PRIVATE int FIif ARGS ((void));
96
PRIVATE int FIndex ARGS ((void));
97
PRIVATE int FIsdst ARGS ((void));
98
PRIVATE int FIsomitted ARGS ((void));
99
PRIVATE int FLanguage ARGS ((void));
100
PRIVATE int FMax ARGS ((void));
101
PRIVATE int FMin ARGS ((void));
102
PRIVATE int FMinute ARGS ((void));
103
PRIVATE int FMinsfromutc ARGS ((void));
104
PRIVATE int FMoondate ARGS ((void));
105
PRIVATE int FMoonphase ARGS ((void));
106
PRIVATE int FMoontime ARGS ((void));
107
PRIVATE int FMon ARGS ((void));
108
PRIVATE int FMonnum ARGS ((void));
109
PRIVATE int FOrd ARGS ((void));
110
PRIVATE int FOstype ARGS ((void));
111
PRIVATE int FPlural ARGS ((void));
112
PRIVATE int FSgn ARGS ((void));
113
PRIVATE int FPsmoon ARGS ((void));
114
PRIVATE int FPsshade ARGS ((void));
115
PRIVATE int FShell ARGS ((void));
116
PRIVATE int FStrlen ARGS ((void));
117
PRIVATE int FSubstr ARGS ((void));
118
PRIVATE int FDawn ARGS ((void));
119
PRIVATE int FDusk ARGS ((void));
120
PRIVATE int FSunset ARGS ((void));
121
PRIVATE int FSunrise ARGS ((void));
122
PRIVATE int FTime ARGS ((void));
123
PRIVATE int FTrigdate ARGS ((void));
124
PRIVATE int FTrigtime ARGS ((void));
125
PRIVATE int FTrigvalid ARGS ((void));
126
PRIVATE int FTypeof ARGS ((void));
127
PRIVATE int FUpper ARGS ((void));
128
PRIVATE int FValue ARGS ((void));
129
PRIVATE int FVersion ARGS ((void));
130
PRIVATE int FWkday ARGS ((void));
131
PRIVATE int FWkdaynum ARGS ((void));
132
PRIVATE int FYear ARGS ((void));
133
PRIVATE int FIsleap ARGS ((void));
134
PRIVATE int FLower ARGS ((void));
135
PRIVATE int FNow ARGS ((void));
136
PRIVATE int FRealnow ARGS ((void));
137
PRIVATE int FRealtoday ARGS ((void));
138
PRIVATE int FToday ARGS ((void));
139
PRIVATE int FTrigger ARGS ((void));
140
PRIVATE int CheckArgs ARGS ((Operator *f, int nargs));
141
PRIVATE int CleanUpAfterFunc ARGS ((void));
142
PRIVATE int SunStuff ARGS ((int rise, double cosz, int jul));
144
#if defined(__MSDOS__) || defined(__BORLANDC__) || defined(AMIGA)
145
PRIVATE FILE *os_popen ARGS((char *cmd, char *mode));
146
PRIVATE int os_pclose ARGS((FILE *fp));
147
#define POPEN os_popen
148
#define PCLOSE os_pclose
150
#if defined(_MSC_VER)
152
#define pclose _pclose
155
#elif defined(_MSC_VER)
157
#define PCLOSE _pclose
161
#define PCLOSE pclose
164
/* "Overload" the struct Operator definition */
169
/* Sigh - we use a global var. to hold the number of args supplied to
170
function being called */
173
/* Use a global var. to hold function return value */
176
/* Temp string buffer */
177
static char Buffer[32];
179
/* Caches for extracting months, days, years from dates - may
180
improve performance slightly. */
181
static int CacheJul = -1;
182
static int CacheYear, CacheMon, CacheDay;
184
static int CacheHebJul = -1;
185
static int CacheHebYear, CacheHebMon, CacheHebDay;
187
/* We need access to the value stack */
188
extern Value ValStack[];
189
extern int ValStackPtr;
191
/* Macro for accessing arguments from the value stack - args are numbered
192
from 0 to (Nargs - 1) */
193
#define ARG(x) (ValStack[ValStackPtr - Nargs + (x)])
195
/* Macro for copying a value while destroying original copy */
196
#define DCOPYVAL(x, y) ( (x) = (y), (y).type = ERR_TYPE )
198
/* Convenience macros */
199
#define UPPER(c) (islower(c) ? toupper(c) : c)
200
#define LOWER(c) (isupper(c) ? tolower(c) : c)
202
/* The array holding the built-in functions. */
204
/* Name minargs maxargs func */
206
{ "abs", 1, 1, FAbs },
207
{ "access", 2, 2, FAccess },
208
{ "args", 1, 1, FArgs },
209
{ "asc", 1, 1, FAsc },
210
{ "baseyr", 0, 0, FBaseyr },
211
{ "char", 1, NO_MAX, FChar },
212
{ "choose", 2, NO_MAX, FChoose },
213
{ "coerce", 2, 2, FCoerce },
214
{ "date", 3, 3, FDate },
215
{ "dawn", 0, 1, FDawn},
216
{ "day", 1, 1, FDay },
217
{ "daysinmon", 2, 2, FDaysinmon },
218
{ "defined", 1, 1, FDefined },
219
{ "dosubst", 1, 3, FDosubst },
220
{ "dusk", 0, 1, FDusk },
221
{ "easterdate", 1, 1, FEasterdate },
222
{ "filedate", 1, 1, FFiledate },
223
{ "filedir", 0, 0, FFiledir },
224
{ "filename", 0, 0, FFilename },
225
{ "getenv", 1, 1, FGetenv },
226
{ "hebdate", 2, 5, FHebdate },
227
{ "hebday", 1, 1, FHebday },
228
{ "hebmon", 1, 1, FHebmon },
229
{ "hebyear", 1, 1, FHebyear },
230
{ "hour", 1, 1, FHour },
231
{ "iif", 1, NO_MAX, FIif },
232
{ "index", 2, 3, FIndex },
233
{ "isdst", 0, 2, FIsdst },
234
{ "isleap", 1, 1, FIsleap },
235
{ "isomitted", 1, 1, FIsomitted },
236
{ "language", 0, 0, FLanguage },
237
{ "lower", 1, 1, FLower },
238
{ "max", 1, NO_MAX, FMax },
239
{ "min", 1, NO_MAX, FMin },
240
{ "minsfromutc", 0, 2, FMinsfromutc },
241
{ "minute", 1, 1, FMinute },
242
{ "mon", 1, 1, FMon },
243
{ "monnum", 1, 1, FMonnum },
244
{ "moondate", 1, 3, FMoondate },
245
{ "moonphase", 0, 2, FMoonphase },
246
{ "moontime", 1, 3, FMoontime },
247
{ "now", 0, 0, FNow },
248
{ "ord", 1, 1, FOrd },
249
{ "ostype", 0, 0, FOstype },
250
{ "plural", 1, 3, FPlural },
251
{ "psmoon", 1, 4, FPsmoon},
252
{ "psshade", 1, 3, FPsshade},
253
{ "realnow", 0, 0, FRealnow},
254
{ "realtoday", 0, 0, FRealtoday },
255
{ "sgn", 1, 1, FSgn },
256
{ "shell", 1, 2, FShell },
257
{ "strlen", 1, 1, FStrlen },
258
{ "substr", 2, 3, FSubstr },
259
{ "sunrise", 0, 1, FSunrise},
260
{ "sunset", 0, 1, FSunset },
261
{ "time", 2, 2, FTime },
262
{ "today", 0, 0, FToday },
263
{ "trigdate", 0, 0, FTrigdate },
264
{ "trigger", 1, 3, FTrigger },
265
{ "trigtime", 0, 0, FTrigtime },
266
{ "trigvalid", 0, 0, FTrigvalid },
267
{ "typeof", 1, 1, FTypeof },
268
{ "upper", 1, 1, FUpper },
269
{ "value", 1, 2, FValue },
270
{ "version", 0, 0, FVersion },
271
{ "wkday", 1, 1, FWkday },
272
{ "wkdaynum", 1, 1, FWkdaynum },
273
{ "year", 1, 1, FYear }
276
/* Need a variable here - Func[] array not really visible to outside. */
277
int NumFuncs = sizeof(Func) / sizeof(Operator) ;
279
/***************************************************************/
283
/* Call a function given a pointer to it, and the number */
284
/* of arguments supplied. */
286
/***************************************************************/
288
PUBLIC int CallFunc(Operator *f, int nargs)
290
int CallFunc(f, nargs)
295
register int r = CheckArgs(f, nargs);
300
RetVal.type = ERR_TYPE;
301
if (DebugFlag & DB_PRTEXPR) {
302
fprintf(ErrFp, "%s(", f->name);
303
for (i=0; i<nargs; i++) {
304
PrintValue(&ARG(i), ErrFp);
305
if (i<nargs-1) fprintf(ErrFp, ", ");
307
fprintf(ErrFp, ") => ");
309
fprintf(ErrFp, "%s\n", ErrMsg[r]);
314
Eprint("%s(): %s", f->name, ErrMsg[r]);
320
DestroyValue(RetVal);
321
if (DebugFlag & DB_PRTEXPR)
322
fprintf(ErrFp, "%s\n", ErrMsg[r]);
324
Eprint("%s(): %s", f->name, ErrMsg[r]);
327
if (DebugFlag & DB_PRTEXPR) {
328
PrintValue(&RetVal, ErrFp);
329
fprintf(ErrFp, "\n");
331
r = CleanUpAfterFunc();
335
/***************************************************************/
339
/* Check that the right number of args have been supplied */
340
/* for a function. */
342
/***************************************************************/
344
PRIVATE int CheckArgs(Operator *f, int nargs)
346
static int CheckArgs(f, nargs)
351
if (nargs < f->MINARGS) return E_2FEW_ARGS;
352
if (nargs > f->MAXARGS && f->MAXARGS != NO_MAX) return E_2MANY_ARGS;
355
/***************************************************************/
357
/* CleanUpAfterFunc */
359
/* Clean up the stack after a function call - remove */
360
/* args and push the new value. */
362
/***************************************************************/
364
PRIVATE int CleanUpAfterFunc(void)
366
static int CleanUpAfterFunc()
372
for (i=0; i<Nargs; i++) {
376
PushValStack(RetVal);
380
/***************************************************************/
384
/* Return a string value from a function. */
386
/***************************************************************/
388
PRIVATE int RetStrVal(const char *s)
390
static int RetStrVal(s)
394
RetVal.type = STR_TYPE;
396
RetVal.v.str = (char *) malloc(1);
397
if (RetVal.v.str) *RetVal.v.str = 0;
399
RetVal.v.str = StrDup(s);
402
RetVal.type = ERR_TYPE;
409
/***************************************************************/
411
/* FStrlen - string length */
413
/***************************************************************/
415
PRIVATE int FStrlen(void)
421
if (v->type != STR_TYPE) return E_BAD_TYPE;
422
RetVal.type = INT_TYPE;
423
RetVal.v.val = strlen(v->v.str);
427
/***************************************************************/
429
/* FBaseyr - system base year */
431
/***************************************************************/
433
PRIVATE int FBaseyr(void)
438
RetVal.type = INT_TYPE;
443
/***************************************************************/
445
/* FDate - make a date from year, month, day. */
447
/***************************************************************/
449
PRIVATE int FDate(void)
455
if (ARG(0).type != INT_TYPE ||
456
ARG(1).type != INT_TYPE ||
457
ARG(2).type != INT_TYPE) return E_BAD_TYPE;
459
m = ARG(1).v.val - 1;
462
if (!DateOK(y, m, d)) return E_BAD_DATE;
464
RetVal.type = DATE_TYPE;
465
RetVal.v.val = Julian(y, m, d);
469
/***************************************************************/
471
/* FCoerce - type coercion function. */
473
/***************************************************************/
475
PRIVATE int FCoerce(void)
482
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
485
/* Copy the value of ARG(1) into RetVal, and make ARG(1) invalid so
486
it won't be destroyed */
487
DCOPYVAL(RetVal, ARG(1));
489
if (! StrCmpi(s, "int")) return DoCoerce(INT_TYPE, &RetVal);
490
else if (! StrCmpi(s, "date")) return DoCoerce(DATE_TYPE, &RetVal);
491
else if (! StrCmpi(s, "time")) return DoCoerce(TIM_TYPE, &RetVal);
492
else if (! StrCmpi(s, "string")) return DoCoerce(STR_TYPE, &RetVal);
493
else return E_CANT_COERCE;
496
/***************************************************************/
498
/* FMax - select maximum from a list of args. */
500
/***************************************************************/
502
PRIVATE int FMax(void)
514
for (i=1; i<Nargs; i++) {
515
if (ARG(i).type != type) return E_BAD_TYPE;
516
if (type != STR_TYPE) {
517
if (ARG(i).v.val > maxptr->v.val) maxptr = &ARG(i);
519
if (strcmp(ARG(i).v.str, maxptr->v.str) > 0) maxptr = &ARG(i);
522
DCOPYVAL(RetVal, *maxptr);
526
/***************************************************************/
528
/* FMin - select minimum from a list of args. */
530
/***************************************************************/
532
PRIVATE int FMin(void)
544
for (i=1; i<Nargs; i++) {
545
if (ARG(i).type != type) return E_BAD_TYPE;
546
if (type != STR_TYPE) {
547
if (ARG(i).v.val < minptr->v.val) minptr = &ARG(i);
549
if (strcmp(ARG(i).v.str, minptr->v.str) < 0) minptr = &ARG(i);
552
DCOPYVAL(RetVal, *minptr);
556
/***************************************************************/
558
/* FAsc - ASCII value of first char of string */
560
/***************************************************************/
562
PRIVATE int FAsc(void)
567
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
568
RetVal.type = INT_TYPE;
569
RetVal.v.val = *(ARG(0).v.str);
573
/***************************************************************/
575
/* FChar - build a string from ASCII values */
577
/***************************************************************/
579
PRIVATE int FChar(void)
587
/* Special case of one arg - if given ascii value 0, create empty string */
589
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
590
if (ARG(0).v.val < -128) return E_2LOW;
591
if (ARG(0).v.val > 255) return E_2HIGH;
592
len = ARG(0).v.val ? 2 : 1;
593
RetVal.v.str = (char *) malloc(len);
594
if (!RetVal.v.str) return E_NO_MEM;
595
RetVal.type = STR_TYPE;
596
*(RetVal.v.str) = ARG(0).v.val;
597
if (len>1) *(RetVal.v.str + 1) = 0;
601
RetVal.v.str = (char *) malloc(Nargs + 1);
602
if (!RetVal.v.str) return E_NO_MEM;
603
RetVal.type = STR_TYPE;
604
for (i=0; i<Nargs; i++) {
605
if (ARG(i).type != INT_TYPE) {
607
RetVal.type = ERR_TYPE;
610
if (ARG(i).v.val < -128 || ARG(i).v.val == 0) {
612
RetVal.type = ERR_TYPE;
615
if (ARG(i).v.val > 255) {
617
RetVal.type = ERR_TYPE;
620
*(RetVal.v.str + i) = ARG(i).v.val;
622
*(RetVal.v.str + Nargs) = 0;
625
/***************************************************************/
627
/* Functions for extracting the components of a date. */
629
/* FDay - get day of month */
630
/* FMonnum - get month (1-12) */
631
/* FYear - get year */
632
/* FWkdaynum - get weekday num (0 = Sun) */
633
/* FWkday - get weekday (string) */
634
/* FMon - get month (string) */
636
/***************************************************************/
638
PRIVATE int FDay(void)
644
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
645
if (ARG(0).v.val == CacheJul)
648
FromJulian(ARG(0).v.val, &y, &m, &d);
649
CacheJul = ARG(0).v.val;
654
RetVal.type = INT_TYPE;
660
PRIVATE int FMonnum(void)
666
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
667
if (ARG(0).v.val == CacheJul)
670
FromJulian(ARG(0).v.val, &y, &m, &d);
671
CacheJul = ARG(0).v.val;
676
RetVal.type = INT_TYPE;
682
PRIVATE int FYear(void)
688
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
689
if (ARG(0).v.val == CacheJul)
692
FromJulian(ARG(0).v.val, &y, &m, &d);
693
CacheJul = ARG(0).v.val;
698
RetVal.type = INT_TYPE;
704
PRIVATE int FWkdaynum(void)
706
static int FWkdaynum()
709
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
710
RetVal.type = INT_TYPE;
712
/* Correct so that 0 = Sunday */
713
RetVal.v.val = (ARG(0).v.val+1) % 7;
718
PRIVATE int FWkday(void)
725
if (ARG(0).type != DATE_TYPE && ARG(0).type != INT_TYPE) return E_BAD_TYPE;
726
if (ARG(0).type == INT_TYPE) {
727
if (ARG(0).v.val < 0) return E_2LOW;
728
if (ARG(0).v.val > 6) return E_2HIGH;
729
/* Convert 0=Sun to 0=Mon */
731
if (ARG(0).v.val < 0) ARG(0).v.val = 6;
732
s = DayName[ARG(0).v.val];
733
} else s = DayName[ARG(0).v.val % 7];
738
PRIVATE int FMon(void)
746
if (ARG(0).type != DATE_TYPE && ARG(0).type != INT_TYPE)
748
if (ARG(0).type == INT_TYPE) {
749
m = ARG(0).v.val - 1;
750
if (m < 0) return E_2LOW;
751
if (m > 11) return E_2HIGH;
753
if (ARG(0).v.val == CacheJul)
756
FromJulian(ARG(0).v.val, &y, &m, &d);
757
CacheJul = ARG(0).v.val;
767
/***************************************************************/
769
/* FHour - extract hour from a time */
770
/* FMinute - extract minute from a time */
771
/* FTime - create a time from hour and minute */
773
/***************************************************************/
775
PRIVATE int FHour(void)
780
if (ARG(0).type != TIM_TYPE) return E_BAD_TYPE;
781
RetVal.type = INT_TYPE;
782
RetVal.v.val = ARG(0).v.val / 60;
787
PRIVATE int FMinute(void)
792
if (ARG(0).type != TIM_TYPE) return E_BAD_TYPE;
793
RetVal.type = INT_TYPE;
794
RetVal.v.val = ARG(0).v.val % 60;
799
PRIVATE int FTime(void)
806
if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
810
if (h<0 || m<0) return E_2LOW;
811
if (h>23 || m>59) return E_2HIGH;
812
RetVal.type = TIM_TYPE;
813
RetVal.v.val = h*60 + m;
817
/***************************************************************/
819
/* FAbs - absolute value */
820
/* FSgn - signum function */
822
/***************************************************************/
824
PRIVATE int FAbs(void)
831
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
833
RetVal.type = INT_TYPE;
834
RetVal.v.val = (v < 0) ? (-v) : v;
839
PRIVATE int FSgn(void)
846
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
848
RetVal.type = INT_TYPE;
849
if (v>0) RetVal.v.val = 1;
850
else if (v<0) RetVal.v.val = -1;
851
else RetVal.v.val = 0;
855
/***************************************************************/
857
/* FOrd - returns a string containing ordinal number. */
859
/* EG - ord(2) == "2nd", etc. */
861
/***************************************************************/
863
PRIVATE int FOrd(void)
871
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
878
if (u == 1 && t != 11) s = "st";
879
if (u == 2 && t != 12) s = "nd";
880
if (u == 3 && t != 13) s = "rd";
881
sprintf(Buffer, "%d%s", v, s);
882
return RetStrVal(Buffer);
885
/***************************************************************/
887
/* FPlural - pluralization function */
889
/* plural(n) --> "" or "s" */
890
/* plural(n, str) --> "str" or "strs" */
891
/* plural(n, str1, str2) --> "str1" or "str2" */
893
/***************************************************************/
895
PRIVATE int FPlural(void)
900
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
904
if (ARG(0).v.val == 1) return RetStrVal("");
905
else return RetStrVal("s");
908
if (ARG(1).type != STR_TYPE) return E_BAD_TYPE;
909
if (ARG(0).v.val == 1) {
910
DCOPYVAL(RetVal, ARG(1));
913
RetVal.type = STR_TYPE;
914
RetVal.v.str = (char *) malloc(strlen(ARG(1).v.str)+2);
916
RetVal.type = ERR_TYPE;
919
strcpy(RetVal.v.str, ARG(1).v.str);
920
strcat(RetVal.v.str, "s");
924
if (ARG(1).type != STR_TYPE || ARG(2).type != STR_TYPE)
926
if (ARG(0).v.val == 1) DCOPYVAL(RetVal, ARG(1));
927
else DCOPYVAL(RetVal, ARG(2));
932
/***************************************************************/
935
/* Choose the nth value from a list of value. If n<1, choose */
936
/* first. If n>N, choose Nth value. Indexes always start */
939
/***************************************************************/
941
PRIVATE int FChoose(void)
948
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
951
if (v > Nargs-1) v = Nargs-1;
952
DCOPYVAL(RetVal, ARG(v));
956
/***************************************************************/
958
/* FVersion - version of Remind */
960
/***************************************************************/
962
PRIVATE int FVersion(void)
964
static int FVersion()
967
return RetStrVal(VERSION);
970
/***************************************************************/
972
/* FOstype - the type of operating system */
973
/* (UNIX, OS/2, or MSDOS) */
975
/***************************************************************/
977
PRIVATE int FOstype(void)
983
return RetStrVal("UNIX");
986
return RetStrVal(OS2MODE ? "OS/2" : "MSDOS");
989
return RetStrVal("QDOS / SMSQ");
992
return RetStrVal("AmigaDOS");
994
return RetStrVal("MSDOS");
1001
/***************************************************************/
1003
/* FUpper - convert string to upper-case */
1004
/* FLower - convert string to lower-case */
1006
/***************************************************************/
1008
PRIVATE int FUpper(void)
1015
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1016
DCOPYVAL(RetVal, ARG(0));
1026
PRIVATE int FLower(void)
1033
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1034
DCOPYVAL(RetVal, ARG(0));
1043
/***************************************************************/
1045
/* FToday - return the system's notion of "today" */
1046
/* Frealtoday - return today's date as read from OS. */
1047
/* FNow - return the system time (or time on cmd line.) */
1048
/* FRealnow - return the true system time */
1050
/***************************************************************/
1052
PRIVATE int FToday(void)
1057
RetVal.type = DATE_TYPE;
1058
RetVal.v.val = JulianToday;
1063
PRIVATE int FRealtoday(void)
1065
static int FRealtoday()
1068
RetVal.type = DATE_TYPE;
1069
RetVal.v.val = RealToday;
1074
PRIVATE int FNow(void)
1079
RetVal.type = TIM_TYPE;
1080
RetVal.v.val = (int) ( SystemTime(0) / 60L );
1085
PRIVATE int FRealnow(void)
1087
static int FRealnow()
1090
RetVal.type = TIM_TYPE;
1091
RetVal.v.val = (int) ( SystemTime(1) / 60L );
1094
/***************************************************************/
1096
/* FGetenv - get the value of an environment variable. */
1098
/***************************************************************/
1100
PRIVATE int FGetenv(void)
1102
static int FGetenv()
1105
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1106
return RetStrVal(getenv(ARG(0).v.str));
1109
/***************************************************************/
1113
/* Get the value of a variable. If a second arg is supplied, */
1114
/* it is returned if variable is undefined. */
1116
/***************************************************************/
1118
PRIVATE int FValue(void)
1125
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1128
return GetVarValue(ARG(0).v.str, &RetVal, NULL);
1131
v = FindVar(ARG(0).v.str, 0);
1133
DCOPYVAL(RetVal, ARG(1));
1136
return CopyValue(&RetVal, &v->v);
1142
/***************************************************************/
1146
/* Return 1 if a variable is defined, 0 if it is not. */
1148
/***************************************************************/
1150
PRIVATE int FDefined(void)
1152
static int FDefined()
1155
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1157
RetVal.type = INT_TYPE;
1159
if (FindVar(ARG(0).v.str, 0))
1166
/***************************************************************/
1168
/* FTrigdate and FTrigtime */
1170
/* Date and time of last trigger. These are stored in global */
1173
/***************************************************************/
1175
PRIVATE int FTrigdate(void)
1177
static int FTrigdate()
1180
RetVal.type = DATE_TYPE;
1181
RetVal.v.val = LastTriggerDate;
1186
PRIVATE int FTrigvalid(void)
1188
static int FTrigvalid()
1191
RetVal.type = INT_TYPE;
1192
RetVal.v.val = LastTrigValid;
1197
PRIVATE int FTrigtime(void)
1199
static int FTrigtime()
1202
RetVal.type = TIM_TYPE;
1203
RetVal.v.val = LastTriggerTime;
1207
/***************************************************************/
1211
/* Returns the number of days in mon,yr */
1213
/***************************************************************/
1215
PRIVATE int FDaysinmon(void)
1217
static int FDaysinmon()
1220
if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
1222
if (ARG(0).v.val > 12 || ARG(0).v.val < 1 ||
1223
ARG(1).v.val < BASE || ARG(1).v.val > BASE+YR_RANGE)
1224
return E_DOMAIN_ERR;
1226
RetVal.type = INT_TYPE;
1227
RetVal.v.val = DaysInMonth(ARG(0).v.val-1, ARG(1).v.val);
1231
/***************************************************************/
1235
/* Return 1 if year is a leap year, zero otherwise. */
1237
/***************************************************************/
1239
PRIVATE int FIsleap(void)
1241
static int FIsleap()
1246
if (ARG(0).type != INT_TYPE && ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1248
/* If it's a date, extract the year */
1249
if (ARG(0).type == DATE_TYPE)
1250
FromJulian(ARG(0).v.val, &y, &m, &d);
1254
RetVal.type = INT_TYPE;
1255
RetVal.v.val = IsLeapYear(y);
1259
/***************************************************************/
1263
/* Put out a date in a format suitable for triggering. */
1265
/***************************************************************/
1267
PRIVATE int FTrigger(void)
1269
static int FTrigger()
1276
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1277
date = ARG(0).v.val;
1279
if (ARG(2).type != INT_TYPE) return E_BAD_TYPE;
1280
if (ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
1282
UTCToLocal(ARG(0).v.val, ARG(1).v.val, &date, &time);
1284
date = ARG(0).v.val;
1285
time = ARG(1).v.val;
1288
FromJulian(date, &y, &m, &d);
1290
if (ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
1291
if (Nargs == 2) time = ARG(1).v.val;
1292
sprintf(buf, "%d %s %d AT %02d:%02d", d, EnglishMonthName[m], y,
1295
sprintf(buf, "%d %s %d", d, EnglishMonthName[m], y);
1297
return RetStrVal(buf);
1300
/***************************************************************/
1304
/* The shell function. */
1306
/* If run is disabled, will not be executed. */
1308
/***************************************************************/
1310
PRIVATE int FShell(void)
1319
/* For compatibility with previous versions of Remind, which
1320
used a static buffer for reading results from shell() command */
1324
if (RunDisabled) return E_RUN_DISABLED;
1325
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1327
if (ARG(1).type != INT_TYPE) return E_BAD_TYPE;
1328
maxlen = ARG(1).v.val;
1330
fp = POPEN(ARG(0).v.str, "r");
1331
if (!fp) return E_IO_ERR;
1337
if (isspace(ch)) ch = ' ';
1338
if (DBufPutc(&buf, (char) ch) != OK) {
1343
if (maxlen > 0 && DBufLen(&buf) >= maxlen) {
1348
/* Delete trailing newline (converted to space) */
1349
if (DBufLen(&buf) && DBufValue(&buf)[DBufLen(&buf)-1] == ' ') {
1350
DBufValue(&buf)[DBufLen(&buf)-1] = 0;
1352
#if defined(__MSDOS__) || defined(__OS2__)
1353
if (DBufLen(&buf) > 1 && DBufValue(&buf)[DBufLen(&buf)-2] == ' ') {
1354
DBufValue(&buf)[DBufLen(&buf)-2] = 0;
1358
r = RetStrVal(DBufValue(&buf));
1363
/***************************************************************/
1367
/* Is a date omitted? */
1369
/***************************************************************/
1371
PRIVATE int FIsomitted(void)
1373
static int FIsomitted()
1376
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1377
RetVal.type = INT_TYPE;
1378
RetVal.v.val = IsOmitted(ARG(0).v.val, 0);
1382
/***************************************************************/
1386
/* The substr function. We destroy the value on the stack. */
1388
/***************************************************************/
1390
PRIVATE int FSubstr(void)
1392
static int FSubstr()
1398
if (ARG(0).type != STR_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
1399
if (Nargs == 3 && ARG(2).type != INT_TYPE) return E_BAD_TYPE;
1403
while (start < ARG(1).v.val) {
1408
if (Nargs == 2 || !*s) return RetStrVal(s);
1411
while (end <= ARG(2).v.val) {
1417
return RetStrVal(t);
1420
/***************************************************************/
1424
/* The index of one string embedded in another. */
1426
/***************************************************************/
1428
PRIVATE int FIndex(void)
1436
if (ARG(0).type != STR_TYPE || ARG(1).type != STR_TYPE ||
1437
(Nargs == 3 && ARG(2).type != INT_TYPE)) return E_BAD_TYPE;
1441
/* If 3 args, bump up the start */
1444
while (start < ARG(2).v.val) {
1451
/* Find the string */
1452
s = strstr(s, ARG(1).v.str);
1453
RetVal.type = INT_TYPE;
1458
RetVal.v.val = (s - ARG(0).v.str) + 1;
1462
/***************************************************************/
1466
/* The IIF function. */
1468
/***************************************************************/
1470
PRIVATE int FIif(void)
1478
if (!(Nargs % 2)) return E_IIF_ODD;
1480
for (arg=0; arg<Nargs-1; arg += 2) {
1481
if (ARG(arg).type != STR_TYPE && ARG(arg).type != INT_TYPE)
1484
if (ARG(arg).type == INT_TYPE)
1485
istrue = ARG(arg).v.val;
1487
istrue = *(ARG(arg).v.str);
1490
DCOPYVAL(RetVal, ARG(arg+1));
1495
DCOPYVAL(RetVal, ARG(Nargs-1));
1499
/***************************************************************/
1503
/* Return name of current file */
1505
/***************************************************************/
1507
PRIVATE int FFilename(void)
1509
static int FFilename()
1512
return RetStrVal(FileName);
1515
/***************************************************************/
1519
/* Return directory of current file */
1521
/***************************************************************/
1523
PRIVATE int FFiledir(void)
1525
static int FFiledir()
1534
if (DBufPuts(&buf, FileName) != OK) return E_NO_MEM;
1535
if (DBufLen(&buf) == 0) {
1537
return RetStrVal(".");
1540
s = DBufValue(&buf) + DBufLen(&buf) - 1;
1541
#if defined(__OS2__) || defined(__MSDOS__)
1542
/* Both '\\' and '/' can be part of path; handle drive letters. */
1543
while (s > DBufValue(&buf) && !strchr("\\/:", *s)) s--;
1544
if (*s == ':') { s[1] = '.'; s += 2; }
1545
if (s > DBufValue(&buf)) *s = '/';
1547
while (s > DBufValue(&buf) && *s != '/') s--;
1551
r = RetStrVal(DBufValue(&buf));
1552
} else r = RetStrVal(".");
1556
/***************************************************************/
1560
/* The UNIX access() system call. */
1562
/***************************************************************/
1564
PRIVATE int FAccess(void)
1566
static int FAccess()
1572
if (ARG(0).type != STR_TYPE ||
1573
(ARG(1).type != INT_TYPE && ARG(1).type != STR_TYPE)) return E_BAD_TYPE;
1575
if (ARG(1).type == INT_TYPE) amode = ARG(1).v.val;
1582
case 'R': amode |= R_OK; break;
1584
case 'W': amode |= W_OK; break;
1586
case 'X': amode |= X_OK; break;
1590
RetVal.type = INT_TYPE;
1591
RetVal.v.val = access(ARG(0).v.str, amode);
1595
#if defined(__MSDOS__) || defined(__BORLANDC__) || defined(AMIGA)
1596
/***************************************************************/
1598
/* popen and pclose */
1600
/* These are some rather brain-dead kludges for MSDOS. */
1601
/* They are just sufficient for the shell() function, and */
1602
/* should NOT be viewed as general-purpose replacements */
1603
/* for the UNIX system calls. */
1605
/***************************************************************/
1610
static char *TmpFile;
1612
PRIVATE FILE *os_popen(char *cmd, char *mode)
1614
static FILE *os_popen(cmd, mode)
1620
#if defined(__OS2__) && !defined(__BORLANDC__)
1622
return(popen(cmd, mode));
1625
TmpFile = tmpnam(NULL);
1626
if (!TmpFile) return NULL;
1627
s = (char *) malloc(strlen(cmd) + 3 + strlen(TmpFile) + 1);
1628
if (!s) return NULL;
1634
return fopen(TmpFile, "r");
1638
PRIVATE int os_pclose(FILE *fp)
1640
static int os_pclose(fp)
1644
#if defined(__OS2__) && !defined(__BORLANDC__)
1658
/***************************************************************/
1662
/* Implement the typeof() function. */
1664
/***************************************************************/
1666
PRIVATE int FTypeof(void)
1668
static int FTypeof()
1671
switch(ARG(0).type) {
1672
case INT_TYPE: return RetStrVal("INT");
1673
case DATE_TYPE: return RetStrVal("DATE");
1674
case TIM_TYPE: return RetStrVal("TIME");
1675
case STR_TYPE: return RetStrVal("STRING");
1676
default: return RetStrVal("ERR");
1680
/***************************************************************/
1684
/* Implement the language() function. */
1686
/***************************************************************/
1688
PRIVATE int FLanguage(void)
1690
static int FLanguage()
1693
return RetStrVal(L_LANGNAME);
1696
/***************************************************************/
1700
/* Implement the args() function. */
1702
/***************************************************************/
1704
PRIVATE int FArgs(void)
1709
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1710
RetVal.type = INT_TYPE;
1711
RetVal.v.val = UserFuncExists(ARG(0).v.str);
1715
/***************************************************************/
1719
/* Implement the dosubst() function. */
1721
/***************************************************************/
1723
PRIVATE int FDosubst(void)
1725
static int FDosubst()
1735
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
1737
if (ARG(1).type != DATE_TYPE) return E_BAD_TYPE;
1740
if (ARG(2).type != TIM_TYPE) return E_BAD_TYPE;
1745
if ((r=DoSubstFromString(ARG(0).v.str, &buf, jul, tim))) return r;
1746
r = RetStrVal(DBufValue(&buf));
1751
/***************************************************************/
1758
/* Hebrew calendar support functions */
1760
/***************************************************************/
1762
PRIVATE int FHebdate(void)
1764
static int FHebdate()
1767
int year, day, mon, jahr;
1772
if (ARG(0).type != INT_TYPE || ARG(1).type != STR_TYPE) return E_BAD_TYPE;
1774
mon = HebNameToNum(ARG(1).v.str);
1775
if (mon < 0) return E_BAD_HEBDATE;
1777
r = GetNextHebrewDate(JulianToday, mon, day, 0, 0, &ans);
1779
RetVal.type = DATE_TYPE;
1784
if (ARG(4).type != INT_TYPE) return E_BAD_TYPE;
1785
adarbehave = ARG(4).v.val;
1786
if (adarbehave < 0) return E_2LOW;
1787
if (adarbehave > 2) return E_2HIGH;
1788
} else adarbehave = 0;
1791
if (ARG(3).type != INT_TYPE) return E_BAD_TYPE;
1792
jahr = ARG(3).v.val;
1793
if (jahr < 0) return E_2LOW;
1795
r = ComputeJahr(jahr, mon, day, &jahr);
1801
if (ARG(2).type == INT_TYPE) {
1802
year = ARG(2).v.val;
1803
r = GetValidHebDate(year, mon, day, 0, &mout, &dout, jahr);
1805
r = HebToJul(year, mout, dout);
1806
if (r<0) return E_DATE_OVER;
1808
RetVal.type = DATE_TYPE;
1810
} else if (ARG(2).type == DATE_TYPE) {
1811
r = GetNextHebrewDate(ARG(2).v.val, mon, day, jahr, adarbehave, &ans);
1814
RetVal.type = DATE_TYPE;
1816
} else return E_BAD_TYPE;
1820
PRIVATE int FHebday(void)
1822
static int FHebday()
1827
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1828
if (ARG(0).v.val == CacheHebJul)
1831
JulToHeb(ARG(0).v.val, &y, &m, &d);
1832
CacheHebJul = ARG(0).v.val;
1837
RetVal.type = INT_TYPE;
1843
PRIVATE int FHebmon(void)
1845
static int FHebmon()
1850
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1851
if (ARG(0).v.val == CacheHebJul) {
1855
JulToHeb(ARG(0).v.val, &y, &m, &d);
1856
CacheHebJul = ARG(0).v.val;
1861
return RetStrVal(HebMonthName(m, y));
1865
PRIVATE int FHebyear(void)
1867
static int FHebyear()
1872
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1873
if (ARG(0).v.val == CacheHebJul)
1876
JulToHeb(ARG(0).v.val, &y, &m, &d);
1877
CacheHebJul = ARG(0).v.val;
1882
RetVal.type = INT_TYPE;
1886
/****************************************************************/
1888
/* FEasterdate - calc. easter Sunday from a year. */
1890
/* from The Art of Computer Programming Vol 1. */
1891
/* Fundamental Algorithms */
1892
/* by Donald Knuth. */
1894
/* Donated by Michael Salmon - thanks! */
1896
/* I haven't examined this in detail, but I *think* int */
1897
/* arithmetic is fine, even on 16-bit machines. */
1899
/****************************************************************/
1901
PRIVATE int FEasterdate(void)
1903
static int FEasterdate()
1907
int g, c, x, z, e, n;
1908
if (ARG(0).type == INT_TYPE) {
1910
if (y < BASE) return E_2LOW;
1911
else if (y > BASE+YR_RANGE) return E_2HIGH;
1912
} else if (ARG(0).type == DATE_TYPE) {
1913
FromJulian(ARG(0).v.val, &y, &m, &d); /* We just want the year */
1914
} else return E_BAD_TYPE;
1917
g = (y % 19) + 1; /* golden number */
1918
c = (y / 100) + 1; /* century */
1919
x = (3 * c)/4 - 12; /* correction for non-leap year centuries */
1920
z = (8 * c + 5)/25 - 5; /* special constant for moon sync */
1921
d = (5 * y)/4 - x - 10; /* find sunday */
1922
e = (11 * g + 20 + z - x) % 30; /* calc epact */
1923
if ( e < 0 ) e += 30;
1924
if ( e == 24 || (e == 25 && g > 11)) e++;
1925
n = 44 - e; /* find full moon */
1926
if ( n < 21 ) n += 30; /* after 21st */
1927
d = n + 7 - (d + n)%7; /* calc sunday after */
1935
RetVal.type = DATE_TYPE;
1936
RetVal.v.val = Julian(y, m, d);
1937
y++; } while (ARG(0).type == DATE_TYPE && RetVal.v.val < ARG(0).v.val);
1941
/***************************************************************/
1943
/* FIsdst and FMinsfromutc */
1945
/* Check whether daylight savings time is in effect, and */
1946
/* get minutes from UTC. */
1948
/***************************************************************/
1949
PRIVATE int FTimeStuff ARGS ((int wantmins));
1951
PRIVATE int FIsdst(void)
1956
return FTimeStuff(0);
1960
PRIVATE int FMinsfromutc(void)
1962
static int FMinsfromutc()
1965
return FTimeStuff(1);
1969
PRIVATE int FTimeStuff(int wantmins)
1971
static int FTimeStuff(wantmins)
1982
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
1985
if (ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
1990
if (CalcMinsFromUTC(jul, tim, &mins, &dst)) return E_MKTIME_PROBLEM;
1991
RetVal.type = INT_TYPE;
1992
if (wantmins) RetVal.v.val = mins; else RetVal.v.val = dst;
1997
/***************************************************************/
1999
/* Sunrise and sunset functions. */
2001
/* Algorithm from "Almanac for computers for the year 1978" */
2002
/* by L. E. Doggett, Nautical Almanac Office, USNO. */
2004
/* This code also uses some ideas found in programs written */
2005
/* by Michael Schwartz and Marc T. Kaufman. */
2007
/***************************************************************/
2011
#define PI 3.14159265358979323846
2012
#define DEGRAD (PI/180.0)
2013
#define RADDEG (180.0/PI)
2016
PRIVATE int SunStuff(int rise, double cosz, int jul)
2018
static int SunStuff(rise, cosz, jul)
2029
double M, L, tanA, sinDelta, cosDelta, a, a_hr, cosH, t, H, T;
2030
double latitude, longdeg, UT, local;
2032
/* Get offset from UTC */
2034
if (CalcMinsFromUTC(jul, 12*60, &mins, NULL)) {
2035
Eprint(ErrMsg[E_MKTIME_PROBLEM]);
2038
} else mins = MinsFromUTC;
2040
/* Get latitude and longitude */
2041
longdeg = (double) LongDeg + (double) LongMin / 60.0
2042
+ (double) LongSec / 3600.0;
2044
latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
2045
+ (double) LatSec / 3600.0);
2048
FromJulian(jul, &year, &mon, &day);
2049
jan0 = jul - Julian(year, 0, 1);
2051
dusk_or_dawn = rise;
2054
/* Following formula on page B6 exactly... */
2056
if (rise) t += (6.0 + longdeg/15.0) / 24.0;
2057
else t += (18.0 + longdeg/15.0) / 24.0;
2059
/* Mean anomaly of sun for 1978 ... how accurate for other years??? */
2060
M = 0.985600 * t - 3.251; /* In degrees */
2062
/* Sun's true longitude */
2063
L = M + 1.916*sin(DEGRAD*M) + 0.02*sin(2*DEGRAD*M) + 282.565;
2064
if (dusk_or_dawn == 2) {/* dusk */
2066
} else if (dusk_or_dawn == 3) {/* dawn */
2069
if (L > 360.0) L -= 360.0;
2071
/* Tan of sun's right ascension */
2072
tanA = 0.91746 * tan(DEGRAD*L);
2073
a = RADDEG * atan(tanA);
2075
/* Move a into same quadrant as L */
2076
if (0.0 <= L && L < 90.0) {
2077
if (a < 0.0) a += 180.0;
2078
} else if (90.0 <= L && L < 180.0) {
2080
} else if (180.0 <= L && L < 270.0) {
2083
if (a > 0.0) a += 180.0;
2085
/* if (fabs(a - L) > 90.0)
2092
/* Sine of sun's declination */
2093
sinDelta = 0.39782 * sin(DEGRAD*L);
2094
cosDelta = sqrt(1 - sinDelta*sinDelta);
2096
/* Cosine of sun's local hour angle */
2097
cosH = (cosz - sinDelta * sin(latitude)) / (cosDelta * cos(latitude));
2099
if (cosH < -1.0) { /* Summer -- permanent daylight */
2100
if (rise) return NO_TIME;
2101
else return -NO_TIME;
2103
if (cosH > 1.0) { /* Winter -- permanent darkness */
2104
if (rise) return -NO_TIME;
2105
else return NO_TIME;
2108
H = RADDEG * acos(cosH);
2109
if (rise) H = 360.0 - H;
2111
T = H / 15.0 + a_hr - 0.065710*t - 6.620;
2112
if (T >= 24.0) T -= 24.0;
2113
else if (T < 0.0) T+= 24.0;
2115
UT = T + longdeg / 15.0;
2118
local = UT + (double) mins / 60.0;
2119
if (local < 0.0) local += 24.0;
2120
else if (local >= 24.0) local -= 24.0;
2122
hours = (int) local;
2123
mins = (int) ((local - hours) * 60.0);
2125
/* Sometimes, we get roundoff error. Check for "reasonableness" of
2128
/* Sunrise so close to midnight it wrapped around -- permament light */
2129
if (hours >= 23) return NO_TIME;
2131
/* Sunset so close to midnight it wrapped around -- permament light */
2132
if (hours <= 1) return -NO_TIME;
2134
return hours*60 + mins;
2137
/***************************************************************/
2139
/* Sunrise and Sunset functions. */
2141
/***************************************************************/
2143
PRIVATE int FSun(int rise)
2145
static int FSun(rise)
2149
int jul = JulianToday;
2150
static double cosz = -0.014543897; /* for sunrise and sunset */
2154
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
2158
r = SunStuff(rise, cosz, jul);
2161
RetVal.type = INT_TYPE;
2162
} else if (r == -NO_TIME) {
2163
RetVal.v.val = 1440;
2164
RetVal.type = INT_TYPE;
2167
RetVal.type = TIM_TYPE;
2173
PRIVATE int FSunrise(void)
2175
static int FSunrise()
2181
PRIVATE int FSunset(void)
2183
static int FSunset()
2190
PRIVATE int FDawn(void)
2198
PRIVATE int FDusk(void)
2206
/***************************************************************/
2210
/* Return modification date of a file */
2212
/***************************************************************/
2214
PRIVATE int FFiledate(void)
2216
static int FFiledate()
2219
struct stat statbuf;
2222
RetVal.type = DATE_TYPE;
2224
if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
2226
if (stat(ARG(0).v.str, &statbuf)) {
2232
t1 = localtime( (time_t *) &(statbuf.st_mtime) );
2234
t1 = localtime(&(statbuf.st_mtime));
2237
if (t1->tm_year + 1900 < BASE)
2240
RetVal.v.val=Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday);
2245
/***************************************************************/
2249
/* Canned PostScript code for shading a calendar square */
2251
/***************************************************************/
2253
PRIVATE int FPsshade(void)
2255
static int FPsshade()
2263
if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
2265
for (i=0; i<Nargs; i++) {
2266
if (ARG(i).type != INT_TYPE) return E_BAD_TYPE;
2267
if (ARG(i).v.val < 0) return E_2LOW;
2268
if (ARG(i).v.val > 100) return E_2HIGH;
2271
sprintf(s, "/_A LineWidth 2 div def ");
2273
sprintf(s, "_A _A moveto ");
2275
sprintf(s, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
2278
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARG(0).v.val);
2280
sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div %d 100 div %d 100 div setrgbcolor fill 0.0 setgray", ARG(0).v.val, ARG(1).v.val, ARG(2).v.val);
2282
return RetStrVal(psbuff);
2285
/***************************************************************/
2289
/* Canned PostScript code for generating moon phases */
2291
/***************************************************************/
2293
PRIVATE int FPsmoon(void)
2295
static int FPsmoon()
2300
char fontsizebuf[30];
2306
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
2307
if (ARG(0).v.val < 0) return E_2LOW;
2308
if (ARG(0).v.val > 3) return E_2HIGH;
2310
if (ARG(1).type != INT_TYPE) return E_BAD_TYPE;
2311
if (ARG(1).v.val < -1) return E_2LOW;
2312
size = ARG(1).v.val;
2314
if (ARG(2).type != STR_TYPE) return E_BAD_TYPE;
2315
extra = ARG(2).v.str;
2317
if (ARG(3).type != INT_TYPE) return E_BAD_TYPE;
2318
if (ARG(3).v.val <= 0) return E_2LOW;
2319
fontsize = ARG(3).v.val;
2324
sprintf(sizebuf, "%d", size);
2326
strcpy(sizebuf, "DaySize 2 div");
2330
sprintf(fontsizebuf, "%d", fontsize);
2332
strcpy(fontsizebuf, "EntrySize");
2335
sprintf(s, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
2338
sprintf(s, " %s 0 360 arc closepath", sizebuf);
2340
switch(ARG(0).v.val) {
2342
sprintf(s, " fill");
2347
sprintf(s, " stroke");
2352
sprintf(s, " stroke");
2354
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
2357
sprintf(s, " %s 90 270 arc closepath fill", sizebuf);
2362
sprintf(s, " stroke");
2364
sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
2367
sprintf(s, " %s 270 90 arc closepath fill", sizebuf);
2372
sprintf(s, " Border %s add %s add Border add BoxHeight border sub %s sub %s sub moveto /EntryFont findfont %s scalefont setfont (%s) show",
2373
sizebuf, sizebuf, sizebuf, sizebuf, fontsizebuf, extra);
2377
sprintf(s, " grestore");
2378
return RetStrVal(psbuff);
2381
/***************************************************************/
2385
/* Phase of moon for specified date/time. */
2387
/***************************************************************/
2389
PRIVATE int FMoonphase(void)
2391
static int FMoonphase()
2402
if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
2403
date = ARG(0).v.val;
2407
if (ARG(0).type != DATE_TYPE && ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
2408
date = ARG(0).v.val;
2409
time = ARG(1).v.val;
2412
default: return E_SWERR;
2415
RetVal.type = INT_TYPE;
2416
RetVal.v.val = MoonPhase(date, time);
2420
/***************************************************************/
2424
/* Hunt for next occurrence of specified moon phase */
2426
/***************************************************************/
2427
PRIVATE int MoonStuff ARGS ((int want_time));
2429
PRIVATE int FMoondate(void)
2431
static int FMoondate()
2434
return MoonStuff(0);
2438
PRIVATE int FMoontime(void)
2440
static int FMoontime()
2443
return MoonStuff(1);
2447
PRIVATE int MoonStuff(int want_time)
2449
static int MoonStuff(want_time)
2453
int startdate, starttim;
2456
startdate = JulianToday;
2459
if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
2460
if (ARG(0).v.val < 0) return E_2LOW;
2461
if (ARG(0).v.val > 3) return E_2HIGH;
2463
if (ARG(1).type != DATE_TYPE) return E_BAD_TYPE;
2464
startdate = ARG(1).v.val;
2466
if (ARG(2).type != TIM_TYPE) return E_BAD_TYPE;
2467
starttim = ARG(2).v.val;
2471
HuntPhase(startdate, starttim, ARG(0).v.val, &d, &t);
2473
RetVal.type = TIM_TYPE;
2476
RetVal.type = DATE_TYPE;