1.

Appendix A: Code Listings
Writing Bug-Free C Code

A.1 APP.H Include File
A.2 BOOK.H Include File
A.3 HEAP.C Module
A.4 RAND.C Module
A.5 DOS.C Module
A.6 OutputDebugString() for MS-DOS Programmers
A.7 ReportWinAssert()


This appendix brings together in one location all the code that was presented in this book. Also available online in a ZIP at http://www.duckware.com/bugfreec/source.zip

A.1 APP.H Include File

APP.H is a place holder include file that represents the global include file for your application. This is the one include file for all your modules. As you write new modules, you will need to modify this include file.

 APP.H /*--- Standard Includes ----------------------------------------*/ #include <string.h>                     /* strcpy/memset        */ #include <stdio.h>                      /* sprintf              */ #include <stdlib.h>                     /* malloc/free          */ /*--- The include file for this book ---------------------------*/ #include "book.h" /*--- NEWHANDLE section ----------------------------------------*/ NEWHANDLE(HRAND); NEWHANDLE(HDOSFH); /*--- USE_* section --------------------------------------------*/ #ifdef USE_HRAND /*----------------------------------------------------------------  *  *  Random number generator  *  *--------------------------------------------------------------*/ EXTERNC HRAND APIENTRY RandCreate  ( int ); EXTERNC HRAND APIENTRY RandDestroy ( HRAND ); EXTERNC int   APIENTRY RandNext    ( HRAND ); #endif #ifdef USE_LOWIO /*--------------------------------------------------------------  *  *  Access to low-level I/O run-time library functions  *  *-------------------------------------------------------------*/ #include <fcntl.h> #include <sys\types.h> #include <sys\stat.h> #include <io.h> #endif #ifdef USE_HDOSFH /*--------------------------------------------------------------  *  *  Code wrapper to low-level file I/O  *  *-------------------------------------------------------------*/ EXTERNC HDOSFH APIENTRY DosOpenFile  ( LPSTR ); EXTERNC WORD   APIENTRY DosRead      ( HDOSFH, LPVOID, WORD ); EXTERNC WORD   APIENTRY DosWrite     ( HDOSFH, LPVOID, WORD ); EXTERNC HDOSFH APIENTRY DosCloseFile ( HDOSFH ); #endif 

The one include file contains several sections. The first does a general include of string.h, stdio.h and malloc.h. These includes are assumed to be needed by all modules. Next, the include for this book, book.h, is included.

When programming for Windows, make sure that windows.h is included before book.h gets included and make sure that you are using either /GA (for applications) or /GD (for DLLs) on the Microsoft C8 command line. This ensures that _WINDOWS gets defined.

The NEWHANDLE section comes next. For every new module that you write, you will need to add a NEWHANDLE(HOBJ) line. The OBJ part is a short descriptive name for the module you are implementing.

The last section of this file is the USE_* section. For every NEWHANDLE(HOBJ) added to this file, you will also add a #ifdef USE_HOBJ section that prototypes the interface to the new module you have written.

A.2 BOOK.H Include File

BOOK.H is the include file for everything that this book describes. You should never include this file directly. Instead, it should be included through APP.H as described in the previous section.

BOOK.H assumes that you have a standard C compiler. If you do not have a standard C compiler, you may still be OK if your C preprocessor follows the Reiser model (§2.2.8). The problem is the usage of the stringizing operator (#) and the token pasting operator (##). See §2.2.7 for more information on preprocessor operators.

 BOOK.H /*--- If target is C8 segmented architecture ---*/ #if (defined(_MSC_VER) && defined(MSDOS)) #define FAR _far #define NEAR _near #define FASTCALL _fastcall #define PASCAL _pascal #define EXPORT _export #define BASEDIN(seg) _based(_segname(#seg)) /*--- Else assume target is flat memory model ---*/ #else #define FAR #define NEAR #define FASTCALL #define PASCAL #define EXPORT #define BASEDIN(seg) #endif /*--- size_t mapping ---*/ #define SIZET size_t /*--- Useful defines ---*/ #ifndef _WINDOWS typedef char FAR*LPSTR; typedef void FAR*LPVOID; typedef unsigned short WORD; typedef int BOOL; #define FALSE (0) #define TRUE (1) #endif /*--- Assert during compiling (not run-time) ---*/ #define CompilerAssert(exp) extern char _CompilerAssert[(exp)?1:-1] /*--- TYPEDEF depends upon C/C++ ---*/ #ifdef __cplusplus #define TYPEDEF #else #define TYPEDEF typedef #endif /*--- EXTERNC depends upon C/C++ ---*/ #ifdef __cplusplus #define EXTERNC extern "C" #else #define EXTERNC #endif /*--- APIENTRY for app/dll ---*/ #ifdef _WINDLL #define APIENTRY EXPORT FAR PASCAL #else #define APIENTRY FAR PASCAL #endif /*--- LOCAL/LOCALASM defines ---*/ #define LOCAL static NEAR FASTCALL #define LOCALASM static NEAR PASCAL /*--- Other useful defines ---*/ #define CSCHAR static char BASEDIN(_CODE) #define NewScope /*--- Absolute value macro ---*/ #define ABS(x) (((x)>0)?(x):-(x)) /*--- Is a number a power of two ---*/ #define ISPOWER2(x) (!((x)&((x)-1))) /*--- Number of static elements in an array ---*/ #define NUMSTATICELS(pArray) (sizeof(pArray)/sizeof(*pArray)) /*--- Loop Macros ---*/ #define LOOP(nArg) { int _nMax=nArg; int loop; \     for (loop=0; loop<_nMax; ++loop) #define LLOOP(lArg) { long _lMax=lArg; long lLoop; \     for (lLoop=0; lLoop<_lMax; ++lLoop) #define ENDLOOP } /*--- WinAssert support ---*/ #define USEWINASSERT CSCHAR szSRCFILE[]=__FILE__;   \   BOOL static NEAR _DoWinAssert( int nLine ) {      \     ReportWinAssert(szSRCFILE, nLine);              \     WinAssert(nLine);                               \     return(FALSE);                                  \     } #define AssertError _DoWinAssert(__LINE__) #define WinAssert(exp) if (!(exp)) {AssertError;} else EXTERNC void APIENTRY ReportWinAssert( LPSTR, int ); /*--- What is a class descriptor---*/ typedef struct {     LPSTR lpVarName;     } CLASSDESC, FAR*LPCLASSDESC; /*--- Declare a new handle ---*/ #define NEWHANDLE(Handle) typedef struct tag##Handle *Handle /*--- Class descriptor name from object name ---*/ #define _CD(hObj) hObj##_ClassDesc /*--- The class macro ---*/ #define CLASS(hObj,Handle) \     static CLASSDESC _CD(hObj)={#hObj}; TYPEDEF struct tag##Handle /*--- Object verification macros---*/ #define VERIFY(hObj) WinAssert(_VERIFY(hObj)) #define VERIFYZ(hObj) if (!(hObj)) {} else VERIFY(hObj) /*--- Object verification helper macros ---*/ #define _S4 (sizeof(LPCLASSDESC)) #define _S8 (sizeof(LPCLASSDESC)+sizeof(LPVOID)) #define _VERIFY(hObj) \     ( FmIsPtrOk(hObj) && \     (((LPVOID)hObj)==*(LPVOID FAR*)((LPSTR)hObj-_S8)) \     && ((&_CD(hObj))==*(LPCLASSDESC FAR*)((LPSTR)hObj-_S4)) ) /*--- Heap manager prototypes ---*/ EXTERNC LPVOID APIENTRY FmNew      ( SIZET, LPCLASSDESC, LPSTR, int); EXTERNC LPVOID APIENTRY FmFree     ( LPVOID ); EXTERNC LPVOID APIENTRY FmRealloc  ( LPVOID, SIZET, LPSTR, int ); EXTERNC LPVOID APIENTRY FmStrDup   ( LPSTR, LPSTR, int ); EXTERNC void   APIENTRY FmWalkHeap ( void ); EXTERNC BOOL   APIENTRY FmIsPtrOk  ( LPVOID ); /*--- NEWOBJ() and FREE() Interface ---*/ #define _LPV(hObj) *(LPVOID FAR*)&hObj #define NEWOBJ(hObj) \   (_LPV(hObj)=FmNew(sizeof(*hObj),&_CD(hObj),szSRCFILE,__LINE__)) #define FREE(hObj) (_LPV(hObj)=FmFree(hObj)) /*--- String interface macros ---*/ #define NEWSTRING(lpDst,wSize) \   (_LPV(lpDst)=FmNew((SIZET)(wSize),NULL,szSRCFILE,__LINE__)) #define MYLSTRDUP(lpDst,lpSrc) \   (_LPV(lpDst)=FmStrDup(lpSrc,szSRCFILE,__LINE__)) /*--- Array interface macros ---*/ #define NEWARRAY(lpArray, wSize) \   (_LPV(lpArray)=FmNew((SIZET)(sizeof(*(lpArray))*(wSize)), \   NULL,szSRCFILE,__LINE__)) #define SIZEARRAY(lpArray, wSize) \   (_LPV(lpArray)=FmRealloc((lpArray), \   (SIZET)(sizeof(*(lpArray))*(wSize)),szSRCFILE,__LINE__)) 


A.3 HEAP.C Module

This code implements the heap manager as described in Chapter 5.

 HEAP.C /*pm--------------------------------------------------------------  *  *  OUTLINE:  *  *    This module REPLACES the memory management routines of  *    the C run-time library.  As such, this new interface  *    should be used exclusively.  *  *  IMPLEMENTATION:  *  *    A wrapper is provided around all memory objects that  *    allows for run-time type checking, symbolic dumps of  *    the heap and validation of heap pointers.  *  *  NOTES:  *  *    - YOU must code an FmIsPtrOk() that works properly for  *      your environment.  *  *--------------------------------------------------------------*/ #include "app.h" USEWINASSERT /*--- Heap objects are aligned on sizeof(int) boundaries ---*/ #define ALIGNMENT (sizeof(int)) #define DOALIGN(num) (((num)+ALIGNMENT-1)&~(ALIGNMENT-1)) CompilerAssert(ISPOWER2(ALIGNMENT)); /*--- Declare what LPPREFIX/LPPOSTFIX are ---*/ typedef struct tagPREFIX  FAR*LPPREFIX; typedef struct tagPOSTFIX FAR*LPPOSTFIX; /*--- Prefix structure before every heap object---*/ typedef struct tagPREFIX {     LPPREFIX lpPrev;           /* previous object in heap      */     LPPREFIX lpNext;           /* next object in heap          */     LPPOSTFIX lpPostfix;       /* ptr to postfix object        */     LPSTR lpFilename;          /* filename ptr or NULL         */     long lLineNumber;          /* line number or 0             */     LPVOID lpMem;              /* FmNew() ptr of object        */     LPCLASSDESC lpClassDesc;   /* class descriptor ptr or NULL */     } PREFIX; /*--- Postfix structure after every heap object ---*/ typedef struct tagPOSTFIX {     LPPREFIX lpPrefix;     } POSTFIX; /*--- Verify alignment of prefix structure ---*/ CompilerAssert(!(sizeof(PREFIX)%ALIGNMENT)); /*--- Points to first object in linked list of heap objects ---*/ static LPPREFIX lpHeapHead=NULL; /*--- Local prototypes ---*/ void LOCAL AddToLinkedList      ( LPPREFIX ); void LOCAL RemoveFromLinkedList ( LPPREFIX ); BOOL LOCAL VerifyHeapPointer    ( LPVOID ); void LOCAL RenderDesc           ( LPPREFIX, LPSTR ); /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Far Memory New)  JLJ  *  *    Allocate a new block of memory from the heap.  *  *  ARGUMENTS:  *  *    wSize       - Size of object to allocate  *    lpClassDesc - Class descriptor for object (or NULL)  *    lpFile      - Filename where object was allocated  *    nLine       - Line number where object was allocated  *  *  RETURNS:  *  *    A long pointer to the memory object or NULL  *  *--------------------------------------------------------------*/ LPVOID APIENTRY FmNew( SIZET wSize, LPCLASSDESC lpClassDesc,     LPSTR lpFile, int nLine ) {   LPPREFIX lpPrefix;   wSize = DOALIGN(wSize);   lpPrefix=(LPPREFIX)malloc(sizeof(PREFIX)+wSize+sizeof(POSTFIX));   if (lpPrefix) {     AddToLinkedList( lpPrefix );     lpPrefix->lpPostfix = (LPPOSTFIX)((LPSTR)(lpPrefix+1)+wSize);     lpPrefix->lpPostfix->lpPrefix = lpPrefix;     lpPrefix->lpFilename = lpFile;     lpPrefix->lLineNumber = nLine;     lpPrefix->lpMem = lpPrefix+1;     lpPrefix->lpClassDesc = lpClassDesc;     memset( lpPrefix->lpMem, 0, wSize );     }   else {     AssertError;             /* Report out of memory error */     }   return(lpPrefix ? lpPrefix+1 : NULL); } /* FmNew */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Far Memory Free)  JLJ  *  *    Free a block of memory that was previously allocated  *    through FmNew().  *  *  ARGUMENTS:  *  *    lpMem - Heap pointer to free or NULL  *  *  RETURNS:  *  *    NULL  *  *--------------------------------------------------------------*/ LPVOID APIENTRY FmFree( LPVOID lpMem ) {     if (VerifyHeapPointer(lpMem)) {        LPPREFIX lpPrefix=(LPPREFIX)lpMem-1;        SIZET wSize=(LPSTR)(lpPrefix->lpPostfix+1)-(LPSTR)lpPrefix;        RemoveFromLinkedList( lpPrefix );        memset( lpPrefix, 0, wSize );        free(lpPrefix);        }     return (NULL); } /* FmFree */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Far Memory String Dup)  JLJ  *  *    Helper function for the MYLSTRDUP() macro  *  *  ARGUMENTS:  *  *    lpS    - String to duplicate (or NULL)  *    lpFile - Filename where string is being duplicated  *    nLine  - Line number where string is being duplicated  *  *  RETURNS:  *  *    A pointer to the duplicated string or NULL  *  *--------------------------------------------------------------*/ LPVOID APIENTRY FmStrDup( LPSTR lpS, LPSTR lpFile, int nLine ) {     LPVOID lpReturn=NULL;     if (lpS) {         SIZET wSize = (SIZET)(strlen(lpS)+1);         lpReturn = FmNew( wSize, NULL, lpFile, nLine );         if (lpReturn) {             memcpy( lpReturn, lpS, wSize );             }         }     return(lpReturn); } /* FmStrDup */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Far Memory Realloc)  JLJ  *  *    Reallocate a block of memory  *  *  ARGUMENTS:  *  *    lpOld  - Heap object to reallocate or NULL  *    wSize  - New size of the object  *    lpFile - Filename where realloc is taking place  *    nLIne  - Line number where realloc is taking place  *  *  RETURNS:  *  *    A pointer to the reallocated memory or NULL  *  *--------------------------------------------------------------*/ LPVOID APIENTRY FmRealloc( LPVOID lpOld, SIZET wSize,     LPSTR lpFile, int nLine ) {   LPVOID lpNew=NULL;   /*--- Try to realloc ---*/   if (lpOld) {     if (VerifyHeapPointer(lpOld)) {       LPPREFIX lpPrefix=(LPPREFIX)lpOld-1;       LPPREFIX lpNewPrefix;       LPPREFIX lpPre;       /*--- Try to reallocate block ---*/       RemoveFromLinkedList( lpPrefix );       memset( lpPrefix->lpPostfix, 0, sizeof(POSTFIX) );       wSize = DOALIGN(wSize);       lpNewPrefix=(LPPREFIX)realloc(lpPrefix,           sizeof(PREFIX)+wSize+sizeof(POSTFIX));       /*--- Add new (or failed old) back in ---*/       lpPre=(lpNewPrefix?lpNewPrefix:lpPrefix);       AddToLinkedList( lpPre );       lpPre->lpPostfix = (LPPOSTFIX)((LPSTR)(lpPre+1)+wSize);       lpPre->lpPostfix->lpPrefix = lpPre;       lpPre->lpMem = lpPre+1;       /*--- Finish ---*/       lpNew = (lpNewPrefix ? &lpNewPrefix[1] : NULL);       if (!lpNew) {         /* Report out of memory error */         AssertError;         }       }     }   /*--- Else try new allocation ---*/   else {     lpNew = FmNew( wSize, NULL, lpFile, nLine );     }   /*--- Return address to object ---*/   return(lpNew); } /* FmRealloc */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Walk Heap)  JLJ  *  *    Display a symbolic dump of the heap by walking the  *    heap and displaying all objects in the heap.  *  *  ARGUMENTS:  *  *    (void)  *  *  RETURNS:  *  *    (void)  *  *--------------------------------------------------------------*/ void APIENTRY FmWalkHeap( void ) {     if (lpHeapHead) {         LPPREFIX lpCur=lpHeapHead;         while (VerifyHeapPointer(&lpCur[1])) {             char buffer[100];             RenderDesc( lpCur, buffer );             /*--- print out buffer ---*/             /* printf( "walk: %s\n", buffer ); */             lpCur = lpCur->lpNext;             if (lpCur==lpHeapHead) {                 break;                 }             }         } } /* FmWalkHeap */ /*p---------------------------------------------------------------  *  *  DESCRIPTION: (Add Heap Object to Linked List)  JLJ  *  *    Add the given heap object into the doubly linked list  *    of heap objects.  *  *  ARGUMENTS:  *  *    lpAdd - Prefix pointer to heap object  *  *  RETURNS:  *  *    (void)  *  *--------------------------------------------------------------*/ void LOCAL AddToLinkedList( LPPREFIX lpAdd ) {     /*--- Add before current head of list ---*/     if (lpHeapHead) {         lpAdd->lpPrev = lpHeapHead->lpPrev;         (lpAdd->lpPrev)->lpNext = lpAdd;         lpAdd->lpNext = lpHeapHead;         (lpAdd->lpNext)->lpPrev = lpAdd;         }     /*--- Else first node ---*/     else {         lpAdd->lpPrev = lpAdd;         lpAdd->lpNext = lpAdd;         }     /*--- Make new item head of list ---*/     lpHeapHead = lpAdd; } /* AddToLinkedList */ /*p---------------------------------------------------------------  *  *  DESCRIPTION: (Remove Heap Object from Linked List)  JLJ  *  *    Remove the given heap object from the doubly linked list  *    of heap objects.  *  *  ARGUMENTS:  *  *    lpRemove - Prefix pointer to heap object  *  *  RETURNS:  *  *    (void)  *  *--------------------------------------------------------------*/ void LOCAL RemoveFromLinkedList( LPPREFIX lpRemove ) {     /*--- Remove from doubly linked list ---*/     (lpRemove->lpPrev)->lpNext = lpRemove->lpNext;     (lpRemove->lpNext)->lpPrev = lpRemove->lpPrev;     /*--- Possibly correct head pointer ---*/     if (lpRemove==lpHeapHead) {         lpHeapHead = ((lpRemove->lpNext==lpRemove) ? NULL :              lpRemove->lpNext);         } } /* RemoveFromLinkedList */ /*p---------------------------------------------------------------  *  *  DESCRIPTION: (Verify Heap Pointer)  JLJ  *  *    Verify that a pointer points into that heap to a valid  *    object in the heap.  *  *  ARGUMENTS:  *  *    lpMem - Heap pointer to validate  *  *  RETURNS:  *  *    Heap pointer is valid (TRUE) or not (FALSE)  *  *--------------------------------------------------------------*/ BOOL LOCAL VerifyHeapPointer( LPVOID lpMem ) {   BOOL bOk=FALSE;   if (lpMem) {     WinAssert(FmIsPtrOk(lpMem)) {       LPPREFIX lpPrefix=(LPPREFIX)lpMem-1;       WinAssert(lpPrefix->lpMem==lpMem) {         WinAssert(lpPrefix->lpPostfix->lpPrefix==lpPrefix) {           bOk = TRUE;           }         }       }     }   return (bOk); } /* VerifyHeapPointer */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Does Pointer Point into the Heap)  JLJ  *  *    Does the given memory pointer point anywhere into  *    the heap.  *  *  ARGUMENTS:  *  *    lpMem - Heap pointer to check  *  *  RETURNS:  *  *    Pointer points into the heap (TRUE) or not (FALSE)  *  *--------------------------------------------------------------*/ #if (defined(_WINDOWS) || defined(_WINDLL)) BOOL APIENTRY FmIsPtrOk( LPVOID lpMem ) {     BOOL bOk=FALSE;     _asm xor ax, ax                  ;; assume bad selector     _asm lsl ax, word ptr [lpMem+2]  ;; get selector limit     _asm cmp word ptr [lpMem], ax    ;; is ptr offset under limit     _asm jae done                    ;; no, bad pointer     _asm mov bOk, 1                  ;; yes, pointer OK     _asm done:     return (bOk); } /* FmIsPtrOk */ #else BOOL APIENTRY FmIsPtrOk( LPVOID lpMem ) {     return ((lpMem) && (!((long)lpMem&(ALIGNMENT-1)))); } /* FmIsPtrOk */ #endif /*p---------------------------------------------------------------  *  *  DESCRIPTION: (Render Description of Heap Object)  JLJ  *  *    Render a text description for the given heap object.  *  *  ARGUMENTS:  *  *    lpPrefix - Prefix pointer to heap object  *    lpBuffer - Where to place text description  *  *  RETURNS:  *  *    (void)  *  *--------------------------------------------------------------*/ void LOCAL RenderDesc( LPPREFIX lpPrefix, LPSTR lpBuffer ) {     if (lpPrefix->lpMem==&lpPrefix[1]) {         sprintf( lpBuffer, "%08lx ", lpPrefix );         if (lpPrefix->lpFilename) {             sprintf( lpBuffer+strlen(lpBuffer), "%12s %4ld ",                 lpPrefix->lpFilename, lpPrefix->lLineNumber );             }         if (lpPrefix->lpClassDesc) {             sprintf( lpBuffer+strlen(lpBuffer), "%s",                 lpPrefix->lpClassDesc->lpVarName );             }         }     else {         strcpy( lpBuffer, "(bad)" );         } } /* RenderDesc */ 


A.4 RAND.C Module

This code implements the random number generator module as described in Chapter 4.

 Random number generator /*pm--------------------------------------------------------------  *  *  OUTLINE:  *  *    This module implements a random number object.  *  *  IMPLEMENTATION:  *  *    The random numbers are implemented just like they are  *    in the Microsoft C8 RTL.  *  *  NOTES:  *  *--------------------------------------------------------------*/ #define USE_HRAND #include "app.h" USEWINASSERT /*--- The random number class object ---*/ CLASS(hRand, HRAND) {     long lRand;     }; /*--- Implement random numbers just like the MS C8 RTL ---*/ #define NEXTRAND(l)  (l*214013L+2531011L) #define FINALRAND(l) ((l>>16)&0x7FFF) /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Create Random Number Object)  JLJ  *  *    Given a seed, create a new random number generator object  *  *  ARGUMENTS:  *  *    nSeed - Seed of the new random number generator  *  *  RETURNS:  *  *    A new random number generator object  *  *--------------------------------------------------------------*/ HRAND APIENTRY RandCreate( int nSeed ) {     HRAND hRand;     NEWOBJ(hRand);     hRand->lRand = nSeed;     return (hRand); } /* RandCreate */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Destroy Random Number Object)  JLJ  *  *    Destroy the given random number generator object  *  *  ARGUMENTS:  *  *    hRand - Random number generator object or NULL  *  *  RETURNS:  *  *    NULL  *  *--------------------------------------------------------------*/ HRAND APIENTRY RandDestroy( HRAND hRand ) {     VERIFYZ(hRand) {         FREE(hRand);         }     return (NULL); } /* RandDestroy */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Generate Next Random Number)  JLJ  *  *    Generate the next random number for the given random  *    number generator object.  *  *  ARGUMENTS:  *  *    hRand - Random number generator object  *  *  RETURNS:  *  *    The next random number  *  *--------------------------------------------------------------*/ int APIENTRY RandNext( HRAND hRand ) {     int nRand=0;     VERIFY(hRand) {         hRand->lRand = NEXTRAND(hRand->lRand);         nRand = (int)FINALRAND(hRand->lRand);         }     return(nRand); } /* RandNext */ 


A.5 DOS.C Module

This code implements the DOS module as described in Chapter 6.

 A DOS interface /****************************************************************/ /*                                                              */ /*                        (project name)                        */ /*                                                              */ /*    Copyright (date) (Company Name). All rights reserved.     */ /*                                                              */ /*    This program contains the confidential trade secret       */ /*    information of (Company Name).  Use, disclosure, or       */ /*    copying without written consent is strictly prohibited.   */ /*                                                              */ /****************************************************************/ /*pm--------------------------------------------------------------  *  *  OUTLINE:  *  *    This module provides access to the low-level file I/O  *    functions of the standard Microsoft C run-time library.  *  *  IMPLEMENTATION:  *  *    This module is simply a code wrapper module.  *  *  NOTES:  *  *--------------------------------------------------------------*/ #define USE_LOWIO #define USE_HDOSFH #include "app.h" USEWINASSERT /*--- The class object ---*/ CLASS(hDosFh, HDOSFH) {     int fh;     }; /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Open File)  JLJ  *  *    Attempt to open a file  *  *  ARGUMENTS:  *  *    lpFilename - The name of the file to open  *  *  RETURNS:  *  *    A file object handle or NULL if there was some error  *    in opening the specified file.  *  *--------------------------------------------------------------*/ HDOSFH APIENTRY DosOpenFile( LPSTR lpFilename ) {     HDOSFH hDosFh=NULL;     int fh=open(lpFilename, _O_RDWR|_O_BINARY);     if (fh!=-1) {         NEWOBJ(hDosFh);         hDosFh->fh = fh;         }     return (hDosFh); } /* DosOpenFile */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Close File)  JLJ  *  *    Close a previously opened file  *  *  ARGUMENTS:  *  *    hDosFh - The file object or NULL  *  *  RETURNS:  *  *    NULL  *  *--------------------------------------------------------------*/ HDOSFH APIENTRY DosCloseFile( HDOSFH hDosFh ) {     VERIFYZ(hDosFh) {         int nResult=close(hDosFh->fh);         WinAssert(!nResult);         FREE(hDosFh);         }     return (NULL); } /* DosCloseFile */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Read File)  JLJ  *  *    Attempt to read a block of information from a file.  *  *  ARGUMENTS:  *  *    hDosFh - The file object  *    lpMem  - Pointer to memory buffer  *    wCount - Number of bytes to read into the memory buffer  *  *  RETURNS:  *  *    The number of bytes that were actually read  *  *--------------------------------------------------------------*/ WORD APIENTRY DosRead( HDOSFH hDosFh, LPVOID lpMem, WORD wCount ) {     WORD wNumRead=0;     VERIFY(hDosFh) {         wNumRead = (WORD)read(hDosFh->fh, lpMem, wCount);         }     return (wNumRead); } /* DosRead */ /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Write File)  JLJ  *  *    Attempt to write a block of information to a file.  *  *  ARGUMENTS:  *  *    hDosFh - The file object  *    lpMem  - Pointer to memory buffer  *    wCount - Number of bytes to write to the file  *  *  RETURNS:  *  *    The number of bytes that were actually written  *  *--------------------------------------------------------------*/ WORD APIENTRY DosWrite( HDOSFH hDosFh, LPVOID lpMem, WORD wCount ) {     WORD wNumWritten=0;     VERIFY(hDosFh) {         wNumWritten = (WORD)write(hDosFh->fh, lpMem, wCount);         }     return (wNumWritten); } /* DosWrite */ 


A.6 OutputDebugString() for MS-DOS Programmers

If you are programming for Windows, you already have access to the OutputDebugString() function for placing messages onto the monochrome screen. This is an option in the DBWIN.EXE program provided with Microsoft C8.

However, if you are programming under MS-DOS, an OutputDebugString() that you can use to place messages onto the monochrome screen is as follows.

 OutputDebugString() for MS-DOS programmers /*pf--------------------------------------------------------------  *  *  DESCRIPTION: (Output String to Mono Screen)  JLJ  *  *    Scrolls the monochrome screen and places a new  *    string on the 25'th line.  *  *  ARGUMENTS:  *  *    lpS - String to place on monochrome screen  *  *  RETURNS:  *  *    (void)  *  *--------------------------------------------------------------*/ void APIENTRY OutputDebugString( LPSTR lpS ) {     LPSTR lpScreen=(LPSTR)0xB0000000; /* base of mono screen    */     int nPos=0;                       /* for walking lpS string */     /*--- Scroll monochrome screen up one line ---*/     _fmemcpy( lpScreen, lpScreen+2*80, 2*80*24 );     /*--- Place new line down in 25'th line ---*/     for (int loop=0; loop<80; ++loop) {         lpScreen[2*(80*24+loop)] = (lpS[nPos]?lpS[nPos++]:' ');         } } /* OutputDebugString */ 
Refer to §7.27 for a description of OutputDebugString().


A.7 ReportWinAssert()

The ReportWinAssert() functions presented here are bare-bones and should be tailored by you. ReportWinAssert() is called whenever there has been an assertion failure in your code. This can happen when there are run-time type checking failures or when the heap manager is reporting a problem.

A ReportWinAssert() that can be used for Windows is as follows.

 ReportWinAssert() for Windows void APIENTRY ReportWinAssert( LPSTR lpFilename, int nLine ) {     char buffer[100];     wsprintf( buffer, "WinAssert: %s %d", lpFilename, nLine );     MessageBox( NULL, buffer, "WinAssert", MB_OK|MB_SYSTEMMODAL ); } /* ReportWinAssert */ 

A ReportWinAssert() that can be used for C console apps is as follows.

 ReportWinAssert() for C console apps void APIENTRY ReportWinAssert( LPSTR lpFilename, int nLine ) {     printf( "WinAssert: %s-%d (Press Enter) ", lpFilename, nLine );     while ('\n'!=getchar()) {         } } /* ReportWinAssert */ 



Copyright © 1993-1995, 2002-2003 Jerry Jongerius
This book was previously published by Person Education, Inc.,
formerly known as Prentice Hall. ISBN: 0-13-183898-9


Writing Bug-Free C Code[c] A Programming Style That Automatically Detects Bugs in C Code
Writing Bug-Free C Code for Windows: A Programming Style That Automatically Detects Bugs in C Code (Prentice Hall Series on Programming Tools and M)
ISBN: 0131838989
EAN: 2147483647
Year: 2005
Pages: 16

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net