home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Media Share 9
/
MEDIASHARE_09.ISO
/
cprog
/
file_cl.zip
/
FILE_CL.DOC
< prev
next >
Wrap
Text File
|
1992-03-01
|
34KB
|
1,051 lines
Type : Documentation
Subject : File_cl class (file objects)
Author : Nat (FRANCE, excuse my loose English !)
Version : 1.1 BETA
Diffusion : Unrestricted
Last version downloadable from :
The Temple of Software BBS (FRANCE)
File Area : C++ classes association
Modem MicroCom QX up to 9600bps
(33) 49837518
Description :
- This class permits file manipulation : one object/one physic file;
one physic file/one object.
- Simultaneously open files limited by the least value of :
* Compiler library (stdio.h slots)
Class methods use standard functions fopen(), fclose() ...
* MAXFIL_OPEN #define value of the class.
User of the class cannot modify it.
* Operating system configuration (for example FILES under MS-DOS)
* Application : user of the class can limit class access to slots.
Method setMaxFilesOpen(int)
In order to enforce portability I have not implemented "tricks"
designated to bypass the limited (20) handles of the compiler's library
- Amount of simultaneously active objects only limited by available core.
- List of physic files maintained open optimized according to access
frequency. Class housekeeping methods aim at maintaining open as long as
possible the physic files most frequently accessed to.
- Read/write operations order indifferent. I/O methods automatically open
files if needed and only insert the necessary fseeks() calls between
two distinct fread() and fwrite()
- Only useful fseek() calls passed to the operating system
- Smart DEBUGGING mode
- Standard library-like prototypes
- Use of standard type FILE permitted
- Buffer optimisation method.
- Core furnishment method through virtually closing physic files, thus
releasing buffers
- Special features :
- Actual destruction : data erasure through writing
- File cutting
- File size increase
- Stock features :
unsigned long pascal crc_32(const unsigned char *p, unsigned int n, unsigned long crc = 0xFFFFFFFFL);
Returns the 32-bit CCITT CRC
(Thanks to JCD)
void strcpyNameFile(char *dst, const char *nom);
Builds the complete physic file pathname
WARNING : does not process correctly expressions containing ".."
char getCrtDrive(void);
Returns the default drive letter
char chDrive(char drive);
Arg. : an uppercase letter
Changes the default drive
char drExists(char drive);
Arg. : an uppercase letter
Return value indicates wether the drive exists (OK) or not (ERR)
Installation :
If the father directory of the Integrated Development Environment is
C:\BORLANDC
Copy DEFS.HPP to C:\BORLANDC\NAT\CLASSES
Copy FILE.HPP to C:\BORLANDC\NAT\CLASSES\INCLUDE
Copy *.LIB to C:\BORLANDC\NAT\CLASSES\LIB
Usage :
Class name : File_cl
Include "FILE_CL.HPP" into your sources and link the associated library
(xdcccNAT.LIB, where 'x' stands for the memory model (C, L or H); 'd' only
present for debugging libraries and 'ccc' compiler code ("BOR" (Borland) or
"ZOR" (Zortech))
For each model two versions of the library exist :
- debugging version
- normal full-size version
The second letter of the debugging libraries names is 'D'
Example : LDBORNAT.LIB (Large model, debugging version, Borland compiler)
When using a debugging library please :
#define NAT_FILE_DEBUG 1
An abort function is necessary, whose prototype is :
void cdecl die(int err, const char *fmt, ...)
You might want to use the following standard :
void cdecl die(int err, const char *msg ...)
{
va_list arg;
if (err)
{
fprintf(stderr, "\n\nERROR :\n");
va_start(arg, msg);
vfprintf(stderr, msg, arg);
va_end(arg);
while(kbhit()) // flushes keyboard buffer
getch();
puts("\nHit a key to continue ...");
getch(); // thus the user cannot but read the error message
}
exit(err);
}
The abort function die() must not call any File_cl class methods
In case of debugging version :
Each explicit call to a method leaves a log in a debugging file.
To ensure this you must :
- #define NAT_FILE_DEBUG of FILE_CL.HPP to 1,
- declare an entire (int) variable named dbg_depth
The log indentation varies according to this value
- declare a FILE pointer variable (for debugging file) named ficdbg
Use of any file object must always be preceded by a call to the assign()
method
Example :
static File_cl *fics[10];
#define NAT_FILE_DEBUG 1 // 1 if debug, 0 if normal version
#ifdef NAT_FILE_DEBUG // debugging mode
// ficdbg : permits access to debugging file
FILE *ficdbg;
// dbg_depth : current indentation level in debugging file
int dbg_depth=0;
#endif
void initialize(void)
{
char caca[16];
#ifdef NAT_FILE_DEBUG // debugging mode
ficdbg=fopen("DEBUG.DBG", "wt");
if (ficdbg==NULL)
die(4, "Access to debugging file impossible");
#endif
for (int rep=0; rep<10; rep++)
{
if ((fic[rep]=new File_cl)==NULL)
exit(4);
if (fics[rep]->assign(itoa(rep, caca, 10), "r")==ERR) // assignations
exit(5);
}
// file objects "fics" ready for use
}
void main(void)
{
initialize();
// program ...
// end of the program
// do not forget to delete all the allocated objects !
for (int rep=0; rep<10; rep++)
delete fic[rep];
}
WARNING : assign() (in access mode "w") deletes existing files without
checking. Please use access() before assign()
As soon as the file object has been "assigned" (method assign()) it can be
freely accessed to.
In some cases you have to temporary virtually close one class File_cl object
by using forceClose() in order to open a standard FILE (fopen() or open())
The argument of forceClose represents the number of file slots desired.
forceClose() then returns actual number of slots released.
Call forceClose(MAXFIL_OPEN) to virtually close all files.
The virtually closed file objects remain processable through the File_cl
class methods, which will then try to reopen the physic files.
Avoid heavy use of standard type FILE since the simultaneous opening of too
many FILEs is likely to cause a file slot saturation - the File_cl class
would freeze since it cannot temporarily close them to reopen one of its
instanciations - so please give up the FILE interface to physic files.
forceClose() is furnished for simultaneous use of the File_cl class and
extern proprietary FILE-related libraries
TRICKS :
- Regroup all initial I/O accesses and then call internFclose() in order to
reduce the simultaneously open files.
- Methods whose names and actions are similar to standard library functions
provided by compilers return identical values.
(Example : rename() returns 0 if there is no problem, -1 otherwise)
- Trig delete (keyword) as soon as possible the destructor for objects which
have since become useless
- Be careful with infinite loops since it can crash the stack !
Example :
If end() calls Bye() and if the latter calls end(), in case of error
during the execution of bye() system may hang ...
Note : the debugging version is compiled with "check stack overflow"
- Use every available means to optimize the class methods performances :
quicken the file reopening, increase the amount of slots (file handles)
Under MS-DOS use FASTOPEN, FILES, FCBS ...
- Before a new object file is assigned (assign()) the File_cl class checks
whether another object is accessing to the same physic file. In this case
new assign() is denied.
Theoretically, all the file objects are global variables in the I/O
modules.
Following is an example that illustrates one of the many causes of this
apparent limitation :
If two distinct objects O1 and O2 access to the same physic file, then,
for instance, so what is File_cl supposed to do if the current offset of O1
is 600 while O2 cuts (cut() method) the file at offset 300 ?
This kind of problem is solved through the
File_cl *whatFile_cl(const char *namefile) const;
method.
It returns a pointer on the file object implying the physic file named
"namefile" (or NULL if any)
- In case of an I/O error its code is memorized in the object. Use the
getErrCod() method to obtain it.
(0 : no error)
- Do not modify the system VERIFY flag
- If you add any new generic feature to this class please feel free to
contact me
By carefully studying the furnished source file (provided for example and
test purposes) you will be able to exploit this class at its best.
Because of the inherent nature of this class pay attention to the following :
============================================================================
Never forget that the compiler automatically calls the destructors of
automatic objects (local instanciations).
Example :
void foo()
{
File_cl nothing;
char str[]="ZUT";
if (nothing.assign("ESSAI", "w")==ERR)
die(254, "Cannot open file");
nothing.fwrite(str, 1, 3);
/* at this point, before completing this function (foo()), a destructor is
called for the object "nothing". It flushes the file buffers, closes the
physic file and releases the core allocated for the "nothing" object.
*/
}
The ANSI norm doesn't comprise the 't' (TEXT) argument for file opening modes.
The File_cl class only manipulates files in binary modes (no CR/LF to '\n'
conversion)
The private members (organic references and methods) detail is not available
to the end user (you !)
For optimization's sake some prototypes are "inline" and/or "pascal"
Never mind.
The "FILE_CL.HPP" file furnished contains only one private declaration :
a char member encapsulating all actual members. Do not modify it !
If you do, the sizeof() calculus ends up erroneous (spoiling "new" and
"delete")
The keyword "const", typed after some methods prototypes, indicates that
the method modifies none of the object's members.
Public methods :
****************
File_cl();
Constructor : automatic call
Don't pay attention to it.
void classVersion(int *major, int *minor);
Indicates the version of the File_cl class used
Note : ugly !
But useful if File_cl becames a DLL and/or another thing like that ...
File_cl(const File_cl&);
Copy-initializer
I know of nobody who can say how this method is supposed to work for a
file-oriented class.
Therefore I prohibited the use of the copy-initializer.
char assign(const char *name, const char *mode, int sizebuf=4096, unsigned char flush_frequency=0);
Assignation
Required before access to physic file !
File attributes must in allc ases permit write access (never assign() a
read-only file, please use internChmod() first)
Arguments :
name : Name of the physic file
Will be expanded in order to build a complete pathname (volume, rep...)
This complete name will be kept in the file-object
mode : Opening mode :
r : read only
w : éwrite only (if file exists it will be replaced)
Add a '+' sign ("r+", "w+") to allow all access modes.
This argument is NULL for temporary files (actual mode will be R/W)
sizebuf : Size of the file buffer (in bytes). Allocated through setvbuf()
flush_frequency : frequency of automatic flushes (expressed in number of
write accesses)
0 : minimal
1 : maximal (after each access)
No flush for files limited to read access !
Avoid assigning the same object several times. Once processed by assign()
objects must be processed by reinit() before being assigned once again.
Examples (no return values tests)
{
file1.assign("ESSAI", "r");
file1.assign("ZUT", "r"); // forbidden
}
{
file1.assign("ESSAI", "r");
file1.reinit();
file1.assign("ZUT", "r"); // tolerated (thanks to reinit())
}
At run-time, when physic files are being reopened before access, the "r+"
mode is set on by the class methods. Debugging library alone can deny illegal
operations (for example any attempt at writing on a physic file open for
read operations only), thus also forbidding direct manipulation of read/only
system tagged files.
Use a NULL "mode" argument for temporary files. In this case a name composed
of TMPx.TMP (x numeric) and prefixed by "name" will be built.
Value returned : OK (no problem) ou ERR (error)
ERR can also mean that another File_cl object already concerns the physic
file in question.
void setAbortOnErr(char s);
Depending on "s" (1 or 0) the class will or will not abort execution after
the first I/O error detected
char getAbortOnErr(void);
Returns the AbortOnErr flag (see setAbortOnErr())
void setUsrErrFct(void (*argusr_err)(const char *, const char*, ...));
Specifies which user function will be called by File_cl in case of an error
Arguments passed to the user function :
"File_cl", "<name of the file>", "<err. msg / function number>"
THIS METHOD WILL CHANGE SOON !
char pascal reinit(void);
Allows (and must precede) a reassignation.
Can be called any time : properly closes the physic file.
This can be dangerous since, in your code, the physic file to which an
object is dedicated at a given location is harder to determine.
It allows to solve some of the problems caused by a limited stack.
For instance when an entire file group is concerned by several functions a
mere global declaration of all the objects and reinit() accesses will do the
job. Actually none of the function should call any of the others.
Example (without error condition test) :
File_cl fic_tmp;
// increments first int values contained in FIL1 to FIL20 files
void fct1(void)
{
char str[MAXPATH_Nat];
int val;
strcpy(str, "FIL");
for (int rep=0; rep<20; rep++)
{
itoa(rep, &str[3], 10);
/* actual status of fic_tmp unknown at this point.
An assign() call could have been carried through.
So reinit() must be called
*/
fic_tmp.reinit();
fic_tmp.assign(str, "w+");
fic_tmp.fread(&val, sizeof(int), 1);
val++;
fic_tmp.fwrite(&val, sizeof(int), 1, 0);
fic_tmp.fclose();
}
}
// other fonctions of the same kind can also use fic_tmp
Return : OK or ERR
ERRCOD_T getErrCod(void);
Returns the last error code (or 0)
OFFSET_T length(size_t *reste=NULL, size_t size_elem=1);
Returns the file size.
length() returns size in bytes
length(X) returns the integer number of elements (X specifies size in bytes)
length(X, *Y) like length(X), but *Y remainder
Note : forces an open call
Returns -1 in case of an error
int fseek(OFFSET_T, int whence, char real=0);
Changes the current offset inside the file.
This is only a logical change, actual system call will be issued just before
an I/O operation.
Arguments : like the standard library fseek()
The "real" argument forces an actual opening
Note : a SEEK_END argument forces the opening and flush of the file
OFFSET_T tell(void) const;
Returns the current offset
size_t fread(void *ptr, size_t size, size_t n, OFFSET_T o=-1);
Reads data
If needed :
- opens the physic file
- issues the fseek call that might be needed between reads and writes
Arguments and return values similar to standard library
The last argument indicates the offset
Warning : polymorphism might cause errors such as :
fread(&variable, sizeof(variable), 0) // false !!
the third argument (0) specifies the number of elements, not the offset
Correct form is :
fread(&variable, sizeof(variable), 1, 0) // OK !!
size_t fwrite(void *ptr, size_t size, size_t n, OFFSET_T o=-1);
Writes data
If needed :
- opens the physic file
- issues the fseek call that might be needed between reads and writes
Flushes the buffer (if necessary, see flush_frequency argument of assign())
Arguments and return values similar to standard library
The last argument indicates the offset
Warning : polymorphism might cause errors such as :
fwrite(&variable, sizeof(variable), 0) // false !!
the third argument (0) specifies the number of elements, not the offset
Correct form is :
fwrite(&variable, sizeof(variable), 1, 0) // OK !!
int fputc(int c, OFFSET_T=-1);
Like standard library
int fgetc(OFFSET_T=-1);
Like standard library
char flush(char ouvre=0);
Flushes the file buffer
Periodically called (depending on the "flush_frequency" of assign()) by
methods of writing
flush(1) forces the physic file open. Never mind !
Returns : NO_OP if physic file closed, OK if normally flushed, ERR otherwise
int flushAll(void);
Flushes all File_cl objects
Returns the number of open physic files
int eof(void);
Calls flush()
Returns 0 if End Of File not reached
int error(void) const;
Returns 0 if no I/O error on the file
ERRCOD_T getErrCod(void) const;
Returns the extended error code (errno)
int fclose(void);
Closes the physic file (if not already closed)
Rewinds physic file : fseek(0, SEEK_SET);
Returns : see ::fclose() : 0 (OK), EOF (error)
Control methods
***************
const char *getName(void) const;
Returns a const pointer to the complete physic file name
WARNING : do not bypass "const" qualifier. It's a STRICTLY private object
zone.
char isWritable(void) const;
Mode of opening control : returns 1 if file readable, 0 otherwise
char isReadable(void) const;
Mode of opening control : returns 1 if file writable, 0 otherwise
int internFclose(void);
Optimization method
Closes the physic file (liberating the handler)
Meant to be used when the probable number of accesses to many other files
before the next access on this one is very high.
Does not alter the logical state of the object at all (offset remains the
same). The next I/O request will be normally processed, yet implying the
physic file opening.
Returns NO_OPS (file was closed before call), OK (file properly closed) or
EOF (error)
If any given File_cl object pointed becomes useless please call its
destructor as soon as possible (explicit delete)
void stayOpen(void);
This optimization method forces the maintenance methods to keep physic files
open as long as possible.
Usage of this method should be limited to files that are very often used.
char isOpen(void) const;
Returns 1 if physic file open, else 0. It is an optimization method
Permits a pseudo-"burst mode"
Example :
char ok[NB_FIL];
/* For optimization purposes, writing in the open files should come first :
in this case maintenance methods do not close any open handle
*/
for (int rep=0; rep<NB_FIL; rep++)
if (fic[rep].isOpen())
{
rien.fwrite("RIEN", 1, 4);
ok[rep]=1;
}
else
ok[rep]=0;
// then the others ...
for (rep=0; rep<NOMBRE_FICS; rep++)
if (!ok[rep])
{
rien.fwrite("RIEN", 1, 4);
ok[rep]=1;
}
void setBuf(int size_buf=0);
Assigns a "size_buf" bytes buffer size
Maximum 32000 bytes
WARNING : This new buffer size will only take effect when the next opening
occurs. setBuf() yet increases the probability of the physic file being
closed by housekeeping methods (scheduling handles conflicts)
In order, for this modification, to take effect immediately call
internFclose()
Buffer is allocated through setvbuf (_IOFBF mode)
void maxBuf(char percent_ram=25);
Maximizes the size of the allocated buffer
Argument is expressed in percent of free core
char minBuf(long recup_ram=10000000L);
Allows you to free some of the core previously allocated to the file buffer
Argument is expressed in number of bytes requested
Returns OK, NO_OP (file was closed) or ERR (close() error)
void setVerify(char c=1) {verify=c;}
Triggers write-checking for this object.
Strictly comparable to the VERIFY system flag, but improved : it is limited
to the object
char getVerify(void) const;
Returns 0 (=> VERIFY off for this objet or 1 (VERIFY ON)
int forceClose(int, char real_fclose=1);
This liberates handles occupied by File_cl objects (for FILE struct use)
Only closes the "this" as a last resort
Argument : number of slots (handles) desired. Use MAXFIL_OPEN to close
all File_cl accessed files
Return : number of liberated handles
Do not use the second argument (for the sake of simplification polymorphism
is not used here)
char setMaxFilesOpen(int x);
Specifies the maximum number of files that can be simultaneously open by
the class.
Closes immediately all supernumerary handles (but objects concerned remain
usable)
When external libraries need additional slots, use this method to avoid
frequent forceClose() calls
Returns OK or ERR (argument too high or too low)
char giveCore(unsigned long howmuch);
Frees RAM
A very stupid method (for the time being) that forces the closure of physic
files (through forceClose() calls) in order to immediately free RAM
(particularly buffers RAM)
Argument is expressed in bytes
Does not affect the logical state of objects (all of them remain accessible)
File_cl *whatFile_cl(const char *namefile) const;
Returns a flag to the File_cl object whose physic file name the same as in
the argument or NULL if no File_cl assigned to the file.
WARNING : for optimization purposes no automatic name expansion (does not
call strcpyNameFile())
Example:
char tmp_nom[MAXPATH_Nat];
unsigned int trouves=0;
File_cl tmp_obj;
strcpyNameFile(tmp_nom, "ESSAI");
if (tmp_obj=whatFile_cl(tmp_nom, &trouves))!=NULL)
printf("Object %s en %Fp\n", tmp_obj->getName(), tmp_obj);
else
puts("No File_cl object for file ESSAI");
High level methods
******************
int internChmod(const char *path, char func, int attr);
Like std _chmod()
void setDriveVerify(char drive, char verif=1);
Sets the VERIFY flag to "verif" (1 or 0) for all writable File_cl objects
(present and to come) implying physic files located on drive "drive"
Arguments :
"drive" : [A, Z]
"verif" : 1 (ON) or 0 (OFF)
int unlink(char secure=0);
Deletes physic file
When equal to 1 the "secure" argument forces a call to writeGarbage() which
rewrites on the data
Return : 0 (OK), -1 (like standard library)
void writeGarbage(OFFSET_T zone_size=-1);
Writes garbage (data from the BIOS area : 0xF000)
WARNING : the part of the file that will be written on begins at the current
offset and its length is specified by "zone_size"
Use default form to delete all file data
Returns OK or ERR
int rename(const char *);
Renames the physic file
Returns : -1 (error), else 0
Note : forces file closure (internFclose() : no logical state modification)
char getCRC32(unsigned long *crc32, OFFSET_T off=0, OFFSET_T len=0);
Calculates the CCITT 32-bit CRC of the zone starting at offset "off" and
which length is "len" bytes
By default : off=0, len=file size
Returns ERR (access error, buffer allocation error, "len"=0) ...
WARNING : ERR may signify that this method can not restore the original file
offset
Places calculated CRC, if everything OK, in *crc32
Does not affect the file state
Thanks to Jean-Christophe Deschamps (fast CRC calculation routine)
char copy(const char *newname, OFFSET_T start=0, OFFSET_T len=0);
Copies the file in a new file named "newname". The zone copied begins
at "start" offset (default 0) and is "len"-byte long.
Returns OK, NO_OP (file "newname" already exists) or ERR
WARNING : offset modified
char copy(File_cl *dst, OFFSET_T start=0, OFFSET_T len=0);
Copies the file in File_cl pointed by "dst".
The zone copied begins at "start" offset (default 0) and is "len"-byte long.
Target file is modified from its current offset
Returns OK or ERR
WARNING : offsets modified
char compare(File_cl *other, OFFSET_T *first_dif, OFFSET_T start1=0, OFFSET_T start2=0, OFFSET_T len=0);
Compares two sections of files
Returns ERR (error), OK (identical content) or NO_OP (differences found)
If the method returns NO_OP (unidentical contents) the OFFSET_T value
pointed by "first_dif" will be the offset (from the beginning of the zone)
of the first distinct byte.
If the method returns ERR various errors may have occurred :
- at least one of the files does not contain enough data
Wrong arguments :
((size of file "this")-start1)<=0 => *first_dif=-2
((size of file "this")-start1)<len => *first_dif=-3
((size of file "other")-start2)<len => *first_dif=-4
- Read error
*first_diff=-5
char move(const char *newname);
Moves file
Returns OK, NO_OP or ERR (see copy() and rename() methods)
Strategy :
This method first tries to call rename() (if "newname" belongs to the same
volume)
Otherwise (or if rename() cannot be done) calls copy() and then unlink()
char cut(OFFSET_T where=-1, char secure=0);
Cuts off file at the offset "where"
If "secure" equals 1, data to be cut are processed by writeGarbage()
Returns OK or ERR
~File_cl(void);
Standard destructor
Closes automatically the physic file
Unlinks automatically temporary files
WARNING : no error code returned (it's C++, not C !)
Other functions
***************
unsigned long pascal crc_32(const unsigned char *p, unsigned int n, unsigned long crc = 0xFFFFFFFFL);
Returns the 32-bit CCITT CRC
(Thanks to JCD)
void strcpyNameFile(char *dst, const char *nom);
Builds the complete physic file pathname
WARNING : does not process correctly the expressions containing ".."
char getCrtDrive(void);
Returns the default drive letter
char chDrive(char drive);
Arg. : an uppercase letter
Changes the default drive
char drExists(char drive);
Arg. : an uppercase letter
Return value indicates wether the drive exists (OK) or not (ERR)
I integrate the excellent match() function, from "SMATCH" package.
Prototype is :
/*
int match: evaluates a *ix style pattern vs. a null terminated string.
returns: 0 - match is good
nonzero - match is not good
*/
int match(char *pat, char *text);
Parts of the original documentation follows :
========================
SMATCH: a *IX compatible wildcard parser
By Stan Adermann, 70721,17
I was working on a database package recently, when I came to the
decision that using the *ix wildcard system would be an extremely flexible
way of retrieving records or making printouts, i.e. [A-E]* to print all
names starting with A,B,C,D,E. (Certainly not an original thought.)
Rather than reinvent the wheel, I looked on Compu$pend to find that a Mr.
J. Kercheval had uploaded the source code I needed only days before. (My
thanks to him. I was not familiar enough with the rules of *ix parsing to
write one out of my skull.) When I read his comments about other routines
being overly recursive or buggy, I sympathized...right up until I saw that
he used recursion as well.
I wondered, "Why recurse at all?" Certainly recursion is a valid way
to do this, but by my own preference, I tend to avoid recursion if at all
possible. My reasoning is that any recursive function has the ability to
run amok and overflow memory, especially on smaller systems, unless you
place limits. If you place limits, you run the risk of actually running
into those limits, with the end result being a program failure or
limitation that would not otherwise be necessary. Granted, in this case
that is about as likely as the Pope using a condom, but as I said, this is
a personal preference.
Well, the thought of writing the same program non-recursively was stuck
in my head, and I knew that I wouldn't sleep or eat until I had done it,
so here it is. Not better, not worse, just different. Speedwise, SMATCH
is equally as fast as Kercheval's MATCH. Sizewise, my program compiles
about 130 bytes longer. Functionally speaking the programs have only two
differences:
1. SMATCH allows patterns with no wildcards.
2. SMATCH supports the '+' (one or more) wildcard.
I compiled using Microsoft C 6.0a, and the following command line:
CL /AT /Ox /D TEST smatch.c -link /NOD:slibce+slibcer
The same command line will also work for Kercheval's MATCH.C
I have also borrowed Kercheval's MATCHTST.BAT to test my code, adding a
few lines to test the '+' character.
This code is public domain.
The rules are:
* matches any sequence of characters, including no characters
* = "", "ABC", "ABCFRED"
+ matches any sequence of characters, but requires one character
+ = "A", "ABCDEFA"
+ != ""
? matches any one character
? = "A", "B", "C", "1"
? != "AB", "", "FRED"
[] matches a single character from specified set.
[aeioub-d] = "a", "b", "c", "d", "e", "i"
[aeioub-d] != "f", "r", "t", "ap"
To use one of the wildcards as a character, preceed it with a '\', i.e.
\* \? \[ \] \\
========================
Thanks Mister Adermann !
Debugging library specific methods
**********************************
unsigned long status(char complete=1) const;
Logical status of the object and class is printed in debugging file
Returns the peak number of slots used (files actually open simultaneously)
unsigned long getNbOpensTot(void) const;
Returns the total number of opening calls issued (by the maintenance
methods)
Favors optimization : for a given environment the least value is the best
Proposed debugging function :
Through this function, your functions are able to share the debugging file
with the class
It leaves a message in the debugging file, preceded by the number of ticks elapsed since the
execution began
Uses dbg_depth
Please use the Dbg_fct_fin macro to decrement the indentation index
void debug(const char *fct, const char *fmt, ...)
{
va_list arg;
if (ficdbg==NULL)
return;
dbg_depth++;
for (int rep=0; rep<dbg_depth; rep++)
::fputc(' ', ficdbg);
::fprintf(ficdbg, "%ld %s ", clock(), fct);
va_start(arg, fmt);
::vfprintf(ficdbg, fmt, arg);
va_end(arg);
::fprintf(ficdbg, "\n");
if (ferror(ficdbg))
die(255, "Cannot write in debugging file");
::flushall();
}
Ideal structure of programs using this class :
**********************************************
Declarations module
<must declare all File_cl objects>
Main module
<extern declarations>
<die(int err, const char *msg ...) function implementation>
<In case of debugging :
FILE ficdbg
int dbg_depth=0
fopen()) of debugging file ficdbg
Example :
=========
File_cl fic;
#ifndef NDEBUG
FILE *ficdbg;
int dbg_depth=0;
#endif
void cdecl die(int err, const char *msg ...)
{
va_list arg;
if (err)
{
fprintf(stderr, "\n\nERROR :\n");
va_start(arg, msg);
vfprintf(stderr, msg, arg);
va_end(arg);
while(kbhit()) // flushes keyboard buffer
getch();
puts("\nHit a key to continue ...");
getch(); // thus the user cannot but read the error message
}
exit(err);
}
int cdecl main(void)
{
// Init
File_cl fic;
#ifndef NDEBUG
ficdbg=fopen("DEBUG.DBG", "wt");
if (ficdbg==NULL)
die(4, "Cannot open debugging file");
#endif
if (fic.assign("ESSAI.TMP", "w+")!=OK)
die(5, "cannot open file");
<misc. processes>
#ifdef NAT_FILE_DEBUG
printf("\n -------->\nPeak number of files simultaneously open : %lu\nNumber of open calls : %lu\n", fic.status(), fic.getNbOpens_tot());
#endif
fclose(ficdbg);
die(0, "BYE");
}
NOTES :
*******
- If you wish to use one error function for each file please use switch()
- The furnished header file (FILE_CL.HPP) might contain several undocumented
prototypes of methods. I strongly advise you NOT TO USE THEM !
- This is a beta test version. Yet, future versions will be as compatible with
this version as can be
- If the relative slowness of the debugging version bothers you, please
understand that they have not only been compiled with all checking pragmas
on (check stack overflow, optimize for size ...) but also that much of the
code is only meant to check the integrity of the environment and objects !
You will get the picture when you will know that the normal version runs
almost two times faster, manipulates objects that are 25% smaller and
itself occupies only about 70% of the core needed by the debugging version.
- How does the following sound :
void strategy(char);
Configures the type of handle conflict management : this is the kind of
action that the maintenance methods try when reopening a physic file implies
closing another.
Argument :
0 : least employed files closed in priority
1 : most employed files closed in priority
Any comments ?
- After thinking about it over and over I thing that I am wrong to propose
methods whose return values agree to ANSI specifications.
Example : rename() could also return OK, NO_OP or ERR instead of the plain
0 or -1 !
The day we agree on the decision to be made, I will design a powerful
procedure of I/O errors control.
Any comments ?
- To increase the maximum number of simultaneously open files :
* adapt the compiler libraries (stdio.h slots : _NFILES)
* order a more effective File_cl class version
(with a higher MAXFIL_OPEN value)
* if possible, increase OS parameters (FILES under MS-DOS)
* check usage of setMaxFilesOpen() method
Versions :
Date format : YYMMDD
Value between parenthesis indicates version returned by classVersion method
920201 First beta version
---
920301 Second beta version (0.1)
New methods :
classVersion, internChmod
New function :
match
---
Feel free to contact me.
I can be reached at BBS "The Temple of Software" (in France, tel.
(33) 49837518, user "Nat") or, by mail :
Nat MAKAREVITCH
22, rue Voltaire
92000 NANTERRE
FRANCE