home *** CD-ROM | disk | FTP | other *** search
- /* options.c - Routines to handle the setting of user options.
- Copyright (C) 1991, 1992, 1993 Kristian Nielsen.
-
- This file is part of XFH, the compressing file system handler.
-
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
-
- #include "CFS.h"
- #include <dossupport.h>
-
- #include <libraries/filehandler.h>
-
- #include <proto/exec.h>
- #include <proto/icon.h>
-
- #include <ctype.h>
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
-
-
- #define EOL '\n' /* Seperates lines in option files. */
- #define STARTUP_SEP '!' /* Seperates entries ("lines") in startup string. */
- #define QUOTE_CHAR '\"' /* Will be stripped from startup string. ("*"->*) */
- #define DEFCHAR '='
- #define FAKEDEFCHAR '&' /* Chars usable in options ('optname * option'). */
-
- struct Library *IconBase;
-
- static BOOL parse_bool_opt(glb glob, char *opt, BOOL *var){
- debug(("parse_bool_opt(): '%s'.\n",opt));
- if(MatchToolValue(opt, "OFF")) *var = FALSE;
- else if(MatchToolValue(opt, "NO")) *var = FALSE;
- else if(MatchToolValue(opt, "ON")) *var = TRUE;
- else if(MatchToolValue(opt, "YES")) *var = TRUE;
- else{
- debug(("Illegal bolean value.\n"));
- return FALSE;
- }
- debug(("Result: %ld.\n",*var));
- return TRUE;
- }
-
- /* This function can be used to set a boolean option. */
-
- static BOOL bool_opt(glb glob, char *opt, BOOL *var, BOOL default_val){
- if(!opt){
- *var = default_val;
- return TRUE;
- }else{
- return parse_bool_opt(glob, opt, var);
- }
- }
-
- /* These two functions can be used to set/sleanup string options. */
-
- static void string_cleanup(glb glob, char **var){
- if(*var){
- dosfree(*var);
- *var = NULL;
- }
- }
-
- static BOOL string_opt(glb glob, char *opt, char **var, char *default_val){
- int len;
- char *p;
-
- if(!opt){
- /* Check for a default value of NULL. */
- if(!default_val){
- string_cleanup(glob, var);
- *var = default_val;
- return TRUE;
- }else{
- opt = default_val;
- }
- }
- len = strlen(opt)+1;
- if(!(p = dosalloc(len))){
- OUTOFMEM;
- return FALSE;
- }
- strcpy(p,opt);
- string_cleanup(glob, var);
- *var = p;
- return TRUE;
- }
-
- /* The option setting functions.
- * Each function is passed the remainder of the options string as
- * entered by the user, and is expected to set the appropriate option
- * and return a boolean succes/failure.
- *
- * If called with a NULL argument, should set a default option.
- *
- * NOTE: A cleanup function will not be called without the corresponding
- * set function being called first.
- */
-
- static BOOL opt_rootdir(glb glob, char *opt){
- char default_name[MAXFILENAME+4];
-
- /* Get assign name to directory to serve as our default root. Obtained
- * by pruning the first char of the device name (ie. XDH0:->DH0:). */
- if(!glob->devname || !glob->devname[0]
- || strlen(glob->devname)>MAXFILENAME+1){
- debug(("PANIC: Bad device name.\n"));
- return FALSE;
- }
- strncpy(default_name,&glob->devname[1],MAXFILENAME+2);
- strcat(default_name,":");
-
- return string_opt(glob, opt, &glob->xRootName, default_name);
- }
-
- static void cleanup_rootdir(glb glob){
- string_cleanup(glob, &glob->xRootName);
- }
-
-
- /* Option 'VOLUMENAME'. */
- static void cleanup_volname(glb glob){
- string_cleanup(glob, &glob->uservolname);
- }
-
- static BOOL opt_volname(glb glob, char *opt){
- /* The default is NULL - this will signify to createvolnode() that it
- * should create a default volume name.
- */
- cleanup_volname(glob);
- if(!string_opt(glob, opt, &glob->uservolname, NULL)) return FALSE;
- if(glob->volnode){
- return SetVolumeNameVolNode(glob, glob->uservolname);
- }else{
- return TRUE; /* createvolnode will set name. */
- }
- }
-
-
- /* Option 'AUTOCOMPRESS'. */
- static BOOL opt_autocompress(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->autocompress, FALSE);
- }
-
-
- /* Option 'STEPDOWN'. */
- static BOOL opt_stepdown(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->stepdown, FALSE);
- }
-
-
- /* Option 'PACKMODE'. */
- static BOOL opt_packmode(glb glob, char *opt){
- return string_opt(glob, opt, &glob->packmode, "NUKE");
- }
-
- static void cleanup_packmode(glb glob){
- string_cleanup(glob, &glob->packmode);
- }
-
-
- /* Option 'PASSWORD'. */
- static BOOL opt_password(glb glob, char *opt){
- /* The default is NULL - no password (valid acc. to 'xpk.doc'). */
- return string_opt(glob, opt, &glob->xpkpassword, NULL);
- }
-
- static void cleanup_password(glb glob){
- return string_cleanup(glob, &glob->xpkpassword);
- }
-
-
- /* Option 'TRUNCATEONPACK'. */
- static BOOL opt_truncateonpack(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->truncateonpack, FALSE);
- }
-
-
- /* Option 'XPKPRIORITY'. */
- static BOOL opt_xpkpriority(glb glob, char *opt){
- if(opt){
- glob->xpksetpri = TRUE;
- glob->xpkpri = atoi(opt);
- }else{
- glob->xpksetpri = FALSE;
- }
- return TRUE;
- }
-
-
- /* Option 'CREATEVOLUME'. */
- static BOOL opt_createvol(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->createvolnode, TRUE);
- }
-
-
- /* Option 'FAILONEXNEXT'. */
- static BOOL opt_failonexnext(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->FailOnExNext, TRUE);
- }
-
-
- /* Option 'COMPRESSREADWRITE'. */
- static BOOL opt_compressrw(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->compressreadwrite, TRUE);
- }
-
-
- /* Option 'ALLOWAPPEND'. */
- static BOOL opt_allowappend(glb glob, char *opt){
- return bool_opt(glob, opt, &glob->allowappend, TRUE);
- }
-
-
- /* Option 'KILLSTARTUP'. */
- static void cleanup_kstartup(glb glob){
- DevNode_Stuff_Startup_String(glob, glob->bcplstartup);
- }
-
-
- static BOOL opt_killstartup(glb glob, char *opt){
- BOOL tmp;
-
- if(!bool_opt(glob, opt, &tmp, TRUE)){
- return FALSE;
- }
- if(tmp){
- DevNode_Stuff_Startup_String(glob, 0L);
- }else{
- cleanup_kstartup(glob);
- }
- return TRUE;
- }
-
-
- /* Option 'PORTNAME'. */
- static BOOL opt_arexxportname(glb glob, char *opt){
- return string_opt(glob, opt, &glob->userarexxportname, NULL);
- }
-
- static void cleanup_arexxpname(glb glob){
- string_cleanup(glob, &glob->userarexxportname);
- }
-
-
- /* The 'options table'. */
-
- static struct opttable{
- char *opt;
- BOOL (*set)(glb, char *); /* 'set' function. */
- void (*cleanup)(glb); /* 'cleanup' function. */
- BOOL persistent; /* True -> option can be set only once. */
- } opttable[] = {
- "ROOTDIR", opt_rootdir, cleanup_rootdir, TRUE,
- "VOLUMENAME", opt_volname, cleanup_volname, FALSE,
- "AUTOCOMPRESS", opt_autocompress, NULL, FALSE,
- "STEPDOWN", opt_stepdown, NULL, FALSE,
- "PACKMODE", opt_packmode, cleanup_packmode, FALSE,
- "PASSWORD", opt_password, cleanup_password, FALSE,
- "TRUNCATEONPACK", opt_truncateonpack, NULL, FALSE,
- "XPKPRIORITY", opt_xpkpriority, NULL, FALSE,
- "CREATEVOLUME", opt_createvol, NULL, TRUE,
- "FAILONEXNEXT", opt_failonexnext, NULL, FALSE,
- "KILLSTARTUP", opt_killstartup, cleanup_kstartup, FALSE,
- "COMPRESSREADWRITE", opt_compressrw, NULL, FALSE,
- "ALLOWAPPEND", opt_allowappend, NULL, FALSE,
- "PORTNAME", opt_arexxportname, cleanup_arexxpname,TRUE,
- NULL
- };
-
-
- /* This function sets the options according to an option file (in
- * char ** form as returned by buf2array()). The first time it is called
- * initial should be TRUE to set default and persistent options.
- * And initial should be TRUE ONLY the first time this is called!!!
- */
- static BOOL SetOptions(glb glob, char **opts, BOOL initial){
- struct opttable *p,*r;
- char *q;
-
- {char **p;for(p=opts;*p;p++) debug(("'%s'\n",*p));}
- for(p=opttable;p->opt;p++){
- q = FindToolType((UBYTE **)opts, p->opt);
- debug(("Setting option '%s': (%ld).\n",p->opt,!!q));
- if((q && !p->persistent) || initial){
- if( !(*p->set)(glob, q) ){
- debug(("Error occured seting option '%s'.\n",p->opt));
- goto optionerror;
- }
- }
- }
- /* All options successfull. */
- if(initial) glob->optionsset = TRUE;
- return TRUE;
-
- optionerror:
- /* An error occured during option setting. Cleanup any set options
- * if nessesary and return, reporting failure.
- */
- glob->badoption = p->opt; /* For error report. */
- if(initial){
- glob->optionsset = FALSE; /* Just to be safe. */
- for(r=opttable;r<p;r++){
- if(r->cleanup) (*r->cleanup)(glob);
- }
- }
- return FALSE;
- }
-
-
- /* Set a single option. This is done by faking an option file with a single
- * entry.
- */
- BOOL set_option(glb glob, char *p){
- char *array[2];
-
- debug(("set_option() received '%s'.\n",p));
- array[0]=p;
- array[1]=NULL;
- return SetOptions(glob, array, FALSE);
- }
-
-
- /* Set a single option using an opt/val pair. */
- BOOL set_option_value(glb glob, char *opt, char *val){
- char *p;
- BOOL res;
-
- if(!(p=dosalloc(strlen(opt)+strlen("=")+strlen(val)+1))){
- debug(("set_option_value(): no mem.\n"));
- OUTOFMEM;
- return FALSE;
- }
- strcpy(p,opt);
- strcat(p,"=");
- strcat(p,val);
- res = set_option(glob, p);
- dosfree(p);
- return res;
- }
- static void CleanupAllOptions(glb glob){
- struct opttable *p;
-
- if(glob->optionsset){
- for(p=opttable; p->opt; p++){
- if(p->cleanup) (*p->cleanup)(glob);
- }
- glob->optionsset = FALSE;
- }
- }
-
- /* Create string array (char**) from buffer (changing "sep" chars to '\0').
- * Also removes whitespace at end of lines.
- * The buffer MUST be (at least) 1 byte longer than 'len'.
- * Returns NULL if not enough memory available.
- */
- static char **buf2array(glb glob, char *buf, int len, char sep){
- int i,j;
- int numlines=0;
- char **p,**q;
-
- debug(("String: '%s'.\n",buf));
- for(i=0;i<len;i++) if(buf[i]==sep) numlines++;
- /* The array size is numlines+2: one extra 'safe' line, and a
- * NULL-terminator. */
- if(!(p=q=dosalloc(sizeof(*p)*(numlines+2)))){
- OUTOFMEM;
- return NULL;
- }
- *q++ = buf;
- for(i=0;i<len;i++){
- if(buf[i]==sep){
- for(j=i-1; (j>=0) && buf[j] && isspace(buf[j]); j--){
- debug(("Skipping '%lc'.\n",buf[j]));
- }
- buf[j+1]='\0';
- *q++=&buf[i+1];
- }
- }
- /* Fix the last line (may not be "sep" terminated). */
- for(j=i-1; (j>=0) && buf[j] && isspace(buf[j]); j--);
- buf[j+1]='\0';
- if(!**(q-1)) *(q-1) = NULL; /* Remove last line if empty. */
- return p;
- }
-
-
- static void deleteoptionfromarray(glb glob, char **array, char *opt){
- char *p;
- char **q;
-
- p = FindToolType((UBYTE **)array, opt);
- if(!p) return;
- /* Delete the entry corresponding to p. */
- for(q=array; *q; q++){
- if(*q<=p && (!q[1] || q[1] > p)) goto deleteit;
- }
- debug(("Strange: Bugus pointer returned by FindToolType().\n"));
- return;
- deleteit:
- while(q[0] = q[1]) q++;
- return;
- }
-
-
- static BOOL writearraytofile(glb glob, char **array, struct FileHandle *fh){
- char **p;
-
- for(p=array; *p; p++){
- if(!xWriteStr(glob, fh, *p)) return FALSE;
- if(!xWriteStr(glob, fh, "\n")) return FALSE;
- }
- return TRUE;
- }
-
-
- /* Attempt to read an option file. If the file could be read, it sets
- * the arg to point to a buffer containing the data. This buffer must
- * be deallocated by the caller (using dosfree()).
- * Returns TRUE if the file was found, FALSE otherwise.
- * NOTE: The arg may be returned NULL even if TRUE is returned.
- * This signifies an 'out of memory' condition.
- */
- static BOOL ReadOptFile(glb glob, struct FileLock *parent, char *name,
- char **buf, LONG *size){
- struct FileHandle *fh;
-
- *buf=NULL;
- if(!(fh = xOpen(glob, parent, name, MODE_OLDFILE))) return FALSE;
- *size = xSeek(glob, fh, 0, OFFSET_END);
- if(*size==-1L){
- xClose(glob, fh);
- return FALSE;
- }
- *size = xSeek(glob, fh, 0, OFFSET_BEGINNING);
- if(*size==-1L){
- xClose(glob, fh);
- return FALSE;
- }
- if(!(*buf = dosalloc(*size+1))){
- OUTOFMEM;
- xClose(glob, fh);
- return TRUE;
- }
- if(*size != xRead(glob, fh, *buf, *size)){
- xClose(glob, fh);
- dosfree(buf);
- *buf = NULL;
- return FALSE;
- }
- xClose(glob, fh);
- return TRUE;
- }
-
-
- static BOOL writeoption(glb glob, struct FileHandle *fh, char *opt, char *val){
- if(!xWriteStr(glob, fh, opt)) return FALSE;
- if(!xWriteStr(glob, fh, "=")) return FALSE;
- if(!xWriteStr(glob, fh, val)) return FALSE;
- if(!xWriteStr(glob, fh, "\n"))return FALSE;
- return TRUE;
- }
-
-
- /* Set a single option, but make it permanent (in :.xfhrc).
- *
- * A little magic is neede here since we share the .xfhrc file with
- * the user. So, first read it, find existing entry (if any), then
- * write back the file, changing the entry in the process.
- */
- BOOL SetOptionPermanent(glb glob, char *opt, char *val){
- struct FileHandle *fh;
- char *buf;
- LONG len;
- char **array;
- BOOL res;
-
- if(!ReadOptFile(glob, glob->xrootlock, ALTOPTIONPATH, &buf, &len)){
- debug((".xfhrc file nonexisting, creating new.\n"));
- if(!(fh=xOpen(glob, glob->xrootlock, ALTOPTIONPATH, MODE_NEWFILE))){
- debug(("Error: Unable to open file: %ld.\n",glob->ioerr));
- return FALSE;
- }
- if(writeoption(glob, fh, opt, val)){
- if(!xClose(glob, fh)) return FALSE;
- return set_option_value(glob, opt, val);
- }else{
- SAVEIOERR;
- xClose(glob, fh);
- RESTIOERR;
- return FALSE;
- }
- }
- if(!buf) return FALSE;
- /* Ok, there's a file there already. Change it. */
- if(!(array = buf2array(glob, buf, len, EOL))){
- dosfree(buf);
- return FALSE;
- }
- deleteoptionfromarray(glob, array, opt);
- if(!(fh=xOpen(glob, glob->xrootlock, ALTOPTIONPATH, MODE_NEWFILE))){
- debug(("Error: Unable to open file again: %ld.\n",glob->ioerr));
- dosfree(array);
- dosfree(buf);
- return FALSE;
- }
- res = writearraytofile(glob, array, fh);
- dosfree(array);
- dosfree(buf);
- if(!res){
- SAVEIOERR;
- xClose(glob, fh);
- RESTIOERR;
- return FALSE;
- }
- if(!writeoption(glob, fh, opt, val)){
- SAVEIOERR;
- xClose(glob, fh);
- RESTIOERR;
- return FALSE;
- }
- if(!xClose(glob, fh)) return FALSE;
- return set_option_value(glob, opt, val);
- }
-
-
- /* Called to read additional option files (after setting the initial
- * options).
- */
- BOOL SetOptionsFromFile(glb glob, struct FileLock *lock, char *name){
- char *buf;
- LONG len;
- char **array;
- BOOL res;
-
- if(!ReadOptFile(glob, lock, name, &buf, &len)) return TRUE;
- if(!buf) return FALSE;
- if(!(array = buf2array(glob, buf, len, EOL))){
- dosfree(buf);
- return FALSE;
- }
- res = SetOptions(glob, array, FALSE);
- dosfree(array);
- dosfree(buf);
- return res;
- }
-
-
- /* Set options given in the "Startup" keyword in the mountlist.
- * NOTE: this function will modify "startup".
- * ONLY called by SetOptionsDayOne() !!!
- */
- static BOOL SetOptionsFromStartup(glb glob, char *startup){
- char **array;
- char *p;
- BOOL res;
-
- /* Change FAKEDEFCHAR to DEFCHAR (hack to fix bug in mount cmd). */
- for(p=startup;*p;p++){
- if(*p==FAKEDEFCHAR) *p=DEFCHAR;
- }
- if(!(array = buf2array(glob, startup, strlen(startup), STARTUP_SEP))){
- return FALSE;
- }
- res = SetOptions(glob, array, TRUE);
- debug(("SetOptions(): result %ld\n",res));
- dosfree(array);
- return res;
- }
-
-
- /* Set all options to their default, since there wasn't an option file.
- * ONLY called by SetOptionsDayOne() !!!
- */
- static BOOL SetDefaultOptions(glb glob){
- static char *fakeopts[] = {NULL};
-
- /* Just pass SetOptions a fake, empty option file. */
- return SetOptions(glob, fakeopts, TRUE);
- }
-
-
- /* Set options from primary option file.
- * ONLY called by SetOptionsDayOne() !!!
- */
- static BOOL SetOptionsFromPrimary(glb glob, char *filename){
- char *buf;
- LONG len;
- char **array;
- struct MsgPort *procid;
- struct FileLock *lock;
- BPTR bcpllock;
- BOOL res;
-
- /* ToDo: This won't work with multi-assigns. */
- procid = DoDeviceProc( (LONG *)&bcpllock, filename, glob );
- /* ToDo: Nasty case if we get a non-null procid but a null lock.
- * For now this is regarded as an error.
- */
- if( !procid || !bcpllock ){
- return SetDefaultOptions(glob);
- }
- lock = b2c(bcpllock);
-
- if(!ReadOptFile(glob, lock, filename, &buf, &len)){
- return SetDefaultOptions(glob);
- }
- if(!buf) return FALSE;
- if(!(array = buf2array(glob, buf, len, EOL))){
- dosfree(buf);
- return FALSE;
- }
- res = SetOptions(glob, array, TRUE);
- dosfree(array);
- dosfree(buf);
- return res;
- }
-
-
- /* Called ONCE to set the initial options.
- * These may either come directly in the "Startup" string, or in an
- * option file. */
- static BOOL SetOptionsDayOne(glb glob){
- char *startup, *s2;
- BOOL res;
-
- /* Check for missing startup string. */
- if(!glob->bcplstartup) return SetDefaultOptions(glob);
- if(!(startup = copybstr(glob->bcplstartup))){
- debug(("Error: No memory for STARTUP string.\n"));
- OUTOFMEM;
- return FALSE;
- }
- /* Check for an empty startup string (""). */
- if(!strcmp("",startup) || !strcmp("\"\"",startup)){
- res = SetDefaultOptions(glob);
- }else{
- /* Check for a quoted string (ie. "foo" -> foo). */
- if(startup[0]==startup[strlen(startup)-1] && startup[0]==QUOTE_CHAR){
- startup[strlen(startup)-1] = '\0';
- s2 = &startup[1];
- }else{
- s2 = startup;
- }
- debug(("Startup string: '%s'\n",s2));
-
- /* If the first character of the STARTUP string is STARTUP_SEP, the
- * string is taken to be a list of option commands seperated by
- * STARTUP_SEP. Otherwise, it is taken to be the name of an option
- * file (which should have an absolute path).
- */
- if(s2[0]==STARTUP_SEP){
- debug(("Setting options from string.\n"));
- res = SetOptionsFromStartup(glob, &s2[1]);
- }else{
- debug(("Setting options from option file '%s'.\n",s2));
- res = SetOptionsFromPrimary(glob, s2);
- }
- }
- freestr(startup);
- return res;
- }
-
-
- BOOL InitOptions(glb glob){
-
- glob->optionsset = FALSE;
-
- if(!(glob->IconBase = OpenLibrary("icon.library",0L))){
- debug(("Error: InitOptions: Cannot open icon.library.\n"));
- return FALSE;
- }
- IconBase = glob->IconBase;
-
- SetOptionsDayOne(glob);
- }
-
- void CleanupOptions(glb glob){
-
- CleanupAllOptions(glob);
-
- if(glob->IconBase){
- CloseLibrary(IconBase);
- glob->IconBase = NULL;
- }
- }
-
-
- /* End of options.c */
-