~ubuntu-branches/ubuntu/karmic/remind/karmic

« back to all changes in this revision

Viewing changes to src/funcs.c

  • Committer: Bazaar Package Importer
  • Author(s): Javier Fernandez-Sanguino Pen~a
  • Date: 1999-02-19 13:36:15 UTC
  • Revision ID: james.westby@ubuntu.com-19990219133615-ovob95sord67b0ks
Tags: 03.00.22-1
* NMU upload, maintainer seems to be missing.
* Changed to main (now GPL) (Closes: #42402)
* New upstream version (Closes: #59447)
* Moved to use debconf.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/***************************************************************/
 
2
/*                                                             */
 
3
/*  FUNCS.C                                                    */
 
4
/*                                                             */
 
5
/*  This file contains the built-in functions used in          */
 
6
/*  expressions.                                               */
 
7
/*                                                             */
 
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.   */
 
11
/*                                                             */
 
12
/***************************************************************/
 
13
 
 
14
#include "config.h"
 
15
static char const RCSID[] = "$Id: funcs.c,v 1.9 2000/02/18 03:45:55 dfs Exp $";
 
16
 
 
17
#include <stdio.h>
 
18
 
 
19
#ifdef HAVE_STDLIB_H
 
20
#include <stdlib.h>
 
21
#endif
 
22
 
 
23
#ifdef HAVE_MALLOC_H
 
24
#include <malloc.h>
 
25
#endif
 
26
 
 
27
#include <string.h>
 
28
#include <ctype.h>
 
29
#include <math.h>
 
30
 
 
31
#ifdef HAVE_UNISTD_H
 
32
#include <unistd.h>
 
33
#endif
 
34
 
 
35
#ifdef HAVE_SYS_FILE_H
 
36
#include <sys/file.h>
 
37
#endif
 
38
 
 
39
#ifdef HAVE_SYS_TYPES_H
 
40
#include <sys/types.h>
 
41
#endif
 
42
 
 
43
#include <sys/stat.h>
 
44
 
 
45
#ifdef TM_IN_SYS_TIME
 
46
#include <sys/time.h>
 
47
#else
 
48
#include <time.h>
 
49
#endif
 
50
 
 
51
#if defined(__MSDOS__) || defined(__OS2__)
 
52
#include <io.h>
 
53
#define R_OK 4
 
54
#define W_OK 2
 
55
#define X_OK 1
 
56
#endif
 
57
 
 
58
#ifndef R_OK
 
59
#define R_OK 4
 
60
#define W_OK 2
 
61
#define X_OK 1
 
62
#endif
 
63
 
 
64
#include "types.h"
 
65
#include "globals.h"
 
66
#include "protos.h"
 
67
#include "err.h"
 
68
#include "expr.h"
 
69
#include "version.h"
 
70
 
 
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));
 
143
 
 
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
 
149
 
 
150
#if defined(_MSC_VER)
 
151
#define popen _popen
 
152
#define pclose _pclose
 
153
#endif
 
154
 
 
155
#elif defined(_MSC_VER)
 
156
#define POPEN _popen
 
157
#define PCLOSE _pclose
 
158
 
 
159
#else
 
160
#define POPEN popen
 
161
#define PCLOSE pclose
 
162
#endif
 
163
 
 
164
/* "Overload" the struct Operator definition */
 
165
#define NO_MAX 127
 
166
#define MINARGS prec
 
167
#define MAXARGS type
 
168
 
 
169
/* Sigh - we use a global var. to hold the number of args supplied to
 
170
   function being called */
 
171
static int Nargs;
 
172
 
 
173
/* Use a global var. to hold function return value */
 
174
static Value RetVal;
 
175
 
 
176
/* Temp string buffer */
 
177
static char Buffer[32];
 
178
 
 
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;
 
183
 
 
184
static int CacheHebJul = -1;
 
185
static int CacheHebYear, CacheHebMon, CacheHebDay;
 
186
 
 
187
/* We need access to the value stack */
 
188
extern Value ValStack[];
 
189
extern int ValStackPtr;
 
190
 
 
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)])
 
194
 
 
195
/* Macro for copying a value while destroying original copy */
 
196
#define DCOPYVAL(x, y) ( (x) = (y), (y).type = ERR_TYPE )
 
197
 
 
198
/* Convenience macros */
 
199
#define UPPER(c) (islower(c) ? toupper(c) : c)
 
200
#define LOWER(c) (isupper(c) ? tolower(c) : c)
 
201
 
 
202
/* The array holding the built-in functions. */
 
203
Operator Func[] = {
 
204
/*      Name            minargs maxargs func   */
 
205
 
 
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   }
 
274
};
 
275
 
 
276
/* Need a variable here - Func[] array not really visible to outside. */
 
277
int NumFuncs = sizeof(Func) / sizeof(Operator) ;
 
278
 
 
279
/***************************************************************/
 
280
/*                                                             */
 
281
/*  CallFunc                                                   */
 
282
/*                                                             */
 
283
/*  Call a function given a pointer to it, and the number      */
 
284
/*  of arguments supplied.                                     */
 
285
/*                                                             */
 
286
/***************************************************************/
 
287
#ifdef HAVE_PROTOS
 
288
PUBLIC int CallFunc(Operator *f, int nargs)
 
289
#else
 
290
int CallFunc(f, nargs)
 
291
Operator *f;
 
292
int nargs;
 
293
#endif
 
294
{
 
295
    register int r = CheckArgs(f, nargs);
 
296
    int i;
 
297
 
 
298
    Nargs = nargs;
 
299
 
 
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, ", ");
 
306
        }
 
307
        fprintf(ErrFp, ") => ");
 
308
        if (r) {
 
309
            fprintf(ErrFp, "%s\n", ErrMsg[r]);
 
310
            return r;
 
311
        }
 
312
    }
 
313
    if (r) {
 
314
        Eprint("%s(): %s", f->name, ErrMsg[r]);
 
315
        return r;
 
316
    }
 
317
 
 
318
    r = (*(f->func))();
 
319
    if (r) {
 
320
        DestroyValue(RetVal);
 
321
        if (DebugFlag & DB_PRTEXPR)
 
322
            fprintf(ErrFp, "%s\n", ErrMsg[r]);
 
323
        else
 
324
            Eprint("%s(): %s", f->name, ErrMsg[r]);
 
325
        return r;
 
326
    }
 
327
    if (DebugFlag & DB_PRTEXPR) {
 
328
        PrintValue(&RetVal, ErrFp);
 
329
        fprintf(ErrFp, "\n");
 
330
    }
 
331
    r = CleanUpAfterFunc();
 
332
    return r;
 
333
}
 
334
 
 
335
/***************************************************************/
 
336
/*                                                             */
 
337
/*  CheckArgs                                                  */
 
338
/*                                                             */
 
339
/*  Check that the right number of args have been supplied     */
 
340
/*  for a function.                                            */
 
341
/*                                                             */
 
342
/***************************************************************/
 
343
#ifdef HAVE_PROTOS
 
344
PRIVATE int CheckArgs(Operator *f, int nargs)
 
345
#else
 
346
static int CheckArgs(f, nargs)
 
347
Operator *f;
 
348
int nargs;
 
349
#endif
 
350
{
 
351
    if (nargs < f->MINARGS) return E_2FEW_ARGS;
 
352
    if (nargs > f->MAXARGS && f->MAXARGS != NO_MAX) return E_2MANY_ARGS;
 
353
    return OK;
 
354
}
 
355
/***************************************************************/
 
356
/*                                                             */
 
357
/*  CleanUpAfterFunc                                           */
 
358
/*                                                             */
 
359
/*  Clean up the stack after a function call - remove          */
 
360
/*  args and push the new value.                               */
 
361
/*                                                             */
 
362
/***************************************************************/
 
363
#ifdef HAVE_PROTOS
 
364
PRIVATE int CleanUpAfterFunc(void)
 
365
#else
 
366
static int CleanUpAfterFunc()
 
367
#endif
 
368
{
 
369
    Value v;
 
370
    int i;
 
371
 
 
372
    for (i=0; i<Nargs; i++) {
 
373
        PopValStack(v);
 
374
        DestroyValue(v);
 
375
    }
 
376
    PushValStack(RetVal);
 
377
    return OK;
 
378
}
 
379
 
 
380
/***************************************************************/
 
381
/*                                                             */
 
382
/*  RetStrVal                                                  */
 
383
/*                                                             */
 
384
/*  Return a string value from a function.                     */
 
385
/*                                                             */
 
386
/***************************************************************/
 
387
#ifdef HAVE_PROTOS
 
388
PRIVATE int RetStrVal(const char *s)
 
389
#else
 
390
static int RetStrVal(s)
 
391
char *s;
 
392
#endif
 
393
{
 
394
    RetVal.type = STR_TYPE;
 
395
    if (!s) {
 
396
        RetVal.v.str = (char *) malloc(1);
 
397
        if (RetVal.v.str) *RetVal.v.str = 0;
 
398
    } else
 
399
        RetVal.v.str = StrDup(s);
 
400
 
 
401
    if (!RetVal.v.str) {
 
402
        RetVal.type = ERR_TYPE;
 
403
        return E_NO_MEM;
 
404
    }
 
405
    return OK;
 
406
}
 
407
 
 
408
 
 
409
/***************************************************************/
 
410
/*                                                             */
 
411
/*  FStrlen - string length                                    */
 
412
/*                                                             */
 
413
/***************************************************************/
 
414
#ifdef HAVE_PROTOS
 
415
PRIVATE int FStrlen(void)
 
416
#else
 
417
static int FStrlen()
 
418
#endif
 
419
{
 
420
    Value *v = &ARG(0);
 
421
    if (v->type != STR_TYPE) return E_BAD_TYPE;
 
422
    RetVal.type = INT_TYPE;
 
423
    RetVal.v.val = strlen(v->v.str);
 
424
    return OK;
 
425
}
 
426
 
 
427
/***************************************************************/
 
428
/*                                                             */
 
429
/*  FBaseyr - system base year                                 */
 
430
/*                                                             */
 
431
/***************************************************************/
 
432
#ifdef HAVE_PROTOS
 
433
PRIVATE int FBaseyr(void)
 
434
#else
 
435
static int FBaseyr()
 
436
#endif
 
437
{
 
438
    RetVal.type = INT_TYPE;
 
439
    RetVal.v.val = BASE;
 
440
    return OK;
 
441
}
 
442
 
 
443
/***************************************************************/
 
444
/*                                                             */
 
445
/*  FDate - make a date from year, month, day.                 */
 
446
/*                                                             */
 
447
/***************************************************************/
 
448
#ifdef HAVE_PROTOS
 
449
PRIVATE int FDate(void)
 
450
#else
 
451
static int FDate()
 
452
#endif
 
453
{
 
454
    int y, m, d;
 
455
    if (ARG(0).type != INT_TYPE ||
 
456
        ARG(1).type != INT_TYPE ||
 
457
        ARG(2).type != INT_TYPE) return E_BAD_TYPE;
 
458
    y = ARG(0).v.val;
 
459
    m = ARG(1).v.val - 1;
 
460
    d = ARG(2).v.val;
 
461
 
 
462
    if (!DateOK(y, m, d)) return E_BAD_DATE;
 
463
 
 
464
    RetVal.type = DATE_TYPE;
 
465
    RetVal.v.val = Julian(y, m, d);
 
466
    return OK;
 
467
}
 
468
 
 
469
/***************************************************************/
 
470
/*                                                             */
 
471
/*  FCoerce - type coercion function.                          */
 
472
/*                                                             */
 
473
/***************************************************************/
 
474
#ifdef HAVE_PROTOS
 
475
PRIVATE int FCoerce(void)
 
476
#else
 
477
static int FCoerce()
 
478
#endif
 
479
{
 
480
    char *s;
 
481
 
 
482
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
483
    s = ARG(0).v.str;
 
484
 
 
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));
 
488
 
 
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;
 
494
}
 
495
 
 
496
/***************************************************************/
 
497
/*                                                             */
 
498
/*  FMax - select maximum from a list of args.                 */
 
499
/*                                                             */
 
500
/***************************************************************/
 
501
#ifdef HAVE_PROTOS
 
502
PRIVATE int FMax(void)
 
503
#else
 
504
static int FMax()
 
505
#endif
 
506
{
 
507
    Value *maxptr;
 
508
    int i;
 
509
    char type;
 
510
 
 
511
    maxptr = &ARG(0);
 
512
    type = maxptr->type;
 
513
 
 
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);
 
518
        } else {
 
519
            if (strcmp(ARG(i).v.str, maxptr->v.str) > 0) maxptr = &ARG(i);
 
520
        }
 
521
    }
 
522
    DCOPYVAL(RetVal, *maxptr);
 
523
    return OK;
 
524
}
 
525
 
 
526
/***************************************************************/
 
527
/*                                                             */
 
528
/*  FMin - select minimum from a list of args.                 */
 
529
/*                                                             */
 
530
/***************************************************************/
 
531
#ifdef HAVE_PROTOS
 
532
PRIVATE int FMin(void)
 
533
#else
 
534
static int FMin()
 
535
#endif
 
536
{
 
537
    Value *minptr;
 
538
    int i;
 
539
    char type;
 
540
 
 
541
    minptr = &ARG(0);
 
542
    type = minptr->type;
 
543
 
 
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);
 
548
        } else {
 
549
            if (strcmp(ARG(i).v.str, minptr->v.str) < 0) minptr = &ARG(i);
 
550
        }
 
551
    }
 
552
    DCOPYVAL(RetVal, *minptr);
 
553
    return OK;
 
554
}
 
555
 
 
556
/***************************************************************/
 
557
/*                                                             */
 
558
/*  FAsc - ASCII value of first char of string                 */
 
559
/*                                                             */
 
560
/***************************************************************/
 
561
#ifdef HAVE_PROTOS
 
562
PRIVATE int FAsc(void)
 
563
#else
 
564
static int FAsc()
 
565
#endif
 
566
{
 
567
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
568
    RetVal.type = INT_TYPE;
 
569
    RetVal.v.val = *(ARG(0).v.str);
 
570
    return OK;
 
571
}
 
572
 
 
573
/***************************************************************/
 
574
/*                                                             */
 
575
/*  FChar - build a string from ASCII values                   */
 
576
/*                                                             */
 
577
/***************************************************************/
 
578
#ifdef HAVE_PROTOS
 
579
PRIVATE int FChar(void)
 
580
#else
 
581
static int FChar()
 
582
#endif
 
583
{
 
584
 
 
585
    int i, len;
 
586
 
 
587
/* Special case of one arg - if given ascii value 0, create empty string */
 
588
    if (Nargs == 1) {
 
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;
 
598
        return OK;
 
599
    }
 
600
 
 
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) {
 
606
            free(RetVal.v.str);
 
607
            RetVal.type = ERR_TYPE;
 
608
            return E_BAD_TYPE;
 
609
        }
 
610
        if (ARG(i).v.val < -128 || ARG(i).v.val == 0) {
 
611
            free(RetVal.v.str);
 
612
            RetVal.type = ERR_TYPE;
 
613
            return E_2LOW;
 
614
        }
 
615
        if (ARG(i).v.val > 255) {
 
616
            free(RetVal.v.str);
 
617
            RetVal.type = ERR_TYPE;
 
618
            return E_2HIGH;
 
619
        }
 
620
        *(RetVal.v.str + i) = ARG(i).v.val;
 
621
    }
 
622
    *(RetVal.v.str + Nargs) = 0;
 
623
    return OK;
 
624
}
 
625
/***************************************************************/
 
626
/*                                                             */
 
627
/*  Functions for extracting the components of a date.         */
 
628
/*                                                             */
 
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)                                  */
 
635
/*                                                             */
 
636
/***************************************************************/
 
637
#ifdef HAVE_PROTOS
 
638
PRIVATE int FDay(void)
 
639
#else
 
640
static int FDay()
 
641
#endif
 
642
{
 
643
    int y, m, d;
 
644
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
645
    if (ARG(0).v.val == CacheJul)
 
646
        d = CacheDay;
 
647
    else {
 
648
        FromJulian(ARG(0).v.val, &y, &m, &d);
 
649
        CacheJul = ARG(0).v.val;
 
650
        CacheYear = y;
 
651
        CacheMon = m;
 
652
        CacheDay = d;
 
653
    }
 
654
    RetVal.type = INT_TYPE;
 
655
    RetVal.v.val = d;
 
656
    return OK;
 
657
}
 
658
 
 
659
#ifdef HAVE_PROTOS
 
660
PRIVATE int FMonnum(void)
 
661
#else
 
662
static int FMonnum()
 
663
#endif
 
664
{
 
665
    int y, m, d;
 
666
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
667
    if (ARG(0).v.val == CacheJul)
 
668
        m = CacheMon;
 
669
    else {
 
670
        FromJulian(ARG(0).v.val, &y, &m, &d);
 
671
        CacheJul = ARG(0).v.val;
 
672
        CacheYear = y;
 
673
        CacheMon = m;
 
674
        CacheDay = d;
 
675
    }
 
676
    RetVal.type = INT_TYPE;
 
677
    RetVal.v.val = m+1;
 
678
    return OK;
 
679
}
 
680
 
 
681
#ifdef HAVE_PROTOS
 
682
PRIVATE int FYear(void)
 
683
#else
 
684
static int FYear()
 
685
#endif
 
686
{
 
687
    int y, m, d;
 
688
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
689
    if (ARG(0).v.val == CacheJul)
 
690
        y = CacheYear;
 
691
    else {
 
692
        FromJulian(ARG(0).v.val, &y, &m, &d);
 
693
        CacheJul = ARG(0).v.val;
 
694
        CacheYear = y;
 
695
        CacheMon = m;
 
696
        CacheDay = d;
 
697
    }
 
698
    RetVal.type = INT_TYPE;
 
699
    RetVal.v.val = y;
 
700
    return OK;
 
701
}
 
702
 
 
703
#ifdef HAVE_PROTOS
 
704
PRIVATE int FWkdaynum(void)
 
705
#else
 
706
static int FWkdaynum()
 
707
#endif
 
708
{
 
709
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
710
    RetVal.type = INT_TYPE;
 
711
 
 
712
    /* Correct so that 0 = Sunday */
 
713
    RetVal.v.val = (ARG(0).v.val+1) % 7;
 
714
    return OK;
 
715
}
 
716
 
 
717
#ifdef HAVE_PROTOS
 
718
PRIVATE int FWkday(void)
 
719
#else
 
720
static int FWkday()
 
721
#endif
 
722
{
 
723
    char *s;
 
724
 
 
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 */
 
730
        ARG(0).v.val--;
 
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];
 
734
    return RetStrVal(s);
 
735
}
 
736
 
 
737
#ifdef HAVE_PROTOS
 
738
PRIVATE int FMon(void)
 
739
#else
 
740
static int FMon()
 
741
#endif
 
742
{
 
743
    char *s;
 
744
    int y, m, d;
 
745
 
 
746
    if (ARG(0).type != DATE_TYPE && ARG(0).type != INT_TYPE)
 
747
        return E_BAD_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;
 
752
    } else {
 
753
        if (ARG(0).v.val == CacheJul)
 
754
            m = CacheMon;
 
755
        else {
 
756
            FromJulian(ARG(0).v.val, &y, &m, &d);
 
757
            CacheJul = ARG(0).v.val;
 
758
            CacheYear = y;
 
759
            CacheMon = m;
 
760
            CacheDay = d;
 
761
        }
 
762
    }
 
763
    s = MonthName[m];
 
764
    return RetStrVal(s);
 
765
}
 
766
 
 
767
/***************************************************************/
 
768
/*                                                             */
 
769
/*  FHour - extract hour from a time                           */
 
770
/*  FMinute - extract minute from a time                       */
 
771
/*  FTime - create a time from hour and minute                 */
 
772
/*                                                             */
 
773
/***************************************************************/
 
774
#ifdef HAVE_PROTOS
 
775
PRIVATE int FHour(void)
 
776
#else
 
777
static int FHour()
 
778
#endif
 
779
{
 
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;
 
783
    return OK;
 
784
}
 
785
 
 
786
#ifdef HAVE_PROTOS
 
787
PRIVATE int FMinute(void)
 
788
#else
 
789
static int FMinute()
 
790
#endif
 
791
{
 
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;
 
795
    return OK;
 
796
}
 
797
 
 
798
#ifdef HAVE_PROTOS
 
799
PRIVATE int FTime(void)
 
800
#else
 
801
static int FTime()
 
802
#endif
 
803
{
 
804
    int h, m;
 
805
 
 
806
    if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
 
807
 
 
808
    h = ARG(0).v.val;
 
809
    m = ARG(1).v.val;
 
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;
 
814
    return OK;
 
815
}
 
816
 
 
817
/***************************************************************/
 
818
/*                                                             */
 
819
/*  FAbs - absolute value                                      */
 
820
/*  FSgn - signum function                                     */
 
821
/*                                                             */
 
822
/***************************************************************/
 
823
#ifdef HAVE_PROTOS
 
824
PRIVATE int FAbs(void)
 
825
#else
 
826
static int FAbs()
 
827
#endif
 
828
{
 
829
    int v;
 
830
 
 
831
    if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
 
832
    v = ARG(0).v.val;
 
833
    RetVal.type = INT_TYPE;
 
834
    RetVal.v.val = (v < 0) ? (-v) : v;
 
835
    return OK;
 
836
}
 
837
 
 
838
#ifdef HAVE_PROTOS
 
839
PRIVATE int FSgn(void)
 
840
#else
 
841
static int FSgn()
 
842
#endif
 
843
{
 
844
    int v;
 
845
 
 
846
    if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
 
847
    v = ARG(0).v.val;
 
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;
 
852
    return OK;
 
853
}
 
854
 
 
855
/***************************************************************/
 
856
/*                                                             */
 
857
/*  FOrd - returns a string containing ordinal number.         */
 
858
/*                                                             */
 
859
/*  EG - ord(2) == "2nd", etc.                                 */
 
860
/*                                                             */
 
861
/***************************************************************/
 
862
#ifdef HAVE_PROTOS
 
863
PRIVATE int FOrd(void)
 
864
#else
 
865
static int FOrd()
 
866
#endif
 
867
{
 
868
    int t, u, v;
 
869
    char *s;
 
870
 
 
871
    if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
 
872
 
 
873
    v = ARG(0).v.val;
 
874
    t = v % 100;
 
875
    if (t < 0) t = -t;
 
876
    u = t % 10;
 
877
    s = "th";
 
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);
 
883
}
 
884
 
 
885
/***************************************************************/
 
886
/*                                                             */
 
887
/*  FPlural - pluralization function                           */
 
888
/*                                                             */
 
889
/*  plural(n) -->  "" or "s"                                   */
 
890
/*  plural(n, str) --> "str" or "strs"                         */
 
891
/*  plural(n, str1, str2) --> "str1" or "str2"                 */
 
892
/*                                                             */
 
893
/***************************************************************/
 
894
#ifdef HAVE_PROTOS
 
895
PRIVATE int FPlural(void)
 
896
#else
 
897
static int FPlural()
 
898
#endif
 
899
{
 
900
    if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
 
901
 
 
902
    switch(Nargs) {
 
903
    case 1:
 
904
        if (ARG(0).v.val == 1) return RetStrVal("");
 
905
        else return RetStrVal("s");
 
906
 
 
907
    case 2:
 
908
        if (ARG(1).type != STR_TYPE) return E_BAD_TYPE;
 
909
        if (ARG(0).v.val == 1) {
 
910
            DCOPYVAL(RetVal, ARG(1));
 
911
            return OK;
 
912
        }
 
913
        RetVal.type = STR_TYPE;
 
914
        RetVal.v.str = (char *) malloc(strlen(ARG(1).v.str)+2);
 
915
        if (!RetVal.v.str) {
 
916
            RetVal.type = ERR_TYPE;
 
917
            return E_NO_MEM;
 
918
        }
 
919
        strcpy(RetVal.v.str, ARG(1).v.str);
 
920
        strcat(RetVal.v.str, "s");
 
921
        return OK;
 
922
 
 
923
    default:
 
924
        if (ARG(1).type != STR_TYPE || ARG(2).type != STR_TYPE)
 
925
            return E_BAD_TYPE;
 
926
        if (ARG(0).v.val == 1) DCOPYVAL(RetVal, ARG(1));
 
927
        else DCOPYVAL(RetVal, ARG(2));
 
928
        return OK;
 
929
    }
 
930
}
 
931
 
 
932
/***************************************************************/
 
933
/*                                                             */
 
934
/*  FChoose                                                    */
 
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    */
 
937
/*  from 1.                                                    */
 
938
/*                                                             */
 
939
/***************************************************************/
 
940
#ifdef HAVE_PROTOS
 
941
PRIVATE int FChoose(void)
 
942
#else
 
943
static int FChoose()
 
944
#endif
 
945
{
 
946
    int v;
 
947
 
 
948
    if (ARG(0).type != INT_TYPE) return E_BAD_TYPE;
 
949
    v = ARG(0).v.val;
 
950
    if (v < 1) v = 1;
 
951
    if (v > Nargs-1) v = Nargs-1;
 
952
    DCOPYVAL(RetVal, ARG(v));
 
953
    return OK;
 
954
}
 
955
 
 
956
/***************************************************************/
 
957
/*                                                             */
 
958
/*  FVersion - version of Remind                               */
 
959
/*                                                             */
 
960
/***************************************************************/
 
961
#ifdef HAVE_PROTOS
 
962
PRIVATE int FVersion(void)
 
963
#else
 
964
static int FVersion()
 
965
#endif
 
966
{
 
967
    return RetStrVal(VERSION);
 
968
}
 
969
 
 
970
/***************************************************************/
 
971
/*                                                             */
 
972
/*  FOstype - the type of operating system                     */
 
973
/*  (UNIX, OS/2, or MSDOS)                                     */
 
974
/*                                                             */
 
975
/***************************************************************/
 
976
#ifdef HAVE_PROTOS
 
977
PRIVATE int FOstype(void)
 
978
#else
 
979
static int FOstype()
 
980
#endif
 
981
{
 
982
#ifdef UNIX
 
983
    return RetStrVal("UNIX");
 
984
#else
 
985
#ifdef __OS2__
 
986
    return RetStrVal(OS2MODE ? "OS/2" : "MSDOS");
 
987
#else
 
988
#ifdef QDOS
 
989
    return RetStrVal("QDOS / SMSQ");
 
990
#else
 
991
#ifdef AMIGA
 
992
    return RetStrVal("AmigaDOS");
 
993
#else
 
994
    return RetStrVal("MSDOS");
 
995
#endif
 
996
#endif
 
997
#endif
 
998
#endif
 
999
}
 
1000
 
 
1001
/***************************************************************/
 
1002
/*                                                             */
 
1003
/*  FUpper - convert string to upper-case                      */
 
1004
/*  FLower - convert string to lower-case                      */
 
1005
/*                                                             */
 
1006
/***************************************************************/
 
1007
#ifdef HAVE_PROTOS
 
1008
PRIVATE int FUpper(void)
 
1009
#else
 
1010
static int FUpper()
 
1011
#endif
 
1012
{
 
1013
    char *s;
 
1014
 
 
1015
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1016
    DCOPYVAL(RetVal, ARG(0));
 
1017
    s = RetVal.v.str;
 
1018
    while (*s) {
 
1019
        *s = UPPER(*s);
 
1020
        s++;
 
1021
    }
 
1022
    return OK;
 
1023
}
 
1024
 
 
1025
#ifdef HAVE_PROTOS
 
1026
PRIVATE int FLower(void)
 
1027
#else
 
1028
static int FLower()
 
1029
#endif
 
1030
{
 
1031
    char *s;
 
1032
 
 
1033
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1034
    DCOPYVAL(RetVal, ARG(0));
 
1035
    s = RetVal.v.str;
 
1036
    while (*s) {
 
1037
        *s = LOWER(*s);
 
1038
        s++;
 
1039
    }
 
1040
    return OK;
 
1041
}
 
1042
 
 
1043
/***************************************************************/
 
1044
/*                                                             */
 
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                     */
 
1049
/*                                                             */
 
1050
/***************************************************************/
 
1051
#ifdef HAVE_PROTOS
 
1052
PRIVATE int FToday(void)
 
1053
#else
 
1054
static int FToday()
 
1055
#endif
 
1056
{
 
1057
    RetVal.type = DATE_TYPE;
 
1058
    RetVal.v.val = JulianToday;
 
1059
    return OK;
 
1060
}
 
1061
 
 
1062
#ifdef HAVE_PROTOS
 
1063
PRIVATE int FRealtoday(void)
 
1064
#else
 
1065
static int FRealtoday()
 
1066
#endif
 
1067
{
 
1068
    RetVal.type = DATE_TYPE;
 
1069
    RetVal.v.val = RealToday;
 
1070
    return OK;
 
1071
}
 
1072
 
 
1073
#ifdef HAVE_PROTOS
 
1074
PRIVATE int FNow(void)
 
1075
#else
 
1076
static int FNow()
 
1077
#endif
 
1078
{
 
1079
    RetVal.type = TIM_TYPE;
 
1080
    RetVal.v.val = (int) ( SystemTime(0) / 60L );
 
1081
    return OK;
 
1082
}
 
1083
 
 
1084
#ifdef HAVE_PROTOS
 
1085
PRIVATE int FRealnow(void)
 
1086
#else
 
1087
static int FRealnow()
 
1088
#endif
 
1089
{
 
1090
    RetVal.type = TIM_TYPE;
 
1091
    RetVal.v.val = (int) ( SystemTime(1) / 60L );
 
1092
    return OK;
 
1093
}
 
1094
/***************************************************************/
 
1095
/*                                                             */
 
1096
/*  FGetenv - get the value of an environment variable.        */
 
1097
/*                                                             */
 
1098
/***************************************************************/
 
1099
#ifdef HAVE_PROTOS
 
1100
PRIVATE int FGetenv(void)
 
1101
#else
 
1102
static int FGetenv()
 
1103
#endif
 
1104
{
 
1105
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1106
    return RetStrVal(getenv(ARG(0).v.str));
 
1107
}
 
1108
 
 
1109
/***************************************************************/
 
1110
/*                                                             */
 
1111
/*  FValue                                                     */
 
1112
/*                                                             */
 
1113
/*  Get the value of a variable.  If a second arg is supplied, */
 
1114
/*  it is returned if variable is undefined.                   */
 
1115
/*                                                             */
 
1116
/***************************************************************/
 
1117
#ifdef HAVE_PROTOS
 
1118
PRIVATE int FValue(void)
 
1119
#else
 
1120
static int FValue()
 
1121
#endif
 
1122
{
 
1123
    Var *v;
 
1124
 
 
1125
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1126
    switch(Nargs) {
 
1127
    case 1:
 
1128
        return GetVarValue(ARG(0).v.str, &RetVal, NULL);
 
1129
 
 
1130
    case 2:
 
1131
        v = FindVar(ARG(0).v.str, 0);
 
1132
        if (!v) {
 
1133
            DCOPYVAL(RetVal, ARG(1));
 
1134
            return OK;
 
1135
        } else {
 
1136
            return CopyValue(&RetVal, &v->v);
 
1137
        }
 
1138
    }
 
1139
    return OK;
 
1140
}
 
1141
 
 
1142
/***************************************************************/
 
1143
/*                                                             */
 
1144
/*  FDefined                                                   */
 
1145
/*                                                             */
 
1146
/*  Return 1 if a variable is defined, 0 if it is not.         */
 
1147
/*                                                             */
 
1148
/***************************************************************/
 
1149
#ifdef HAVE_PROTOS
 
1150
PRIVATE int FDefined(void)
 
1151
#else
 
1152
static int FDefined()
 
1153
#endif
 
1154
{
 
1155
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1156
 
 
1157
    RetVal.type = INT_TYPE;
 
1158
 
 
1159
    if (FindVar(ARG(0).v.str, 0))
 
1160
        RetVal.v.val = 1;
 
1161
    else
 
1162
        RetVal.v.val = 0;
 
1163
    return OK;
 
1164
}
 
1165
 
 
1166
/***************************************************************/
 
1167
/*                                                             */
 
1168
/*  FTrigdate and FTrigtime                                    */
 
1169
/*                                                             */
 
1170
/*  Date and time of last trigger.  These are stored in global */
 
1171
/*  vars.                                                      */
 
1172
/*                                                             */
 
1173
/***************************************************************/
 
1174
#ifdef HAVE_PROTOS
 
1175
PRIVATE int FTrigdate(void)
 
1176
#else
 
1177
static int FTrigdate()
 
1178
#endif
 
1179
{
 
1180
    RetVal.type = DATE_TYPE;
 
1181
    RetVal.v.val = LastTriggerDate;
 
1182
    return OK;
 
1183
}
 
1184
 
 
1185
#ifdef HAVE_PROTOS
 
1186
PRIVATE int FTrigvalid(void)
 
1187
#else
 
1188
static int FTrigvalid()
 
1189
#endif
 
1190
{
 
1191
    RetVal.type = INT_TYPE;
 
1192
    RetVal.v.val = LastTrigValid;
 
1193
    return OK;
 
1194
}
 
1195
 
 
1196
#ifdef HAVE_PROTOS
 
1197
PRIVATE int FTrigtime(void)
 
1198
#else
 
1199
static int FTrigtime()
 
1200
#endif
 
1201
{
 
1202
    RetVal.type = TIM_TYPE;
 
1203
    RetVal.v.val = LastTriggerTime;
 
1204
    return OK;
 
1205
}
 
1206
 
 
1207
/***************************************************************/
 
1208
/*                                                             */
 
1209
/*  FDaysinmon                                                 */
 
1210
/*                                                             */
 
1211
/*  Returns the number of days in mon,yr                       */
 
1212
/*                                                             */
 
1213
/***************************************************************/
 
1214
#ifdef HAVE_PROTOS
 
1215
PRIVATE int FDaysinmon(void)
 
1216
#else
 
1217
static int FDaysinmon()
 
1218
#endif
 
1219
{
 
1220
    if (ARG(0).type != INT_TYPE || ARG(1).type != INT_TYPE) return E_BAD_TYPE;
 
1221
 
 
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;
 
1225
 
 
1226
    RetVal.type = INT_TYPE;
 
1227
    RetVal.v.val = DaysInMonth(ARG(0).v.val-1, ARG(1).v.val);
 
1228
    return OK;
 
1229
}
 
1230
 
 
1231
/***************************************************************/
 
1232
/*                                                             */
 
1233
/*  FIsleap                                                    */
 
1234
/*                                                             */
 
1235
/*  Return 1 if year is a leap year, zero otherwise.           */
 
1236
/*                                                             */
 
1237
/***************************************************************/
 
1238
#ifdef HAVE_PROTOS
 
1239
PRIVATE int FIsleap(void)
 
1240
#else
 
1241
static int FIsleap()
 
1242
#endif
 
1243
{
 
1244
    int y, m, d;
 
1245
 
 
1246
    if (ARG(0).type != INT_TYPE && ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1247
 
 
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);
 
1251
    else
 
1252
        y = ARG(0).v.val;
 
1253
 
 
1254
    RetVal.type = INT_TYPE;
 
1255
    RetVal.v.val = IsLeapYear(y);
 
1256
    return OK;
 
1257
}
 
1258
 
 
1259
/***************************************************************/
 
1260
/*                                                             */
 
1261
/*  FTrigger                                                   */
 
1262
/*                                                             */
 
1263
/*  Put out a date in a format suitable for triggering.        */
 
1264
/*                                                             */
 
1265
/***************************************************************/
 
1266
#ifdef HAVE_PROTOS
 
1267
PRIVATE int FTrigger(void)
 
1268
#else
 
1269
static int FTrigger()
 
1270
#endif
 
1271
{
 
1272
    int y, m, d;
 
1273
    int date, time;
 
1274
    char buf[40];
 
1275
 
 
1276
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1277
    date = ARG(0).v.val;
 
1278
    if (Nargs > 2) {
 
1279
        if (ARG(2).type != INT_TYPE) return E_BAD_TYPE;
 
1280
        if (ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
 
1281
        if (ARG(2).v.val) {
 
1282
            UTCToLocal(ARG(0).v.val, ARG(1).v.val, &date, &time);
 
1283
        } else {
 
1284
            date = ARG(0).v.val;
 
1285
            time = ARG(1).v.val;
 
1286
        }
 
1287
    }
 
1288
    FromJulian(date, &y, &m, &d);
 
1289
    if (Nargs > 1) {
 
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,
 
1293
                time/60, time%60);
 
1294
    } else {
 
1295
        sprintf(buf, "%d %s %d", d, EnglishMonthName[m], y);
 
1296
    }
 
1297
    return RetStrVal(buf);
 
1298
}
 
1299
 
 
1300
/***************************************************************/
 
1301
/*                                                             */
 
1302
/*  FShell                                                     */
 
1303
/*                                                             */
 
1304
/*  The shell function.                                        */
 
1305
/*                                                             */
 
1306
/*  If run is disabled, will not be executed.                  */
 
1307
/*                                                             */
 
1308
/***************************************************************/
 
1309
#ifdef HAVE_PROTOS
 
1310
PRIVATE int FShell(void)
 
1311
#else
 
1312
static int FShell()
 
1313
#endif
 
1314
{
 
1315
    DynamicBuffer buf;
 
1316
    int ch, r;
 
1317
    FILE *fp;
 
1318
 
 
1319
    /* For compatibility with previous versions of Remind, which
 
1320
       used a static buffer for reading results from shell() command */
 
1321
    int maxlen = 511;
 
1322
 
 
1323
    DBufInit(&buf);
 
1324
    if (RunDisabled) return E_RUN_DISABLED;
 
1325
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1326
    if (Nargs >= 2) {
 
1327
        if (ARG(1).type != INT_TYPE) return E_BAD_TYPE;
 
1328
        maxlen = ARG(1).v.val;
 
1329
    }
 
1330
    fp = POPEN(ARG(0).v.str, "r");
 
1331
    if (!fp) return E_IO_ERR;
 
1332
    while (1) {
 
1333
        ch = getc(fp);
 
1334
        if (ch == EOF) {
 
1335
            break;
 
1336
        }
 
1337
        if (isspace(ch)) ch = ' ';
 
1338
        if (DBufPutc(&buf, (char) ch) != OK) {
 
1339
            PCLOSE(fp);
 
1340
            DBufFree(&buf);
 
1341
            return E_NO_MEM;
 
1342
        }
 
1343
        if (maxlen > 0 && DBufLen(&buf) >= maxlen) {
 
1344
            break;
 
1345
        }
 
1346
    }
 
1347
 
 
1348
    /* Delete trailing newline (converted to space) */
 
1349
    if (DBufLen(&buf) && DBufValue(&buf)[DBufLen(&buf)-1] == ' ') {
 
1350
        DBufValue(&buf)[DBufLen(&buf)-1] = 0;
 
1351
    }
 
1352
#if defined(__MSDOS__) || defined(__OS2__)
 
1353
    if (DBufLen(&buf) > 1 && DBufValue(&buf)[DBufLen(&buf)-2] == ' ') {
 
1354
        DBufValue(&buf)[DBufLen(&buf)-2] = 0;
 
1355
    }
 
1356
#endif
 
1357
    PCLOSE(fp);
 
1358
    r = RetStrVal(DBufValue(&buf));
 
1359
    DBufFree(&buf);
 
1360
    return r;
 
1361
}
 
1362
 
 
1363
/***************************************************************/
 
1364
/*                                                             */
 
1365
/*  FIsomitted                                                 */
 
1366
/*                                                             */
 
1367
/*  Is a date omitted?                                         */
 
1368
/*                                                             */
 
1369
/***************************************************************/
 
1370
#ifdef HAVE_PROTOS
 
1371
PRIVATE int FIsomitted(void)
 
1372
#else
 
1373
static int FIsomitted()
 
1374
#endif
 
1375
{
 
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);
 
1379
    return OK;
 
1380
}
 
1381
 
 
1382
/***************************************************************/
 
1383
/*                                                             */
 
1384
/*  FSubstr                                                    */
 
1385
/*                                                             */
 
1386
/*  The substr function.  We destroy the value on the stack.   */
 
1387
/*                                                             */
 
1388
/***************************************************************/
 
1389
#ifdef HAVE_PROTOS
 
1390
PRIVATE int FSubstr(void)
 
1391
#else
 
1392
static int FSubstr()
 
1393
#endif
 
1394
{
 
1395
    char *s, *t;
 
1396
    int start, end;
 
1397
 
 
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;
 
1400
 
 
1401
    s = ARG(0).v.str;
 
1402
    start = 1;
 
1403
    while (start < ARG(1).v.val) {
 
1404
        if (!*s) break;
 
1405
        s++;
 
1406
        start++;
 
1407
    }
 
1408
    if (Nargs == 2 || !*s) return RetStrVal(s);
 
1409
    end = start;
 
1410
    t = s;
 
1411
    while (end <= ARG(2).v.val) {
 
1412
        if (!*s) break;
 
1413
        s++;
 
1414
        end++;
 
1415
    }
 
1416
    *s = 0;
 
1417
    return RetStrVal(t);
 
1418
}
 
1419
 
 
1420
/***************************************************************/
 
1421
/*                                                             */
 
1422
/*  FIndex                                                     */
 
1423
/*                                                             */
 
1424
/*  The index of one string embedded in another.               */
 
1425
/*                                                             */
 
1426
/***************************************************************/
 
1427
#ifdef HAVE_PROTOS
 
1428
PRIVATE int FIndex(void)
 
1429
#else
 
1430
static int FIndex()
 
1431
#endif
 
1432
{
 
1433
    char *s;
 
1434
    int start;
 
1435
 
 
1436
    if (ARG(0).type != STR_TYPE || ARG(1).type != STR_TYPE ||
 
1437
        (Nargs == 3 && ARG(2).type != INT_TYPE)) return E_BAD_TYPE;
 
1438
 
 
1439
    s = ARG(0).v.str;
 
1440
 
 
1441
/* If 3 args, bump up the start */
 
1442
    if (Nargs == 3) {
 
1443
        start = 1;
 
1444
        while (start < ARG(2).v.val) {
 
1445
            if (!*s) break;
 
1446
            s++;
 
1447
            start++;
 
1448
        }
 
1449
    }
 
1450
 
 
1451
/* Find the string */
 
1452
    s = strstr(s, ARG(1).v.str);
 
1453
    RetVal.type = INT_TYPE;
 
1454
    if (!s) {
 
1455
        RetVal.v.val = 0;
 
1456
        return OK;
 
1457
    }
 
1458
    RetVal.v.val = (s - ARG(0).v.str) + 1;
 
1459
    return OK;
 
1460
}
 
1461
 
 
1462
/***************************************************************/
 
1463
/*                                                             */
 
1464
/*  FIif                                                       */
 
1465
/*                                                             */
 
1466
/*  The IIF function.                                          */
 
1467
/*                                                             */
 
1468
/***************************************************************/
 
1469
#ifdef HAVE_PROTOS
 
1470
PRIVATE int FIif(void)
 
1471
#else
 
1472
static int FIif()
 
1473
#endif
 
1474
{
 
1475
    int istrue;
 
1476
    int arg;
 
1477
 
 
1478
    if (!(Nargs % 2)) return E_IIF_ODD;
 
1479
 
 
1480
    for (arg=0; arg<Nargs-1; arg += 2) {
 
1481
        if (ARG(arg).type != STR_TYPE && ARG(arg).type != INT_TYPE)
 
1482
            return E_BAD_TYPE;
 
1483
 
 
1484
        if (ARG(arg).type == INT_TYPE)
 
1485
            istrue = ARG(arg).v.val;
 
1486
        else
 
1487
            istrue = *(ARG(arg).v.str);
 
1488
 
 
1489
        if (istrue) {
 
1490
            DCOPYVAL(RetVal, ARG(arg+1));
 
1491
            return OK;
 
1492
        }
 
1493
    }
 
1494
 
 
1495
    DCOPYVAL(RetVal, ARG(Nargs-1));
 
1496
    return OK;
 
1497
}
 
1498
 
 
1499
/***************************************************************/
 
1500
/*                                                             */
 
1501
/*  FFilename                                                  */
 
1502
/*                                                             */
 
1503
/*  Return name of current file                                */
 
1504
/*                                                             */
 
1505
/***************************************************************/
 
1506
#ifdef HAVE_PROTOS
 
1507
PRIVATE int FFilename(void)
 
1508
#else
 
1509
static int FFilename()
 
1510
#endif
 
1511
{
 
1512
    return RetStrVal(FileName);
 
1513
}
 
1514
 
 
1515
/***************************************************************/
 
1516
/*                                                             */
 
1517
/*  FFiledir                                                   */
 
1518
/*                                                             */
 
1519
/*  Return directory of current file                           */
 
1520
/*                                                             */
 
1521
/***************************************************************/
 
1522
#ifdef HAVE_PROTOS
 
1523
PRIVATE int FFiledir(void)
 
1524
#else
 
1525
static int FFiledir()
 
1526
#endif
 
1527
{
 
1528
    char *s;
 
1529
    DynamicBuffer buf;
 
1530
    int r;
 
1531
 
 
1532
    DBufInit(&buf);
 
1533
 
 
1534
    if (DBufPuts(&buf, FileName) != OK) return E_NO_MEM;
 
1535
    if (DBufLen(&buf) == 0) {
 
1536
        DBufFree(&buf);
 
1537
        return RetStrVal(".");
 
1538
    }
 
1539
 
 
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 = '/';
 
1546
#else
 
1547
    while (s > DBufValue(&buf) && *s != '/') s--;
 
1548
#endif
 
1549
    if (*s == '/') {
 
1550
        *s = 0;
 
1551
        r = RetStrVal(DBufValue(&buf));
 
1552
    } else r = RetStrVal(".");
 
1553
    DBufFree(&buf);
 
1554
    return r;
 
1555
}
 
1556
/***************************************************************/
 
1557
/*                                                             */
 
1558
/*  FAccess                                                    */
 
1559
/*                                                             */
 
1560
/*  The UNIX access() system call.                             */
 
1561
/*                                                             */
 
1562
/***************************************************************/
 
1563
#ifdef HAVE_PROTOS
 
1564
PRIVATE int FAccess(void)
 
1565
#else
 
1566
static int FAccess()
 
1567
#endif
 
1568
{
 
1569
    int amode;
 
1570
    char *s;
 
1571
 
 
1572
    if (ARG(0).type != STR_TYPE ||
 
1573
        (ARG(1).type != INT_TYPE && ARG(1).type != STR_TYPE)) return E_BAD_TYPE;
 
1574
 
 
1575
    if (ARG(1).type == INT_TYPE) amode = ARG(1).v.val;
 
1576
    else {
 
1577
        amode = 0;
 
1578
        s = ARG(1).v.str;
 
1579
        while (*s) {
 
1580
            switch(*s++) {
 
1581
            case 'r':
 
1582
            case 'R': amode |= R_OK; break;
 
1583
            case 'w':
 
1584
            case 'W': amode |= W_OK; break;
 
1585
            case 'x':
 
1586
            case 'X': amode |= X_OK; break;
 
1587
            }
 
1588
        }
 
1589
    }
 
1590
    RetVal.type = INT_TYPE;
 
1591
    RetVal.v.val = access(ARG(0).v.str, amode);
 
1592
    return OK;
 
1593
}
 
1594
 
 
1595
#if defined(__MSDOS__) || defined(__BORLANDC__) || defined(AMIGA)
 
1596
/***************************************************************/
 
1597
/*                                                             */
 
1598
/*  popen and pclose                                           */
 
1599
/*                                                             */
 
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.                                 */
 
1604
/*                                                             */
 
1605
/***************************************************************/
 
1606
#ifdef __TURBOC__
 
1607
#pragma argsused
 
1608
#endif
 
1609
 
 
1610
static char *TmpFile;
 
1611
#ifdef HAVE_PROTOS
 
1612
PRIVATE FILE *os_popen(char *cmd, char *mode)
 
1613
#else
 
1614
static FILE *os_popen(cmd, mode)
 
1615
char *cmd, *mode;
 
1616
#endif
 
1617
{
 
1618
    char *s;
 
1619
 
 
1620
#if defined(__OS2__) && !defined(__BORLANDC__)
 
1621
    if (OS2MODE)
 
1622
        return(popen(cmd, mode));
 
1623
#endif
 
1624
 
 
1625
    TmpFile = tmpnam(NULL);
 
1626
    if (!TmpFile) return NULL;
 
1627
    s = (char *) malloc(strlen(cmd) + 3 + strlen(TmpFile) + 1);
 
1628
    if (!s) return NULL;
 
1629
    strcpy(s, cmd);
 
1630
    strcat(s, " > ");
 
1631
    strcat(s, TmpFile);
 
1632
    system(s);
 
1633
    free(s);
 
1634
    return fopen(TmpFile, "r");
 
1635
}
 
1636
 
 
1637
#ifdef HAVE_PROTOS
 
1638
PRIVATE int os_pclose(FILE *fp)
 
1639
#else
 
1640
static int os_pclose(fp)
 
1641
FILE *fp;
 
1642
#endif
 
1643
{
 
1644
#if defined(__OS2__) && !defined(__BORLANDC__)
 
1645
    if (OS2MODE)
 
1646
        return(pclose(fp));
 
1647
#endif
 
1648
 
 
1649
    unlink(TmpFile);
 
1650
#ifdef AMIGA
 
1651
    free(TmpFile);
 
1652
#endif
 
1653
    return fclose(fp);
 
1654
}
 
1655
 
 
1656
#endif
 
1657
 
 
1658
/***************************************************************/
 
1659
/*                                                             */
 
1660
/*  FTypeof                                                    */
 
1661
/*                                                             */
 
1662
/*  Implement the typeof() function.                           */
 
1663
/*                                                             */
 
1664
/***************************************************************/
 
1665
#ifdef HAVE_PROTOS
 
1666
PRIVATE int FTypeof(void)
 
1667
#else
 
1668
static int FTypeof()
 
1669
#endif
 
1670
{
 
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");
 
1677
    }
 
1678
}
 
1679
 
 
1680
/***************************************************************/
 
1681
/*                                                             */
 
1682
/*  FLanguage                                                  */
 
1683
/*                                                             */
 
1684
/*  Implement the language() function.                         */
 
1685
/*                                                             */
 
1686
/***************************************************************/
 
1687
#ifdef HAVE_PROTOS
 
1688
PRIVATE int FLanguage(void)
 
1689
#else
 
1690
static int FLanguage()
 
1691
#endif
 
1692
{
 
1693
    return RetStrVal(L_LANGNAME);
 
1694
}
 
1695
 
 
1696
/***************************************************************/
 
1697
/*                                                             */
 
1698
/*  FArgs                                                      */
 
1699
/*                                                             */
 
1700
/*  Implement the args() function.                             */
 
1701
/*                                                             */
 
1702
/***************************************************************/
 
1703
#ifdef HAVE_PROTOS
 
1704
PRIVATE int FArgs(void)
 
1705
#else
 
1706
static int FArgs()
 
1707
#endif
 
1708
{
 
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);
 
1712
    return OK;
 
1713
}
 
1714
 
 
1715
/***************************************************************/
 
1716
/*                                                             */
 
1717
/*  FDosubst                                                   */
 
1718
/*                                                             */
 
1719
/*  Implement the dosubst() function.                          */
 
1720
/*                                                             */
 
1721
/***************************************************************/
 
1722
#ifdef HAVE_PROTOS
 
1723
PRIVATE int FDosubst(void)
 
1724
#else
 
1725
static int FDosubst()
 
1726
#endif
 
1727
{
 
1728
    int jul, tim, r;
 
1729
    DynamicBuffer buf;
 
1730
 
 
1731
    DBufInit(&buf);
 
1732
 
 
1733
    jul = NO_DATE;
 
1734
    tim = NO_TIME;
 
1735
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
1736
    if (Nargs >= 2) {
 
1737
        if (ARG(1).type != DATE_TYPE) return E_BAD_TYPE;
 
1738
        jul = ARG(1).v.val;
 
1739
        if (Nargs >= 3) {
 
1740
            if (ARG(2).type != TIM_TYPE) return E_BAD_TYPE;
 
1741
            tim = ARG(2).v.val;
 
1742
        }
 
1743
    }
 
1744
 
 
1745
    if ((r=DoSubstFromString(ARG(0).v.str, &buf, jul, tim))) return r;
 
1746
    r = RetStrVal(DBufValue(&buf));
 
1747
    DBufFree(&buf);
 
1748
    return r;
 
1749
}
 
1750
 
 
1751
/***************************************************************/
 
1752
/*                                                             */
 
1753
/*  FHebdate                                                   */
 
1754
/*  FHebday                                                    */
 
1755
/*  FHebmon                                                    */
 
1756
/*  FHebyear                                                   */
 
1757
/*                                                             */
 
1758
/*  Hebrew calendar support functions                          */
 
1759
/*                                                             */
 
1760
/***************************************************************/
 
1761
#ifdef HAVE_PROTOS
 
1762
PRIVATE int FHebdate(void)
 
1763
#else
 
1764
static int FHebdate()
 
1765
#endif
 
1766
{
 
1767
    int year, day, mon, jahr;
 
1768
    int mout, dout;
 
1769
    int ans, r;
 
1770
    int adarbehave;
 
1771
 
 
1772
    if (ARG(0).type != INT_TYPE || ARG(1).type != STR_TYPE) return E_BAD_TYPE;
 
1773
    day = ARG(0).v.val;
 
1774
    mon = HebNameToNum(ARG(1).v.str);
 
1775
    if (mon < 0) return E_BAD_HEBDATE;
 
1776
    if (Nargs == 2) {
 
1777
        r = GetNextHebrewDate(JulianToday, mon, day, 0, 0, &ans);
 
1778
        if (r) return r;
 
1779
        RetVal.type = DATE_TYPE;
 
1780
        RetVal.v.val = ans;
 
1781
        return OK;
 
1782
    }
 
1783
    if (Nargs == 5) {
 
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;
 
1789
 
 
1790
    if (Nargs >= 4) {
 
1791
        if (ARG(3).type != INT_TYPE) return E_BAD_TYPE;
 
1792
        jahr = ARG(3).v.val;
 
1793
        if (jahr < 0) return E_2LOW;
 
1794
        if (jahr > 2) {
 
1795
            r = ComputeJahr(jahr, mon, day, &jahr);
 
1796
            if (r) return r;
 
1797
        }
 
1798
    } else jahr = 0;
 
1799
 
 
1800
 
 
1801
    if (ARG(2).type == INT_TYPE) {
 
1802
        year = ARG(2).v.val;
 
1803
        r = GetValidHebDate(year, mon, day, 0, &mout, &dout, jahr);
 
1804
        if (r) return r;
 
1805
        r = HebToJul(year, mout, dout);
 
1806
        if (r<0) return E_DATE_OVER;
 
1807
        RetVal.v.val = r;
 
1808
        RetVal.type = DATE_TYPE;
 
1809
        return OK;
 
1810
    } else if (ARG(2).type == DATE_TYPE) {
 
1811
        r = GetNextHebrewDate(ARG(2).v.val, mon, day, jahr, adarbehave, &ans);
 
1812
        if (r) return r;
 
1813
        RetVal.v.val = ans;
 
1814
        RetVal.type = DATE_TYPE;
 
1815
        return OK;
 
1816
    } else return E_BAD_TYPE;
 
1817
}
 
1818
 
 
1819
#ifdef HAVE_PROTOS
 
1820
PRIVATE int FHebday(void)
 
1821
#else
 
1822
static int FHebday()
 
1823
#endif
 
1824
{
 
1825
    int y, m, d;
 
1826
 
 
1827
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1828
    if (ARG(0).v.val == CacheHebJul)
 
1829
        d = CacheHebDay;
 
1830
    else {
 
1831
        JulToHeb(ARG(0).v.val, &y, &m, &d);
 
1832
        CacheHebJul = ARG(0).v.val;
 
1833
        CacheHebYear = y;
 
1834
        CacheHebMon = m;
 
1835
        CacheHebDay = d;
 
1836
    }
 
1837
    RetVal.type = INT_TYPE;
 
1838
    RetVal.v.val = d;
 
1839
    return OK;
 
1840
}
 
1841
 
 
1842
#ifdef HAVE_PROTOS
 
1843
PRIVATE int FHebmon(void)
 
1844
#else
 
1845
static int FHebmon()
 
1846
#endif
 
1847
{
 
1848
    int y, m, d;
 
1849
 
 
1850
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1851
    if (ARG(0).v.val == CacheHebJul) {
 
1852
        m = CacheHebMon;
 
1853
        y = CacheHebYear;
 
1854
    } else {
 
1855
        JulToHeb(ARG(0).v.val, &y, &m, &d);
 
1856
        CacheHebJul = ARG(0).v.val;
 
1857
        CacheHebYear = y;
 
1858
        CacheHebMon = m;
 
1859
        CacheHebDay = d;
 
1860
    }
 
1861
    return RetStrVal(HebMonthName(m, y));
 
1862
}
 
1863
 
 
1864
#ifdef HAVE_PROTOS
 
1865
PRIVATE int FHebyear(void)
 
1866
#else
 
1867
static int FHebyear()
 
1868
#endif
 
1869
{
 
1870
    int y, m, d;
 
1871
 
 
1872
    if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1873
    if (ARG(0).v.val == CacheHebJul)
 
1874
        y = CacheHebYear;
 
1875
    else {
 
1876
        JulToHeb(ARG(0).v.val, &y, &m, &d);
 
1877
        CacheHebJul = ARG(0).v.val;
 
1878
        CacheHebYear = y;
 
1879
        CacheHebMon = m;
 
1880
        CacheHebDay = d;
 
1881
    }
 
1882
    RetVal.type = INT_TYPE;
 
1883
    RetVal.v.val = y;
 
1884
    return OK;
 
1885
}
 
1886
/****************************************************************/
 
1887
/*                                                              */
 
1888
/*  FEasterdate - calc. easter Sunday from a year.              */
 
1889
/*                                                              */
 
1890
/*    from The Art of Computer Programming Vol 1.               */
 
1891
/*            Fundamental Algorithms                            */
 
1892
/*    by Donald Knuth.                                          */
 
1893
/*                                                              */
 
1894
/* Donated by Michael Salmon - thanks!                          */
 
1895
/*                                                              */
 
1896
/* I haven't examined this in detail, but I *think* int         */
 
1897
/* arithmetic is fine, even on 16-bit machines.                 */
 
1898
/*                                                              */
 
1899
/****************************************************************/
 
1900
#ifdef HAVE_PROTOS
 
1901
PRIVATE int FEasterdate(void)
 
1902
#else
 
1903
static int FEasterdate()
 
1904
#endif
 
1905
{
 
1906
    int y, m, d;
 
1907
    int g, c, x, z, e, n;
 
1908
    if (ARG(0).type == INT_TYPE) {
 
1909
        y = ARG(0).v.val;
 
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;
 
1915
 
 
1916
    do {
 
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 */
 
1928
        if (d <= 31) m = 2;
 
1929
        else
 
1930
        {
 
1931
            d = d - 31;
 
1932
            m = 3;
 
1933
        }
 
1934
 
 
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);
 
1938
 
 
1939
    return OK;
 
1940
}
 
1941
/***************************************************************/
 
1942
/*                                                             */
 
1943
/*  FIsdst and FMinsfromutc                                    */
 
1944
/*                                                             */
 
1945
/*  Check whether daylight savings time is in effect, and      */
 
1946
/*  get minutes from UTC.                                      */
 
1947
/*                                                             */
 
1948
/***************************************************************/
 
1949
PRIVATE int FTimeStuff ARGS ((int wantmins));
 
1950
#ifdef HAVE_PROTOS
 
1951
PRIVATE int FIsdst(void)
 
1952
#else
 
1953
static int FIsdst()
 
1954
#endif
 
1955
{
 
1956
    return FTimeStuff(0);
 
1957
}
 
1958
 
 
1959
#ifdef HAVE_PROTOS
 
1960
PRIVATE int FMinsfromutc(void)
 
1961
#else
 
1962
static int FMinsfromutc()
 
1963
#endif
 
1964
{
 
1965
    return FTimeStuff(1);
 
1966
}
 
1967
 
 
1968
#ifdef HAVE_PROTOS
 
1969
PRIVATE int FTimeStuff(int wantmins)
 
1970
#else
 
1971
static int FTimeStuff(wantmins)
 
1972
int wantmins;
 
1973
#endif
 
1974
{
 
1975
    int jul, tim;
 
1976
    int mins, dst;
 
1977
 
 
1978
    jul = JulianToday;
 
1979
    tim = 0;
 
1980
 
 
1981
    if (Nargs >= 1) {
 
1982
        if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
1983
        jul = ARG(0).v.val;
 
1984
        if (Nargs >= 2) {
 
1985
            if (ARG(1).type != TIM_TYPE) return E_BAD_TYPE;
 
1986
            tim = ARG(1).v.val;
 
1987
        }
 
1988
    }
 
1989
 
 
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;
 
1993
 
 
1994
    return OK;
 
1995
}
 
1996
 
 
1997
/***************************************************************/
 
1998
/*                                                             */
 
1999
/*  Sunrise and sunset functions.                              */
 
2000
/*                                                             */
 
2001
/*  Algorithm from "Almanac for computers for the year 1978"   */
 
2002
/*  by L. E. Doggett, Nautical Almanac Office, USNO.           */
 
2003
/*                                                             */
 
2004
/*  This code also uses some ideas found in programs written   */
 
2005
/*  by Michael Schwartz and Marc T. Kaufman.                   */
 
2006
/*                                                             */
 
2007
/***************************************************************/
 
2008
#ifdef PI
 
2009
#undef PI
 
2010
#endif
 
2011
#define PI 3.14159265358979323846
 
2012
#define DEGRAD (PI/180.0)
 
2013
#define RADDEG (180.0/PI)
 
2014
 
 
2015
#ifdef HAVE_PROTOS
 
2016
PRIVATE int SunStuff(int rise, double cosz, int jul)
 
2017
#else
 
2018
static int SunStuff(rise, cosz, jul)
 
2019
int rise;
 
2020
double cosz;
 
2021
int jul;
 
2022
#endif
 
2023
{
 
2024
    int year, mon, day;
 
2025
    int jan0;
 
2026
    int mins, hours;
 
2027
    int dusk_or_dawn;
 
2028
 
 
2029
    double M, L, tanA, sinDelta, cosDelta, a, a_hr, cosH, t, H, T;
 
2030
    double latitude, longdeg, UT, local;
 
2031
 
 
2032
/* Get offset from UTC */
 
2033
    if (CalculateUTC) {
 
2034
        if (CalcMinsFromUTC(jul, 12*60, &mins, NULL)) {
 
2035
            Eprint(ErrMsg[E_MKTIME_PROBLEM]);
 
2036
            return NO_TIME;
 
2037
        }
 
2038
    } else mins = MinsFromUTC;
 
2039
 
 
2040
/* Get latitude and longitude */
 
2041
    longdeg = (double) LongDeg + (double) LongMin / 60.0
 
2042
        + (double) LongSec / 3600.0;
 
2043
 
 
2044
    latitude = DEGRAD * ((double) LatDeg + (double) LatMin / 60.0
 
2045
                         + (double) LatSec / 3600.0);
 
2046
 
 
2047
 
 
2048
    FromJulian(jul, &year, &mon, &day);
 
2049
    jan0 = jul - Julian(year, 0, 1);
 
2050
 
 
2051
    dusk_or_dawn = rise;
 
2052
    if (rise > 1)
 
2053
        rise -= 2;
 
2054
/* Following formula on page B6 exactly... */
 
2055
    t = (double) jan0;
 
2056
    if (rise) t += (6.0 + longdeg/15.0) / 24.0;
 
2057
    else      t += (18.0 + longdeg/15.0) / 24.0;
 
2058
 
 
2059
/* Mean anomaly of sun for 1978 ... how accurate for other years??? */
 
2060
    M = 0.985600 * t - 3.251;  /* In degrees */
 
2061
 
 
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 */
 
2065
        L += 6;
 
2066
    } else if (dusk_or_dawn == 3) {/* dawn */
 
2067
        L -= 14;
 
2068
    }
 
2069
    if (L > 360.0) L -= 360.0;
 
2070
 
 
2071
/* Tan of sun's right ascension */
 
2072
    tanA = 0.91746 * tan(DEGRAD*L);
 
2073
    a = RADDEG * atan(tanA);
 
2074
 
 
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) {
 
2079
        a += 180.0;
 
2080
    } else if (180.0 <= L && L < 270.0) {
 
2081
        a += 180.0;
 
2082
    } else {
 
2083
        if (a > 0.0) a += 180.0;
 
2084
    }
 
2085
/*   if (fabs(a - L) > 90.0)
 
2086
     a += 180.0; */
 
2087
    
 
2088
    if (a > 360.0)
 
2089
        a -= 360.0;
 
2090
    a_hr = a / 15.0;
 
2091
 
 
2092
/* Sine of sun's declination */
 
2093
    sinDelta = 0.39782 * sin(DEGRAD*L);
 
2094
    cosDelta = sqrt(1 - sinDelta*sinDelta);
 
2095
    
 
2096
/* Cosine of sun's local hour angle */
 
2097
    cosH = (cosz - sinDelta * sin(latitude)) / (cosDelta * cos(latitude));
 
2098
    
 
2099
    if (cosH < -1.0) { /* Summer -- permanent daylight */
 
2100
        if (rise) return NO_TIME;
 
2101
        else      return -NO_TIME;
 
2102
    }
 
2103
    if (cosH > 1.0) { /* Winter -- permanent darkness */
 
2104
        if (rise) return -NO_TIME;
 
2105
        else      return NO_TIME;
 
2106
    }
 
2107
 
 
2108
    H = RADDEG * acos(cosH);
 
2109
    if (rise) H = 360.0 - H;
 
2110
 
 
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;
 
2114
    
 
2115
    UT = T + longdeg / 15.0;
 
2116
    
 
2117
 
 
2118
    local = UT + (double) mins / 60.0;
 
2119
    if (local < 0.0) local += 24.0;
 
2120
    else if (local >= 24.0) local -= 24.0;
 
2121
 
 
2122
    hours = (int) local;
 
2123
    mins = (int) ((local - hours) * 60.0);
 
2124
    
 
2125
    /* Sometimes, we get roundoff error.  Check for "reasonableness" of
 
2126
       answer. */
 
2127
    if (rise) {
 
2128
        /* Sunrise so close to midnight it wrapped around -- permament light */
 
2129
        if (hours >= 23) return NO_TIME;
 
2130
    } else {
 
2131
        /* Sunset so close to midnight it wrapped around -- permament light */
 
2132
        if (hours <= 1) return -NO_TIME;
 
2133
    }
 
2134
    return hours*60 + mins;
 
2135
}
 
2136
 
 
2137
/***************************************************************/
 
2138
/*                                                             */
 
2139
/*  Sunrise and Sunset functions.                              */
 
2140
/*                                                             */
 
2141
/***************************************************************/
 
2142
#ifdef HAVE_PROTOS
 
2143
PRIVATE int FSun(int rise)
 
2144
#else
 
2145
static int FSun(rise)
 
2146
int rise;
 
2147
#endif
 
2148
{
 
2149
    int jul = JulianToday;
 
2150
    static double cosz = -0.014543897;  /* for sunrise and sunset */
 
2151
    int r;
 
2152
 
 
2153
    if (Nargs >= 1) {
 
2154
        if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
2155
        jul = ARG(0).v.val;
 
2156
    }
 
2157
   
 
2158
    r = SunStuff(rise, cosz, jul);
 
2159
    if (r == NO_TIME) {
 
2160
        RetVal.v.val = 0;
 
2161
        RetVal.type = INT_TYPE;
 
2162
    } else if (r == -NO_TIME) {
 
2163
        RetVal.v.val = 1440;
 
2164
        RetVal.type = INT_TYPE;
 
2165
    } else {
 
2166
        RetVal.v.val = r;
 
2167
        RetVal.type = TIM_TYPE;
 
2168
    }
 
2169
    return OK;
 
2170
}
 
2171
      
 
2172
#ifdef HAVE_PROTOS
 
2173
PRIVATE int FSunrise(void)
 
2174
#else
 
2175
static int FSunrise()
 
2176
#endif
 
2177
{
 
2178
    return FSun(1);
 
2179
}
 
2180
#ifdef HAVE_PROTOS
 
2181
PRIVATE int FSunset(void)
 
2182
#else
 
2183
static int FSunset()
 
2184
#endif
 
2185
{
 
2186
    return FSun(0);
 
2187
}
 
2188
 
 
2189
#ifdef HAVE_PROTOS
 
2190
PRIVATE int FDawn(void)
 
2191
#else
 
2192
static int FDawn()
 
2193
#endif
 
2194
{
 
2195
    return FSun(3);
 
2196
}
 
2197
#ifdef HAVE_PROTOS
 
2198
PRIVATE int FDusk(void)
 
2199
#else
 
2200
static int FDusk()
 
2201
#endif
 
2202
{
 
2203
    return FSun(2);
 
2204
}
 
2205
 
 
2206
/***************************************************************/
 
2207
/*                                                             */
 
2208
/*  FFiledate                                                  */
 
2209
/*                                                             */
 
2210
/*  Return modification date of a file                         */
 
2211
/*                                                             */
 
2212
/***************************************************************/
 
2213
#ifdef HAVE_PROTOS
 
2214
PRIVATE int FFiledate(void)
 
2215
#else
 
2216
static int FFiledate()
 
2217
#endif
 
2218
{
 
2219
    struct stat statbuf;
 
2220
    struct tm *t1;
 
2221
 
 
2222
    RetVal.type = DATE_TYPE;
 
2223
 
 
2224
    if (ARG(0).type != STR_TYPE) return E_BAD_TYPE;
 
2225
 
 
2226
    if (stat(ARG(0).v.str, &statbuf)) {
 
2227
        RetVal.v.val = 0;
 
2228
        return OK;
 
2229
    }
 
2230
 
 
2231
#ifdef __TURBOC__
 
2232
    t1 = localtime( (time_t *) &(statbuf.st_mtime) );
 
2233
#else
 
2234
    t1 = localtime(&(statbuf.st_mtime));
 
2235
#endif
 
2236
 
 
2237
    if (t1->tm_year + 1900 < BASE)
 
2238
        RetVal.v.val=0;
 
2239
    else
 
2240
        RetVal.v.val=Julian(t1->tm_year+1900, t1->tm_mon, t1->tm_mday);
 
2241
 
 
2242
    return OK;
 
2243
}
 
2244
 
 
2245
/***************************************************************/
 
2246
/*                                                             */
 
2247
/*  FPsshade                                                   */
 
2248
/*                                                             */
 
2249
/*  Canned PostScript code for shading a calendar square       */
 
2250
/*                                                             */
 
2251
/***************************************************************/
 
2252
#ifdef HAVE_PROTOS
 
2253
PRIVATE int FPsshade(void)
 
2254
#else
 
2255
static int FPsshade()
 
2256
#endif
 
2257
{
 
2258
    char psbuff[256];
 
2259
    char *s = psbuff;
 
2260
    int i;
 
2261
 
 
2262
    /* 1 or 3 args */
 
2263
    if (Nargs != 1 && Nargs != 3) return E_2MANY_ARGS;
 
2264
 
 
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;
 
2269
    }
 
2270
 
 
2271
    sprintf(s, "/_A LineWidth 2 div def ");
 
2272
    s += strlen(s);
 
2273
    sprintf(s, "_A _A moveto ");
 
2274
    s += strlen(s);
 
2275
    sprintf(s, "BoxWidth _A sub _A lineto BoxWidth _A sub BoxHeight _A sub lineto ");
 
2276
    s += strlen(s);
 
2277
    if (Nargs == 1) {
 
2278
        sprintf(s, "_A BoxHeight _A sub lineto closepath %d 100 div setgray fill 0.0 setgray", ARG(0).v.val);
 
2279
    } else {
 
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);
 
2281
    }
 
2282
    return RetStrVal(psbuff);
 
2283
}
 
2284
 
 
2285
/***************************************************************/
 
2286
/*                                                             */
 
2287
/*  FPsmoon                                                    */
 
2288
/*                                                             */
 
2289
/*  Canned PostScript code for generating moon phases          */
 
2290
/*                                                             */
 
2291
/***************************************************************/
 
2292
#ifdef HAVE_PROTOS
 
2293
PRIVATE int FPsmoon(void)
 
2294
#else
 
2295
static int FPsmoon()
 
2296
#endif
 
2297
{
 
2298
    char psbuff[512];
 
2299
    char sizebuf[30];
 
2300
    char fontsizebuf[30];
 
2301
    char *s = psbuff;
 
2302
    char *extra = NULL;
 
2303
    int size = -1;
 
2304
    int fontsize = -1;
 
2305
 
 
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;
 
2309
    if (Nargs > 1) {
 
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;
 
2313
        if (Nargs > 2) {
 
2314
            if (ARG(2).type != STR_TYPE) return E_BAD_TYPE;
 
2315
            extra = ARG(2).v.str;
 
2316
            if (Nargs > 3) {
 
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;
 
2320
            }
 
2321
        }
 
2322
    }
 
2323
    if (size > 0) {
 
2324
        sprintf(sizebuf, "%d", size);
 
2325
    } else {
 
2326
        strcpy(sizebuf, "DaySize 2 div");
 
2327
    }
 
2328
 
 
2329
    if (fontsize > 0) {
 
2330
        sprintf(fontsizebuf, "%d", fontsize);
 
2331
    } else {
 
2332
        strcpy(fontsizebuf, "EntrySize");
 
2333
    }
 
2334
 
 
2335
    sprintf(s, "gsave 0 setgray newpath Border %s add BoxHeight Border sub %s sub",
 
2336
            sizebuf, sizebuf);
 
2337
    s += strlen(s);
 
2338
    sprintf(s, " %s 0 360 arc closepath", sizebuf);
 
2339
    s += strlen(s);
 
2340
    switch(ARG(0).v.val) {
 
2341
    case 0:
 
2342
        sprintf(s, " fill");
 
2343
        s += strlen(s);
 
2344
        break;
 
2345
 
 
2346
    case 2:
 
2347
        sprintf(s, " stroke");
 
2348
        s += strlen(s);
 
2349
        break;
 
2350
 
 
2351
    case 1:
 
2352
        sprintf(s, " stroke");
 
2353
        s += strlen(s);
 
2354
        sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
 
2355
                sizebuf, sizebuf);
 
2356
        s += strlen(s);
 
2357
        sprintf(s, " %s 90 270 arc closepath fill", sizebuf);
 
2358
        s += strlen(s);
 
2359
        break;
 
2360
 
 
2361
    default:
 
2362
        sprintf(s, " stroke");
 
2363
        s += strlen(s);
 
2364
        sprintf(s, " newpath Border %s add BoxHeight Border sub %s sub",
 
2365
                sizebuf, sizebuf);
 
2366
        s += strlen(s);
 
2367
        sprintf(s, " %s 270 90 arc closepath fill", sizebuf);
 
2368
        s += strlen(s);
 
2369
        break;
 
2370
    }
 
2371
    if (extra) {
 
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);
 
2374
        s += strlen(s);
 
2375
    }
 
2376
 
 
2377
    sprintf(s, " grestore");
 
2378
    return RetStrVal(psbuff);
 
2379
}
 
2380
 
 
2381
/***************************************************************/
 
2382
/*                                                             */
 
2383
/*  FMoonphase                                                 */
 
2384
/*                                                             */
 
2385
/*  Phase of moon for specified date/time.                     */
 
2386
/*                                                             */
 
2387
/***************************************************************/
 
2388
#ifdef HAVE_PROTOS
 
2389
PRIVATE int FMoonphase(void)
 
2390
#else
 
2391
static int FMoonphase()
 
2392
#endif
 
2393
{
 
2394
    int date, time;
 
2395
 
 
2396
    switch(Nargs) {
 
2397
    case 0:
 
2398
        date = JulianToday;
 
2399
        time = 0;
 
2400
        break;
 
2401
    case 1:
 
2402
        if (ARG(0).type != DATE_TYPE) return E_BAD_TYPE;
 
2403
        date = ARG(0).v.val;
 
2404
        time = 0;
 
2405
        break;
 
2406
    case 2:
 
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;
 
2410
        break;
 
2411
 
 
2412
    default: return E_SWERR;
 
2413
    }
 
2414
 
 
2415
    RetVal.type = INT_TYPE;
 
2416
    RetVal.v.val = MoonPhase(date, time);
 
2417
    return OK;
 
2418
}
 
2419
 
 
2420
/***************************************************************/
 
2421
/*                                                             */
 
2422
/*  FMoondate                                                  */
 
2423
/*                                                             */
 
2424
/*  Hunt for next occurrence of specified moon phase           */
 
2425
/*                                                             */
 
2426
/***************************************************************/
 
2427
PRIVATE int MoonStuff ARGS ((int want_time));
 
2428
#ifdef HAVE_PROTOS
 
2429
PRIVATE int FMoondate(void)
 
2430
#else
 
2431
static int FMoondate()
 
2432
#endif
 
2433
{
 
2434
    return MoonStuff(0);
 
2435
}
 
2436
 
 
2437
#ifdef HAVE_PROTOS
 
2438
PRIVATE int FMoontime(void)
 
2439
#else
 
2440
static int FMoontime()
 
2441
#endif
 
2442
{
 
2443
    return MoonStuff(1);
 
2444
}
 
2445
 
 
2446
#ifdef HAVE_PROTOS
 
2447
PRIVATE int MoonStuff(int want_time)
 
2448
#else
 
2449
static int MoonStuff(want_time)
 
2450
int want_time;
 
2451
#endif
 
2452
{
 
2453
    int startdate, starttim;
 
2454
    int d, t;
 
2455
 
 
2456
    startdate = JulianToday;
 
2457
    starttim = 0;
 
2458
 
 
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;
 
2462
    if (Nargs >= 2) {
 
2463
        if (ARG(1).type != DATE_TYPE) return E_BAD_TYPE;
 
2464
        startdate = ARG(1).v.val;
 
2465
        if (Nargs >= 3) {
 
2466
            if (ARG(2).type != TIM_TYPE) return E_BAD_TYPE;
 
2467
            starttim = ARG(2).v.val;
 
2468
        }
 
2469
    }
 
2470
 
 
2471
    HuntPhase(startdate, starttim, ARG(0).v.val, &d, &t);
 
2472
    if (want_time) {
 
2473
        RetVal.type = TIM_TYPE;
 
2474
        RetVal.v.val = t;
 
2475
    } else {
 
2476
        RetVal.type = DATE_TYPE;
 
2477
        RetVal.v.val = d;
 
2478
    }
 
2479
    return OK;
 
2480
}
 
2481
 
 
2482