/* * General setup routine for DOS. (Compiles also under AT&T unix, but * does not run. AT&T Unix prevents patching of a running program) * The file is tested under Turbo-C version 2.0 (that's the version I own * myself) compact model only (may run on other models too). There are no * language quircks so it should run under Microsoft-C also. * * Application: * * in your "main" program include file: * * #include "patch.h" * * The variables to be patched should be defined as follows: * * STARTPATCH * int var1=0; * char *var2="test"; * float var3=1.0; * ENDPATCH * * Remember to give the variables an initial value, otherwise the used approach * will fail completely (uninitialized variables will be moved to another * addressing space/data area than initialized ones). * * define argc and argv in main: * * int main(argc,argv) * int argc; * char * argv[]; * * After setting the local variables, but before doing anything else include * the word "SETUP;" * * Also create the setup routine the following way: * * void setup() * { * /* your code to change the variables between STARTPATCH and * ENDPATCH */ /* } * * This file is put in the PUBLIC DOMAIN. I request to leave my * name in this file (I don't demand it however). Since this file is * free of charge, I don't accept any responcebility for damages due to * the use of this software. * * Auhor: Henk de Groot groot@idca.tds.philips.nl. */ /* see if has been included already, if not we do it */ #ifndef EOF #include #endif /* see if has been included already, if not we do it */ #ifndef O_RDWR #include #endif /* Unix doesn't know O_BINARY so we set it to zero if it's not defined yet */ #ifndef O_BINARY #define O_BINARY 0 /* no effect (used for UNIX) */ #endif /* SEEK_SET is in for Turbo-C, it's in for AT&T UNIX */ #ifndef SEEK_SET #include #endif /* Macro's to mark the patch-area. Note that having another string "PATCH-AREA-START in the program will break this code */ #define STARTPATCH char patch_start[]="PATCH-AREA-START"; #define ENDPATCH long patch_offset = 0; char patch_end[]="PATCH-AREA-END"; /* SETUP - to be included in "main" just after the local varables have been defined. Note that SETUP uses "argc" and "argv" */ #define SETUP \ if(argc==2)\ {\ if((argv[1][0]=='-') && ((argv[1][1]=='s') || (argv[1][1]=='S'))\ && (argv[1][2]=='\0'))\ {\ setup();\ patch(argv[0]);\ exit(0);\ }\ } /* forward declaration, "patch" needs them */ void setup(); extern char patch_start[]; extern long patch_offset; extern char patch_end[]; /* patch - patch the new values into the binary. Note that the first time after complilation the use of patch will be slow. It has to search for the patch area. The found offset will be patched into the program, so the next time the setup is run it will patch fast. Searching for the patch area is done with stdio routines, because bufferd I/O will be much faster than raw-I/O. Patching is done by means of the "raw" routines because lseek can be used without converision of "FILE *" to "int" file descriptiors. Inplementation is straiged forward. */ void patch(s) char *s; { FILE * sid; int fd; long i; int j; long n; char *p; char c; i=0; if(patch_offset==0) { sid=fopen(s,"rb"); if(sid==NULL) { perror(s); exit(1); } j=0; while(j != 16) { /* find "PATCH_AREA_START" */ if(fread(&c,1,1,sid)!=1) { perror(s); exit(1); } i++; /* check aganst string */ if(c == patch_start[j]) /* Ok, next character */ j++; else { /* Fail, reset pointer */ j=0; /* could be a 'P' again.. */ if(c == patch_start[j]) j++; } } patch_offset = i; fclose(sid); } n = ((long) patch_end - 1) - ((long) patch_start + 16); p = &patch_start[16]; fd=open(s,O_RDWR|O_BINARY); if(fd<0) { perror(s); exit(1); } if(lseek(fd,patch_offset,SEEK_SET) < 0) { perror(s); exit(1); } if(write(fd,p,n) < 0) { perror(s); exit(1); } close(fd); }