home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ARM Club 3
/
TheARMClub_PDCD3.iso
/
hensa
/
programming
/
andylib_1
/
AndyLib
/
c
/
options
< prev
next >
Wrap
Text File
|
1995-05-15
|
13KB
|
547 lines
/* options.c */
#include <ctype.h>
#include <string.h>
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include "os.h"
#include "swis.h"
#include "wimp.h"
#include "wimpt.h"
#include "win.h"
#include "msgs.h"
#include "flex.h"
#include "intalk.h"
#include "options.h"
#define options_NAME "<AWOptions$Dir>.Options"
#define options_AWPATH "AWShared$Path"
#define options_VAR "AWOptions$Dir"
#define options_CMD "<AWOptions$Dir>"
typedef struct options__watcher
{ struct options__watcher *link;
options_changedhandler ch;
void *handle;
} options__watcher;
static char *options; /* flex */
static int options__size;
static options__watcher *options__world;
static BOOL options__changed;
static BOOL options__internal;
#define options__taginitchar(c) ((c) == '_' || (c) == '$' || isalpha(c))
#define options__tagchar(c) (options__taginitchar(c) || isdigit(c))
static os_error *options__err(char *msg, ...)
{ static os_error eb;
va_list ap;
va_start(ap, msg);
vsprintf(eb.errmess, msgs_lookup(msg), ap);
va_end(ap);
return &eb;
}
static int options__strcicmp(const char *s1, const char *s2)
{ while (*s1 && toupper(*s1) == toupper(*s2))
s1++, s2++;
return toupper(*s1) - toupper(*s2);
}
static os_error *options__falloc(void **ptr, int size)
{ if (!flex_alloc(ptr, size))
return options__err("options9:Not enough memory to load or process options file");
return NULL;
}
static os_error *options__fextend(void **ptr, int by)
{ if (!flex_extend(ptr, by))
return options__err("options9:Not enough memory to load or process options file");
return NULL;
}
static os_error *options__fmidextend(void **ptr, int at, int by)
{ if (!flex_midextend(ptr, at, by))
return options__err("options9:Not enough memory to load or process options file");
return NULL;
}
#if 0
static void options__ffree(void **ptr)
{ if (*ptr) flex_free(ptr);
}
#endif
static os_error *options__malloc(void **ptr, int size)
{ void *m;
if (m = malloc(size), !m)
return options__err("options9:Not enough memory to load or process options file");
*ptr = m;
return NULL;
}
static void options__free(void **ptr)
{ free(*ptr);
*ptr = NULL;
}
static os_error *options__syntax(void)
{ int lp, ln;
for (lp = 0, ln = 1; lp < options__size; )
{ while (lp < options__size && options[lp] != '\n' && isspace(options[lp]))
lp++;
if (lp >= options__size) goto endfile;
switch (options[lp])
{ case '\n':
lp++;
ln++;
break;
case '#': case ';': case '|':
lp++;
while (lp < options__size && options[lp] != '\n')
lp++;
if (lp >= options__size)
goto missingeol;
lp++;
ln++;
break;
default:
if (!options__taginitchar(options[lp]))
goto badchar;
lp++;
while (lp < options__size && options__tagchar(options[lp]))
lp++;
if (lp >= options__size)
goto missingeol;
if (options[lp] != ':')
return options__err("options5:Missing ':' after tag in line %d of options file", ln);
lp++;
while (lp < options__size && options[lp] != '\n')
lp++;
if (lp >= options__size)
goto missingeol;
lp++;
ln++;
break;
}
}
endfile:
return NULL;
badchar:
return options__err("options4:Bad character in options tag in line %d", ln);
missingeol:
return options__err("options3:Missing newline before end of options file");
}
static os_error *options__notify(void)
{ os_error *err;
options__watcher *watcher;
for (watcher = options__world; watcher; watcher = watcher->link)
if (err = watcher->ch(watcher->handle), err)
return err;
return NULL;
}
/* Load the options file */
os_error *options_reload(void)
{ os_regset regs;
os_filestr fcb;
os_error *err;
regs.r[0] = (int) options_AWPATH;
regs.r[1] = NULL;
regs.r[2] = -1;
regs.r[3] = 0;
regs.r[4] = 0;
os_swix(OS_ReadVarVal, ®s);
if (regs.r[2] == 0)
return options__err("options1:AWShared directory not found");
fcb.action = 17;
fcb.name = options_NAME;
if (err = os_file(&fcb), err)
return err;
if (fcb.action == 0) /* not found isn't an error */
{ options__size = 0;
return NULL;
}
else if (fcb.action != 1)
{ fcb.loadaddr = fcb.action;
fcb.action = 19;
return os_file(&fcb);
}
if ((fcb.loadaddr & 0xFFFFFF00) != 0xFFFFFF00)
return options__err("options2:" options_NAME " is not a text file");
options__size = fcb.start;
if (err = options__falloc((void **) &options, options__size), err)
return err;
fcb.action = 0xff;
fcb.loadaddr = (int) options;
fcb.execaddr = 0;
if (err = os_file(&fcb), err)
return err;
if (err = options__syntax(), err)
return err;
options__changed = FALSE;
return options__notify();
}
static BOOL options__ukhandler(wimp_eventstr *e, void *handle)
{ handle = handle;
switch (e->e)
{ case wimp_ESEND:
case wimp_ESENDWANTACK:
switch (e->data.msg.hdr.action)
{ case intalk_MOPTIONSCHANGED:
if (options__internal)
options__internal = FALSE;
else
wimpt_complain(options_reload());
}
}
return FALSE;
}
os_error *options_init(void)
{ options__world = NULL;
win_add_unknown_event_processor(options__ukhandler, &options__world);
return options_reload();
}
/* Lines must be one of
*
* blank
* # comment
* tag:value
*/
static int options__findtag(char *tag, int *solp)
{ int lp, sol;
char *tp;
for (lp = 0; lp < options__size; )
{ sol = lp; /* start of line */
while (lp < options__size && options[lp] != '\n' && isspace(options[lp]))
lp++;
if (lp >= options__size) return -1;
switch (options[lp])
{ case '\n':
lp++;
break;
default:
if (options__taginitchar(options[lp]))
{ for (tp = tag;
lp < options__size &&
options__tagchar(options[lp]) && *tp &&
tolower(options[lp]) == tolower(*tp); lp++, tp++)
;
if (lp >= options__size)
return -1;
if (options[lp] == ':' && *tp == '\0')
{ if (solp) *solp = sol;
return lp+1;
}
}
/* fall through */
case '#': case ';': case '|':
lp++;
while (lp < options__size && options[lp] != '\n')
lp++;
if (lp >= options__size)
return -1;
lp++;
break;
}
}
return -1;
}
os_error *options_readstrx(char *tag, char *buf, int size, char *def)
{ int pos;
if (pos = options__findtag(tag, NULL), pos >= 0)
{ while (pos < options__size && options[pos] != '\n' && size > 1)
{ *buf++ = options[pos++];
size--;
}
*buf = '\0';
}
else if (def)
strcpy(buf, def);
else
*buf = '\0';
return NULL;
}
os_error *options_readstr(char *tag, char *buf, int size)
{ return options_readstrx(tag, buf, size, NULL);
}
os_error *options_readintx(char *tag, int *num, int def)
{ char nbuf[20], dbuf[20], *np;
os_error *err;
sprintf(dbuf, "%d", def);
if (err = options_readstrx(tag, nbuf, 20, dbuf), err)
return err;
for (np = nbuf; *np; np++)
if (!isdigit(*np))
return options__err("options6:%s is not a numeric option", tag);
if (num) *num = atoi(nbuf);
return NULL;
}
os_error *options_readint(char *tag, int *num)
{ return options_readintx(tag, num, 0);
}
os_error *options_readboolx(char *tag, BOOL *flag, BOOL def)
{ char bbuf[20], dbuf[5];
os_error *err;
strcpy(dbuf, def ? "yes" : "no");
if (err = options_readstrx(tag, bbuf, 20, dbuf), err)
return err;
if (options__strcicmp(bbuf, "yes") == 0)
*flag = TRUE;
else if (*bbuf == '\0' || options__strcicmp(bbuf, "no") == 0)
*flag = FALSE;
else
return options__err("options7:%s is not a boolean option (yes or no required)", tag);
return NULL;
}
os_error *options_readbool(char *tag, BOOL *flag)
{ return options_readboolx(tag, flag, FALSE);
}
static os_error *options__writestr(char *tag, char *buf, BOOL purge)
{ int pos, p2;
int nlen, olen, tlen, by, sol;
os_error *err;
char *tp;
BOOL ch;
nlen = strlen(buf);
if (pos = options__findtag(tag, &sol), pos >= 0)
{ ch = FALSE;
if (purge && nlen == 0)
{ pos = sol; /* go back to start of line */
nlen = -1; /* make by smaller by 1 to get \n too */
ch = TRUE;
}
for (p2 = pos, tp = buf;
!ch && p2 < options__size && options[p2] != '\n' && *tp != '\0';
p2++, tp++)
ch = options[p2] != *tp;
if (!ch) ch = (p2 < options__size && options[p2] != '\n') || *tp;
for (p2 = pos, olen = 0; p2 < options__size && options[p2] != '\n'; p2++)
olen++;
by = nlen - olen;
if (by != 0 && (err = options__fmidextend((void **) &options, by > 0 ? pos : pos - by, by), err))
return err;
if (nlen > 0) memcpy(options + pos, buf, nlen);
options__size += nlen - olen;
options__changed |= ch;
}
else if (!purge || nlen > 0)
{ tlen = strlen(tag);
if (!options__taginitchar(*tag))
goto badtag;
for (tp = tag; *tp; tp++)
if (!options__tagchar(*tp))
goto badtag;
if (options)
err = options__fextend((void **) &options, options__size + nlen + tlen + 2);
else
err = options__falloc((void **) &options, nlen + tlen + 2);
memcpy(options + options__size, tag, tlen);
options[options__size + tlen] = ':';
memcpy(options + options__size + tlen + 1, buf, nlen);
options[options__size + nlen + tlen + 1] = '\n';
options__size += tlen + nlen + 2;
options__changed = TRUE;
}
return NULL;
badtag:
return options__err("options8:%s is not a legal tag\n", tag);
}
os_error *options_writestr(char *tag, char *buf)
{ return options__writestr(tag, buf, FALSE);
}
os_error *options_writeif(char *tag, char *buf)
{ return options__writestr(tag, buf, TRUE);
}
os_error *options_writeint(char *tag, int num)
{ char nbuf[20];
sprintf(nbuf, "%d", num);
return options_writestr(tag, nbuf);
}
os_error *options_writebool(char *tag, BOOL flag)
{ return options_writestr(tag, flag ? "yes" : "no");
}
os_error *options_written(void)
{ os_error *err;
os_filestr fcb;
wimp_msgstr msg;
if (!options__changed) return NULL;
fcb.action = 10;
fcb.name = options_NAME;
fcb.loadaddr = 0xFFF;
fcb.start = (int) options;
fcb.end = (int) options + options__size;
if (err = os_file(&fcb), err) return err;
options__changed = FALSE;
options__internal = TRUE;
msg.hdr.action = (wimp_msgaction) intalk_MOPTIONSCHANGED;
msg.hdr.size = sizeof(wimp_msghdr);
msg.hdr.your_ref = 0;
if (err = wimp_sendmessage(wimp_ESEND, &msg, (wimp_t) 0), err)
return err;
return options__notify();
}
static options__watcher *options__unlink(options__watcher *list, options__watcher *cb)
{ if (cb == list)
return list->link;
list->link = options__unlink(list->link, cb);
return list;
}
os_error *options_register(options_changedhandler ch, void *handle)
{ options__watcher *cb;
os_error *err;
if (err = options__malloc((void **) &cb, sizeof(options__watcher)), err) return err;
cb->link = options__world;
cb->ch = ch;
cb->handle = handle;
options__world = cb;
return NULL;
}
os_error *options_unregister(options_changedhandler ch, void *handle)
{ options__watcher *me;
for (me = options__world; me; me = me->link)
if (me->ch == ch && me->handle == handle)
goto found;
return NULL;
found:
options__world = options__unlink(options__world, me);
options__free((void **) &me);
return NULL;
}
os_error *options_set(void)
{ os_regset regs;
regs.r[0] = (int) options_VAR;
regs.r[1] = NULL;
regs.r[2] = -1; /* check only */
regs.r[3] = 0;
regs.r[4] = 0;
os_swix(OS_ReadVarVal, ®s);
if (regs.r[2] < 0)
return wimp_starttask(options_CMD);
return options__err("options10:Can't find !Options");
}