home *** CD-ROM | disk | FTP | other *** search
- /*
- * Copyright (C) 1996 by Raphael Quinet. All rights reserved.
- *
- * Permission to use, copy, modify, and distribute this software and
- * its documentation for any purpose and without fee is hereby
- * granted, provided that the above copyright notice appear in all
- * copies and that both that copyright notice and this permission
- * notice appear in supporting documentation. If more than a few
- * lines of this code are used in a program which displays a copyright
- * notice or credit notice, the following acknowledgment must also be
- * displayed on the same screen: "This product includes software
- * developed by Raphael Quinet for use in the Quake Editing Utilities
- * project." THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR
- * IMPLIED WARRANTY.
- *
- * More information about the QEU project can be found on the WWW:
- * "http://www.montefiore.ulg.ac.be/~quinet/games/editing.html" or by
- * mail: Raphael Quinet, 9 rue des Martyrs, B-4550 Nandrin, Belgium.
- */
-
- /*
- * Q_MISC.C - Error logs, memory management, selection of objects, etc.
- *
- * This file was derived from D_MISC.C (Doom Editing Utilities 5.3),
- * written by the DEU Team: Raphael Quinet, Brandon Wyber, Ted
- * Vessenes and others.
- */
-
- /* the includes */
- #include "qeu.h"
- #ifdef QEU_UNIX
- #include <sys/types.h>
- #include <sys/time.h>
- #else
- #include <dos.h>
- #include <time.h>
- #endif
- #if defined (__TURBOC__)
- #include <alloc.h>
- #elif defined(__GO32__)
- #include <pc.h>
- #endif
- #include "q_misc.h"
-
- /*! Dirty hack while the config stuff is not available */
- struct
- {
- Bool debug;
- } Config;
-
- /* global variable */
- FILE *logfile = NULL; /* file pointer to the error log */
-
-
- /*
- * Wait for a specified number of milliseconds.
- */
- void MSleep(int msec)
- {
- #ifdef QEU_UNIX
- struct timeval tv;
-
- tv.tv_sec = msec / 1000;
- tv.tv_usec = 1000 * (msec % 1000);
- (void) select(0, (fd_set *)0, (fd_set *)0, (fd_set *)0, &tv);
- #else
- delay(msec);
- #endif
- }
-
-
- /*
- * Report a non-fatal error.
- */
- void ProgWarning(char *errstr, ...)
- {
- va_list args;
-
- va_start(args, errstr);
- printf("\nWarning: ");
- vprintf(errstr, args);
- printf("\n");
- if (Config.debug == TRUE && logfile != NULL)
- {
- fprintf(logfile, "\nWarning: *** ");
- vfprintf(logfile, errstr, args);
- fprintf(logfile, " ***\n");
- fclose(logfile);
- }
- va_end(args);
-
- }
-
-
- /*
- * Terminate the program reporting an error.
- */
- void ProgError(char *errstr, ...)
- {
- va_list args;
-
- va_start(args, errstr);
- printf("\nProgram Error: *** ");
- vprintf(errstr, args);
- printf(" ***\n");
- if (Config.debug == TRUE && logfile != NULL)
- {
- fprintf(logfile, "\nProgram Error: *** ");
- vfprintf(logfile, errstr, args);
- fprintf(logfile, " ***\n");
- }
- va_end(args);
- exit(5);
- }
-
-
- /*
- * Write a message in the log file.
- */
- void LogMessage(char *logstr, ...)
- {
- va_list args;
- time_t tval;
- char *tstr;
-
- if (Config.debug == TRUE && logfile != NULL)
- {
- va_start(args, logstr);
- /* if the messsage begins with ":", output the current date & time first */
- if (logstr[0] == ':')
- {
- time(&tval);
- tstr = ctime(&tval);
- tstr[strlen(tstr) - 1] = '\0';
- fprintf(logfile, "%s", tstr);
- }
- vfprintf(logfile, logstr, args);
- /* write the message immediately, in case something bad happens next */
- fflush(logfile);
- va_end(args);
- }
- }
-
-
- /*
- * Open the log file and write a first message in it.
- */
- void OpenLogFile(char *logfilename)
- {
- if (Config.debug == TRUE)
- {
- logfile = fopen(logfilename, "a");
- if (logfile == NULL)
- printf("Warning: Could not open log file \"%s\"", logfilename);
- LogMessage(": Starting QEU %s\n", QEU_VERSION);
- }
- }
-
- /*
- * Close the log file.
- */
- void CloseLogFile(void)
- {
- if (logfile != NULL)
- {
- LogMessage(": The end!\n\n\n");
- fclose(logfile);
- }
- }
-
-
- /*
- * Test if an object is in the selection list.
- */
- Bool IsSelected(SelPtr list, Int16 objnum)
- {
- SelPtr cur;
-
- for (cur = list; cur; cur = cur->next)
- if (cur->objnum == objnum)
- return TRUE;
- return FALSE;
- }
-
-
- /*
- * Add an object to the selection list.
- */
- void SelectObject(SelPtr *list, Int16 objnum)
- {
- SelPtr cur;
-
- #ifdef DEBUG
- if (objnum < 0)
- ProgError("BUG: SelectObject called with %d", objnum);
- #endif
- cur = (SelPtr) QMalloc(sizeof(struct SelectionList));
- cur->next = *list;
- cur->objnum = objnum;
- *list = cur;
- }
-
-
- /*
- * Remove an object from the selection list.
- */
- void UnSelectObject(SelPtr *list, Int16 objnum)
- {
- SelPtr cur, prev;
-
- #ifdef DEBUG
- if (objnum < 0)
- ProgError("BUG: UnSelectObject called with %d", objnum);
- #endif
- prev = NULL;
- cur = *list;
- while (cur)
- {
- if (cur->objnum == objnum)
- {
- if (prev)
- prev->next = cur->next;
- else
- *list = cur->next;
- QFree(cur);
- if (prev)
- cur = prev->next;
- else
- cur = NULL;
- }
- else
- {
- prev = cur;
- cur = cur->next;
- }
- }
- }
-
-
- /*
- * Forget the selection list.
- */
- void ForgetSelection(SelPtr *list)
- {
- SelPtr cur, prev;
-
- cur = *list;
- while (cur)
- {
- prev = cur;
- cur = cur->next;
- QFree(prev);
- }
- *list = NULL;
- }
-
-
- /*
- Note from RQ:
- In order to prevent memory fragmentation on large blocks (greater
- than 1K), you can define MEMORY_LOWFRAG and the size of all blocks
- will be rounded up to 8K. Thus, "realloc" will move the block if
- and only if it has grown or shrunk enough to cross a 8K boundary.
- I don't do that for smaller blocks (smaller than 1K), because this
- would waste too much space if these blocks were rounded up to 8K.
- There are lots of "malloc"'s for very small strings (9 characters)
- or filenames, etc.
- Thanks to Craig Smith (bcs@cs.tamu.edu) for his ideas about memory
- fragmentation.
- */
-
- #ifdef MEMORY_LOWFRAG
- #define SIZE_THRESHOLD 1024
- #define SIZE_OF_BLOCK 4095 /* actually, this is (size - 1) */
- #endif
-
-
- /*
- * Allocate memory with error checking.
- */
- void huge *QMalloc(UInt32 size)
- {
- void huge *ret;
-
- #ifdef MEMORY_LOWFRAG
- /* limit fragmentation on large blocks */
- if (size >= (UInt32) SIZE_THRESHOLD)
- size = (size + (UInt32) SIZE_OF_BLOCK) & ~((UInt32) SIZE_OF_BLOCK);
- #endif
- #ifdef __TURBOC__
- ret = farmalloc(size);
- #else
- ret = malloc(size);
- #endif
- if (!ret)
- ProgError("out of memory (cannot allocate %lu far bytes)", size);
- return ret;
- }
-
-
- /*
- * Reallocate memory with error checking.
- */
- void huge *QRealloc(void huge *old, UInt32 size)
- {
- void huge *ret;
-
- #ifdef MEMORY_LOWFRAG
- /* limit fragmentation on large blocks */
- if (size >= (UInt32) SIZE_THRESHOLD)
- size = (size + (UInt32) SIZE_OF_BLOCK) & ~((UInt32) SIZE_OF_BLOCK);
- #endif
- #ifdef __TURBOC__
- ret = farrealloc(old, size);
- #else
- ret = realloc(old, size);
- #endif
- if (!ret)
- ProgError("out of memory (cannot reallocate %lu far bytes)", size);
- return ret;
- }
-
-
- /*
- * Free memory.
- */
- void QFree(void huge *ptr)
- {
- /* just a wrapper around farfree(), but provide an entry point */
- /* for memory debugging routines... */
- #ifdef __TURBOC__
- farfree(ptr);
- #else
- free(ptr);
- #endif
- }
-
-
- /*
- * Duplicate an area of memory in a newly allocated location.
- */
- UInt8 *QMemDup(UInt8 *src, UInt32 size)
- {
- UInt8 *ret;
- UInt8 *sp, *dp;
-
- if (src == NULL)
- ProgError("BUG: cannot duplicate NULL pointer");
- ret = (UInt8 *)QMalloc(size);
- /* copy 32K blocks at a time, because old DOS doesn't like >64K blocks */
- sp = src;
- dp = ret;
- while (size > 0x8000L)
- {
- memcpy(dp, sp, 0x8000);
- sp = sp + 0x8000;
- dp = dp + 0x8000;
- size -= 0x8000;
- }
- if (size > 0)
- memcpy(dp, sp, size);
- return ret;
- }
-
-
- /*
- * Duplicate a string in a newly allocated location, with error checking.
- */
- char *QStrDup(char *src)
- {
- char *ret;
-
- if (src == NULL)
- ProgError("BUG: cannot duplicate NULL pointer");
- ret = (char *)QMalloc(strlen(src) + 1);
- return strcpy(ret, src);
- }
-
-
- /*
- * Copy a string into another (like strncpy) and pad the destination string
- * with zeroes. The destination string will not be null-terminated if
- * strlen(src) > n.
- */
- char *QStrNCpy(char *dest, char *src, int n)
- {
- int i;
- char *dp, *sp;
-
- dp = dest;
- sp = src;
- for (i = 0; *sp && i < n; i++)
- *dp++ = *sp++;
- for (; i < n; i++)
- *dp++ = 0;
- return dest;
- }
-
-
- /*
- * Does something strange with a string... :-) Strips leading
- * directory name from "src", removes the extension (anything that
- * follows a dot '.'), converts the string to upper case and truncate
- * it after "n" characters. Useful for making a WAD or WAD2 entry
- * name from a file name.
- */
- char *QStrNDupHack(char *src, int n)
- {
- int i;
- char *ret, *dp, *sp;
-
- if (src == NULL)
- ProgError("BUG: cannot convert a NULL string to an entry name");
- if (n <= 0)
- ProgError("BUG: entry size must be greater than 0 (%d)", n);
- sp = src;
- for (dp = sp; *dp; dp++)
- if (*dp == '/' || *dp == '\\')
- sp = dp + 1;
- ret = (char *)QMalloc(n);
- dp = ret;
- for (i = 0; *sp && *sp != '.' && i < n; i++)
- *dp++ = (char)toupper((int)*sp++);
- for (; i < n; i++)
- *dp++ = 0;
- return ret;
- }
-
-
- #ifndef QEU_DOS
- /*
- * Convert a string to upper case, overwriting its space.
- */
-
- char *strupr(char *s)
- {
- char *cp;
-
- if (s == NULL)
- ProgError("BUG: cannot convert a NULL string to upper case");
- for (cp = s; *cp != '\0'; cp++)
- *cp = (char)toupper((int)*cp);
- return s;
- }
- #endif /* QEU_DOS */
-
-
- /*
- * Convert numbers depending on endianness.
- */
- #ifdef FAT_ENDIAN
- UInt16 SwapInt16(UInt16 x)
- {
- return ((x<<8) & 0xff00) | ((x>>8) & 0x00ff);
- }
-
-
- UInt32 SwapInt32(UInt32 x)
- {
- return (((x << 24) & 0xff000000)
- | ((x<< 8) & 0x00ff0000)
- | ((x>> 8) & 0x0000ff00)
- | ((x>>24) & 0x000000ff));
- }
-
-
- Float32 SwapFloat32(Float32 x)
- {
- UInt32 i;
- i = SwapInt32(*((UInt32 *)&x));
- return *((Float32 *)&i);
- }
- #endif /* FAT_ENDIAN */
-
- /* end of file */
-