/* * Now that I own both MSC 7.0 and BC 3.1 and have linux, lets rearrange stuff * so many compilers can compile TDE. Several implementation specific * functions needed for several environments were gathered into this file. * * In version 3.2, these functions changed to support unix. * * Incidentally, there is difference between a NULL line pointer and * a pointer to a line that contains no characters. For example, calling * * line = malloc( 0 ); * * or, more precisely in TDE: * * line = _fmalloc( 0 ); * line = farmalloc( 0 ); * * will return a valid pointer to an item of 0 length in some compilers * and a NULL pointer in other compilers. malloc( 0 ) will return a valid * pointer to an object of zero length in MSC. malloc( 0 ) will return a * NULL pointer in BC. The problem with returning a NULL pointer for * malloc( 0 ) is that it's a little harder to tell if the heap is out of * memory or if we have a valid NULL pointer. On the other hand, the good * part about returning a NULL pointer for malloc( 0 ) is that extra space * is not wasted for an object of 0 length. In TDE, we will test for 0 * before calling my_malloc( ) and set an ERROR code if out of memory. * * Although many PC C compilers have findfirst and findnext functions for * finding files, let's write our own to keep a closer watch on * critical errors. * * * New editor name: TDE, the Thomson-Davis Editor. * Author: Frank Davis * Date: June 5, 1991, version 1.0 * Date: July 29, 1991, version 1.1 * Date: October 5, 1991, version 1.2 * Date: January 20, 1992, version 1.3 * Date: February 17, 1992, version 1.4 * Date: April 1, 1992, version 1.5 * Date: June 5, 1992, version 2.0 * Date: October 31, 1992, version 2.1 * Date: April 1, 1993, version 2.2 * Date: June 5, 1993, version 3.0 * Date: August 29, 1993, version 3.1 * Date: November 13, 1993, version 3.2 * Date: June 5, 1994, version 4.0 * * This code is released into the public domain, Frank Davis. * You may use and distribute it freely. */ #include "tdestr.h" #include "common.h" #include "tdefunc.h" #include "define.h" #if !defined( __UNIX__ ) #include /* for REGS */ #include /* for intdos */ #endif #if defined( __UNIX__ ) /* ********************************************************************** ****************************** PART 1 ****************************** ********************************************************************** * * Let's try to make unix have the look and feel of a PC. */ /* * Name: my_malloc * Purpose: malloc from the far heap * Date: November 13, 1993 * Passed: size: memory needed heap * rc: pointer to return code * Notes: set the return code only if an ERROR occured with malloc. * returning a NULL pointer is not neccessarily an ERROR. */ void *my_malloc( size_t size, int *rc ) { void *mem; assert( size < MAX_LINE_LENGTH ); if (size == 0) /* * if 0 bytes are requested, return NULL */ mem = NULL; else { mem = malloc( size ); /* * if malloc failed, return NULL and an ERROR. */ if (mem == NULL) *rc = ERROR; } return( mem ); } /* * Name: my_free * Purpose: free memory from the far heap * Date: November 13, 1993 * Passed: mem: pointer to memory to free in far heap */ void my_free( void *mem ) { assert( mem != NULL ); free( mem ); } /* * Name: my_heapavail * Purpose: available free memory from the far heap * Date: June 5, 1994 * Notes: use /proc/meminfo to find available free memory. let's count * the free memory in the swap space(s), too. */ long my_heapavail( void ) { FILE *f; /* file pointer */ char buf[82]; /* let's hope lines in /proc/meminfo are < 80 chars */ char temp[82]; /* space to ascii free mem */ char *p; /* pointer walks down line in buf */ char *q; /* pointer for temp */ long mem; /* free memory */ int no; /* current line number in /proc/meminfo */ if ((f = fopen( "/proc/meminfo", "r" )) == NULL) mem = 0; else { for (no=1,mem=0; !feof( f ); no++) { fgets( buf, 80, f ); if (feof( f )) break; if (no >= 2) { /* * assume line looks like: * "mem: total used free buffers" */ p = buf; q = temp; while (*p++ == ' '); while (*p++ != ' '); while (*p++ == ' '); while (*p++ != ' '); while (*p++ == ' '); while (*p++ != ' '); while (*p++ == ' '); --p; while ((*q++ = *p++) && *p != ' '); *q = '\0'; mem += atol( temp ); } } fclose( f ); } return( mem ); } /* * Name: my_memcpy * Purpose: copy memory * Date: November 13, 1993 * Passed: dest: pointer to destination * src: pointer to source * size: number of bytes to copy */ void my_memcpy( void *dest, void *src, size_t size ) { if (size > 0) { assert( dest != NULL ); assert( src != NULL ); memcpy( dest, src, size ); } } /* * Name: my_memmove * Purpose: move memory * Date: November 13, 1993 * Passed: dest: pointer to destination * src: pointer to source * size: number of bytes to copy */ void my_memmove( void *dest, void *src, size_t size ) { if (size > 0) { assert( dest != NULL ); assert( src != NULL ); memmove( dest, src, size ); } } /* * Name: my_ltoa * Purpose: ltoa is not ANSI - write our own * Date: November 13, 1993 * Passed: lnum: number to convert to ASCII. in linux, an int is 32 bits. * s: pointer to buffer * radix: 0 < radix <= 16 * Notes: store the ascii string in a 20 character stack. */ char *my_ltoa( int lnum, char *s, int radix ) { int sign; char *digit = "0123456789abcdef"; char stack[20]; char *sp; char *p; if (radix < 0) radix = -radix; /* * default an empty string. */ *s = '\0'; if (radix > 0 && radix <= 16) { sign = 0; if (lnum < 0) { lnum = -lnum; sign = -1; } /* * put a '\0' at the beginning of our stack. * * standard procedure: generate the digits in reverse order. */ sp = stack; *sp = '\0'; do { *++sp = digit[lnum % radix]; lnum = lnum / radix; } while (lnum > 0); /* * now, pop the ascii digits off the stack. the '\0' that we stored * at the beginning of the stack terminates the string copy. */ p = s; if (sign == -1) *p++ = '-'; while (*p++ = *sp--); } return( s ); } /* * Name: my_findfirst * Purpose: find the first file matching a pattern * Date: November 13, 1993 * Passed: dta: disk transfer address * path: path to search for files * f_attr: attributes of files to search for * Notes: we don't use this function in a unix environment */ int my_findfirst( DTA FAR *dta, char FAR *path, int f_attr ) { return( ERROR ); } /* * Name: my_findnext * Purpose: find the next file matching a pattern using POSIX readdir * Date: November 13, 1993 * Passed: dp: directory pointer (DIR is defined in * unix_dta: a pointer for TDE's dta * Notes: find directory elements. the readdir( ) function gets the * next directory element. it is up to TDE to figure the * directory element type, i.e. file, link, FIFO, subdirectory, etc... */ int my_findnext( DIR *dp, UNIX_DTA *unix_dta ) { struct dirent *dir; /* dirent defined in */ int rc; /* * make sure our directory pointers aren't null */ if (dp == NULL || unix_dta == NULL) rc = ERROR; else if ((dir = readdir( dp )) == NULL) rc = ERROR; else { /* * copy the directory element name and length to our unix_dta buffer. * to figure the element, we will append the element name to the * directory stem and call stat( ). */ strcpy( unix_dta->fname, dir->d_name ); unix_dta->name_len = strlen( unix_dta->fname ); rc = OK; } return( rc ); } #else /* ********************************************************************** ****************************** PART 2 ****************************** ********************************************************************** * * DOS malloc and findfirst and findnext. */ /* * Name: my_malloc * Purpose: malloc from the far heap * Date: April 1, 1993 * Passed: mem: pointer to memory to free in far heap * rc: pointer to return code * Notes: set the return code only if an ERROR occured with malloc. * returning a NULL pointer is not neccessarily an ERROR. */ void FAR * my_malloc( size_t size, int *rc ) { void FAR *mem; assert( size < MAX_LINE_LENGTH ); if (size == 0) /* * if 0 bytes are requested, return NULL */ mem = NULL; else { #if defined( __MSC__ ) mem = _fmalloc( size ); #else mem = farmalloc( size ); #endif /* * if malloc failed, return NULL and an ERROR. */ if (mem == NULL) *rc = ERROR; } return( mem ); } /* * Name: my_free * Purpose: free memory from the far heap * Date: April 1, 1993 * Passed: mem: pointer to memory to free in far heap */ void my_free( void FAR *mem ) { assert( mem != NULL ); #if defined( __MSC__ ) _ffree( mem ); #else farfree( mem ); #endif } /* * Name: my_heapavail * Purpose: available free memory from the far heap * Date: November 13, 1993 */ long my_heapavail( void ) { long avail_mem; #if defined( __MSC__ ) unsigned paragraphs; _dos_allocmem( 0xffff, ¶graphs ); /* * A paragraph is 16 bytes. Convert paragraphs to bytes by shifting left * 4 bits. */ avail_mem = (long)paragraphs << 4; #else /* * use the Borland farcoreleft( ) function. */ avail_mem = farcoreleft( ); #endif return( avail_mem ); } /* * Name: my_memcpy * Purpose: copy memory * Date: November 13, 1993 * Passed: dest: pointer to destination * src: pointer to source * size: number of bytes to copy * Notes: far memory copy in DOS real mode */ void my_memcpy( void FAR *dest, void FAR *src, size_t size ) { if (size > 0) { assert( dest != NULL ); assert( src != NULL ); _fmemcpy( dest, src, size ); } } /* * Name: my_memmove * Purpose: move memory * Date: November 13, 1993 * Passed: dest: pointer to destination * src: pointer to source * size: number of bytes to copy * Notes: far memory move in DOS real mode - handles mem overlap */ void my_memmove( void FAR *dest, void FAR *src, size_t size ) { if (size > 0) { assert( dest != NULL ); assert( src != NULL ); _fmemmove( dest, src, size ); } } /* * Name: my_ltoa * Purpose: ltoa is not ANSI * Date: June 5, 1991 * Passed: lnum: number to convert to ASCII * s: pointer to buffer * radix: 0 < radix <= 16 * Notes: If in insert mode, then this function adds the required * number of spaces in the file. * If not in insert mode, then tab simply moves the cursor right * the required distance. */ char *my_ltoa( long lnum, char *s, int radix ) { return( ltoa( lnum, s, radix ) ); } /* * Name: my_findfirst * Purpose: find the first file matching a pattern using DOS interrupt * Date: January 6, 1992 * Passed: dta: disk transfer address * path: path to search for files * f_attr: attributes of files to search for * Notes: return codes for my_findfirst: * 0 no error * 2 file is invalid or does not exist * 3 path is invalid or does not exist * 18 no matching directory entry was found * -1 check the critical error flag for critical errors */ int my_findfirst( DTA FAR *dta, char FAR *path, int f_attr ) { void FAR *old_dta; void FAR *new_dta; int rc; new_dta = (void FAR *)dta; ASSEMBLE { /* ; save the old dta */ mov ah, 0x2f /* DOS get dta */ int 0x21 /* DOS interrupt */ mov WORD PTR old_dta, bx /* save OFFSET of old DTA */ mov ax, es mov WORD PTR old_dta+2, ax /* save SEGMENT of old DTA */ /* ; set the new dta */ push ds /* save ds */ mov dx, WORD PTR new_dta /* get OFFSET of new dta */ mov ax, WORD PTR new_dta+2 /* get SEGMENT of new dta */ mov ds, ax /* put it in ds */ mov ah, 0x1a /* DOS set dta */ int 0x21 /* DOS interrupt */ pop ds /* get back ds */ /* ; find first matching file */ push ds /* save ds */ mov cx, WORD PTR f_attr /* file attributes to search for */ mov dx, WORD PTR path /* get OFFSET of path */ mov ax, WORD PTR path+2 /* get SEGMENT of path */ mov ds, ax /* put it in ds */ mov ah, 0x4e /* DOS find first file */ int 0x21 /* DOS interrupt */ pop ds /* get back ds */ /* ; save the return code */ jc an_error /* carry is set if an error occured */ xor ax, ax /* zero out ax, return OK if no error */ } an_error: ASSEMBLE { mov WORD PTR rc, ax /* save the return code */ /* ; get back old dta */ push ds /* save ds */ mov dx, WORD PTR old_dta /* get OFFSET of old dta */ mov ax, WORD PTR old_dta+2 /* get SEGMENT of old dta */ mov ds, ax /* put it in ds */ mov ah, 0x1a /* DOS set dta */ int 0x21 /* DOS interrupt */ pop ds /* get back ds */ } if (ceh.flag == ERROR) rc = ERROR; return( rc ); } /* * Name: my_findnext * Purpose: find the next file matching a pattern using DOS interrupt * Date: January 6, 1992 * Passed: dta: disk transfer address * Notes: my_findfirst() MUST be called before calling this function. * return codes for my_findnext (see DOS tech ref manuals): * 0 no error * 2 path is invalid or does not exist * 18 no matching directory entry was found * -1 check the critical error flag for critical errors */ int my_findnext( DTA FAR *dta ) { void FAR *old_dta; void FAR *new_dta; int rc; new_dta = (void FAR *)dta; ASSEMBLE { /* ; save the old dta */ mov ah, 0x2f /* DOS get dta */ int 0x21 /* DOS interrupt */ mov WORD PTR old_dta, bx /* save OFFSET of old DTA */ mov ax, es mov WORD PTR old_dta+2, ax /* save SEGMENT of old DTA */ /* ; set the new dta */ push ds /* save ds */ mov dx, WORD PTR new_dta /* get OFFSET of new dta */ mov ax, WORD PTR new_dta+2 /* get SEGMENT of new dta */ mov ds, ax /* put it in ds */ mov ah, 0x1a /* DOS set dta */ int 0x21 /* DOS interrupt */ pop ds /* get back ds */ /* ; find next matching file */ mov ah, 0x4f /* DOS find first file */ int 0x21 /* DOS interrupt */ /* ; save the return code */ jc an_error /* carry is set if an error occured */ xor ax, ax /* zero out ax, return OK if no error */ } an_error: ASSEMBLE { mov WORD PTR rc, ax /* save the return code */ /* ; get back old dta */ push ds /* save ds */ mov dx, WORD PTR old_dta /* get OFFSET of old dta */ mov ax, WORD PTR old_dta+2 /* get SEGMENT of old dta */ mov ds, ax /* put it in ds */ mov ah, 0x1a /* DOS set dta */ int 0x21 /* DOS interrupt */ pop ds /* get back ds */ } if (ceh.flag == ERROR) rc = ERROR; return( rc ); } #endif