diff --git a/libcevap/cgen.c b/libcevap/cgen.c new file mode 100644 index 0000000..77c1be9 --- /dev/null +++ b/libcevap/cgen.c @@ -0,0 +1,1488 @@ + +#include +#include +#include +#include +#include +#include +#include + + +#include "smem.h" + +char *Sfile_fgets(); +int Sregex_string(); +int Sregex_trimline(); + + +#include "ctyp.h" + +#include "cgen.h" + + + +/* ----------------------------- CgeN ------------------------- */ + +int Cgen_new(cgen,flag) +struct CgeN **cgen; +int flag; +{ + int ret; + struct CgeN *c; + + *cgen= c= TSOB_FELD(struct CgeN,1); + if(c==NULL) { + fprintf(stderr,"+++ Cannot create cgen object : %s\n",strerror(errno)); + return(-1); + } + c->classname= NULL; + c->structname= NULL; + c->functname= NULL; + c->is_managed_list= 0; + c->is_bossless_list= 0; + c->gen_for_stic= 1; + c->make_ansi= 0; + c->make_lowercase= 0; + c->global_include_file[0]= 0; + c->global_include_fp= NULL; + c->elements= NULL; + c->last_element= NULL; + c->may_overwrite= 0; + c->fp= NULL; + c->filename[0]= 0; + c->ptt_fp= NULL; + c->ptt_filename[0]= 0; + c->msg[0]= 0; + return(1); +} + + +int Cgen_destroy(cgen,flag) +struct CgeN **cgen; +int flag; +{ + struct CgeN *c; + struct CtyP *ct,*next_ct; + + c= *cgen; + if(c==NULL) + return(0); + + if(c->fp!=NULL) + fclose(c->fp); + if(c->ptt_fp!=NULL) + fclose(c->ptt_fp); + Sregex_string(&(c->classname),NULL,0); + Sregex_string(&(c->structname),NULL,0); + Sregex_string(&(c->functname),NULL,0); + for(ct= c->elements; ct!=NULL; ct= next_ct) { + next_ct= ct->next; + Ctyp_destroy(&ct,0); + } + + free((char *) c); + *cgen= NULL; + return(1); +} + + +int Cgen_make_names(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int l; + + if(Sregex_string(&(cgen->structname),cgen->classname,0)<=0) + return(-1); + if(Sregex_string(&(cgen->functname),cgen->classname,0)<=0) + return(-1); + if(!cgen->make_lowercase) { + cgen->structname[0]= toupper(cgen->structname[0]); + l= strlen(cgen->structname); + cgen->structname[l-1]= toupper(cgen->structname[l-1]); + cgen->functname[0]= toupper(cgen->functname[0]); + } + return(1); +} + + +int Cgen_read_fp(cgen,fp,flag) +struct CgeN *cgen; +FILE *fp; +int flag; +/* + bit0= return 0 if eof at classname +*/ +{ + char line[4096],*cpt,*bpt; + int ret; + + line[0]= 0; + while(1) { + printf("[-list] classname ?\n"); + if(Sfile_fgets(line,sizeof(line)-1,fp)==NULL) { + if(!(flag&1)) + return(2); +no_name:; + sprintf(cgen->msg,"No classname given."); + return(0); + } + printf("%s\n",line); + if(strcmp(line,"@@@")==0) + return(2); + + if(line[0]==0 || line[0]=='#') { + + /* >>> record class comments */; + + } else + break; + } + cpt= line; + while(cpt[0]=='-') { + /* look for management specifiers: + -l* listable by prev-next chain + */ + if(cpt[1]=='l' || cpt[1]=='L') { + cgen->is_managed_list= 1; + } else if(cpt[1]=='b' || cpt[1]=='B') { + cgen->is_bossless_list= 1; + } + while(*cpt!=0 && !isspace(*cpt)) cpt++; + while(*cpt!=0 && isspace(*cpt)) cpt++; + if(*cpt==0) + goto no_name; + } + if(Sregex_string(&(cgen->classname),cpt,0)<=0) + return(-1); + ret= Cgen_make_names(cgen,0); + if(ret<=0) + return(ret); + + while(1) { + ret= Ctyp_read_fp(&(cgen->last_element),fp,cgen->msg, + !!cgen->make_lowercase); + if(ret<=0) + return(ret); + if(ret==2) + break; + if(cgen->elements==NULL) + cgen->elements= cgen->last_element; + } + if(cgen->is_managed_list) { + sprintf(line,"-c struct %s *prev",cgen->structname); + ret= Ctyp_new_from_line(&(cgen->last_element),cgen->last_element, + line,cgen->msg,0); + if(ret<=0) + return(ret); + if(cgen->elements==NULL) + cgen->elements= cgen->last_element; + sprintf(line,"-c struct %s *next",cgen->structname); + ret= Ctyp_new_from_line(&(cgen->last_element),cgen->last_element, + line,cgen->msg,0); + if(ret<=0) + return(ret); + } + return(1); +} + + +int Cgen_open_wfile(cgen,flag) +struct CgeN *cgen; +int flag; +/* + bit0-3: modes + 0= open cgen->fp + 1= open cgen->ptt_fp + 2= open cgen->global_include_fp +*/ +{ + struct stat stbuf; + int ret, mode; + char *name, fmode[4]; + FILE *fp; + + mode= flag&15; + strcpy(fmode,"w"); + if(mode==0) { + name= cgen->filename; + fp= cgen->fp; + cgen->fp= NULL; + } else if(mode==1) { + name= cgen->ptt_filename; + fp= cgen->ptt_fp; + cgen->ptt_fp= NULL; + } else if(mode==2) { + strcpy(fmode,"a"); + name= cgen->global_include_file; + fp= cgen->global_include_fp; + cgen->global_include_fp= NULL; + } else { + fprintf(stderr,"+++ Cgen_open_wfile : program error : unknown mode %d\n", + mode); + ret= -1; goto ex; + } + if(fmode[0]=='w' && stat(name,&stbuf)!=-1 && !cgen->may_overwrite) { + sprintf(cgen->msg,"File '%s' already existing.",name); + ret= 0; goto ex; + } + if(fp!=NULL) + {fclose(fp); fp= NULL;} + fp= fopen(name,fmode); + if(fp==NULL) { + sprintf(cgen->msg,"Cannot open file '%s' in %s-mode. %s", + name,fmode,strerror(errno)); + ret= 0; goto ex; + } + ret= 1; +ex:; + if(mode==0) + cgen->fp= fp; + else if(mode==1) + cgen->ptt_fp= fp; + else if(mode==2) + cgen->global_include_fp= fp; + return(ret); +} + + +int Cgen_write_datestr(cgen,flag) +struct CgeN *cgen; +int flag; +/* + bit0= operate on ptt (= ANSI prototype) file rather than on internal header +*/ +{ + time_t t0; + char timetext[81]; + FILE *fp; + + if(flag&1) + fp= cgen->ptt_fp; + else + fp= cgen->fp; + t0= time(0); + strftime(timetext,sizeof(timetext),"%a, %d %b %Y %H:%M:%S GMT", + gmtime(&t0)); + fprintf(fp,"/* ( derived from stub generated by CgeN on %s ) */\n", + timetext); + return(1); +} + + +int Cgen_write_h(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,i,pointer_level; + FILE *fp= NULL; + struct CtyP *ct; + char pvt[16],macro_name[4096],*cpt; + + if(cgen->make_ansi) { + sprintf(cgen->filename,"%s_private.h",cgen->classname); + strcpy(pvt,"_private"); + } else { + sprintf(cgen->filename,"%s.h",cgen->classname); + strcpy(pvt,""); + } + + ret= Cgen_open_wfile(cgen,0); + if(ret<=0) + goto ex; + sprintf(macro_name,"%s%s_includeD",cgen->functname,pvt); + macro_name[0]= toupper(macro_name[0]); + fp= cgen->fp; + + /* >>> print class comments */; + + fprintf(fp,"\n"); + fprintf(fp,"#ifndef %s\n",macro_name); + fprintf(fp,"#define %s\n",macro_name); + fprintf(fp,"\n"); + if(strlen(cgen->global_include_file)!=0) { + fprintf(fp,"#include \"%s\"\n",cgen->global_include_file); + fprintf(fp,"\n\n"); + } + if(cgen->make_ansi) + fprintf(fp,"/* For function prototypes see file %s.h */\n",cgen->classname); + fprintf(fp,"\n\n"); + fprintf(fp,"struct %s {\n",cgen->structname); + fprintf(fp,"\n"); + ct= cgen->elements; + for(ct= cgen->elements;ct!=NULL;ct= ct->next) { + + if(ct->is_comment) { + if(ct->name[0]==0) { + fprintf(fp,"\n"); + continue; + } + fprintf(fp," /* "); + for(cpt= ct->name; *cpt!=0; cpt++) { + fprintf(fp,"%c",*cpt); + if(cpt[0]=='*' && cpt[1]=='/') + fprintf(fp," "); + } + fprintf(fp," */\n"); + continue; + } + + if(ct->is_volatile) + fprintf(fp," volatile"); + if(Ctyp_is_struct(ct,0)) + fprintf(fp," struct"); + else if(ct->is_unsigned) + fprintf(fp," unsigned"); + fprintf(fp," %s ",ct->dtype); + pointer_level= Ctyp_get_pointer_level(ct,0); + for(i=0;iname); + } + fprintf(fp,"\n"); + fprintf(fp,"};\n"); + fprintf(fp,"\n"); + fprintf(fp,"\n"); + fprintf(fp,"#endif /* %s */\n",macro_name); + fprintf(fp,"\n"); + Cgen_write_datestr(cgen,0); + + /* Eventually write start of ANSI prototype include file */ + if(!cgen->make_ansi) + goto after_ansi_h; + sprintf(cgen->ptt_filename,"%s.h",cgen->classname); + ret= Cgen_open_wfile(cgen,1); + if(ret<=0) + goto ex; + sprintf(macro_name,"%s_includeD",cgen->functname); + macro_name[0]= toupper(macro_name[0]); + fp= cgen->ptt_fp; + + /* >>> print class comments */; + + fprintf(fp,"\n"); + fprintf(fp,"#ifndef %s\n",macro_name); + fprintf(fp,"#define %s\n",macro_name); + fprintf(fp,"\n\n"); + if(strlen(cgen->global_include_file)!=0) { + fprintf(fp,"#include \"%s\"\n",cgen->global_include_file); + } else { + fprintf(fp,"struct %s;\n",cgen->structname); + } + fprintf(fp,"\n\n"); + fprintf(fp,"/* For inner details see file %s_private.h */\n",cgen->classname); + fprintf(fp,"\n\n"); + +after_ansi_h:; + if(strlen(cgen->global_include_file)==0) + goto after_global_include; + ret= Cgen_open_wfile(cgen,2); + if(ret<=0) + goto ex; + fprintf(cgen->global_include_fp,"struct %s;\n",cgen->structname); + +after_global_include:; + ret= 1; +ex:; + if(cgen->fp!=NULL) + {fclose(cgen->fp); cgen->fp= NULL;} + /* ( note: cgen->ptt_fp stays open ) */ + if(cgen->global_include_fp!=NULL) + {fclose(cgen->global_include_fp); cgen->global_include_fp= NULL;} + return(ret); +} + + +int Cgen_write_to_ptt(cgen,ptt,flag) +struct CgeN *cgen; +char *ptt; +int flag; +{ + if(cgen->ptt_fp==NULL) + return(-1); + fprintf(cgen->ptt_fp,"%s;\n",ptt); + return(1); +} + + +int Cgen_finish_public_h(cgen,flag) +struct CgeN *cgen; +int flag; +{ + char macro_name[4096]; + + if(cgen->ptt_fp==NULL) + return(-1); + fprintf(cgen->ptt_fp,"\n"); + fprintf(cgen->ptt_fp,"\n"); + sprintf(macro_name,"%s_includeD",cgen->functname); + macro_name[0]= toupper(macro_name[0]); + fprintf(cgen->ptt_fp,"#endif /* %s */\n",macro_name); + fprintf(cgen->ptt_fp,"\n"); + Cgen_write_datestr(cgen,1); + if(cgen->ptt_fp!=NULL) + {fclose(cgen->ptt_fp); cgen->ptt_fp= NULL;} + return(1); +} + + +int Cgen_write_c_head(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,is_pointer,is_struct,array_size; + FILE *fp= NULL; + struct CtyP *ct,*hct; + char *dtype= NULL,*name= NULL; + + fp= cgen->fp; + fprintf(fp,"\n"); + fprintf(fp,"/*\n"); + fprintf(fp," cc -g -o %s.c\n",cgen->classname); + fprintf(fp,"*/\n"); + Cgen_write_datestr(cgen,0); + fprintf(fp,"\n"); + fprintf(fp,"#include \n"); + fprintf(fp,"#include \n"); + fprintf(fp,"#include \n"); + fprintf(fp,"#include \n"); + fprintf(fp,"#include \n"); + fprintf(fp,"\n"); + fprintf(fp,"#include \"%s.h\"\n",cgen->classname); + if(cgen->make_ansi) { + fprintf(fp,"#include \"%s_private.h\"\n",cgen->classname); + } + fprintf(fp,"\n"); + for(ct= cgen->elements; ct!=NULL; ct= ct->next) { + if(ct->is_comment) + continue; + Ctyp_get_dtype(ct,&dtype,0); + Ctyp_get_type_mod(ct,&is_pointer,&is_struct,&array_size,0); +/* + fprintf(stderr,"DEBUG: %s %s\n",(is_struct?"struct ":""),dtype); +*/ + /* already included ? */ + if(strcmp(dtype,cgen->structname)==0) + continue; + for(hct= cgen->elements; hct!=NULL && hct!=ct; hct= hct->next) + if(strcmp(ct->dtype,dtype)==0) + break; + if(hct!=ct) + continue; + + if(is_struct && (isupper(dtype[0]) && isupper(dtype[strlen(dtype)-1]))) { + dtype[0]= tolower(dtype[0]); + dtype[strlen(dtype)-1]= tolower(dtype[strlen(dtype)-1]); + fprintf(fp,"#include \"%s.h\"\n",dtype); + } + } + fprintf(fp,"\n"); + if(cgen->gen_for_stic==1) { + fprintf(fp,"#include \"../s_tools/smem.h\"\n"); + fprintf(fp,"#include \"../s_tools/sfile.h\"\n"); + fprintf(fp,"#include \"../s_tools/sregex.h\"\n"); + fprintf(fp,"\n"); + } else if(cgen->gen_for_stic==2) { + fprintf(fp,"#include \"smem.h\"\n"); + fprintf(fp,"\n"); + } + fprintf(fp,"\n"); + fprintf(fp,"/* -------------------------- %s ----------------------- */\n", + cgen->structname); + fprintf(fp,"\n"); + + if(dtype!=NULL) + Sregex_string(&dtype,NULL,0); + if(name!=NULL) + Sregex_string(&name,NULL,0); + return(1); +} + + +int Cgen_write_c_new(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,pointer_level,management,boss_parm= 0; + unsigned long array_size; + FILE *fp= NULL; + struct CtyP *ct; + char ptt[4096]; + + fp= cgen->fp; + + if(!cgen->is_bossless_list) { + if(cgen->elements!=NULL) + if(strcmp(cgen->elements->name,"boss")==0 && cgen->elements->is_struct && + cgen->elements->is_pointer==1 && cgen->elements->no_initializer==0) + boss_parm= 1; + if(cgen->is_managed_list && boss_parm==0) + fprintf(stderr, + "+++ Warning: -l %s without -v struct ... *boss as first attribute\n", + cgen->classname); + } + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt,"int %s_new(struct %s **objpt, ", + cgen->functname,cgen->structname); + if(boss_parm) + sprintf(ptt+strlen(ptt),"struct %s *boss, ",cgen->elements->dtype); + sprintf(ptt+strlen(ptt),"int flag)"); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_new(objpt,\n",cgen->functname); + if(boss_parm) + fprintf(fp,"boss,"); + fprintf(fp,"flag)\n"); + fprintf(fp,"struct %s **objpt;\n",cgen->structname); + if(boss_parm) + fprintf(fp,"struct %s *boss;",cgen->elements->dtype); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"{\n"); + fprintf(fp," struct %s *o;\n",cgen->structname); + fprintf(fp,"\n"); + if(cgen->gen_for_stic) + fprintf(fp," *objpt= o= TSOB_FELD(struct %s,1);\n",cgen->structname); + else + fprintf(fp," *objpt= o= (struct %s *) malloc(sizeof(struct %s));\n", + cgen->structname, cgen->structname); + fprintf(fp," if(o==NULL)\n"); + fprintf(fp," return(-1);\n"); + fprintf(fp,"\n"); + for(ct= cgen->elements; ct!=NULL; ct= ct->next) { + if(ct->is_comment || ct->no_initializer) + continue; + array_size= Ctyp_get_array_size(ct,0); + pointer_level= Ctyp_get_pointer_level(ct,0); + if(ct==cgen->elements && boss_parm) { + fprintf(fp," o->boss= boss;\n"); + } else if(array_size>0) { + if(strcmp(ct->dtype,"char")==0) { + fprintf(fp," o->%s[0]= 0;\n;",ct->name); + } else if(pointer_level>0) { + fprintf(fp," { int i;"); + fprintf(fp," for(i=0;i%s[i]= NULL;\n",ct->name); + fprintf(fp," }"); + } else { + fprintf(fp," { int i;"); + fprintf(fp," for(i=0;i%s[i]= 0;\n",ct->name); + fprintf(fp," }"); + } + } else if(pointer_level>0) { + fprintf(fp," o->%s= NULL;\n",ct->name); + } else + fprintf(fp," o->%s= 0;\n",ct->name); + } + fprintf(fp,"\n"); + fprintf(fp," return(1);\n"); + fprintf(fp,"/*\n"); + fprintf(fp,"failed:;\n"); + fprintf(fp," %s_destroy(objpt,0);\n",cgen->functname); + fprintf(fp," return(-1);\n"); + fprintf(fp,"*/\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + for(ct= cgen->elements; ct!=NULL; ct= ct->next) { + if(ct->is_comment) + continue; + management= Ctyp_get_management(ct,0); + if(management==4) { + if(ct->next==NULL) { +no_last_pt:; + sprintf(cgen->msg, + "Lonely -l found. A -v of same type must follow.\nName is : %s", + ct->name); + return(0); + } + if(strcmp(ct->next->dtype,ct->dtype)!=0 + || ct->next->is_pointer!=ct->is_pointer) + goto no_last_pt; + ct->next->with_getter= ct->next->with_setter= 0; + ret= Cgen_write_c_new_type(cgen,ct,ct->next,0); + if(ret<=0) + return(ret); + } + } + return(1); +} + + +int Cgen_write_c_new_type(cgen,ct_first,ct_last,flag) +struct CgeN *cgen; +struct CtyP *ct_first,*ct_last; +int flag; +{ + int ret,l,management,pointer_level,i; + FILE *fp= NULL; + char funct[4096],classname[4096],*npt,ptt[4096]; + + strcpy(funct,ct_first->dtype); + strcpy(classname,funct); + l= strlen(funct); + if(l>0) { + if(cgen->make_lowercase) + funct[0]= tolower(funct[0]); + else + funct[0]= toupper(funct[0]); + funct[l-1]= tolower(funct[l-1]); + classname[0]= tolower(funct[0]); + classname[l-1]= funct[l-1]; + } + fp= cgen->fp; + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, "int %s_new_%s(struct %s *o, int flag)", + cgen->functname,ct_first->name,cgen->structname); + fprintf(fp,"%s\n",ptt); + if(ct_first->with_setter) { + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } + } else { + fprintf(fp,"int %s_new_%s(o,flag)\n",cgen->functname,ct_first->name); + fprintf(fp,"struct %s *o;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"{\n"); + fprintf(fp," int ret;\n"); + fprintf(fp," struct %s *c= NULL;\n",ct_first->dtype); + fprintf(fp,"\n"); + if(ct_first->bossless_list) + fprintf(fp," ret= %s_new(&c,0);\n",funct); + else + fprintf(fp," ret= %s_new(&c,o,0);\n",funct); + fprintf(fp," if(ret<=0)\n"); + fprintf(fp," return(ret);\n"); + fprintf(fp," %s_link(c,o->%s,0);\n",funct,ct_last->name); + fprintf(fp," o->%s= c;\n",ct_last->name); + fprintf(fp," if(o->%s==NULL)\n",ct_first->name); + fprintf(fp," o->%s= c;\n",ct_first->name); + fprintf(fp," return(1);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + ret= 1; +ex:; + return(ret); +} + + +int Cgen_write_c_destroy(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,l,management,pointer_level,i; + FILE *fp= NULL; + struct CtyP *ct,*next; + char funct[4096],*npt,ptt[4096]; + + fp= cgen->fp; + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, "int %s_destroy(struct %s **objpt, int flag)", + cgen->functname,cgen->structname); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_destroy(objpt,flag)\n",cgen->functname); + fprintf(fp,"struct %s **objpt;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"{\n"); + fprintf(fp," struct %s *o;\n",cgen->structname); + fprintf(fp,"\n"); + fprintf(fp," o= *objpt;\n"); + fprintf(fp," if(o==NULL)\n"); + fprintf(fp," return(0);\n"); + fprintf(fp,"\n"); + for(ct= cgen->elements; ct!=NULL; ct= ct->next) { + if(ct->is_comment) + continue; + management= Ctyp_get_management(ct,0); + if(management==1 || management==4) { + strcpy(funct,ct->dtype); + l= strlen(funct); + if(l>0) { + if(cgen->make_lowercase) + funct[0]= tolower(funct[0]); + else + funct[0]= toupper(funct[0]); + funct[l-1]= tolower(funct[l-1]); + } + if(strcmp(ct->dtype,"char")==0) { + if(cgen->gen_for_stic==1) + fprintf(fp," Sregex_string("); + else if(cgen->gen_for_stic==2) + fprintf(fp," Smem_freE((char *) "); + else + fprintf(fp," free("); + } else if(strcmp(ct->dtype,"LstrinG")==0 || management==4) + fprintf(fp," %s_destroy_all(",funct); + else + fprintf(fp," %s_destroy(",funct); + + pointer_level= Ctyp_get_pointer_level(ct,0)-2; + for(i=0; i>pointer_level; i--) + fprintf(fp,"&"); + for(i=0; i%s)",ct->name); + if(strcmp(ct->dtype,"char")==0) { + if(cgen->gen_for_stic==1) + fprintf(fp,",NULL,0);\n"); + else + fprintf(fp,");\n"); + } else + fprintf(fp,",0);\n"); + } else if(management==2) { + next= ct->next; + if(next==NULL) { +broken_chain:; + sprintf(cgen->msg, + "Lonely -c found. They have to appear in pairs.\nName is : %s", + ct->name); + ret= 0; goto ex; + } + if(next->management!=3) + goto broken_chain; + fprintf(fp," if(o->%s!=NULL)\n",ct->name); + fprintf(fp," o->%s->%s= o->%s;\n",ct->name,next->name,next->name); + fprintf(fp," if(o->%s!=NULL)\n",next->name); + fprintf(fp," o->%s->%s= o->%s;\n",next->name,ct->name,ct->name); + ct= next; + } + } + fprintf(fp,"\n"); + if(cgen->gen_for_stic) + fprintf(fp," Smem_freE((char *) o);\n"); + else + fprintf(fp," free((char *) o);\n"); + fprintf(fp," *objpt= NULL;\n"); + fprintf(fp," return(1);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + if(cgen->is_managed_list){ + ret= Cgen_write_c_destroy_all(cgen,0); + if(ret<=0) + goto ex; + } + ret= 1; +ex:; + return(ret); +} + + +int Cgen_write_c_destroy_all(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,l,management,pointer_level,i; + FILE *fp= NULL; + struct CtyP *ct; + char ptt[4096]; + + fp= cgen->fp; + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, "int %s_destroy_all(struct %s **objpt, int flag)", + cgen->functname, cgen->structname); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_destroy_all(objpt,flag)\n",cgen->functname); + fprintf(fp,"struct %s **objpt;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"{\n"); + fprintf(fp," struct %s *o,*n;\n",cgen->structname); + fprintf(fp,"\n"); + fprintf(fp," o= *objpt;\n"); + fprintf(fp," if(o==NULL)\n"); + fprintf(fp," return(0);\n"); + fprintf(fp," for(;o->prev!=NULL;o= o->prev);\n"); + fprintf(fp," for(;o!=NULL;o= n) {\n"); + fprintf(fp," n= o->next;\n"); + fprintf(fp," %s_destroy(&o,0);\n",cgen->functname); + fprintf(fp," }\n"); + fprintf(fp," *objpt= NULL;\n"); + fprintf(fp," return(1);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + ret= 1; +ex:; + return(ret); +} + + +int Cgen_write_c_access(cgen,flag) +struct CgeN *cgen; +int flag; +{ + int ret,l,mgt,pointer_level,i; + FILE *fp= NULL; + struct CtyP *ct; + char funct[4096],*npt,ptt[4096]; + + fp= cgen->fp; + for(ct= cgen->elements; ct!=NULL; ct= ct->next) { + if(ct->is_comment) + continue; + pointer_level= Ctyp_get_pointer_level(ct,0); + if(Ctyp_get_with_getter(ct,0)<=0) + goto after_getter; + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, "int %s_get_%s(struct %s *o, ", + cgen->functname,ct->name,cgen->structname); + if(Ctyp_is_struct(ct,0)) + strcat(ptt,"struct "); + strcat(ptt,ct->dtype); + strcat(ptt," "); + for(i=0; i0) + strcat(ptt,"*"); + strcat(ptt,"pt"); + if(ct->management==4) + strcat(ptt,", int idx"); + strcat(ptt,", int flag)"); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_get_%s(o,pt",cgen->functname,ct->name); + if(ct->management==4) + fprintf(fp,",idx"); + fprintf(fp,",flag)\n"); + fprintf(fp,"struct %s *o;\n",cgen->structname); + if(Ctyp_is_struct(ct,0)) + fprintf(fp,"struct "); + fprintf(fp,"%s ",ct->dtype); + for(i=0; i0) + fprintf(fp,"*"); + fprintf(fp,"pt;\n"); + if(ct->management==4) + fprintf(fp,"int idx;\n"); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"/* Note: idx==-1 fetches the last item of the list */\n"); + fprintf(fp,"{\n"); + if(ct->management==4) { + strcpy(funct,ct->dtype); + l= strlen(funct); + if(cgen->make_lowercase) + funct[0]= tolower(funct[0]); + if(l>1) + funct[l-1]= tolower(funct[l-1]); + fprintf(fp," if(idx==-1) {\n"); + fprintf(fp," *pt= o->%s;\n",ct->next->name); + fprintf(fp," return(*pt!=NULL);\n"); + fprintf(fp," }\n"); + fprintf(fp," return(%s_by_idx(o->%s,(flag&1?1:idx),pt,flag&1));\n", + funct,ct->name); + } else { + fprintf(fp," *pt= o->%s;\n",ct->name); + fprintf(fp," return(1);\n"); + } + fprintf(fp,"}\n"); + fprintf(fp,"\n"); +after_getter:; + + if(Ctyp_get_with_setter(ct,0)<=0) + goto after_setter; + + /* <<< provisory : develop a setter for arrays */ + if(Ctyp_get_array_size(ct,0)>0) + goto after_setter; + + mgt= Ctyp_get_management(ct,0); + if(mgt==0 || + (mgt==1 && pointer_level==1)) { + /* -value or -managed pointers */ + /* was: -value or -managed char * */ + /* (mgt==1 && strcmp(ct->dtype,"char")==0 && pointer_level==1)) { */ + + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, "int %s_set_%s(struct %s *o, ", + cgen->functname,ct->name,cgen->structname); + if(Ctyp_is_struct(ct,0)) + strcat(ptt,"struct "); + strcat(ptt,ct->dtype); + strcat(ptt," "); + for(i=0; ifunctname,ct->name); + fprintf(fp,"struct %s *o;\n",cgen->structname); + if(Ctyp_is_struct(ct,0)) + fprintf(fp,"struct "); + fprintf(fp,"%s ",ct->dtype); + for(i=0; idtype,"char")==0) { + if(cgen->gen_for_stic==1) { + fprintf(fp," if(Sregex_string(&(o->%s),value,0)<=0)\n",ct->name); + fprintf(fp," return(-1);\n"); + } else if(cgen->gen_for_stic==2) { + fprintf(fp," if(Smem_clone_string(&(o->%s),value)<=0)\n",ct->name); + fprintf(fp," return(-1);\n"); + } else { + fprintf(fp," char *cpt;\n"); + fprintf(fp,"\n"); + fprintf(fp," cpt= malloc(strlen(value)+1);\n"); + fprintf(fp," if(cpt==NULL)\n"); + fprintf(fp," return(-1);\n"); + fprintf(fp," o->%s= cpt;\n",ct->name); + fprintf(fp," \n"); + } + } else { + fprintf(fp," o->%s= value;\n",ct->name); + } + fprintf(fp," return(1);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + } + +after_setter:; + } + + if(cgen->is_managed_list) { + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt,"int %s_link(struct %s *o, struct %s *link, int flag)", + cgen->functname,cgen->structname,cgen->structname); + fprintf(fp,"%s\n",ptt); +/* if(cgen->readonly) */ + { + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } + } else { + fprintf(fp,"int %s_link(o,link,flag)\n",cgen->functname); + fprintf(fp,"struct %s *o;\n",cgen->structname); + fprintf(fp,"struct %s *link;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"/*\n"); + fprintf(fp," bit0= insert as link->prev rather than as link->next\n"); + fprintf(fp,"*/\n"); + fprintf(fp,"{\n"); + fprintf(fp," if(o->prev!=NULL)\n"); + fprintf(fp," o->prev->next= o->next;\n"); + fprintf(fp," if(o->next!=NULL)\n"); + fprintf(fp," o->next->prev= o->prev;\n"); + fprintf(fp," o->prev= o->next= NULL;\n"); + fprintf(fp," if(link==NULL)\n"); + fprintf(fp," return(1);\n"); + fprintf(fp," if(flag&1) {\n"); + fprintf(fp," o->next= link;\n"); + fprintf(fp," o->prev= link->prev;\n"); + fprintf(fp," if(o->prev!=NULL)\n"); + fprintf(fp," o->prev->next= o;\n"); + fprintf(fp," link->prev= o;\n"); + fprintf(fp," } else {\n"); + fprintf(fp," o->prev= link;\n"); + fprintf(fp," o->next= link->next;\n"); + fprintf(fp," if(o->next!=NULL)\n"); + fprintf(fp," o->next->prev= o;\n"); + fprintf(fp," link->next= o;\n"); + fprintf(fp," }\n"); + fprintf(fp," return(1);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt,"int %s_count(struct %s *o, int flag)", + cgen->functname,cgen->structname); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_count(o,flag)\n",cgen->functname); + fprintf(fp,"struct %s *o;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp,"/* flag: bit1= count from start of list */\n"); + fprintf(fp,"{\n"); + fprintf(fp," int counter= 0;\n"); + fprintf(fp,"\n"); + fprintf(fp," if(flag&2)\n"); + fprintf(fp," for(;o->prev!=NULL;o= o->prev);\n"); + fprintf(fp," for(;o!=NULL;o= o->next)\n"); + fprintf(fp," counter++;\n"); + fprintf(fp," return(counter);\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + + fprintf(fp,"\n"); + if(cgen->make_ansi) { + sprintf(ptt, + "int %s_by_idx(struct %s *o, int idx, struct %s **pt, int flag)", + cgen->functname,cgen->structname,cgen->structname); + fprintf(fp,"%s\n",ptt); + ret= Cgen_write_to_ptt(cgen, ptt, 0); + if(ret<=0) + return(ret); + } else { + fprintf(fp,"int %s_count(o,idx,pt,flag)\n",cgen->functname); + fprintf(fp,"struct %s *o;\n",cgen->structname); + fprintf(fp,"int idx;\n"); + fprintf(fp,"struct %s **pt;\n",cgen->structname); + fprintf(fp,"int flag;\n"); + } + fprintf(fp, + "/* flag: bit0= fetch first (idx<0) or last (idx>0) item in list\n"); + fprintf(fp, + " bit1= address from start of list */\n"); + fprintf(fp,"{\n"); + fprintf(fp," int i,abs_idx;\n"); + fprintf(fp,"struct %s *npt;\n",cgen->structname); + fprintf(fp,"\n"); + fprintf(fp," if(flag&2)\n"); + fprintf(fp," for(;o->prev!=NULL;o= o->prev);\n"); + fprintf(fp," abs_idx= (idx>0?idx:-idx);\n"); + fprintf(fp," *pt= o;\n"); + fprintf(fp," for(i= 0;(i0)\n"); + fprintf(fp," npt= o->next;\n"); + fprintf(fp," else\n"); + fprintf(fp," npt= o->prev;\n"); + fprintf(fp," if(npt==NULL && (flag&1))\n"); + fprintf(fp," break;\n"); + fprintf(fp," *pt= npt;\n"); + fprintf(fp," }\n"); + fprintf(fp," return(*pt!=NULL);\n"); + fprintf(fp," ;\n"); + fprintf(fp,"}\n"); + fprintf(fp,"\n"); + } + + return(1); +} + + +int Cgen_write_c_method_include(cgen,flag) +struct CgeN *cgen; +int flag; +{ + FILE *fp= NULL; + char filename[4096],line[4096]; + struct stat stbuf; + time_t t0; + + sprintf(filename,"%s.c.methods",cgen->classname); + if(stat(filename,&stbuf)!=-1) + goto write_include; + fp= fopen(filename,"w"); + if(fp==NULL) { + sprintf(cgen->msg,"Cannot open file '%s' in %s-mode. %s", + filename,"w",strerror(errno)); + return(0); + } + fprintf(fp,"\n"); + fprintf(fp,"/* File %s */\n",filename); + fprintf(fp,"/* Manually provided C code for class %s */\n", + cgen->classname); + fprintf(fp,"/* This file gets copied to the end of %s.c */\n", + cgen->classname); + fprintf(fp,"\n"); + fclose(fp); fp= NULL; + +write_include:; + fp= fopen(filename,"r"); + if(fp==NULL) { + sprintf(cgen->msg,"Cannot open file '%s' in %s-mode. %s", + filename,"r",strerror(errno)); + return(0); + } + fprintf(cgen->fp,"\n"); + fprintf(cgen->fp, +"/* -------------- end of automatically regenerated code -------------- */\n"); + fprintf(cgen->fp,"\n"); + while(1) { + if(Sfile_fgets(line,sizeof(line)-1,fp)==NULL) + break; + fprintf(cgen->fp,"%s\n",line); + } + fclose(fp); fp= NULL; + return(1); +} + +int Cgen_write_c(cgen,flag) +struct CgeN *cgen; +int flag; +/* + bit0= also write access functions *_set_* *_get_* [*_link_*] +*/ +{ + int ret; + + sprintf(cgen->filename,"%s.c",cgen->classname); + ret= Cgen_open_wfile(cgen,0); + if(ret<=0) + goto ex; + ret= Cgen_write_c_head(cgen,0); + if(ret<=0) + goto ex; + ret= Cgen_write_c_new(cgen,0); + if(ret<=0) + goto ex; + ret= Cgen_write_c_destroy(cgen,0); + if(ret<=0) + goto ex; + if(flag&1) { + ret= Cgen_write_c_access(cgen,0); + if(ret<=0) + goto ex; + } + ret= Cgen_write_c_method_include(cgen,0); + if(ret<=0) + goto ex; + + if(cgen->make_ansi) { /* public .h file collected ANSI prototypes */ + ret= Cgen_finish_public_h(cgen,0); + if(ret<=0) + goto ex; + } + + ret= 1; +ex:; + if(cgen->fp!=NULL) + {fclose(cgen->fp); cgen->fp= NULL;} + return(ret); +} + + +int Cgen__write_global_include(global_include_file,flag) +char *global_include_file; +int flag; +/* + bit0= write footer rather than header + bit1= allow overwriting of existing file +*/ +{ + FILE *fp= NULL; + int ret; + char fmode[4],timetext[81],macro_name[4096],*cpt; + time_t t0; + struct stat stbuf; + + strcpy(macro_name,global_include_file); + for(cpt= macro_name; *cpt!=0; cpt++) { + if(*cpt>='A' && *cpt<='Z') + *cpt= tolower(*cpt); + else if((*cpt>='a' && *cpt<='z') || (*cpt>='0' && *cpt<='9') || *cpt=='_') + ; + else + *cpt= '_'; + } + macro_name[0]= toupper(macro_name[0]); + strcat(macro_name,"_includeD"); + + strcpy(fmode,"w"); + if(flag&1) { + strcpy(fmode,"a"); + } else { + if(stat(global_include_file,&stbuf)!=-1 && !(flag&2)) { + fprintf(stderr,"+++ File '%s' already existing.",global_include_file); + ret= 0; goto ex; + } + } + fp= fopen(global_include_file,fmode); + if(fp==NULL) { + fprintf(stderr,"+++ Cannot open file '%s' in %s-mode. %s", + global_include_file,fmode,strerror(errno)); + ret= 0; goto ex; + } + if(flag&1) { + fprintf(fp,"\n"); + fprintf(fp,"#endif /* %s */\n\n",macro_name); + t0= time(0); + strftime(timetext,sizeof(timetext),"%a, %d %b %Y %H:%M:%S GMT", + gmtime(&t0)); + fprintf(fp,"/* ( derived from stub generated by CgeN on %s ) */\n", + timetext); + + } else { + fprintf(fp,"\n"); + fprintf(fp,"#ifndef %s\n",macro_name); + fprintf(fp,"#define %s\n",macro_name); + fprintf(fp,"\n"); + } + +ex:; + if(fp!=NULL) + fclose(fp); + return(ret); +} + + +/* ---------------- Sfile and Sregex Emancipation copies ---------------- */ + + +char *Sfile_fgets(line,maxl,fp) +char *line; +int maxl; +FILE *fp; +{ +int l; +char *ret; + ret= fgets(line,maxl,fp); + if(ret==NULL) + return(NULL); + l= strlen(line); + if(l>0) if(line[l-1]=='\r') line[--l]= 0; + if(l>0) if(line[l-1]=='\n') line[--l]= 0; + if(l>0) if(line[l-1]=='\r') line[--l]= 0; + return(ret); +} + + +int Sregex_string_cut(handle,text,len,flag) +char **handle; +char *text; +int len; +int flag; +/* + bit0= append (text!=NULL) + bit1= prepend (text!=NULL) +*/ +{ + int l=0; + char *old_handle; + + if((flag&(1|2))&&*handle!=NULL) + l+= strlen(*handle); + old_handle= *handle; + if(text!=NULL) { + l+= len; + *handle= TSOB_FELD(char,l+1); + if(*handle==NULL) { + *handle= old_handle; + return(0); + } + if((flag&2) && old_handle!=NULL) { + strncpy(*handle,text,len); + strcpy((*handle)+len,old_handle); + } else { + if((flag&1) && old_handle!=NULL) + strcpy(*handle,old_handle); + else + (*handle)[0]= 0; + if(len>0) + strncat(*handle,text,len); + } + } else { + *handle= NULL; + } + if(old_handle!=NULL) + Smem_freE(old_handle); + return(1); +} + + +int Sregex_string(handle,text,flag) +char **handle; +char *text; +int flag; +/* + bit0= append (text!=NULL) + bit1= prepend (text!=NULL) +*/ +{ + int ret,l=0; + + if(text!=NULL) + l= strlen(text); + +/* #define Sregex_looking_for_contenT 1 */ +#ifdef Sregex_looking_for_contenT + /* a debugging point if a certain text content has to be caught */ + if(text!=NULL) + if(strcmp(text,"clear")==0) + ret= 0; +#endif + + ret= Sregex_string_cut(handle,text,l,flag&(1|2)); + return(ret); +} + + +int Sregex_trimline(line,flag) +/* + removes line endings as well as leading and trailing blanks +*/ +char *line; +int flag; +/* + bit0= do not remove line end (protects trailing blanks if line end is present) + bit1= do not remove leading blanks + bit2= do not remove trailing blanks + bit3= remove surrounding quotation marks (after removing line end) +*/ +{ + char *cpt,*wpt; + int l; + + if(!(flag&1)){ + l= strlen(line); + if(l>0) if(line[l-1]=='\r') line[--l]= 0; + if(l>0) if(line[l-1]=='\n') line[--l]= 0; + if(l>0) if(line[l-1]=='\r') line[--l]= 0; + } + if(flag&3){ + l= strlen(line); + if(l>1) if(line[0]==34 && line[l-1]==34) { + wpt= line; + cpt= wpt+1; + while(*cpt!=0) + *(wpt++)= *(cpt++); + line[l-2]= 0; + } + } + if(!(flag&2)){ + wpt= cpt= line; + while(*(cpt)!=0) { + if(!isspace(*cpt)) + break; + cpt++; + } + while(*(cpt)!=0) + *(wpt++)= *(cpt++); + *wpt= 0; + } + if(!(flag&4)){ + l= strlen(line); + if(l<=0) + return(1); + cpt= line+l; + while(cpt-->=line){ + if(!isspace(*cpt)) + break; + *(cpt)= 0; + } + } + return(1); +} + + +/* -------------------------------------------------------------- */ + + +main(argc,argv) +int argc; +char **argv; +{ + struct CgeN *cgen= NULL; + int ret, msg_printed= 0,first=1,gen_for_stic= 1, make_ansi= 0, i; + int make_lowercase= 0, may_overwrite= 0; + char global_include_file[4096]; + + global_include_file[0]= 0; + + for(i= 1; i=argc) + strcpy(global_include_file,"global_include.h"); + else { + i++; + strcpy(global_include_file,argv[i]); + } + } else if(strcmp(argv[i],"-lowercase")==0) { + make_lowercase= 1; + } else if(strcmp(argv[i],"-overwrite")==0) { + may_overwrite= 1; + } else { + fprintf(stderr,"+++ %s: Unrecognized option: %s\n",argv[0],argv[i]); + {ret= 0; goto ex;} + } + } + + if(strlen(global_include_file)>0) { + /* begin */ + ret= Cgen__write_global_include(global_include_file,(!!may_overwrite)<<1); + if(ret<=0) + goto ex; + } + while(!feof(stdin)) { + ret= Cgen_new(&cgen,0); + if(ret<=0) + goto ex; + + /* <<< can be done neater */ + cgen->gen_for_stic= gen_for_stic; + cgen->make_ansi= make_ansi; + strcpy(cgen->global_include_file,global_include_file); + cgen->make_lowercase= make_lowercase; + cgen->may_overwrite= may_overwrite; + + ret= Cgen_read_fp(cgen,stdin,first); + if(ret<=0) + goto ex; + if(ret==2) + break; + first= 0; + ret= Cgen_write_h(cgen,0); + if(ret<=0) + goto ex; + ret= Cgen_write_c(cgen,1); + if(ret<=0) + goto ex; + } + if(strlen(global_include_file)>0) { + /* finalize */ + ret= Cgen__write_global_include(global_include_file,1); + if(ret<=0) + goto ex; + } + ret= 1; +ex: + if(cgen!=NULL) + if(cgen->msg[0]!=0) { + fprintf(stderr,"+++ %s\n",cgen->msg); + msg_printed= 1; + } + if(ret<=0 &&!msg_printed) { + if(errno>0) + fprintf(stderr,"+++ Error : %s\n",strerror(errno)); + else if(ret==-1) + fprintf(stderr, + "+++ Program run failed (probably due to lack of memory)\n"); + else + fprintf(stderr,"+++ Program run failed\n"); + } + Cgen_destroy(&cgen,0); + exit(1-ret); +} diff --git a/libcevap/cgen.h b/libcevap/cgen.h new file mode 100644 index 0000000..5b464a0 --- /dev/null +++ b/libcevap/cgen.h @@ -0,0 +1,35 @@ + +#ifndef Cgen_includeD +#define Cgen_includeD Yes + + + +struct CgeN { + + char *classname; + char *structname; + char *functname; + + int is_managed_list; + int is_bossless_list; + int gen_for_stic; /* 0=no smem,srgex,sfile , 1=all three, 2=smem only */ + int make_ansi; + int make_lowercase; + char global_include_file[4096]; + FILE *global_include_fp; + + struct CtyP *elements; + struct CtyP *last_element; + + int may_overwrite; + FILE *fp; + char filename[4096]; + FILE *ptt_fp; + char ptt_filename[4096]; + + char msg[8192]; +}; + + +#endif /* Cgen_includeD */ + diff --git a/libcevap/cgen.txt b/libcevap/cgen.txt new file mode 100644 index 0000000..d260af9 --- /dev/null +++ b/libcevap/cgen.txt @@ -0,0 +1,222 @@ + + +Description of the helper program stic*/bin/cgen + +cgen is copyright 2001 to 2007, Thomas Schmitt +and provided under BSD license. + +Compilation: + cc -g -o cgen cgen.c ctyp.c smem.c + + +cgen produces a class stub in C programming language. The data structure of +the class is described by some lines which get read from stdin. The stub will +consist of four files which emerge in the current working directory: + .h public header file of the class + .c automatically generated C code of the class + plus a copy of .c.methods + _private.h private header file of the class + .c.methods safe storage for manually created functions. + From here they get copied into the generated stub. + If such a file is missing, a dummy gets created. +It will define a struct for representing the class data aspects, +construtor _new(), destructor _destroy(), +getter __get() for each structure element. +Some more functions get added for particular class and element roles. + +cgen normally refuses to overwrite existing files because it supposes that +those contain code added by the human programmer. +Human programmer enhancements may be explanatory comments, class specific +methods, initial element values and other special precautions within the +generated functions. +As long as the modelling phase is going on, one may store such human code +in .c.methods and may use command line option -overwrite for +modelling development cycles. + +At some point of model matureness one may decide to give up cgen and the +.c.method files and to go on only with _private.h , .h and .c files. + + +Command line options + + -no_stic prevents usage of stic_dir/s_tools/*.[ch] + + -ansi generates ANSI C function heads and makes file .h hold + only public definitions: an opaque declaration of the class struct + and a list of function prototypes. The definiton of the class + struct is then in _private.h . + -global_include filename + sets the name of a file which will contain globally necessary + declarations. Currently it lists the existence of all class + structs. + -lowercase generate struct rather than struct and + function names _func() rather than _func() . + -overwrite allows to overwrite files _private.h, .h + and .c, but not .c.methods. + + +Input line format: + +There are two states of input: class level and element level. +Exampes are shown below with class roles and element roles. + +Input starts at class level. A class level line may be one of + +- Comment. A line which begins with '#' is ignored on class level. + +- Empty. A line with no characters is a comment with empty text (i.e. ignored). + +- Class. Options which begin with '-' and finally a word in lowercase letters + which defines the . The classname leads to a struct ClassnamE + and some class methods implemented as C functions _(). + +- End of input. Line "@@@" or EOF at stdin end the program run. + +After a class line, input switches to element level where a line may be: + +- Comment. A line which after some white space begins with '#' is considered + a comment. The preceeding white space is ignored and the text after '#' is + eventuellay trimmed by a single blank at both ends. This text will be part + of the class struct definition within file .h as a single + C comment line /* ... */. The sequence of elements and comments is preserved. + An empty comment text leads to an empty line in .h. + +- Empty. A line with no characters is a comment with empty text. + +- Element. Options which begin with '-', eventual C keywords "unsigned" or + "volatile", type or "struct ", element name. This leads to a struct + element which is taken into respect in some class methods. Depending on the + options in this line, some element methods __() + may get generated. + +- End of class. A single '@' marks the end of the element list and brings + input back to class level. I.e. next is expected another class name or + "@@@" or EOF at stdin. + +Input semantics: + +A class can have one of two roles: + +- Standalone class. + Input example: + my_class + +- Listable class, which has pointers to peer instances: .prev and .next + Such classes get a list destructor _destroy_all() which destroys + all members of a list (which is given by any of the list members). + Such a class should have a pointer *boss as first element in which case + the constructor will look like + _new(struct **o,struct *boss,int flag); + There is a function _link() which inserts an instance into a list + and a function _count() which tells the number of list members. + For pseudo random access there is function _by_idx(). + Input example: + -l my_class + + +A modifier is defined for classes: + +- Bossless. Disables a special boss-subordinate relationship which is created + if the first element of a class is a struct pointer with the name "boss". + Like + -l + -v struct Some_clasS *boss + Normally such a parameter *boss becomes part of the constructor method + _new(struct **o, struct Some_clasS *boss, int flag); + This relationship is typical for a listable class and a single class which + is designed to host instances of that listable class. Therefore one gets a + warning if a listable class does not begin with a struct pointer *boss. + But if -b is given, then CgeN ill not include a parameter *boss into the + constructor. It will rather look normal: + _new(struct **o, int flag); + It will not warn if the first element of a listable class is not struct + pointer *boss. + + +Elements have one of the following roles: + +- Value. It provides only storage for a C data type (which may be a C pointer + despite the role name "value"), a getter method __get(), + and a setter method __set(). + Input examples: + -v int i + -v int a[100] + -v char *cpt + -v struct xyz x + -v struct xyz *xpt + +- Managed. This has to be a pointer to a struct or to char. It will not + get attached to an object by the stub's code but its destructor + _destroy() will be called by _destruct(). In case of (char *) + it is supposed that a non-NULL value has been allocated by malloc(). + Managed (char *) types get a setter function __set() + which allocates memory and copies the textstring from its parameter. + Input examples: + -m struct XyZ *xyzpt + -m char *textstring + +- Chainlink. A pair of prev-next-style pointers to the own class struct. + Function _destruct() will unlink the affected instance and + put together its link partners. + Input example (there must always be two consequtive -c lines): + -c struct My_clasS *up + -c struct My_clasS *down + +- List. A pair of pointers to the struct of a listable class. The first + one holds the start of the list, the second one holds the end. + The getter function has an additional argument idx: + _get_(struct *o, int idx, struct **pt, + int flag) + idx == 0 is the start of the list, idx=1 the next element, ... + idx == -1 retrieves the last element of the list. + For insertion of list items there is provided method _new_(). + The inserted item is reachable via the getter function with idx == -1 + _destroy() instance calls _destroy_all(). Note that the end + pointer is always generated as private element (-p). + Input example (there must always be a -l and a -v line): + -l struct XyZ *list_start + -v struct XyZ *list_end + +The availability of getter method _get_(), and setter +method _set__set() can be controled by two modifiers: + +- Readonly. Only a getter method. + Input example + -r -v int broadcasted_status + +- Private. Neither getter nor setter method. + Input example + -p -v int private_value + +- Bossless listable. This marks elements which are listable objects but do not + expect a boss pointer in their constructor. See above: Listable class and + the bossless modifier for classes. + Input example + -b -l struct XyZ *list + -v struct XyZ *last_in_list + +- Initialization free. The class constructor will not initialize this element. + This modifier has to be used if neither NULL nor 0 are suitable + initialization values. + +Example run: + + rm class_x.c class_x.h class_y.c class_y.h + bin/cgen <<+ +-l class_x +-r -v struct Boss_clasS *boss +-v int x +-r -v struct stat stbuf +-m struct Class_Y *y +-m char *text +-c struct Class_X *master +-c struct Class_X *slave +-b -l struct Class_X *provider +-p -v struct Class_X *last_provider +@ +-b -l class_y +-r -v char providername[80] +@ ++ + + diff --git a/libcevap/ctyp.c b/libcevap/ctyp.c new file mode 100644 index 0000000..122bfc2 --- /dev/null +++ b/libcevap/ctyp.c @@ -0,0 +1,364 @@ + +/* + cc -g -o ctyp.c +*/ + +#include +#include +#include +#include +#include + +#include "smem.h" +extern char *Sfile_fgets(); +extern int Sregex_string(); +extern int Sregex_trimline(); + +#include "ctyp.h" + + +/* -------------------------- CtyP ----------------------- */ + + +int Ctyp_new(objpt,link,flag) +struct CtyP **objpt; +struct CtyP *link; +int flag; +{ + struct CtyP *o; + int ret; + + *objpt= o= TSOB_FELD(struct CtyP,1); + if(o==NULL) + return(-1); + + o->is_comment= 0; + o->is_pointer= 0; + o->is_struct= 0; + o->is_unsigned= 0; + o->is_volatile= 0; + o->array_size= 0; + o->management= 0; + o->with_getter= 1; + o->with_setter= 1; + o->bossless_list= 0; + o->no_initializer= 0; + o->dtype= NULL; + o->name= NULL; + o->prev= NULL; + o->next= NULL; + + if(link!=NULL) + link->next= o; + o->prev= link; + + return(1); +failed:; + Ctyp_destroy(objpt,0); + return(-1); +} + + +int Ctyp_destroy(objpt,flag) +struct CtyP **objpt; +int flag; +{ + struct CtyP *o; + + o= *objpt; + if(o==NULL) + return(0); + + if(o->prev!=NULL) + o->prev->next= o->next; + if(o->next!=NULL) + o->next->prev= o->prev; + Sregex_string(&(o->dtype),NULL,0); + Sregex_string(&(o->name),NULL,0); + + free((char *) o); + *objpt= NULL; + return(1); +} + + +int Ctyp_get_pointer_level(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->is_pointer); +} + + +int Ctyp_is_struct(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->is_struct); +} + + +int Ctyp_get_array_size(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->array_size); +} + + +int Ctyp_get_management(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->management); +} + + +int Ctyp_get_with_getter(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->with_getter); +} + + +int Ctyp_get_with_setter(ct,flag) +struct CtyP *ct; +int flag; +{ + return(ct->with_setter); +} + + +int Ctyp_get_dtype(ct,text,flag) +struct CtyP *ct; +char **text; /* must point to NULL of freeable memory */ +int flag; +/* + bit0=eventually prepend "struct " +*/ +{ + if((flag&1) && ct->is_struct) { + if(Sregex_string(text,"struct ",0)<=0) + return(-1); + } else { + if(Sregex_string(text,"",0)<=0) + return(-1); + } + if(Sregex_string(text,ct->dtype,1)<=0) + return(-1); + return(1); +} + + +int Ctyp_get_name(ct,text,flag) +struct CtyP *ct; +char **text; /* must point to NULL of freeable memory */ +int flag; +{ + if(Sregex_string(text,ct->name,0)<=0) + return(-1); + return(1); +} + + +int Ctyp_get_type_mod(ct,is_spointer,is_struct,array_size,flag) +struct CtyP *ct; +int *is_spointer,*is_struct,*array_size; +int flag; +{ + *is_spointer= ct->is_pointer; + *is_struct= ct->is_struct; + *array_size= ct->array_size; +} + +int Ctyp_new_from_line(ct,link,line,msg,flag) +struct CtyP **ct; +struct CtyP *link; +char *line; +char *msg; +int flag; +/* + bit0= make struct ClassnamE to struct classname +*/ +{ + struct CtyP *o; + char *cpt,*bpt; + int ret,l; + char orig_line[4096]; + + ret= Ctyp_new(ct,*ct,0); + if(ret<=0) { + sprintf(msg,"Failed to create CtyP object (due to lack of memory ?)"); + goto ex; + } + o= *ct; + + strcpy(orig_line,line); + cpt= line; + while(*cpt!=0 && isspace(*cpt)) cpt++; + if(cpt[0]=='#') { + cpt++; + if(cpt[1]==' ') + cpt++; + l= strlen(cpt); + if(cpt[0]==' ') + cpt++; + if(l>1) + if(cpt[l-1]==' ') + cpt[l-1]= 0; + if(Sregex_string(&(o->name),cpt,0)<=0) + {ret= -1; goto ex;} + o->is_comment= 1; + {ret= 1; goto ex;} + } else if(cpt[0]==0) { + if(Sregex_string(&(o->name),cpt,0)<=0) + {ret= -1; goto ex;} + o->is_comment= 1; + {ret= 1; goto ex;} + } else if(cpt[0]=='/' && cpt[1]=='*') { + sprintf(msg, + "C-style multi line comments (/* ... */) not supported yet. Use #."); + goto ex; + + /* >>> */ + + } + cpt= line; + while(cpt[0]=='-') { + /* look for management specifiers: + -v* just a value + -m* allocated memory which needs to be freed + -c* mutual link (like prev+next) + -l* list of -m chained by mutual links prev and next + + -r* read-only : no setter function + -p* private : neither setter nor getter function + -b* bossless_list : Class_new(o,flag), not Class_new(o,boss,flag) + -i* no_initializer : do not initialize element in _new() + #... line is a comment + */ + if(cpt[1]=='v' || cpt[1]=='V') { + o->management= 0; + } else if(cpt[1]=='m' || cpt[1]=='M') { + o->management= 1; + } else if(cpt[1]=='c' || cpt[1]=='C') { + o->management= 2; + if(o->prev!=NULL) + if(o->prev->management==2) + o->management= 3; + } else if(cpt[1]=='l' || cpt[1]=='L') { + o->management= 4; + } else if(cpt[1]=='r' || cpt[1]=='R') { + o->with_setter= 0; + } else if(cpt[1]=='p' || cpt[1]=='P') { + o->with_setter= 0; + o->with_getter= 0; + } else if(cpt[1]=='b' || cpt[1]=='B') { + o->bossless_list= 1; + } else if(cpt[1]=='i' || cpt[1]=='I') { + o->no_initializer= 1; + } + while(*cpt!=0 && !isspace(*cpt)) cpt++; + while(*cpt!=0 && isspace(*cpt)) cpt++; + if(*cpt==0) + goto no_name; + } + + if(strncmp(cpt,"struct ",7)==0) { + o->is_struct= 1; + cpt+= 7; + } else if(strncmp(cpt,"unsigned ",9)==0) { + o->is_unsigned= 1; + cpt+= 9; + } else if(strncmp(cpt,"volatile ",9)==0) { + o->is_volatile= 1; + cpt+= 9; + if(strncmp(cpt,"unsigned ",9)==0) { + o->is_unsigned= 1; + cpt+= 9; + } + } + if(*cpt==0) + goto no_name; + while(*cpt!=0 && isspace(*cpt)) cpt++; + bpt= cpt; + while(*bpt!=0 && !isspace(*bpt)) bpt++; + if(*bpt==0) + goto no_name; + if(*bpt==0) { +no_name:; + sprintf(msg,"No name found after type description : %s",orig_line); + ret= 0; goto ex; + } + *bpt= 0; + if(Sregex_string(&(o->dtype),cpt,0)<=0) + {ret= -1; goto ex;} + if((flag&1) && o->is_struct && strlen(o->dtype)>=3) + if(isupper(o->dtype[0]) && islower(o->dtype[1]) && + isupper(o->dtype[strlen(o->dtype)-1])) { + o->dtype[0]= tolower(o->dtype[0]); + o->dtype[strlen(o->dtype)-1]= tolower(o->dtype[strlen(o->dtype)-1]); + } + cpt= bpt+1; + while(*cpt!=0 && isspace(*cpt)) cpt++; + if(*cpt==0) + goto no_name; + for(;*cpt=='*';cpt++) + o->is_pointer++; + if(*cpt==0) + goto no_name; + bpt= strchr(cpt,'['); + if(bpt!=NULL) { + if(strchr(bpt,']')!=NULL) + *strchr(bpt,']')= 0; + sscanf(bpt,"%lu",&(o->array_size)); + *bpt= 0; + } + if(Sregex_string(&(o->name),cpt,0)<=0) + {ret= -1; goto ex;} + if(o->management==1) { + if((!(o->is_pointer>=1 && o->is_pointer<=2)) || + ((!o->is_struct) && strcmp(o->dtype,"char")!=0 && + (strcmp(o->dtype,"unsigned char")!=0))) { + sprintf(msg,"-m can only be applied to pointers of struct or char : %s", + orig_line); + ret= 0; goto ex; + } + } + ret= 1; +ex:; + return(ret); +} + + +int Ctyp_read_fp(ct,fp,msg,flag) +struct CtyP **ct; +FILE *fp; +char msg[]; /* at least [4096+256] */ +int flag; +/* + bit0= make struct ClassnamE to struct classname +*/ +{ + int ret; + char line[4096]; + struct CtyP *o; + + line[0]= 0; + printf( + "[-value|-managed|-chain|-list] class element ? (e.g.: -l struct XyZ)\n"); + if(Sfile_fgets(line,sizeof(line)-1,fp)==NULL) + {ret= 2; goto ex;} + printf("%s\n",line); + Sregex_trimline(line,0); + if(strcmp(line,"@")==0) + {ret= 2; goto ex;} + ret= Ctyp_new_from_line(ct,*ct,line,msg,flag&1); + if(ret<=0) + goto ex; + ret= 1; +ex:; + return(ret); +} + diff --git a/libcevap/ctyp.h b/libcevap/ctyp.h new file mode 100644 index 0000000..13657b0 --- /dev/null +++ b/libcevap/ctyp.h @@ -0,0 +1,41 @@ + +#ifndef Ctyp_includeD +#define Ctyp_includeD + + + +struct CtyP { + + /* if 1 : .name contains comment text, all other elements are invalid */ + int is_comment; + + int is_pointer; /* number of asterisks */ + int is_struct; + int is_unsigned; + int is_volatile; + unsigned long array_size; + + int management; /* + -v 0= just a value + -m 1= allocated memory which needs to be freed + -c 2= mutual link with the next element + -c 3= mutual link with the prev element + -l 4= list of -m , chained by -c pair named 'prev','next' + supposed to be followed by a -v of the same type + which will mark the end of the list + */ + int with_getter; + int with_setter; + int bossless_list; + int no_initializer; + + char *dtype; + char *name; + + struct CtyP *prev; + struct CtyP *next; +}; + + +#endif /* Ctyp_includeD */ + diff --git a/libcevap/smem.c b/libcevap/smem.c new file mode 100644 index 0000000..94aed82 --- /dev/null +++ b/libcevap/smem.c @@ -0,0 +1,445 @@ + +#include +#include +#include +#include +#include + + +#define Smem_included_by_smem_C +#include "smem.h" + + + +/* ------------------------------ SmemiteM ----------------------------- */ + + +int Smemitem_new(item,data,size,next,hash_start,flag) +struct SmemiteM **item; +char *data; +size_t size; +struct SmemiteM *next; +struct SmemiteM **hash_start; +int flag; +{ + struct SmemiteM *t; + + *item= t= (struct SmemiteM *) malloc(sizeof(struct SmemiteM)); + if(t==NULL) + return(-1); + t->data= data; + t->size= size; + t->prev= NULL; + t->next= next; + +#ifdef Smem_with_hasH + t->hash_next= NULL; + t->hash_prev= NULL; +#endif /* Smem_with_hasH */ + + if(next!=NULL) { + if(next->prev!=NULL) { + t->prev= next->prev; + next->prev->next= t; + } + next->prev= t; + } + +#ifdef Smem_with_hasH + if(hash_start!=NULL) { + t->hash_next= *hash_start; + if(t->hash_next!=NULL) { + t->hash_next->hash_prev= t; + } + *hash_start= t; + } +#endif /* Smem_with_hasH */ + + return(1); +} + + +int Smemitem_destroy(in_item,hash_start,flag) +struct SmemiteM **in_item; +struct SmemiteM **hash_start; +int flag; +{ + struct SmemiteM *item; + + item= *in_item; + if(item==NULL) + return(0); + if(item==Smem_start_iteM) + Smem_start_iteM= item->next; + if(item->prev!=NULL) + item->prev->next= item->next; + if(item->next!=NULL) + item->next->prev= item->prev; + +#ifdef Smem_with_hasH + if(hash_start!=NULL) { + if(item==*hash_start) + *hash_start= item->hash_next; + if(item->hash_prev!=NULL) + item->hash_prev->hash_next= item->hash_next; + if(item->hash_next!=NULL) + item->hash_next->hash_prev= item->hash_prev; + } +#endif /* Smem_with_hasH */ + + free((char *) item); + *in_item= NULL; + return(1); +} + + +int Smemitem_report(item,line,flag) +struct SmemiteM *item; +char line[1024]; +int flag; +{ + char *cpt; + int i,upto; + + sprintf(line,"%4lu bytes at %8.8lx ",(unsigned long) item->size, + (unsigned long) item->data); + cpt= line+strlen(line); + if(item->size<=256) + upto= item->size; + else + upto= 256; + if(item->data!=NULL) { + strcpy(cpt,"= \""); + cpt+= 3; + for(i=0;idata[i]<32 || item->data[i]>=127 || item->data[i]=='\\') { + sprintf(cpt,"\\%2.2X",(unsigned char) item->data[i]); + cpt+= 3; + } else { + *(cpt++)= item->data[i]; + } + } + if(isize) { + sprintf(cpt,"\" [truncated]"); + } else { + *(cpt++)= '"'; + *cpt= 0; + } + } + return(1); +} + + +int Smemitem_stderr(item,flag) +struct SmemiteM *item; +int flag; +{ + char line[1024]; + Smemitem_report(item,line,0); + fprintf(stderr,"%s\n",line); + return(1); +} + + + +/* -------------------------------- Smem ------------------------------ */ + + +int Smem_protest(line,flag) +char *line; +int flag; +{ + fprintf(stderr,"%s\n",line); + return(1); +} + + +int Smem_hashindex(ptr,flag) +char *ptr; +int flag; +{ + unsigned long idx; + + idx= (unsigned long) ptr; + return((idx>>Smem_hashshifT)%(Smem_hashsizE)); +} + + +/* find a certain memory item */ +struct SmemiteM *Smem_find_item(ptr,flag) +char *ptr; +int flag; +{ + int misscount= 0,idx; + struct SmemiteM *current; + +#ifdef Smem_with_hasH + + idx= Smem_hashindex(ptr,0); + for(current= Smem_hasH[idx];current!=NULL;current= current->hash_next) { + if(current->data==ptr) + return(current); + misscount++; + } + +#else /* Smem_with_hasH */ + + for(current= Smem_start_iteM;current!=NULL;current= current->next) { + if(current->data==ptr) + return(current); + misscount++; + } + +#endif /* ! Smem_with_hasH */ + + return(NULL); +} + + +int Smem_search_and_delete(ptr,flag) +char *ptr; +int flag; +/* + bit0= revoke registration : decrement counters +*/ +{ + int idx; + struct SmemiteM *current; + + current= Smem_find_item(ptr,0); + if(current==NULL) + return(0); + Smem_record_counT--; + Smem_record_byteS-= current->size; + idx= Smem_hashindex(ptr,0); + Smemitem_destroy(¤t,&(Smem_hasH[idx]),0); + Smem_hash_counteR[idx]-= 1.0; + if(flag&1) { + Smem_malloc_counT--; + Smem_pending_counT--; + } + return(1); +} + + +char *Smem_malloc(size) +size_t size; +{ + int idx; + char *cpt; + + if(size==0) { + Smem_protest("########### smem.c : malloc(0) caught",0); + return(NULL); + } + + /* if(size==1032) + cpt= NULL; / * set breakpoint here to find requests of certain size */ + + cpt= (char *) malloc(size); + if(cpt==NULL) { + char text[161]; + sprintf(text,"########### smem.c : malloc( %lu ) returned NULL", + (unsigned long) size); + Smem_protest(text,0); + return(NULL); + } + /* if(cpt==0x080a1e20) + cpt= NULL; / * set breakpoint here to find origin of certain address */ + + Smem_malloc_counT++; + Smem_pending_counT++; + if(Smem_record_itemS) { + idx= Smem_hashindex(cpt,0); + Smem_hash_counteR[idx]+= 1.0; + if(Smemitem_new(&Smem_start_iteM,cpt,size,Smem_start_iteM, + &(Smem_hasH[idx]),0)<=0) { + Smem_protest( + "########### smem.c : malloc( sizeof(SmemiteM) ) returned NULL",0); + return(NULL); + } + Smem_record_counT++; + Smem_record_byteS+= size; + } + return(cpt); +} + + +int Smem_free(ptr) +char *ptr; +{ + if(ptr==NULL) { + Smem_protest("########### smem.c : free() of NULL pointer caught",0); + return(0); + } + if(Smem_record_itemS) { + if(Smem_search_and_delete(ptr,0)<=0) { + Smem_protest("########### smem.c : free() of unrecorded pointer caught",0); + return(0); + } + } + Smem_free_counT++; + Smem_pending_counT--; + free(ptr); + return(1); +} + + +int Smem_report(line,flag) +char line[1024]; +int flag; +{ + sprintf(line,"malloc= %.f , free= %.f , pending= %.f", + Smem_malloc_counT,Smem_free_counT,Smem_pending_counT); + if(Smem_record_itemS) { + sprintf(line+strlen(line)," , bytes=%.f , records= %.f", + Smem_record_byteS,Smem_record_counT); + } + return(1); +} + + +int Smem_stderr(flag) +int flag; +/* + bit0= report 50 youngest pending items too + bit1= do not report if nothing is pending +*/ +{ + struct SmemiteM *current; + char line[1024]; + int i= 0; + + if(flag&2) + if(Smem_pending_counT==0.0 + && Smem_record_counT==0.0 + && Smem_record_byteS==0.0) + return(2); + Smem_report(line,0); + fprintf(stderr,"%s\n",line); + if(flag&1) { + for(current= Smem_start_iteM;current!=NULL;current= current->next) { + Smemitem_stderr(current,0); + if(++i>=50) + break; + } + if(current!=NULL) + if(current->next!=NULL) + fprintf(stderr,"[list truncated]\n"); + } + return(1); +} + + +int Smem_set_record_items(value) +int value; +{ + int i; + + if(!Smem_hash_initializeD) { + for(i=0;i0) { + for(;current!=NULL;current= current->next) { + if(step==0) + return(current); + step--; + } + } else if(step<0) { + for(;current!=NULL;current= current->prev) { + if(step==0) + return(current); + step++; + } + } else { + return(current); + } + return(NULL); +} + + +int Smem_print_hash_counter() { + int i; + + for(i=0;idata); + if(ret<=0) + return(0); + } + return(1); +} + + diff --git a/libcevap/smem.h b/libcevap/smem.h new file mode 100644 index 0000000..ba5193f --- /dev/null +++ b/libcevap/smem.h @@ -0,0 +1,161 @@ + +#ifndef Smem_includeD +#define Smem_includeD + + +/* compile time adjustable parameters : */ + +/* if not defined, flat malloc() and free() is used */ +#define Smem_own_functionS +#ifdef Smem_no_own_functionS +#undef Smem_own_functionS +#endif /* Smem_no_own_functionS */ + +/* if not defined, the record items will be smaller by 8 byte + but deletion of items may be much slower */ +#define Smem_with_hasH + + + +struct SmemiteM { + + char *data; + size_t size; + + struct SmemiteM *prev,*next; + + struct SmemiteM *hash_prev,*hash_next; + +}; + + + + +#ifdef Smem_own_functionS + +char *Smem_malloc(); +#define TSOB_FELD(typ,anz) (typ *) Smem_malloc((anz)*sizeof(typ)); +#define Smem_malloC Smem_malloc +#define Smem_freE Smem_free + +#else /* Smem_own_functionS */ + +#define TSOB_FELD(typ,anz) (typ *) malloc((anz)*sizeof(typ)); +#define Smem_malloC malloc +#define Smem_freE free + +#endif /* ! Smem_own_functionS */ + + + + +#define Smem_hashsizE 251 +#define Smem_hashshifT 8 + +#ifdef Smem_included_by_smem_C + +double Smem_malloc_counT= 0.0; +double Smem_free_counT= 0.0; +double Smem_pending_counT= 0.0; +struct SmemiteM *Smem_start_iteM= NULL; +struct SmemiteM *Smem_hasH[Smem_hashsizE]; +double Smem_hash_counteR[Smem_hashsizE]; + +/* these both init values are essential, since setting Smem_record_itemS=1 + by use of Smem_set_record_items() initializes the hash array + (i do not really trust the compiler producers to have read K&R) */ +int Smem_hash_initializeD= 0; +int Smem_record_itemS= 0; + +double Smem_record_counT= 0.0; +double Smem_record_byteS= 0.0; + +#else /* Smem_included_by_smem_C */ + +extern double Smem_malloc_counT; +extern double Smem_free_counT; +extern double Smem_pending_counT; +extern struct SmemiteM *Smem_start_iteM; +extern struct SmemiteM *Smem_hasH[Smem_hashsizE]; +extern double Smem_hash_counteR[Smem_hashsizE]; +extern int Smem_hash_initializeD; +extern int Smem_record_itemS; +extern double Smem_record_counT; +extern double Smem_record_byteS; + +#endif /* ! Smem_included_by_smem_C */ + + + +#endif /* ! Smem_includeD */ + + +/* + + smem + + Functions to replace malloc() and free() in order to get more control + over memory leaks or spurious errors caused by faulty usage of malloc() + and free(). + + + Sourcecode provisions: + + Use only the following macros for memory management: + TSOB_FELD(type,count) creates an array of items of given type + Smem_malloC() analogue of malloc() + Smem_freE() analogue of free() + One may #define malloc Smem_malloC resp. #define free Smem_freE + but better would be to review (and often to streamline) the sourcecode + in respect to those two functions. + + + Speed versus control: + + In production versions, where maximum speed is required, one may undefine + the macro Smem_own_functionS in smem.h . + This causes the above macros to directly invoke malloc() and free() without + any speed reduction (and without any additional use). + Undefinitio can be done globaly by modifying smem.h or locally by defining + Smem_no_own_functionS before including smem.h . + + If Smem_own_functionS remains defined, then the functions + Smem_malloc() + Smem_free() + are used rather than malloc() and free(). + They count the number of calls to maintain a rough overview of memory usage. + Smem_malloc() additionally checks for 0 size and Smem_free() checks for + NULL pointers, which they both report to stderr. Eventually one should set + a breakpoint in function Smem_protest() to learn about the origin of such + messages. + A status line may be obtained by Smem_report() or printed by Smem_stderr(). + + As long as the variable Smem_record_itemS is set to 0, there is not very much + overhead compared with malloc() and free(). + If the variable is set to 1 by Smem_set_record_items() then all malloc() + results are kept in a list where they will be deleted by their corresponding + Smem_free() calls. If a pointer is to be freed, which is not recorded in the + list then an error message will be printed to stderr. The memory will not + be freed ! + This mode not only may be very slow, it also consumes at least 16 byte per + piece of data which was obtained by malloc as long as it has not been freed. + Due to the current nature of the list, large numbers of memory items are freed + much faster in the reverse order of their creation. If there is a list of + 100000 strings to delete, it is very rewarding to free the youngest ones first. + A shortcut via hashing is available but consumes 24 bytes rather than 16. + (see above Smem_with_hasH ) + + The function Smem_is_recorded() can be used to check wether a pointer is + valid according to the list. It returns : + 0 = is not in list , 1 = is in list , 2 = recording is off + + If one decides to start recording malloc() results in the midst of a program + run, one has to be aware of false protests of Smem_free() if a memory piece + has been allocated before recording started. This will also cause those pieces + to be memory leaks because Smem_free() refuses to delete them. (Freeing memory + that was not obtained by malloc or was already freed previously can result in + deferred SIGSEGV or similar trouble, depending on OS and library.) + Also in that case one should stop recording before ending the program, to + avoid a lot of false complaints about longliving memory objects. + +*/