home *** CD-ROM | disk | FTP | other *** search
- /* 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");
- }
-