1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144
|
/*
* File: genlib.c
* Version: 1.0
* Last modified on Sun Jul 24 10:29:46 1994 by eroberts
* -----------------------------------------------------
* This file implements the general C library package. See the
* interface description in genlib.h for details.
*/
#include <stdio.h>
#include <stddef.h>
#include <string.h>
#include <stdarg.h>
#include "genlib.h"
#include "gcalloc.h"
#include "exception.h"
/*
* Constants:
* ----------
* ErrorExitStatus -- Status value used in exit call
* MaxErrorMessage -- Longest error message allowed
*/
#define ErrorExitStatus 1
#define MaxErrorMessage 500
/* Section 1 -- Define new "primitive" types */
/*
* Constant: UNDEFINED
* -------------------
* This entry defines the target of the UNDEFINED constant.
*/
char undefined_object[] = "UNDEFINED";
/* Section 2 -- Memory allocation */
/*
* Implementation notes:
* ---------------------
* The code for the memory allocator is divided between
* genlib.c and gcalloc.c, and the division strategy may at
* first seem unnatural, since the function ProtectBlock is
* declared in gcalloc.h but defined here in genlib.c. The
* intention is to minimize the size of object files
* produced by linkers that search a library for modules
* that are actually referenced. The libraries themselves
* need to call ProtectBlock (usually through the macro
* ProtectVariable), but will not require the actual code
* for the allocator unless InitGCAllocator is explicitly
* called.
*/
/*
* Global variable: _acb
* ---------------------
* This variable is used to hold a method suite that makes it
* easy to substitute a garbage-collecting allocator for the
* ANSI allocator.
*/
_GCControlBlock _acb = NULL;
/* Memory allocation implementation */
void *GetBlock(size_t nbytes)
{
void *result;
if (_acb == NULL) {
result = malloc(nbytes);
} else {
result = _acb->allocMethod(nbytes);
}
if (result == NULL) Error("No memory available");
return (result);
}
void FreeBlock(void *ptr)
{
if (_acb == NULL) {
free(ptr);
} else {
_acb->freeMethod(ptr);
}
}
void ProtectBlock(void *ptr, size_t nbytes)
{
if (_acb != NULL) _acb->protectMethod(ptr, nbytes);
}
/* Section 3 -- Basic error handling */
/*
* Implementation notes: Error
* ---------------------------
* Writing the Error function requires some care, since it is
* called in circumstances in which parts of the system may be
* broken. In particular, it is not acceptable for Error to
* call GetBlock, since the error condition may be that the
* system is out of memory, in which case calling GetBlock would
* fail. The error string should be allocated dynamically,
* so that this function can be used in reentrant code.
* Note that it is critical to exit if the length bound for
* an error message is exceeded, since this error almost
* certainly corrupts the stack.
*/
void Error(string msg, ...)
{
va_list args;
char errbuf[MaxErrorMessage + 1];
string errmsg;
int errlen;
va_start(args, msg);
vsprintf(errbuf, msg, args);
va_end(args);
errlen = strlen(errbuf);
if (errlen > MaxErrorMessage) {
fprintf(stderr, "Error: Error Message too long\n");
exit(ErrorExitStatus);
}
if (_acb == NULL) {
errmsg = malloc(errlen + 1);
} else {
errmsg = _acb->allocMethod(errlen + 1);
}
if (errmsg == NULL) {
errmsg = "No memory available";
} else {
strcpy(errmsg, errbuf);
}
if (HandlerExists(&ErrorException)) {
RaiseException(&ErrorException, "ErrorException", errmsg);
} else {
fprintf(stderr, "Error: %s\n", errmsg);
exit(ErrorExitStatus);
}
}
|