mirror of
https://github.com/amiwm/amiwm.git
synced 2026-04-14 11:04:18 +00:00
Initial commit!
This commit is contained in:
537
libami/readargs.c
Normal file
537
libami/readargs.c
Normal file
@@ -0,0 +1,537 @@
|
||||
#include "libami.h"
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#ifdef AMIGAOS
|
||||
|
||||
void initargs(int argc, char **argv)
|
||||
{
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
static char *cmdline=NULL;
|
||||
int cmdline_allocated=0, cmdline_used=0;
|
||||
|
||||
static void addachar(char c)
|
||||
{
|
||||
if(cmdline_used>=cmdline_allocated) {
|
||||
if(!cmdline_allocated) cmdline_allocated=128;
|
||||
while(cmdline_allocated<=cmdline_used)
|
||||
cmdline_allocated<<=1;
|
||||
if(cmdline!=NULL)
|
||||
cmdline=realloc(cmdline, cmdline_allocated);
|
||||
else
|
||||
cmdline=malloc(cmdline_allocated);
|
||||
}
|
||||
cmdline[cmdline_used++]=c;
|
||||
}
|
||||
|
||||
static void addquoted(const char *arg)
|
||||
{
|
||||
char ch;
|
||||
addachar(' '); addachar('"');
|
||||
while((ch=*arg++)) switch(ch) {
|
||||
case '\n': addachar('*'); addachar('N'); break;
|
||||
case '\"': addachar('*'); addachar('\"'); break;
|
||||
case '*': addachar(ch);
|
||||
default: addachar(ch);
|
||||
}
|
||||
addachar('"');
|
||||
}
|
||||
|
||||
static void addunquoted(const char *arg, int cnt)
|
||||
{
|
||||
if(cnt) {
|
||||
addachar(' ');
|
||||
while(cnt--)
|
||||
addachar(*arg++);
|
||||
}
|
||||
}
|
||||
|
||||
static void addarg(const char *arg)
|
||||
{
|
||||
if(*arg!='\"') {
|
||||
int plain=strcspn(arg, "\t\n ;=");
|
||||
if(!arg[plain]) {
|
||||
addunquoted(arg, plain);
|
||||
return;
|
||||
} else if(arg[plain]=='=') {
|
||||
addunquoted(arg, plain);
|
||||
addunquoted("=", 1);
|
||||
arg+=plain+1;
|
||||
if(!*arg)
|
||||
return;
|
||||
}
|
||||
}
|
||||
addquoted(arg);
|
||||
}
|
||||
|
||||
void initargs(int argc, char **argv)
|
||||
{
|
||||
while(--argc) addarg(*++argv);
|
||||
addachar('\n');
|
||||
addachar('\0');
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef AMIGAOS
|
||||
|
||||
#define RDAF_PRIVATE1 0x40000000
|
||||
#define RDAF_PRIVATE2 0x20000000
|
||||
|
||||
|
||||
void FreeArgs(struct RDArgs *rdargs)
|
||||
{
|
||||
if(rdargs) {
|
||||
APTR daelt, nextda = (APTR)rdargs->RDA_DAList;
|
||||
|
||||
rdargs->RDA_Buffer = NULL;
|
||||
rdargs->RDA_Flags &= (RDAF_PRIVATE1 | RDAF_PRIVATE2);
|
||||
rdargs->RDA_DAList = NULL;
|
||||
while((daelt = nextda)) {
|
||||
nextda = ((Argtype *)daelt)->ptr;
|
||||
free(daelt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
static UBYTE * ra_alloc(struct RDArgs *rdargs, ULONG size)
|
||||
{
|
||||
UBYTE *ptr=NULL;
|
||||
|
||||
if((!(rdargs->RDA_Flags & RDAF_NOALLOC)) &&
|
||||
(ptr=malloc(size+sizeof(Argtype)))) {
|
||||
memset(ptr, 0, size+sizeof(Argtype));
|
||||
((Argtype *)ptr)->ptr=rdargs->RDA_DAList;
|
||||
rdargs->RDA_DAList=ptr;
|
||||
ptr+=sizeof(Argtype);
|
||||
}
|
||||
return ptr;
|
||||
}
|
||||
|
||||
static UBYTE * ra_realloc(struct RDArgs *rdargs, UBYTE **start, UBYTE **end)
|
||||
{
|
||||
UBYTE *oldstart=*start;
|
||||
ULONG newlength=((*end-oldstart+144)&~0x7f)-8;
|
||||
UBYTE *newstart=ra_alloc(rdargs, newlength+4);
|
||||
|
||||
if(!newstart)
|
||||
return NULL;
|
||||
|
||||
*start=newstart;
|
||||
*end=newstart+newlength;
|
||||
return oldstart;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static LONG CS_ReadChar(struct CSource *cSource)
|
||||
{
|
||||
if(!cSource || ((LONG)cSource)==-1 || !cSource->CS_Buffer) {
|
||||
if(cmdline && *cmdline) {
|
||||
return (unsigned char)(*cmdline++);
|
||||
} else
|
||||
return getchar();
|
||||
}
|
||||
if(cSource->CS_CurChr >= cSource->CS_Length)
|
||||
return -1;
|
||||
return cSource->CS_Buffer[cSource->CS_CurChr++];
|
||||
}
|
||||
|
||||
static void CS_UnReadChar(struct CSource *cSource, UBYTE ch)
|
||||
{
|
||||
if(!cSource || ((LONG)cSource)==-1 || !cSource->CS_Buffer) {
|
||||
if(cmdline && *cmdline)
|
||||
--cmdline;
|
||||
else
|
||||
ungetc(ch, stdin);
|
||||
} else if(cSource->CS_CurChr > 0)
|
||||
--cSource->CS_CurChr;
|
||||
}
|
||||
|
||||
static LONG intreaditem(STRPTR buffer, LONG maxchars, struct CSource *input,
|
||||
int mode, UBYTE **start, UBYTE **end)
|
||||
{
|
||||
int itemlen=0;
|
||||
int ch, quote='\0';
|
||||
|
||||
buffer[0]='\0';
|
||||
do ch=CS_ReadChar(input); while(ch==' ' || ch=='\t');
|
||||
if(ch=='"') { quote=ch; ch=CS_ReadChar(input); }
|
||||
|
||||
while(ch!='\n' && ch>=0) {
|
||||
if(quote) {
|
||||
if(ch==quote)
|
||||
return ITEM_QUOTED;
|
||||
if(ch=='*') {
|
||||
ch=CS_ReadChar(input);
|
||||
if(ch<0 || ch=='\n') break;
|
||||
if(ch=='e' || ch=='E') ch='\033';
|
||||
if(ch=='n' || ch=='N') ch='\n';
|
||||
}
|
||||
} else {
|
||||
if(ch==';')
|
||||
break;
|
||||
if(ch==' ' || ch=='\t' || (ch=='=' && itemlen)) {
|
||||
if(mode<0)
|
||||
CS_UnReadChar(input, ch);
|
||||
return ITEM_UNQUOTED;
|
||||
}
|
||||
if(ch=='=')
|
||||
return ITEM_EQUAL;
|
||||
}
|
||||
if(++itemlen>=maxchars) {
|
||||
UBYTE *bufswap;
|
||||
if(mode<=0 || !(bufswap=ra_realloc((struct RDArgs *)input, start, end)))
|
||||
return ITEM_ERROR;
|
||||
memcpy(*start, bufswap, itemlen-1);
|
||||
buffer=*start+itemlen-1;
|
||||
maxchars=*end-*start;
|
||||
}
|
||||
if(mode<0) {
|
||||
buffer[itemlen]=ch;
|
||||
buffer[itemlen+1]='\0';
|
||||
buffer[0]=itemlen;
|
||||
} else {
|
||||
*buffer++=ch;
|
||||
*buffer='\0';
|
||||
}
|
||||
ch=CS_ReadChar(input);
|
||||
}
|
||||
CS_UnReadChar(input, ch);
|
||||
return (quote? ITEM_ERROR : (itemlen? ITEM_UNQUOTED : ITEM_NOTHING));
|
||||
}
|
||||
|
||||
LONG ReadItem(STRPTR buffer, LONG maxchars, struct CSource *input)
|
||||
{
|
||||
return intreaditem(buffer, maxchars, input, 0, NULL, NULL);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
LONG FindArg(STRPTR template, STRPTR keyword)
|
||||
{
|
||||
int kwlen=strlen((char *)keyword);
|
||||
int kwindex, argindex=0;
|
||||
char ch;
|
||||
|
||||
for(;;) {
|
||||
|
||||
kwindex=0;
|
||||
do {
|
||||
ch=*template++;
|
||||
if(!ch)
|
||||
return (kwindex == kwlen? argindex : -1);
|
||||
if(ch == ',' || ch == '=' || ch == '/')
|
||||
if(kwindex == kwlen)
|
||||
return argindex;
|
||||
else
|
||||
break;
|
||||
} while(ToUpper(ch) == ToUpper(keyword[kwindex++]));
|
||||
|
||||
while(ch != '=') {
|
||||
if(ch == ',') {
|
||||
argindex++;
|
||||
break;
|
||||
}
|
||||
ch=*template++;
|
||||
if(!ch)
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#define RA_ALWAYS 1
|
||||
#define RA_KEYWORD 2
|
||||
#define RA_SWITCH 4
|
||||
#define RA_NUMERIC 8
|
||||
#define RA_FORCE 16
|
||||
#define RA_TOGGLE 32
|
||||
#define RA_MULTI 64
|
||||
#define RA_FOUND 128
|
||||
|
||||
static LONG parseswitches(STRPTR template, LONG len, UBYTE *flags, int *numargs)
|
||||
{
|
||||
static struct ra_switch { UBYTE flag, ch; } switches[] = {
|
||||
{ RA_ALWAYS, 'A' },
|
||||
{ RA_KEYWORD, 'K' },
|
||||
{ RA_SWITCH, 'S' },
|
||||
{ RA_NUMERIC, 'N' },
|
||||
{ RA_FORCE, 'F' },
|
||||
{ RA_TOGGLE, 'T' },
|
||||
{ RA_MULTI, '.' },
|
||||
{ RA_MULTI, 'M' },
|
||||
{ 0, 0 }
|
||||
};
|
||||
struct ra_switch *sw;
|
||||
int m_used=0;
|
||||
UBYTE ch;
|
||||
|
||||
*numargs=0;
|
||||
while(++*numargs<=MAX_TEMPLATE_ITEMS) {
|
||||
*flags++=0;
|
||||
do {
|
||||
if(--len<0)
|
||||
return 0;
|
||||
|
||||
if((ch=*template++)=='/') {
|
||||
ch=ToUpper(*template++);
|
||||
--len;
|
||||
|
||||
for(sw=switches; sw->ch; sw++)
|
||||
if(sw->ch == ch) {
|
||||
flags[-1]|=sw->flag;
|
||||
if((sw->flag&RA_MULTI) && m_used++)
|
||||
return ERROR_BAD_TEMPLATE;
|
||||
}
|
||||
}
|
||||
} while(ch != ',');
|
||||
}
|
||||
return ERROR_LINE_TOO_LONG;
|
||||
}
|
||||
|
||||
static LONG rareaditem(struct RDArgs *rdargs, UBYTE **start, UBYTE **end)
|
||||
{
|
||||
while(*end-*start-1<0)
|
||||
if(!rdargs || !ra_realloc(rdargs, start, end))
|
||||
return ITEM_ERROR;
|
||||
return (rdargs?
|
||||
intreaditem(*start, *end-*start-1, &rdargs->RDA_Source, 1, start, end):
|
||||
intreaditem(*start, *end-*start-2, (struct CSource *)-1, -1, start, end));
|
||||
}
|
||||
|
||||
struct RDArgs * ReadArgs(STRPTR template, LONG *array, struct RDArgs *rdargs)
|
||||
{
|
||||
LONG itemtype;
|
||||
UBYTE *multiargs[MAX_MULTIARGS+1];
|
||||
UBYTE switches[MAX_TEMPLATE_ITEMS];
|
||||
UBYTE *start, *end, sw, *swptr;
|
||||
Argtype *lastmarg=NULL;
|
||||
int multinum=0;
|
||||
int argnum;
|
||||
LONG ch, error=0;
|
||||
int numargs;
|
||||
int munched;
|
||||
|
||||
if(rdargs) {
|
||||
rdargs->RDA_DAList=NULL;
|
||||
if(!rdargs->RDA_Buffer) {
|
||||
if(!(rdargs->RDA_Buffer=ra_alloc(rdargs, 128+4)))
|
||||
goto nomemfail;
|
||||
rdargs->RDA_BufSiz=128;
|
||||
}
|
||||
} else {
|
||||
rdargs=malloc(128+4+sizeof(struct RDArgs)+sizeof(Argtype));
|
||||
if(!rdargs)
|
||||
goto nomemfail;
|
||||
memset(rdargs, 0, 128+4+sizeof(struct RDArgs)+sizeof(Argtype));
|
||||
rdargs=(struct RDArgs *)(((char *)rdargs)+sizeof(Argtype));
|
||||
rdargs->RDA_Buffer=((UBYTE*)rdargs)+sizeof(struct RDArgs);
|
||||
rdargs->RDA_DAList=(((char *)rdargs)-sizeof(Argtype));
|
||||
rdargs->RDA_BufSiz=128;
|
||||
}
|
||||
start=rdargs->RDA_Buffer;
|
||||
end=rdargs->RDA_Buffer+rdargs->RDA_BufSiz;
|
||||
if((error=parseswitches(template, strlen((char *)template),
|
||||
switches, &numargs)))
|
||||
goto fail;
|
||||
|
||||
for(;;) {
|
||||
argnum=-1;
|
||||
switch(itemtype=rareaditem(rdargs, &start, &end)) {
|
||||
case ITEM_NOTHING:
|
||||
|
||||
swptr=switches;
|
||||
|
||||
while(numargs-->0) {
|
||||
int isnumeric=0;
|
||||
|
||||
if((*swptr)&RA_MULTI)
|
||||
if(multinum) {
|
||||
((Argtype *)array)->ptr=ra_alloc(rdargs,
|
||||
sizeof(Argtype)*(multinum+1));
|
||||
if(!((Argtype *)array)->ptr)
|
||||
goto nomemfail;
|
||||
memcpy(((Argtype *)array)->ptr, multiargs, sizeof(Argtype)*multinum);
|
||||
lastmarg=((Argtype *)(((Argtype *)array)->ptr))+multinum-1;
|
||||
lastmarg[1].ptr=NULL;
|
||||
isnumeric=((*swptr)&RA_NUMERIC)!=0;
|
||||
}
|
||||
else ((Argtype *)array)->ptr=NULL;
|
||||
array=(LONG*)(((Argtype *)array)+1);
|
||||
if(!((sw=*swptr++)&RA_FOUND) && (sw&RA_ALWAYS)) {
|
||||
if((!lastmarg) || (sw&RA_KEYWORD) || multinum<2 ||
|
||||
isnumeric!=((sw&RA_NUMERIC)!=0)) {
|
||||
error=ERROR_REQUIRED_ARG_MISSING;
|
||||
goto fail;
|
||||
}
|
||||
((Argtype *)array)[-1].ptr=lastmarg->ptr;
|
||||
(lastmarg--)->ptr=NULL;
|
||||
--multinum;
|
||||
}
|
||||
}
|
||||
CS_ReadChar(&rdargs->RDA_Source);
|
||||
return rdargs;
|
||||
|
||||
case ITEM_UNQUOTED:
|
||||
argnum=FindArg(template, start);
|
||||
if(argnum<0)
|
||||
goto not_namedarg;
|
||||
sw=switches[argnum];
|
||||
if(sw&RA_SWITCH) {
|
||||
((Argtype *)array)[argnum].num=-1;
|
||||
break;
|
||||
}
|
||||
if(!(sw&RA_FORCE)) {
|
||||
LONG argt;
|
||||
if((argt=rareaditem(rdargs, &start, &end))==ITEM_EQUAL)
|
||||
argt=rareaditem(rdargs, &start, &end);
|
||||
if(argt==ITEM_NOTHING) {
|
||||
error=ERROR_KEY_NEEDS_ARG;
|
||||
goto fail;
|
||||
} else if(argt<0) {
|
||||
error=ERROR_LINE_TOO_LONG;
|
||||
goto fail;
|
||||
} else
|
||||
goto quoted;
|
||||
}
|
||||
munched=0;
|
||||
force:
|
||||
if(end-start<=munched) {
|
||||
UBYTE *old;
|
||||
if(!(old=ra_realloc(rdargs, &start, &end)))
|
||||
goto nomemfail;
|
||||
memcpy(start, old, munched);
|
||||
}
|
||||
if((ch=CS_ReadChar(&rdargs->RDA_Source))>=0 && ch!='\n') {
|
||||
start[munched++]=ch;
|
||||
goto force;
|
||||
}
|
||||
if(itemtype!=ITEM_QUOTED)
|
||||
while((start[munched-1]==' ' || start[munched-1]=='\t') && --munched>0);
|
||||
start[munched]='\0';
|
||||
goto quoted2;
|
||||
|
||||
not_namedarg:
|
||||
ch=CS_ReadChar(&rdargs->RDA_Source);
|
||||
if(ch<0)
|
||||
goto quoted;
|
||||
if(ch=='\n' && start[0]=='?' && start[1]=='\0' &&
|
||||
!(rdargs->RDA_Flags & RDAF_NOPROMPT)) {
|
||||
UBYTE *helptext = template;
|
||||
if(!(rdargs->RDA_Flags & RDAF_PRIVATE1)) {
|
||||
rdargs->RDA_Flags |= RDAF_PRIVATE1;
|
||||
if(rdargs->RDA_ExtHelp)
|
||||
helptext=rdargs->RDA_ExtHelp;
|
||||
}
|
||||
fprintf(stderr, "%s: ", (char *)helptext);
|
||||
fflush(stderr);
|
||||
break;
|
||||
}
|
||||
quoted2:
|
||||
CS_UnReadChar((struct CSource *)rdargs, ch);
|
||||
|
||||
quoted:
|
||||
case ITEM_QUOTED:
|
||||
if(argnum<0) {
|
||||
swptr=switches;
|
||||
error=ERROR_TOO_MANY_ARGS;
|
||||
for(;;) {
|
||||
if(++argnum>=numargs)
|
||||
goto fail;
|
||||
if((*swptr)&RA_MULTI)
|
||||
break;
|
||||
if((sw=*swptr++)&RA_FOUND)
|
||||
continue;
|
||||
if(sw&RA_FORCE) {
|
||||
munched=strlen((char *)start);
|
||||
if(itemtype!=ITEM_QUOTED)
|
||||
start[munched++]=' ';
|
||||
goto force;
|
||||
}
|
||||
if(!(sw&RA_KEYWORD))
|
||||
if(!(sw&=(RA_TOGGLE|RA_SWITCH)))
|
||||
break;
|
||||
}
|
||||
}
|
||||
sw=switches[argnum];
|
||||
switches[argnum]|=RA_FOUND;
|
||||
if(!rdargs) {
|
||||
((Argtype *)array)[argnum].num=((LONG)start)>>2;
|
||||
start+=((*start)&~3)+4;
|
||||
continue;
|
||||
}
|
||||
if(sw&RA_MULTI) {
|
||||
if(multinum>=MAX_MULTIARGS-1) {
|
||||
error=ERROR_LINE_TOO_LONG;
|
||||
goto fail;
|
||||
} if(sw&RA_NUMERIC)
|
||||
goto numeric;
|
||||
multiargs[multinum++]=start;
|
||||
} else if((sw&RA_FOUND)&&!(sw&RA_SWITCH)) {
|
||||
error=ERROR_TOO_MANY_ARGS;
|
||||
goto fail;
|
||||
} else if(sw&RA_TOGGLE) {
|
||||
if(Stricmp(start, (STRPTR)"yes"))
|
||||
((Argtype*)array)[argnum].num=-1;
|
||||
else if(Stricmp(start, (STRPTR)"no"))
|
||||
((Argtype*)array)[argnum].num=0;
|
||||
else if(Stricmp(start, (STRPTR)"on"))
|
||||
((Argtype*)array)[argnum].num=-1;
|
||||
else if(Stricmp(start, (STRPTR)"off"))
|
||||
((Argtype*)array)[argnum].num=0;
|
||||
else {
|
||||
error=ERROR_KEY_NEEDS_ARG;
|
||||
goto fail;
|
||||
}
|
||||
} else if(sw&RA_NUMERIC) {
|
||||
LONG n; int len;
|
||||
numeric:
|
||||
if((len=StrToLong(start, &n))<=0 || len!=strlen((char *)start)) {
|
||||
error=ERROR_BAD_NUMBER;
|
||||
goto fail;
|
||||
}
|
||||
start+=sizeof(Argtype)-1;
|
||||
start-=((LONG)start)&(sizeof(Argtype)-1);
|
||||
if(end-start<sizeof(LONG))
|
||||
if(!ra_realloc(rdargs, &start, &end))
|
||||
goto nomemfail;
|
||||
*(LONG *)start=n;
|
||||
if(sw&RA_MULTI)
|
||||
multiargs[multinum++]=start;
|
||||
else
|
||||
((Argtype*)array)[argnum].ptr=start;
|
||||
start+=sizeof(LONG);
|
||||
continue;
|
||||
} else
|
||||
((Argtype*)array)[argnum].ptr=start;
|
||||
|
||||
start+=strlen((char *)start)+1;
|
||||
break;
|
||||
|
||||
default:
|
||||
error=ERROR_LINE_TOO_LONG;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
|
||||
nomemfail:
|
||||
error=ERROR_NO_FREE_STORE;
|
||||
fail:
|
||||
do
|
||||
ch=CS_ReadChar(&rdargs->RDA_Source);
|
||||
while(ch!='\n' && ch!=';' && ch>=0);
|
||||
if(rdargs)
|
||||
FreeArgs(rdargs);
|
||||
SetIoErr(error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#endif
|
||||
Reference in New Issue
Block a user