The C code generator mentioned in doc/libdax_model.txt. See there.
This commit is contained in:
parent
ba0e977e42
commit
88ad4a4ee1
1488
libcevap/cgen.c
Normal file
1488
libcevap/cgen.c
Normal file
File diff suppressed because it is too large
Load Diff
35
libcevap/cgen.h
Normal file
35
libcevap/cgen.h
Normal file
@ -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 */
|
||||||
|
|
222
libcevap/cgen.txt
Normal file
222
libcevap/cgen.txt
Normal file
@ -0,0 +1,222 @@
|
|||||||
|
|
||||||
|
|
||||||
|
Description of the helper program stic*/bin/cgen
|
||||||
|
|
||||||
|
cgen is copyright 2001 to 2007, Thomas Schmitt <stic-source@gmx.net>
|
||||||
|
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:
|
||||||
|
<classname>.h public header file of the class
|
||||||
|
<classname>.c automatically generated C code of the class
|
||||||
|
plus a copy of <classname>.c.methods
|
||||||
|
<classname>_private.h private header file of the class
|
||||||
|
<classname>.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 <ClassnamE> for representing the class data aspects,
|
||||||
|
construtor <Classname>_new(), destructor <Classname>_destroy(),
|
||||||
|
getter <Classname>_<element>_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 <classname>.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 <classname>.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 <classname>_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 <classname> rather than struct <ClassnamE> and
|
||||||
|
function names <classname>_func() rather than <Classname>_func() .
|
||||||
|
-overwrite allows to overwrite files <classname>_private.h, <classname>.h
|
||||||
|
and <classname>.c, but not <classname>.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 <classname>. The classname leads to a struct ClassnamE
|
||||||
|
and some class methods implemented as C functions <Classnname>_<func>().
|
||||||
|
|
||||||
|
- 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 <classname_private>.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 <classname_private>.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 <NamE>", 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 <Classnname>_<func>_<element>()
|
||||||
|
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 <Classname>_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
|
||||||
|
<Classname>_new(struct <ClassnamE> **o,struct <Some_clasS> *boss,int flag);
|
||||||
|
There is a function <Classname>_link() which inserts an instance into a list
|
||||||
|
and a function <Classname>_count() which tells the number of list members.
|
||||||
|
For pseudo random access there is function <Classname>_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 <classname>
|
||||||
|
-v struct Some_clasS *boss
|
||||||
|
Normally such a parameter *boss becomes part of the constructor method
|
||||||
|
<Classname>_new(struct <ClassnamE> **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:
|
||||||
|
<Classname>_new(struct <ClassnamE> **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 <Classname>_<element>_get(),
|
||||||
|
and a setter method <Classname>_<element>_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 <XyZ> or to char. It will not
|
||||||
|
get attached to an object by the stub's code but its destructor
|
||||||
|
<Xyz>_destroy() will be called by <Classname>_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 <Classname>_<element>_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 <Classname>_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 <XyZ> of a listable class. The first
|
||||||
|
one <ls> holds the start of the list, the second one <eol> holds the end.
|
||||||
|
The getter function has an additional argument idx:
|
||||||
|
<Classname>_get_<ls>(struct <ClassnamE> *o, int idx, struct <XyZ> **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 <Classname>_new_<ls>().
|
||||||
|
The inserted item is reachable via the getter function with idx == -1
|
||||||
|
<Classname>_destroy() instance calls <Xyz>_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 <Classname>_get_<element>(), and setter
|
||||||
|
method <Classname>_set_<element>_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]
|
||||||
|
@
|
||||||
|
+
|
||||||
|
|
||||||
|
|
364
libcevap/ctyp.c
Normal file
364
libcevap/ctyp.c
Normal file
@ -0,0 +1,364 @@
|
|||||||
|
|
||||||
|
/*
|
||||||
|
cc -g -o ctyp.c
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#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 <Class>_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);
|
||||||
|
}
|
||||||
|
|
41
libcevap/ctyp.h
Normal file
41
libcevap/ctyp.h
Normal file
@ -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 */
|
||||||
|
|
445
libcevap/smem.c
Normal file
445
libcevap/smem.c
Normal file
@ -0,0 +1,445 @@
|
|||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
|
||||||
|
#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;i<upto;i++){
|
||||||
|
if(item->data[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(i<item->size) {
|
||||||
|
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;i<Smem_hashsizE;i++) {
|
||||||
|
Smem_hasH[i]= NULL;
|
||||||
|
Smem_hash_counteR[i]= 0.0;
|
||||||
|
}
|
||||||
|
Smem_hash_initializeD= 1;
|
||||||
|
}
|
||||||
|
Smem_record_itemS= value;
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Smem_is_recorded(ptr,flag)
|
||||||
|
char *ptr;
|
||||||
|
int flag;
|
||||||
|
/*
|
||||||
|
bit0= complain if return(0)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
if(Smem_record_itemS==0)
|
||||||
|
return(2);
|
||||||
|
if(Smem_find_item(ptr,0)!=NULL)
|
||||||
|
return(1);
|
||||||
|
if(flag&1)
|
||||||
|
Smem_protest("########### smem.c : free() of unrecorded pointer caught",0);
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* A simple C string cloner */
|
||||||
|
int Smem_clone_string(ptr,text)
|
||||||
|
char **ptr;
|
||||||
|
char *text;
|
||||||
|
{
|
||||||
|
*ptr= Smem_malloC(strlen(text)+1);
|
||||||
|
if(*ptr==NULL)
|
||||||
|
return(-1);
|
||||||
|
strcpy(*ptr,text);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* ----------------- for usage via debugger commands --------------------- */
|
||||||
|
|
||||||
|
|
||||||
|
/* find a certain memory item */
|
||||||
|
struct SmemiteM *Smem_find_data(ptr)
|
||||||
|
char *ptr;
|
||||||
|
{
|
||||||
|
return(Smem_find_item(ptr,0));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* browsing the list */
|
||||||
|
struct SmemiteM *Smem_fetch_item(step,flag)
|
||||||
|
int step;
|
||||||
|
int flag;
|
||||||
|
/*
|
||||||
|
bit0= reset cursor (and therefore address absolutely)
|
||||||
|
*/
|
||||||
|
{
|
||||||
|
static struct SmemiteM *current= NULL;
|
||||||
|
|
||||||
|
if((flag&1)||current==NULL)
|
||||||
|
current= Smem_start_iteM;
|
||||||
|
if(step>0) {
|
||||||
|
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;i<Smem_hashsizE;i++)
|
||||||
|
printf("%4d : %10.f\n",i,Smem_hash_counteR[i]);
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* delete all recorded memory items */
|
||||||
|
int Smem_delete_all_items()
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
while(Smem_start_iteM!=NULL) {
|
||||||
|
ret= Smem_free(Smem_start_iteM->data);
|
||||||
|
if(ret<=0)
|
||||||
|
return(0);
|
||||||
|
}
|
||||||
|
return(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
161
libcevap/smem.h
Normal file
161
libcevap/smem.h
Normal file
@ -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.
|
||||||
|
|
||||||
|
*/
|
Loading…
Reference in New Issue
Block a user