home *** CD-ROM | disk | FTP | other *** search
- /*
- EXEMOD.C - Modify global variables in EXE or COM file
-
- Kevin Dean
- 16 Kellythorne Drive
- Don Mills, Ontario
- Canada M3A 2L4
-
- March 27, 1990
-
- Modifies global variables in initialized data segment of EXE or COM files.
- Cannot modify global variables that are declared but not initialized as these
- lie in the BSS segment of the program and are not in fact in the EXE image file
- itself.
-
- Copyright (c) 1990 by Kevin Dean
-
- For Turbo C versions 2.0 and above. This code is public domain.
- */
-
-
- #include <dir.h>
- #include <dos.h>
- #include <errno.h>
- #include <fcntl.h>
- #include <io.h>
- #include <stdarg.h>
- #include <stdlib.h>
- #include <string.h>
-
- #include <exemod.h>
-
-
- /***/
- /*
- Name exemodify
-
- Function Modifies static data in EXE or COM files.
-
- Syntax int exemodify(char *progname, int keepdt, [void *data1,
- unsigned n1, [void *data2, unsigned n2, [ ... ]]]
- NULL);
-
- Prototype in exemod.h
-
- Remarks exemodify modifies global variables in the initialized data
- segment of the current EXE or COM file. In DOS versions 3.0
- and up, exemodify takes the program name from _argv[0]. In DOS
- versions below 3.0, exemodify searches the DOS path for the
- program passed in progname.
-
- If keepdt is true, then the original file date/time stamp is
- preserved.
-
- exemodify cannot modify global variables that are declared but
- not initialized as these lie in the BSS segment of the program
- and are not in fact in the EXE or COM image file itself.
-
- WARNING: Huge model programs treat uninitialized data the same
- as initialized data with values of 0 in that the uninitialized
- data is also written to the EXE file. Because of the model,
- the Turbo C startup code does not initialize this data to 0.
- Since the compiler itself does not differentiate between
- initialized and uninitialized data in the huge model, neither
- can this module, and so any changes written to what was
- intended to be the uninitialized data segment in the huge model
- could have unpredictable results.
-
- Return value exemodify returns the number of data items successfully
- modified (which may not be the same as the number of items
- passed) or -1 in case of error (such as file not found or
- invalid EXE file format).
-
- In the event of an error, the global variable errno is set to
- one of the following:
-
- ENOENT No such file or directory
- EMFILE Too many open files
- EACCES Permission denied
- EINVACC Invalid access code
- EINVFMT Invalid format
-
- Portability exemodify is unique to DOS.
- */
- int exemodify(const char *progname, int keepdt, ...)
- {
- char *pathptr; /* Pointer to program path */
- char _progname[MAXPATH]; /* Program name */
- int retcode; /* Function return code */
- char ext[MAXEXT]; /* Program extension */
- int progfile; /* Program file handle */
- int iscomfile; /* True if program is a COM file */
- struct exeheader exe; /* EXE file header */
- long filelen; /* Program file length */
- struct ftime dtstamp; /* Program date/time stamp */
- va_list datalist; /* List of data items to be written to file */
- char *data; /* Pointer to current data item */
- unsigned n; /* Size of current data item */
- long seeklen; /* Seek length into program file */
-
- if (_osmajor < 3)
- /* Search DOS PATH for program */
- if ((pathptr = searchpath(progname)) != NULL)
- strcpy(_progname, pathptr);
- else
- _progname[0] = 0;
- else
- /* Program name is 0th parameter in DOS versions 3.0 and up */
- strcpy(_progname, _argv[0]);
-
- /* Assume error */
- retcode = -1;
-
- if (_progname[0])
- {
- if ((progfile = open(_progname, O_RDWR | O_BINARY)) != -1)
- {
- iscomfile = fnsplit(_progname, NULL, NULL, NULL, ext) & EXTENSION && !strnicmp(ext, ".COM", 4);
-
- if (!iscomfile && (read(progfile, &exe, EXEH_SIZE) != EXEH_SIZE || exe.id != EXE_ID))
- /* File is not a COM file and does not have a valid EXE file header */
- errno = EINVFMT;
- else
- {
- /* Cannot write beyond end of file */
- filelen = filelength(progfile);
-
- if (keepdt)
- /* Save date/time stamp */
- getftime(progfile, &dtstamp);
-
- retcode = 0;
- va_start(datalist, keep_attribs);
-
- while ((data = va_arg(datalist, char *)) != NULL)
- {
- if (iscomfile)
- /* Seek length is data offset - PSP size */
- seeklen = FP_OFF(data) - 256;
- else
- /* Seek length is (data segment - (PSP + PSP size) + EXE size) * 16 + data offset */
- seeklen = ((unsigned long)(FP_SEG(data) - (_psp + 16) + exe.size) << 4) + (unsigned long)FP_OFF(data);
-
- n = va_arg(datalist, unsigned);
-
- if (seeklen + n <= filelen && lseek(progfile, seeklen, SEEK_SET) != -1L && write(progfile, data, n) == n)
- /* Seek and write was successful */
- retcode++;
- }
-
- va_end(datalist);
-
- if (keepdt)
- /* Restore date/time stamp */
- setftime(progfile, &dtstamp);
- }
-
- close(progfile);
- }
- }
- else
- /* File not found */
- errno = ENOENT;
-
- return (retcode);
- }