#include #include enum _serVarType {emptyt, stringt, spacet}; typedef enum _serVarType serVarType; struct serVarData{ serVarType type; void *data; }; /*Everything regarding LLists here should probably be replaced with trees or some other efficient structure, so I'm encapselating it a bit excessively.*/ struct serVarLListNode{ struct serVarLListNode *next; char *key; struct serVarData data; }; typedef struct serVarLListNode _serVarNSpace; typedef _serVarNSpace* serVarNSpace; void clearSpace(serVarNSpace* space); void delByKey(serVarNSpace* space, char* key){ struct serVarLListNode* tmp; if (!strcmp((*space)->key,key)){ tmp=*space; *space=(*space)->next; free(tmp); }else{ delByKey(&((*space)->next),key); } } /*void setByKey(setVarNSpace* space, char* key, struct serVarData data){ if (!*space){ *space=(struct serVarLListNode*)malloc(sizeof(serVarLListNode)); (*space)->key=(char*)malloc(sizeof(char)*(1+strlen(key))); strcpy((*space)->key,key); (*space)->data=data; }else if (!strcmp(key,(*space)->key)){ (*space)->data=data; }else{ setByKey(&((*space)->next),key,data); } }*/ struct serVarData* getByKey(serVarNSpace* space, char* key){ if (!(*space)){ *space=(struct serVarLListNode*)malloc(sizeof(struct serVarLListNode)); (*space)->key=(char*)malloc(sizeof(char)*(1+strlen(key))); strcpy((*space)->key,key); (*space)->data.type=emptyt; (*space)->data.data=NULL; return(&((*space)->data)); } if (!strcmp((*space)->key,key)) return(&((*space)->data)); return(getByKey(&((*space)->next),key)); } serVarNSpace makeNewSpace(){ /*OK, this is a little silly, but it makes the API more elegant, so who care about the internals? ;) */ return(NULL); } void deldata(struct serVarData* targ){ switch (targ->type){ case stringt: free(targ->data); break; case spacet: clearSpace((serVarNSpace*)&(targ->data)); } } void clearSpace(serVarNSpace* space){ if (*space==NULL) return; clearSpace(&((*space)->next)); deldata(&((*space)->data)); free(*space); *space=NULL; } void removeByKey(serVarNSpace* space,char* key){ serVarNSpace tmp; if (!space || !*space) return; if (!strcmp((*space)->key,key)){ deldata(&((*space)->data)); tmp=*space; *space=(*space)->next; free(tmp); } removeByKey(&((*space)->next),key); } void dumpSpace(serVarNSpace space, FILE* outf){ if (!space){ fprintf(outf,"}"); return; } if (space->data.type==emptyt){ fprintf(outf,"%s: EMPTY\n",space->key); } if (space->data.type==stringt){ fprintf(outf,"%s: \"%s\"\n",space->key,(char*)(space->data.data)); } if (space->data.type==spacet){ fprintf(outf,"%s{\n",space->key); dumpSpace((serVarNSpace)(space->data.data),outf); } dumpSpace(space->next,outf); } /*Begin the real code*/ void parseCommandSet(char**,serVarNSpace*); char ** splitprotect(char* string,char* on){ int i,j,num_out=0,length_in=strlen(string),in_quotes=0,brace_level=0; char** out; for(i=0;itype!=spacet) return(NULL); out=getByKey((serVarNSpace*)&(out->data),*i); } free(path); return(out); } void setComm(char **args, serVarNSpace* space){ struct serVarData *tmp; /* fprintf(stderr,"setting %s to %s\n",args[0],args[1]);*/ tmp=getByPath(splitprotect(args[0],"."),space); /* fprintf(stderr,"tmp=%d\n",tmp);*/ if (!tmp) /*For invalid pathes or other errors*/ return; tmp->type=stringt; tmp->data=(void*)malloc(sizeof(char)*(strlen(args[1])+1)); strcpy(tmp->data,args[1]); } void delComm(char **args, serVarNSpace* space){ serVarNSpace *tmp=space; char **path; char **i; path=splitprotect(args[0],"."); for(i=path;*(i+1);i++) tmp=(serVarNSpace*)&(getByKey(tmp,*i)->data); removeByKey(tmp,*i); free(path); } void withComm(char **args,serVarNSpace* space){ struct serVarData *tmp; tmp=getByPath(splitprotect(args[0],"."),space); if (!tmp || tmp->type!=spacet) return; args[1][strlen(args[1])-1]=0; parseCommandSet(splitprotect(args[1]+1,";\n"),(serVarNSpace*)&(tmp->data)); } void createComm(char **args,serVarNSpace* space){ struct serVarData *tmp; tmp=getByPath(splitprotect(args[0],"."),space); if (!tmp) /*For invalid pathes or other errors*/ return; if (tmp->type==stringt) free(tmp->data); tmp->type=spacet; tmp->data=makeNewSpace(); if (args[1]) withComm(args,space); } void parseCommand(char **comm, serVarNSpace* space){ if (!comm[0][0]){ /*this can get generated by adjacent termination tokens (i.e. ";\n") */ return; /*or by overtaking by the read command (i.e. no chomp function).*/ } /*In any case, we want to ignore it quietly*/ if (!strcmp(comm[0],"set")){ setComm(comm+1,space); free(comm); return; } if (!strcmp(comm[0],"with")){ withComm(comm+1,space); free(comm); return; } if (!strcmp(comm[0],"create")){ createComm(comm+1,space); free(comm); return; } if (!strcmp(comm[0],"destroy")){ delComm(comm+1,space); free(comm); return; } if (!strcmp(comm[0],"quit")){ /*handled elsewhere*/ free(comm); return; } fprintf(stderr,"Invalid command: \"%s\"\n",comm[0]); free(comm); } void parseCommandSet(char **comms, serVarNSpace* space){ char **i; for(i=comms;*i;i++) parseCommand(splitprotect(*i," ="),space); free(comms); } int complete(char *str){ char *i; int inquotes=0,bracelevel=0; if (!*str) return(0); /*the empty string isn't complete*/ for(i=str;*i;i++){ if (*i=='\\'){ /*Anything backslashified doesn't concern us*/ i++; continue; } if (*i=='"') inquotes=!inquotes; if (!inquotes && *i=='{') bracelevel++; if (!inquotes && *i=='}') bracelevel--; } return(!inquotes && bracelevel==0); } main(){ char in1[1024]; int c; serVarNSpace top=makeNewSpace(); in1[0]=0; while(strcmp(in1,"quit")){ in1[0]=0; /* while(!feof(stdin))*/ /*This is just to demonstrate*/ c=0; write(1,">",1); while(!complete(in1)){ c+=read(0,in1+c,1024-c); in1[c]=0; } parseCommandSet(splitprotect(in1,";\n"),&top); } dumpSpace(top,stdout); }