1
/***************************************************************/
5
/* This file contains routines, structures, etc for */
6
/* user- and system-defined variables. */
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: var.c,v 1.7 2000/02/18 03:46:15 dfs Exp $";
35
#define UPPER(c) (islower(c) ? toupper(c) : c)
37
/* The variable hash table */
38
#define VAR_HASH_SIZE 64
39
#define VARIABLE ErrMsg[E_VAR]
40
#define VALUE ErrMsg[E_VAL]
41
#define UNDEF ErrMsg[E_UNDEF]
43
static Var *VHashTbl[VAR_HASH_SIZE];
45
/***************************************************************/
48
/* Given a string, compute the hash value. */
50
/***************************************************************/
52
PUBLIC unsigned int HashVal(const char *str)
54
unsigned int HashVal(str)
58
register unsigned int i=0;
59
register unsigned int j=1;
60
register unsigned int len=0;
62
while(*str && len < VAR_NAME_LEN) {
63
i += j * (unsigned int) UPPER(*str);
71
/***************************************************************/
74
/* Given a string, find the variable whose name is that */
75
/* string. If create is 1, create the variable. */
77
/***************************************************************/
79
PUBLIC Var *FindVar(const char *str, int create)
81
Var *FindVar(str, create)
90
h = HashVal(str) % VAR_HASH_SIZE;
95
if (! StrinCmp(str, v->name, VAR_NAME_LEN)) return v;
99
if (!create) return v;
101
/* Create the variable */
105
v->v.type = INT_TYPE;
108
StrnCpy(v->name, str, VAR_NAME_LEN);
110
if (prev) prev->next = v; else VHashTbl[h] = v;
114
/***************************************************************/
117
/* Given a string, find the variable whose name is that */
118
/* string and delete it. */
120
/***************************************************************/
122
PUBLIC int DeleteVar(const char *str)
132
h = HashVal(str) % VAR_HASH_SIZE;
137
if (! StrinCmp(str, v->name, VAR_NAME_LEN)) break;
141
if (!v) return E_NOSUCH_VAR;
143
if (prev) prev->next = v->next; else VHashTbl[h] = v->next;
148
/***************************************************************/
152
/* Set the indicate variable to the specified value. */
154
/***************************************************************/
156
PUBLIC int SetVar(const char *str, Value *val)
163
Var *v = FindVar(str, 1);
165
if (!v) return E_NO_MEM; /* Only way FindVar can fail */
172
/***************************************************************/
176
/* Get a copy of the value of the variable. */
178
/***************************************************************/
180
PUBLIC int GetVarValue(const char *str, Value *val, Var *locals)
182
int GetVarValue(str, val, locals)
190
/* Try searching local variables first */
193
if (! StrinCmp(str, v->name, VAR_NAME_LEN))
194
return CopyValue(val, &v->v);
201
Eprint("%s: %s", ErrMsg[E_NOSUCH_VAR], str);
204
return CopyValue(val, &v->v);
207
/***************************************************************/
209
/* DoSet - set a variable. */
211
/***************************************************************/
213
PUBLIC int DoSet (Parser *p)
225
r = ParseIdentifier(p, &buf);
228
r = EvaluateExpr(p, &v);
234
if (*DBufValue(&buf) == '$') r = SetSysVar(DBufValue(&buf)+1, &v);
235
else r = SetVar(DBufValue(&buf), &v);
240
/***************************************************************/
242
/* DoUnset - delete a bunch of variables. */
244
/***************************************************************/
246
PUBLIC int DoUnset (Parser *p)
257
r = ParseToken(p, &buf);
259
if (!DBufLen(&buf)) {
264
(void) DeleteVar(DBufValue(&buf)); /* Ignore error - nosuchvar */
268
r = ParseToken(p, &buf);
270
if (!DBufLen(&buf)) {
274
(void) DeleteVar(DBufValue(&buf));
278
/***************************************************************/
282
/* Command file command to dump variable table. */
284
/***************************************************************/
286
PUBLIC int DoDump(ParsePtr p)
297
r = ParseToken(p, &buf);
299
if (!*DBufValue(&buf) ||
300
*DBufValue(&buf) == '#' ||
301
*DBufValue(&buf) == ';') {
306
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
308
if (*DBufValue(&buf) == '$') {
309
DumpSysVarByName(DBufValue(&buf)+1);
311
v = FindVar(DBufValue(&buf), 0);
312
DBufValue(&buf)[VAR_NAME_LEN] = 0;
313
if (!v) fprintf(ErrFp, "%*s %s\n", VAR_NAME_LEN,
314
DBufValue(&buf), UNDEF);
316
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
317
PrintValue(&(v->v), ErrFp);
318
fprintf(ErrFp, "\n");
321
r = ParseToken(p, &buf);
323
if (!*DBufValue(&buf) ||
324
*DBufValue(&buf) == '#' ||
325
*DBufValue(&buf) == ';') {
332
/***************************************************************/
336
/* Dump the variable table to stderr. */
338
/***************************************************************/
340
PUBLIC void DumpVarTable(void)
348
fprintf(ErrFp, "%*s %s\n\n", VAR_NAME_LEN, VARIABLE, VALUE);
350
for (i=0; i<VAR_HASH_SIZE; i++) {
353
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, v->name);
354
PrintValue(&(v->v), ErrFp);
355
fprintf(ErrFp, "\n");
361
/***************************************************************/
365
/* Free all the memory used by variables, but don't delete */
366
/* preserved variables unless ALL is non-zero. */
368
/***************************************************************/
370
PUBLIC void DestroyVars(int all)
372
void DestroyVars(all)
377
Var *v, *next, *prev;
379
for (i=0; i<VAR_HASH_SIZE; i++) {
384
if (all || !v->preserve) {
389
if (prev) prev->next = v;
390
else VHashTbl[i] = v;
400
/***************************************************************/
404
/* Given the name of a variable, "preserve" it. */
406
/***************************************************************/
408
PUBLIC int PreserveVar(char *name)
410
int PreserveVar(name)
416
v = FindVar(name, 1);
417
if (!v) return E_NO_MEM;
422
/***************************************************************/
424
/* DoPreserve - preserve a bunch of variables. */
426
/***************************************************************/
428
PUBLIC int DoPreserve (Parser *p)
439
r = ParseToken(p, &buf);
441
if (!DBufLen(&buf)) {
446
r = PreserveVar(DBufValue(&buf));
452
r = ParseToken(p, &buf);
454
if (!DBufLen(&buf)) {
458
r = PreserveVar(DBufValue(&buf));
464
/***************************************************************/
466
/* SYSTEM VARIABLES */
468
/* Interface for modifying and reading system variables. */
470
/***************************************************************/
472
/* The structure of a system variable */
482
/* If the type of a sys variable is STR_TYPE, then min is redefined
483
to be a flag indicating whether or not the value has been malloc'd. */
484
#define been_malloced min
486
/* Flag for no min/max constraint */
488
/* All of the system variables sorted alphabetically */
489
static SysVar SysVarArr[] = {
490
/* name mod type value min/mal max */
491
{ "CalcUTC", 1, INT_TYPE, &CalculateUTC, 0, 1 },
492
{ "CalMode", 0, INT_TYPE, &DoCalendar, 0, 0 },
493
{ "Daemon", 0, INT_TYPE, &Daemon, 0, 0 },
494
{ "DefaultPrio", 1, INT_TYPE, &DefaultPrio, 0, 9999 },
495
{ "DontFork", 0, INT_TYPE, &DontFork, 0, 0 },
496
{ "DontQueue", 0, INT_TYPE, &DontQueue, 0, 0 },
497
{ "DontTrigAts", 0, INT_TYPE, &DontIssueAts, 0, 0 },
498
{ "EndSent", 1, STR_TYPE, &EndSent, 0, 0 },
499
{ "EndSentIg", 1, STR_TYPE, &EndSentIg, 0, 0 },
500
{ "FirstIndent", 1, INT_TYPE, &FirstIndent, 0, 132 },
501
{ "FoldYear", 1, INT_TYPE, &FoldYear, 0, 1 },
502
{ "FormWidth", 1, INT_TYPE, &FormWidth, 20, 132 },
503
{ "HushMode", 0, INT_TYPE, &Hush, 0, 0 },
504
{ "IgnoreOnce", 0, INT_TYPE, &IgnoreOnce, 0, 0 },
505
{ "InfDelta", 0, INT_TYPE, &InfiniteDelta, 0, 0 },
506
{ "LatDeg", 1, INT_TYPE, &LatDeg, -90, 90 },
507
{ "LatMin", 1, INT_TYPE, &LatMin, -59, 59 },
508
{ "LatSec", 1, INT_TYPE, &LatSec, -59, 59 },
509
{ "Location", 1, STR_TYPE, &Location, 0, 0 },
510
{ "LongDeg", 1, INT_TYPE, &LongDeg, -180, 180 },
511
{ "LongMin", 1, INT_TYPE, &LongMin, -59, 59 },
512
{ "LongSec", 1, INT_TYPE, &LongSec, -59, 59 },
513
{ "MaxSatIter", 1, INT_TYPE, &MaxSatIter, 10, ANY },
514
{ "MinsFromUTC", 1, INT_TYPE, &MinsFromUTC, -13*60, 13*60 },
515
{ "NextMode", 0, INT_TYPE, &NextMode, 0, 0 },
516
{ "NumQueued", 0, INT_TYPE, &NumQueued, 0, 0 },
517
{ "NumTrig", 0, INT_TYPE, &NumTriggered, 0, 0 },
518
{ "PSCal", 0, INT_TYPE, &PsCal, 0, 0 },
519
{ "RunOff", 0, INT_TYPE, &RunDisabled, 0, 0 },
520
{ "SimpleCal", 0, INT_TYPE, &DoSimpleCalendar, 0, 0 },
521
{ "SortByDate", 0, INT_TYPE, &SortByDate, 0, 0},
522
{ "SortByPrio", 0, INT_TYPE, &SortByPrio, 0, 0},
523
{ "SortByTime", 0, INT_TYPE, &SortByTime, 0, 0},
524
{ "SubsIndent", 1, INT_TYPE, &SubsIndent, 0, 132}
527
#define NUMSYSVARS ( sizeof(SysVarArr) / sizeof(SysVar) )
528
PRIVATE SysVar *FindSysVar ARGS((const char *name));
529
PRIVATE void DumpSysVar ARGS((const char *name, const SysVar *v));
530
/***************************************************************/
534
/* Set a system variable to the indicated value. */
536
/***************************************************************/
538
PUBLIC int SetSysVar(const char *name, Value *value)
540
int SetSysVar(name, value)
545
SysVar *v = FindSysVar(name);
546
if (!v) return E_NOSUCH_VAR;
547
if (v->type != value->type) return E_BAD_TYPE;
548
if (!v->modifiable) {
549
Eprint("%s: `$%s'", ErrMsg[E_CANT_MODIFY], name);
550
return E_CANT_MODIFY;
553
/* If it's a string variable, special measures must be taken */
554
if (v->type == STR_TYPE) {
555
if (v->been_malloced) free(*((char **)(v->value)));
556
v->been_malloced = 1;
557
*((char **) v->value) = value->v.str;
558
value->type = ERR_TYPE; /* So that it's not accidentally freed */
560
if (v->max != ANY && value->v.val > v->max) return E_2HIGH;
561
if (v->min != ANY && value->v.val < v->min) return E_2LOW;
562
*((int *)v->value) = value->v.val;
567
/***************************************************************/
571
/* Get the value of a system variable */
573
/***************************************************************/
575
PUBLIC int GetSysVar(const char *name, Value *val)
577
int GetSysVar(name, val)
582
SysVar *v = FindSysVar(name);
584
val->type = ERR_TYPE;
585
if (!v) return E_NOSUCH_VAR;
586
if (v->type == STR_TYPE) {
587
val->v.str = StrDup(*((char **) v->value));
588
if (!val->v.str) return E_NO_MEM;
590
val->v.val = *((int *) v->value);
594
/* In "verbose" mode, print attempts to test $RunOff */
595
if (DebugFlag & DB_PRTLINE) {
596
if (v->value == (void *) &RunDisabled) {
597
Eprint("(Security note: $RunOff variable tested.)\n");
598
/* Allow further messages from this line */
605
/***************************************************************/
609
/* Find a system var with specified name. */
611
/***************************************************************/
613
PRIVATE SysVar *FindSysVar(const char *name)
615
static SysVar *FindSysVar(name)
619
int top=NUMSYSVARS-1, bottom=0;
620
int mid=(top + bottom) / 2;
623
while (top >= bottom) {
624
r = StrCmpi(name, SysVarArr[mid].name);
625
if (!r) return &SysVarArr[mid];
626
else if (r>0) bottom = mid+1;
628
mid = (top+bottom) / 2;
633
/***************************************************************/
635
/* DumpSysVarByName */
637
/* Given the name of a system variable, display it. */
638
/* If name is "", dump all system variables. */
640
/***************************************************************/
642
PUBLIC void DumpSysVarByName(const char *name)
644
void DumpSysVarByName(name)
651
if (!name || !*name) {
652
for (i=0; i<NUMSYSVARS; i++) DumpSysVar(name, SysVarArr + i);
656
v = FindSysVar(name);
661
/***************************************************************/
665
/* Dump the system variable. */
667
/***************************************************************/
669
PRIVATE void DumpSysVar(const char *name, const SysVar *v)
671
static void DumpSysVar(name, v)
676
char buffer[VAR_NAME_LEN+10];
678
if (name && !*name) name=NULL;
679
if (!v && !name) return; /* Shouldn't happen... */
681
buffer[0]='$'; buffer[1] = 0;
682
if (name) strcat(buffer, name); else strcat(buffer, v->name);
683
fprintf(ErrFp, "%*s ", VAR_NAME_LEN, buffer);
685
if (v->type == STR_TYPE) {
686
char *s = *((char **)v->value);
689
for (y=0; y<MAX_PRT_LEN && *s; y++) Putc(*s++, ErrFp);
691
if (*s) fprintf(ErrFp, "...");
694
if (!v->modifiable) fprintf(ErrFp, "%d\n", *((int *)v->value));
696
fprintf(ErrFp, "%-10d ", *((int *)v->value));
697
if (v->min == ANY) fprintf(ErrFp, "(-Inf, ");
698
else fprintf(ErrFp, "[%d, ", v->min);
699
if (v->max == ANY) fprintf(ErrFp, "Inf)\n");
700
else fprintf(ErrFp, "%d]\n", v->max);
703
} else fprintf(ErrFp, "%s\n", UNDEF);