Branching for libburn release 0.7.4

This commit is contained in:
2009-12-06 14:56:46 +00:00
parent 451dd1136e
commit c3027b97ad
125 changed files with 63351 additions and 0 deletions

File diff suppressed because it is too large Load Diff

View 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 */

View 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]
@
+

View 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+1,"%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);
}

View 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 */

View File

@ -0,0 +1,30 @@
#!/bin/sh
copy_mode=0
while true
do
read line
if test "$copy_mode" = "0"
then
if echo " $line" | grep '^ Cgen=' >/dev/null 2>&1
then
copy_mode=1
if echo " $line" | grep '^ Cgen=..' >/dev/null 2>&1
then
echo " $line" | sed -e 's/^ Cgen=//'
fi
elif echo " $line" | grep '^ =end Model=' >/dev/null 2>&1
then
break
fi
else
if test " $line" = " @"
then
copy_mode=0
echo "@"
else
echo " $line" | sed -e 's/^ //'
fi
fi
done

View File

@ -0,0 +1,16 @@
#!/bin/sh
test_dir=.
model_file=./libdax_model.txt
xtr_dir=.
cgen_dir=.
# cgen_dir=~/projekte/cdrskin_dir/libburn-develop/libcevap
cd "$test_dir" || exit 1
test -e smem.h || exit 1
cat "$model_file" | \
"$xtr_dir"/extract_cgen_input.sh | \
"$cgen_dir"/cgen -smem_local -ansi -global_include cevap_global.h \
-overwrite "$@"

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

View File

@ -0,0 +1,944 @@
#
# libdax is the early working name for the successor software of libburn,
# a library for writing information onto optical media, i.e. CD and DVD.
# The current working name is libcevap, refering to various kinds of roasts in
# Europe and Asia which share the property to be structured in smaller pieces.
#
# The reason for the replacement is the unclear copyright situation as well
# as libburn's sketchy original state and the subsequential evolutionary
# damages done by us in libburn code.
# This does not mean libburn is shaky. Its current state just reflects the
# virtual conflict of at least two programmer personalities and their goals.
#
#
# Please: Nobody shall take the development of libcevap as a reason for not
# programming an application which uses libburn.
# libburn works now. libcevap is planned to work in future.
#
# libcevap will replace libburn in a controlled, application friendly way.
# The first application of libcevap will be a libburn API wrapper which will
# allow to perform all API calls of libburn which are proveable to work in
# the current implementation. (Some CD stuff is not understood by us yet.
# We will have to learn.)
#
# The libburn API will be frozen when libcevap has closed up to its current
# capabilities. Nevertheless it may take profit from some of the future
# progress in libcevap (e.g. new media types).
# We hope that finally libcevap will have capabilities superior to libburn.
# This will then be a reason to port applications to the libcevap API.
#
# Application programmers are advised to encapsulate their libburn API calls
# in an own abstraction layer. The semantic concepts of burning will be
# compatible between libburn and libcevap. I.e you will have a library object
# to be started up, drives to be found and grabbed, media and their states
# to be identified, sessions, tracks, burn options to be set, blanking,
# formatting, and so on.
# Data types, function calls, and quirks will be incompatible between both
# APIs, though.
#
# -------------------------------------------------------------------------
# Originally this was a backup of text input clicketitoggled into ArgoUML
# Meanwhile it becomes an intermediate storage for attributes and
# class interconnections in the notation of my C stub generator CgeN
# (see also end of this text)
# next : work on completeness : cevapformat
# Open questions:
# - how to connect to GESTURES ? Globally ?
Model=libdax
ClassDiagram=Overview
Class=API
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
The API is the only layer visible to the applications. It exposes MMC concepts
which it reflects and augments by its own architectural concepts.
Subordinates=EQUIP,JOB,AUX
Cgen=\
cevapi
-r -m struct CevapequiP *equip
-r -m struct CevapjoB *job
-r -m struct CevapauX *aux
-r -m struct CevapgestureS *gestures
@
=end Class
Class=EQUIP
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
EQUIP represents the physical and logical equipment in reach of libdax.
This includes the system, drives, media, and their current states.
PeerToPeer=GESTURES
Boss=API
Cgen=\
cevapequip
-r -v struct CevapI *boss
-r -m struct CevapsysteM *sys
-v struct CevapgestureS *gestures
@
=end Class
Class=JOB
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
JOB models the tasks to be performed via libdax.
This includes disc, session, track, source, fifo, dewav, burn options.
PeerToPeer=GESTURES
Boss=API
Cgen=\
cevapjob
-r -v struct CevapI *boss
-r -m struct CevaptodO *todo
-v struct CevapgestureS *gestures
# >>>
@
=end Class
Class=AUX
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
AUX bundles any models which are neither EQUIP nor JOB.
This includes abort handler and message system.
PeerToPeer=GESTURES
Boss=API
Cgen=\
cevapaux
-r -v struct CevapI *boss
-v struct CevapgestureS *gestures
# >>>
@
=end Class
Class=GESTURES
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
GESTURES ist the procedural repertoire which interconnects EQUIP, JOB, and AUX
and also provides to them the services from the SCSI oriented layers.
PeerToPeer=EQUIP,JOB,AUX
Subordinates=SCSI_CMD
Cgen=\
cevapgestures
-r -v struct CevapI *boss
-v struct CevapequiP *equip
-v struct CevapjoB *job
-v struct CevapauX *aux
-r -m struct CevapscmD *scsi_cmd
# >>>
@
=end Class
Class=SCSI_CMD
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
SCSI_CMD represents the semantic part of SCSI (i.e. mainly MMC) specs.
This layer models each SCSI command that is used by libdax. It knows about
its parameters and constraints with particular equipment and jobs.
Boss=GESTURES
Subordinates=Classes with SCSI_EXEC Interface
Cgen=\
cevapscmd
-r -v struct CevapgestureS *boss
-r -m struct CevapsexeC *scsi_exec
# >>>
@
=end Class
Interface=SCSI_EXEC
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
SCSI_EXEC hides the difference between the implementation principle of
SCSI format+transport and the principle of SCSI service.
Boss=SCSI_CMD
Implementations=SCSI_FORMAT,SCSI_SERVICE
Cgen=\
cevapsexec
-r -v struct CevapscmD *boss
-p -v struct CevapsforM *scsi_format
-p -v struct CevapsservicE *scsi_service
-v int silent_on_scsi_error
# >>>
@
=end Interface
Class=OSDriveAspect
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.08.2007
Documentation=\
OSDriveAspect encapsulates operating system specific properties of an
individual drive. It shall be handed out by SCSI_EXEC via the GESTURES layer
to EquipDrive where it forms the link between cevap drive model and operating
system driver.
This class description models the implementation specific to Linux.
Cgen=\
cevaposdrv
-r -v int fd
# >>> ??? implement the sibling stuff which never worked properly ?
@
=end Class
Class=SCSI_FORMAT
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
SCSI_FORMAT translates parameters of SCSI commands into CDBs, takes care for
transport and decodes the reply into parameters.
Boss=SCSI_CMD via SCSI_EXEC
Subordinates=SCSI_TRANSPORT
Cgen=\
cevapsform
-r -v struct CevapsexeC *boss
-p -v struct CevapstransP *scsi_transport
# former struct command
-v unsigned char opcode[16]
-v int oplen
-v int dir
-v int dxfer_len
-v unsigned char sense[128]
-v int error
-v int retry
-v struct CevapbuffeR *page
# >>>
@
=end Class
Class=SCSI_TRANSPORT
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
SCSI_TRANSPORT takes a formatted CDB from SCSI_FORMAT and makes the operating
system perform a SCSI transaction. It then returns the reply data in raw form.
Boss=SCSI_FORMAT
Os_specific=yes
Cgen=\
cevapstransp
-r -v struct CevapsforM *boss
# >>>
@
=end Class
Class=SCSI_SERVICE
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=11.03.2007
Documentation=\
SCSI_SERVICE provides the combined services of SCSI_FORMAT and SCSI_TRANSPORT
via a set of parametrized functions which abstract SCSI command transactions.
Boss=SCSI_CMD via SCSI_EXEC
Os_specific=yes
Cgen=\
cevapsservice
-r -v struct CevapsexeC *boss
# >>>
@
=end Class
=end ClassDiagram=Overview
ClassDiagram=Equip_overview
Class=EquipSystem
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
EquipSystem is the inner root class of EQUIP. It describes the system on
which libdax is working. This includes the operating system, the system
adapter classes, the drives.
Boss=EQUIP
Subordinates=EquipDrive*N
Cgen=\
cevapsystem
-r -v struct CevapequiP *boss
-r -m char *infotext
-r -l struct CevapdrivE *drive
-p -v struct CevapdrivE *eol_drive
# >>> be boss of SCSI_CMD ? (Rather than GESTURES)
# >>>
@
=end Class
Class=EquipDrive
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
EquipDrive represents a drive, including its capabilities, its processing
status, the media loaded.
Subordinates=EquipMedia
Boss=EquipSystem
Cgen=\
-l cevapdrive
-r -v struct CevapsysteM *boss
# Drive number
-r -v int global_index
# Persistent system drive address
-r -m char *devname
# Traditional SCSI address parameters (-1 if not applicable)
-r -v int bus_no
-r -v int host
-r -v int id
-r -v int channel
-r -v int lun
# (former struct burn_scsi_inquiry_data idata)
# From 12h INQUIRY , spc3r23.pdf , 6.4.2 , Table 81
-r -v char vendor[9]
-r -v char product[17]
-r -v char revision[5]
# 1= above elements contain valid information
-r -v int idata_valid
# mc5r03c.pdf 5.3.2 Physical Interface Standard
# 1=SCSI, 2=ATAPI, 3,4,6=FireWire, 7=SATA, 8=USB
-r -v int phys_if_std
# MMC-5 5.3.2 table 91 , e.g. "SCSI Family"
-r -m char *phys_if_name
# System despendent aspect of the drive (e.g. int fd;)
-r -v struct CevaposdrV *system_dep_drive_info
# Result of the CD write mode x block type tests:
# Index is for write mode : 0=packet , 1=TAO , 2=SAO , 3=raw
# Bits are for block type
# Numbering as in mc5r03c.pdf 7.5.4.13 Data Block Type, Table 668 :
# 0=RAW0 (2352, Raw data)
# 1=RAW16 (2368, Raw data with P and Q Sub-channel
# 2=RAW96P (2448, Raw data with P-W Sub-channel appended)
# 3=RAW96R (2448, Raw data with raw P-W Sub-channel appended)
# 8=MODE1 (2048, ISO/IEC 10149)
# 9=MODE2R (2336, Mode 2 formless)
# 10=MODE2F1 (2048, CD-ROM XA, form 1)
# 11=MODE2F1X (2056, CD-ROM XA, form 1 plus 8 byte subheader)
# 12=MODE2F2 (2324, CD-ROM XA, form 2)
# 13=MODE2MIX (2332, CD-ROM XA, form 1, form 2, or mixed form)
-r -v int block_types[4]
# (former struct scsi_mode_data)
# Information about the drive's capabilities, obtained via 5Ah MODE SENSE
# from mode page 2Ah , mmc3r10g.pdf , 6.3.11 , Table 361
# (which is deprecated in MMC-5 E.11)
-p -v int mdata_buffer_size
-p -v int mdata_dvdram_read
-p -v int mdata_dvdram_write
-p -v int mdata_dvdr_read
-p -v int mdata_dvdr_write
-p -v int mdata_dvdrom_read
-p -v int mdata_cdrw_read
-p -v int mdata_cdrw_write
-p -v int mdata_cdr_read
-p -v int mdata_cdr_write
-p -v int mdata_max_read_speed
-p -v int mdata_max_write_speed
-p -v int madata_min_write_speed
-p -v int mdata_cur_read_speed
-p -v int mdata_cur_write_speed
-p -v int mdata_simulate
-p -v int mdata_c2_pointers
-r -v int mdata_underrun_proof
# Results from ACh GET PERFORMANCE, Type 03h
# (Speed values go into *_*_speed)
# (speed_descriptors became cevapperf which is under cevapmedia)
-p -v int min_end_lba
-p -v int max_end_lba
# from mode page 01h , mmc5r03c.pdf , 7.3.2.1 , Table 657
-p -v int mdata_retry_page_length
-p -v int mdata_retry_page_valid
# from mode page 05h , mmc5r03c.pdf , 7.5.4.1 , Table 664
-p -v int mdata_write_page_length
-p -v int mdata_write_page_valid
# 1= above elements contain valid information
-p -v int mdata_valid
# The mutex shall be used to coordinate access to the drive in situations
# where multi-threaded race conditions could disturb operations.
# E.g. lock, read busy state, interpret, set busy state, unlock
# A mere reader of the busy state does not have to lock because
# reading of the state itself is atomar.
-i -v pthread_mutex_t access_lock
# Flags from feature 002Fh feature descriptor mmc5r03c.pdf 5.3.25 :
# bit1= DVD-RW supported
# bit2= Test Write available
# bit3= DVD-R DL supported
# bit6= Buffer Under-run Free recording available (page 05h BUFE)
# Value -1 indicates that no 002Fh was current in the features list.
-r -v int current_feat2fh_byte4
# 0= drive is grabbed, 1= drive is not grabbed
-v volatile int released
# File descriptor of an eventual emulated drive
-v int stdio_fd
# >>> ???
# (do we need a drive owned buffer to carry data from call to call or what ?)
-v struct CevapbuffeR *buffer
# List of profiles as reported by the drive
-r -l struct CevapprofilE *profile
-p -v struct CevapprofilE *eol_profile
# Media currently loaded in the drive
-r -m struct CevapmediA *media
# >>> transport.h : toc_temp (what is this ? It belongs to BURN_WRITE_RAW)
# >>>
@
=end Class
Class=EquipMedia
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
EquipMedia represents an optical disc, including its type, its writeability,
its formatting, its available formats and performances.
Subordinates=\
EquipProfile*N,EquipFormat*N,EquipPerformance*N,EquipStatus,EquipMulticaps
Boss=EquipDrive
Cgen=\
cevapmedia
-r -v struct CevapdrivE *boss
# Volatile and/or public properties of the media
-r -m struct CevapstatuS *status
# MMC-to-MMC feature info from 46h for DVD-RW.
# Quite internal. Regard as opaque :)
# 1 = incremental recording available, 0 = not available
-r -v int current_has_feat21h
# Link Size item number 0 from feature 0021h descriptor
-r -v int current_feat21h_link_size
# Wether a DVD-RW media holds an incomplete session
# (which could need closing after write)
-v int needs_close_session
# From 51h READ DISC INFORMATION
# 0=needs format start, 1=needs format restart
-r -v int bg_format_status
# From 23h READ FORMAT CAPACITY mmc5r03c.pdf 6.24
# 1=unformatted, 2=formatted, 3=unclear
-r -v int format_descr_type
# meaning depends on format_descr_type
-r -v off_t format_curr_max_size
# dito
-r -v unsigned int format_curr_blsas
-r -v int best_format_type
-r -v off_t best_format_size
-r -l struct CevapformaT *format_descriptor
-p -v struct CevapformaT *eol_format_descriptor
# The specific capabilities and restrictions of the media
-r -m struct CevapmcapS *multicaps
# Results from ACh GET PERFORMANCE, Type 03h
# (Speed values go into drive.mdata_*_*_speed)
-r -l struct CevapperF *speed_descriptor
-p -v struct CevapperF *eol_speed_descriptor
# >>>
@
=end Class
Class=EquipProfile
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
EquipProfile maps a MMC profile into libdax (See mmc5r03c.pdf chapter 5).
A profile describes a set of features and may be either current, possible,
disabled, or unavailable.
Subordinates=EquipFeature*N
Boss=EquipMedia
Cgen=\
-l cevapprofile
-r -v struct CevapdrivE *boss
-r -v int is_current
-r -v int profile_code
-r -v char *profile_text
-r -v int is_cd_profile
-r -v int is_supported_profile
-r -l struct CevapfeaturE *feature
-p -v struct CevapfeaturE *eol_feature
@
=end Class
Class=EquipFeature
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=16.03.2007
Documentation=\
EquipFeature maps a MMC feature into libdax (See mmc5r03c.pdf chapter 5).
A feature describes a set of SCSI commands and (implicitely) of use cases.
Boss=EquipProfile
Cgen=\
-l cevapfeature
-r -v struct CevapprofilE *boss
# >>>
@
=end Class
Class=EquipFormat
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=
Documentation=\
EquipFormat represents a single Formattable Capacity Descriptor
as of mmc5r03c.pdf 6.24.3.3 .
Boss=EquipMedia
Cgen=\
-l cevapformat
-r -v struct CevapmediA *boss
# format type: e.g 0x00 is "Full", 0x15 is "Quick"
-r -v int type
# the size in bytes derived from Number of Blocks
-r -v off_t size
# the Type Dependent Parameter (usually the write alignment size)
-r -v unsigned int tdp
# >>>
@
=end Class
Class=EquipPerformance
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=
Documentation=\
>>> EquipPerformance
Boss=EquipMedia
Cgen=\
-l cevapperf
-r -v struct CevapmediA *boss
# >>>
@
=end Class
Class=EquipStatus
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=17.3.2007
Documentation=\
EquipStatus represents the status of media and drive. This includes
blank/appendable/closed, progress indicator.
Boss=EquipMedia
Cgen=\
cevapstatus
-r -v struct CevapmediA *boss
-v int status
-m char *status_text
-v volatile int busy
# From various sources : free space on media (in bytes)
# With CD this might change after particular write
# parameters have been set and nwa has been inquired.
-v off_t media_capacity_remaining
# Current write address during write jobs. (Next address to be written)
# <<< does this belong to JOB ?
-r -v int nwa
# if > 0 : first lba on media that is too high for write
-v int media_lba_limit
-v struct CevapprogresS *progress
# >>>
@
=end Class
Class=EquipMulticaps
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=14.8.2007
Documentation=\
EquipMulticaps represents media dependent properties and media states which
are either volatile or especially interesting to several other modules. This
includes eventually existing sessions, closure status, profile dependent
capabilities.
Boss=EquipMedia
Cgen=\
cevapmcaps
# The current profile out of the drive profile list
-v struct CevapprofilE *current_profile
# Wether the media is erasable (or overwriteable)
-v int erasable
# A description of the existing media content structure
-r -m struct CevapdisC *disc
# Start and end addresses out of ATIP.
# From 43h READ TOC/PMA/ATIP , mmc5r03c.pdf , 6.26
-r -v int start_lba
-r -v int end_lba
# From 51h READ DISC INFORMATION Number of Sessions (-1)
-v int complete_sessions
# From 51h READ DISC INFORMATION Last Track Number in Last Session
-v int last_track_no
# >>> libburn.h:struct burn_multi_caps
@
=end Class
Class=EquipTocItem
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=14.8.2007
Boss=
Cgen=\
-l cevaptocitem
-r -v struct CevapdisC *boss
-v int session
-v int valid
-v int control
# obscure info from CD TOC : possibly length of track
-v unsigned char point
-v unsigned char min
-v unsigned char sec
-v unsigned char frame
-v int pmin
-v int psec
-v int pframe
-v int start_lba
-v int track_blocks
@
=end Class
=end ClassDiagram=Equip_overview
ClassDiagram=Job_overview
Class=JobTodo
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobTodo records what is to be done during a job. This includes peripheral
actions like tray load/eject and central actions like blank, format, burn.
Subordinates=JobDisc,JobOptions
Cgen=\
cevaptodo
-v volatile int cancel
# >>>
@
=end Class
Class=JobDisc
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobDisc models a disc structure. Either one which already exists or
one which is to be created in a job run.
Subordinates=JobSession*N
Boss=JobTodo
Cgen=\
cevapdisc
-l struct CevapsessioN *session
-p -v struct CevapsessioN *eol_session
-l struct CevaptociteM *toc_entry
-p -v struct CevaptociteM *eol_toc_entry
# >>> take over services of struct burn_disc
@
=end Class
Class=JobSession
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobSession represents a recording session. A session usually bundles
several tracks. Traditionally the last session of a disc is recognized
by operating systems as the thing to be mounted.
Subordinates=JobTrack*N,JobFifo
Boss=JobDisc
Cgen=\
-l cevapsession
-r -v struct CevapdisC *boss
# >>>
-l struct CevaptracK *track
-p -v struct CevaptracK *eol_track
# >>>
@
=end Class
Class=JobTrack
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobTrack represents a track to be recorded. A track mainly is associated with
a data source but in many cases it also becomes a recognizable entity on the
target media.
Subordinates=JobBlock*N,JobTrackFilter,JobSource
Boss=JobSession
Cgen=\
-l cevaptrack
-r -v struct CevapsessioN *boss
# >>>
@
=end Class
Class=JobBlock
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobBlock represents a single output data transaction unit. On CD this is
the same as an addressable media block resp. sector. On DVD this might be
an addressable block od 2k or a packet of e.g. 32k.
Boss=JobTrack
Cgen=\
cevapblock
-v int alba
-v int rlba
# >>>
@
=end Class
Class=JobSource
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=8.4.2007
Documentation=\
JobSource represents a data source for a track. Typically this is a disk
file or a stream file descriptor like stdin.
Subordinates=JobSourceBlock*N
Boss=JobTrack
=end Class
Class=JobSourceBlock
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=8.4.2007
Documentation=\
JobSourceBlock represents a single input data transaction unit.
Boss=JobSource
=end Class
Class=JobFifo
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=8.4.2007
Documentation=\
JobFifo reads data via JobTrackFilter and buffers them until JobBlock can
accept them.
Boss=JobSession
=end Class
Class=JobTrackFilter
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=8.4.2007
Documentation=\
JobTrackFilter reads data from JobSourceBlock, processes them and presents
them to JobFifo or JobBlock. This includes stripping of .wav headers.
Boss=JobTrack
=end Class
Class=JobOptions
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=18.3.2007
Documentation=\
JobOptions bundles the adjustable parameters of a job. This includes dummy
mode, speed, appendability, blank mode, format selection, write mode,
underrun protection, random access addressing.
Boss=JobTodo
Cgen=\
cevapjobopts
# >>>
# Keeping an eye on the drive buffer
-v int wait_for_buffer_free
-v unsigned int wfb_min_usec
-v unsigned int wfb_max_usec
-v unsigned int wfb_timeout_sec
-v unsigned int wfb_min_percent
-v unsigned int wfb_max_percent
# >>> -m struct params params (used by disabled read cd funtionality)
@
=end Class
Class=JobBuffer
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=13.8.2007
Documentation=\
JobBuffer is an intermediate storage for the content of several JobBlock
or JobSourceBlock.
Cgen=\
cevapbuffer
-r -m unsigned char *data
-v int sectors
-v int bytes
@
=end Class
Class=JobProgress
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=13.8.2007
Documentation=\
JobProgress reflects the state and parts of the history of a job
Cgen=\
cevapprogress
# Keeping an eye on the drive buffer
-v int nominal_write_speed
-v off_t pessimistic_buffer_free
-v int pbf_altered
-v unsigned int pessimistic_writes
-v unsigned int waited_writes
-v unsigned int waited_tries
-v unsigned int waited_usec
# >>> the info provided by struct burn_progress
# >>>
@
=end Class
Class=
Author=Thomas Schmitt <scdbackup@gmx.net>
Version=1.0
Since=
Documentation=\
=end Class
=end ClassDiagram=Equip_overview
ClassDiagram=Gestures_overview
# >>>
=end ClassDiagram=Gestures_overview
=end Model=libdax
----------------------------------------------------------------------------
Notes:
----------------------------------------------------------------------------
Compile cgen:
( cd libcevap && cc -g -o cgen cgen.c ctyp.c smem.c )
Generate C stubs:
( cd libcevap && ./libcevap_gen.sh )
Option -lowercase would generate all lowercase struct and function names
Compile test:
( cd libcevap && ( rm a.out ; cc -g main.c cevap*.c smem.c ) )
Option -DCevap_lowercasE would tell main.c that -lowercase was used above.
----------------------------------------------------------------------------
For a description of CgeN see libcevap/cgen.txt
The generated code uses smem.[ch] out of one of my BSD licensed projects.
For a description see end of libcevap/smem.h .
------------------------------------------------------------------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

View File

@ -0,0 +1,39 @@
/*
cc -g -DCevap_lowercasE -c main.c
*/
#include <stdio.h>
#include <stdlib.h>
#include "cevapi.h"
#include "smem.h"
int main(int argc, char **argv)
{
#ifdef Cevap_lowercasE
struct cevapi *cevap= NULL;
#else
struct CevapI *cevap= NULL;
#endif
int ret;
/* full memory supervision */
Smem_set_record_items(1);
/* one short trip for testing */
#ifdef Cevap_lowercasE
ret= cevapi_new(&cevap,0);
if(ret>0)
cevapi_destroy(&cevap,0);
#else /* Cevap_lowercasE */
ret= Cevapi_new(&cevap,0);
if(ret>0)
Cevapi_destroy(&cevap,0);
#endif /* ! Cevap_lowercasE */
/* report any leaked memory */
Smem_stderr(1|2);
exit(ret<=0);
}

View 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(&current,&(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);
}

View File

@ -0,0 +1,165 @@
#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();
int Smem_free();
#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 */
int Smem_set_record_items();
int Smem_stderr();
int Smem_clone_string();
#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.
*/