1 /*
2 * Copyright (c) 1991, 2002 Michael J. Roberts. All Rights Reserved.
3 *
4 * Please see the accompanying license file, LICENSE.TXT, for information
5 * on using and copying this software.
6 */
7 /*
8 Name
9 t3std.h - standard definitions
10 Function
11 Various standard definitions
12 Notes
13 None
14 Modified
15 10/17/98 MJRoberts - creation (from TADS 2 lib.h)
16 */
17
18 #ifndef T3_STD_INCLUDED
19 #define T3_STD_INCLUDED
20
21 #include <stddef.h>
22 #include <string.h>
23 #include <stdlib.h>
24 #include <stdarg.h>
25 #include <ctype.h>
26
27 #include "os.h"
28
29
30 /* short-hand for various types */
31 #ifndef OS_UCHAR_DEFINED
32 typedef unsigned char uchar;
33 #endif
34
35 #ifndef OS_USHORT_DEFINED
36 typedef unsigned short ushort;
37 #endif
38
39 #ifndef OS_UINT_DEFINED
40 typedef unsigned int uint;
41 #endif
42
43 #ifndef OS_ULONG_DEFINED
44 typedef unsigned long ulong;
45 #endif
46
47 /* maximum/minimum portable values for various types */
48 #define ULONGMAXVAL 0xffffffffUL
49 #define USHORTMAXVAL 0xffffU
50 #define UCHARMAXVAL 0xffU
51 #define SLONGMAXVAL 0x7fffffffL
52 #define SSHORTMAXVAL 0x7fff
53 #define SCHARMAXVAL 0x7f
54 #define SLONGMINVAL (-(0x7fffffff)-1)
55 #define SSHORTMINVAL (-(0x7fff)-1)
56 #define SCHARMINVAL (-(0x7f)-1)
57
58
59 /*
60 * Text character
61 */
62 typedef char textchar_t;
63
64 /*
65 * 16-bit signed/unsigned integer types
66 */
67 typedef short int16;
68 typedef unsigned short uint16;
69
70 /*
71 * 32-bit signed/unsigned integer types
72 */
73 typedef long int32;
74 typedef unsigned long uint32;
75
76 /* unsigned byte */
77 typedef unsigned char uchar;
78
79
80 /* clear a struture */
81 #define CLRSTRUCT(x) memset(&(x), 0, (size_t)sizeof(x))
82 #define CPSTRUCT(dst,src) memcpy(&(dst), &(src), (size_t)sizeof(dst))
83
84
85 /* TRUE and FALSE */
86 #ifndef TRUE
87 # define TRUE 1
88 #endif /* TRUE */
89 #ifndef FALSE
90 # define FALSE 0
91 #endif /* FALSE */
92
93
94 /* bitwise operations */
95 #define bit(va, bt) ((va) & (bt))
96 #define bis(va, bt) ((va) |= (bt))
97 #define bic(va, bt) ((va) &= ~(bt))
98
99
100 /* conditionally compile code if debugging is enabled */
101 #ifdef DEBUG
102 # define IF_DEBUG(x) x
103 #else /* DEBUG */
104 # define IF_DEBUG(x)
105 #endif /* DEBUG */
106
107 /* offset within a structure of a member of the structure */
108 #ifndef offsetof
109 # define offsetof(s_name, m_name) (size_t)&(((s_name *)0)->m_name)
110 #endif /* offsetof */
111
112 /* ------------------------------------------------------------------------ */
113 /*
114 * Allocate space for a null-terminated string and save a copy of the
115 * string
116 */
117 char *lib_copy_str(const char *str);
118 char *lib_copy_str(const char *str, size_t len);
119
120 /*
121 * allocate space for a string of a given length; we'll add in space for
122 * a null terminator
123 */
124 char *lib_alloc_str(size_t len);
125
126 /*
127 * Free a string previously allocated with lib_copy_str() or
128 * lib_alloc_str()
129 */
130 void lib_free_str(char *buf);
131
132 /* ------------------------------------------------------------------------ */
133 /*
134 * Compare two strings, ignoring differences in whitespace between the
135 * strings. Returns true if the strings are equal (other than
136 * whitespace, false if not.
137 *
138 * Note that we do not ignore the *presence* of whitespace; we only
139 * ignore differences in the amount of whitespace. For example, "login"
140 * does not equal "log_in" (underscore = whitespace for these examples
141 * only, to emphasize the spacing), because the first lacks whitespace
142 * where the second has it; but "log_in" equals "log___in", because both
143 * strings have whitespace, albeit in different amounts, in the same
144 * place, and are otherwise the same.
145 */
146 int lib_strequal_collapse_spaces(const char *a, size_t a_len,
147 const char *b, size_t b_len);
148
149
150 /* ------------------------------------------------------------------------ */
151 /*
152 * Find a version suffix in an identifier string. A version suffix
153 * starts with the given character. If we don't find the character,
154 * we'll return the default version suffix. In any case, we'll set
155 * name_len to the length of the name portion, excluding the version
156 * suffix and its leading separator.
157 *
158 * For example, with a '/' suffix, a versioned name string would look
159 * like "tads-gen/030000" - the name is "tads_gen" and the version is
160 * "030000".
161 */
162 const char *lib_find_vsn_suffix(const char *name_string, char suffix_char,
163 const char *default_vsn, size_t *name_len);
164
165
166 /* ------------------------------------------------------------------------ */
167 /*
168 * Unicode-compatible character classification functions. These
169 * functions accept any Unicode character, but classify all non-ASCII
170 * characters in the Unicode character set as unknown; hence,
171 * is_digit(ch) will always return false for any non-ASCII character,
172 * even if the character is considered a digit in the Unicode character
173 * set, and to_upper(ch) will return ch for any non-ASCII character,
174 * even if the character has a case conversion defined in the Unicode
175 * set.
176 *
177 * Use the t3_is_xxx() and t3_to_xxx() functions defined vmuni.h for
178 * classifications and conversions that operate over the entire Unicode
179 * character set.
180 */
181
182 /* determine if a character is an ASCII character */
is_ascii(wchar_t c)183 inline int is_ascii(wchar_t c) { return (((unsigned int)c) <= 127); }
184
185 /* determine if a character is an ASCII space */
is_space(wchar_t c)186 inline int is_space(wchar_t c) { return (is_ascii(c) && isspace((char)c)); }
187
188 /* determine if a character is an ASCII alphabetic character */
is_alpha(wchar_t c)189 inline int is_alpha(wchar_t c) { return (is_ascii(c) && isalpha((char)c)); }
190
191 /* determine if a character is an ASCII numeric character */
is_digit(wchar_t c)192 inline int is_digit(wchar_t c) { return (is_ascii(c) && isdigit((char)c)); }
193
194 /* determine if a character is an ASCII octal numeric character */
is_odigit(wchar_t c)195 inline int is_odigit(wchar_t c)
196 { return (is_ascii(c) && isdigit((char)c) && c <= '7'); }
197
198 /* determine if a character is an ASCII hex numeric character */
is_xdigit(wchar_t c)199 inline int is_xdigit(wchar_t c)
200 {
201 return (is_ascii(c)
202 && (isdigit((char)c)
203 || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F')));
204 }
205
206 /* get the numeric value of a decimal digit character */
value_of_digit(wchar_t c)207 inline int value_of_digit(wchar_t c)
208 {
209 return (int)(c - '0');
210 }
211
212 /* get the numeric value of an octal numeric character */
value_of_odigit(wchar_t c)213 inline int value_of_odigit(wchar_t c)
214 {
215 return (int)(c - '0');
216 }
217
218 /* get the numeric value of a hex numeric character */
value_of_xdigit(wchar_t c)219 inline int value_of_xdigit(wchar_t c)
220 {
221 /*
222 * since our internal characters are always in unicode, we can take
223 * advantage of the order of unicode characters to reduce the number
224 * of comparisons we must make here
225 */
226 return (int)(c >= 'a'
227 ? c - 'a' + 10
228 : c >= 'A' ? c - 'A' + 10
229 : c - '0');
230 }
231
232 /* determine if a character is a symbol initial character */
is_syminit(wchar_t c)233 inline int is_syminit(wchar_t c)
234 {
235 /* underscores and alphabetic characters can start symbols */
236 return (is_ascii(c) && (c == '_' || isalpha((char)c)));
237 }
238
239 /* determine if a character is a symbol non-initial character */
is_sym(wchar_t c)240 inline int is_sym(wchar_t c)
241 {
242 /* underscores, alphabetics, and digits can be in symbols */
243 return (is_ascii(c) && (c == '_' || isalpha((char)c)
244 || isdigit((char)c)));
245 }
246
247 /* determine if a character is ASCII lower-case */
is_lower(wchar_t c)248 inline int is_lower(wchar_t c) { return (is_ascii(c) && islower((char)c)); }
249
250 /* convert ASCII lower-case to upper-case */
to_upper(wchar_t c)251 inline wchar_t to_upper(wchar_t c)
252 {
253 return (is_ascii(c) ? toupper((char)c) : c);
254 }
255
256 /* ------------------------------------------------------------------------ */
257 /*
258 * sprintf and vsprintf replacements. These versions provide subsets of
259 * the full 'printf' format capabilities, but check for buffer overflow,
260 * which the standard library's sprintf functions do not.
261 */
262 void t3sprintf(char *buf, size_t buflen, const char *fmt, ...);
263 void t3vsprintf(char *buf, size_t buflen, const char *fmt, va_list args);
264
265
266 /* ------------------------------------------------------------------------ */
267 /*
268 * Basic heap allocation functions. We don't call malloc and free
269 * directly, but use our own cover functions; when we compile the system
270 * for debugging, we use diagnostic memory allocators so that we can more
271 * easily find memory mismanagement errors (such as leaks, multiple
272 * deletes, and use after deletion).
273 */
274
275 #ifdef T3_DEBUG
276
277 /*
278 * Compiling in debug mode - use our diagnostic heap functions.
279 * Override C++ operators new, new[], delete, and delete[] as well, so
280 * that we can handle those allocations through our diagnostic heap
281 * manager, too.
282 */
283
284 void *t3malloc(size_t siz);
285 void *t3realloc(void *oldptr, size_t siz);
286 void t3free(void *ptr);
287
288 void *operator new(size_t siz);
289 void *operator new[](size_t siz);
290 void operator delete(void *ptr);
291 void operator delete[](void *ptr);
292
293 /*
294 * List all allocated memory blocks - displays heap information on stdout.
295 * This can be called at program termination to detect un-freed memory
296 * blocks, the existence of which could indicate a memory leak.
297 *
298 * If cb is provided, we'll display output through the given callback
299 * function; otherwise we'll display the output directly on stderr.
300 */
301 void t3_list_memory_blocks(void (*cb)(const char *msg));
302
303 #else /* T3_DEBUG */
304
305 /*
306 * Compiling in production mode - use the system memory allocators
307 * directly. Note that we go through the osmalloc() et. al. functions
308 * rather than calling malloc() directly, so that individual ports can
309 * use customized memory management where necessary or desirable.
310 */
311 #define t3malloc(siz) (::osmalloc(siz))
312 #define t3realloc(ptr, siz) (::osrealloc(ptr, siz))
313 #define t3free(ptr) (::osfree(ptr))
314
315 #define t3_list_memory_blocks(cb)
316
317 #endif /* T3_DEBUG */
318
319
320 /* ------------------------------------------------------------------------ */
321 /*
322 * A simple array list type. We keep an underlying array of elements,
323 * automatically expanding the underlying array as needed to accomodate new
324 * elements.
325 */
326
327 /* array list element type codes */
328 #define ARRAY_LIST_ELE_INT 1
329 #define ARRAY_LIST_ELE_LONG 2
330 #define ARRAY_LIST_ELE_PTR 3
331
332 /* array list element - we can store various types here */
333 union array_list_ele_t
334 {
array_list_ele_t(int i)335 array_list_ele_t(int i) { intval = i; }
array_list_ele_t(long l)336 array_list_ele_t(long l) { longval = l; }
array_list_ele_t(void * p)337 array_list_ele_t(void *p) { ptrval = p; }
338
339 int intval;
340 long longval;
341 void *ptrval;
342
343 /* compare to a given value for equality */
equals(array_list_ele_t other,int typ)344 int equals(array_list_ele_t other, int typ)
345 {
346 return ((typ == ARRAY_LIST_ELE_INT && intval == other.intval)
347 || (typ == ARRAY_LIST_ELE_LONG && longval == other.longval)
348 || (typ == ARRAY_LIST_ELE_PTR && ptrval == other.ptrval));
349 }
350 };
351
352 /*
353 * The array list type
354 */
355 class CArrayList
356 {
357 public:
CArrayList()358 CArrayList()
359 {
360 /* we have nothing allocated yet */
361 arr_ = 0;
362 cnt_ = 0;
363
364 /* use default initial size and increment */
365 alloc_ = 16;
366 inc_siz_ = 16;
367 }
CArrayList(size_t init_cnt,size_t inc_siz)368 CArrayList(size_t init_cnt, size_t inc_siz)
369 {
370 /* we have nothing allocated yet */
371 arr_ = 0;
372 cnt_ = 0;
373
374 /* remember the initial size and increment */
375 alloc_ = init_cnt;
376 inc_siz_ = inc_siz;
377 }
378
~CArrayList()379 virtual ~CArrayList()
380 {
381 /* delete our underlying array */
382 free_mem(arr_);
383 }
384
385 /* get the number of elements in the array */
get_count()386 size_t get_count() const { return cnt_; }
387
388 /* get the element at the given index (no error checking) */
get_ele_int(size_t idx)389 int get_ele_int(size_t idx) const { return arr_[idx].intval; }
get_ele_long(size_t idx)390 long get_ele_long(size_t idx) const { return arr_[idx].longval; }
get_ele_ptr(size_t idx)391 void *get_ele_ptr(size_t idx) const { return arr_[idx].ptrval; }
392
393 /* find an element's index; returns -1 if not found */
find_ele(int i)394 int find_ele(int i) const
395 { return find_ele(array_list_ele_t(i), ARRAY_LIST_ELE_INT); }
find_ele(long l)396 int find_ele(long l) const
397 { return find_ele(array_list_ele_t(l), ARRAY_LIST_ELE_LONG); }
find_ele(void * p)398 int find_ele(void *p) const
399 { return find_ele(array_list_ele_t(p), ARRAY_LIST_ELE_PTR); }
400
401 /* find an element's index; returns -1 if not found */
find_ele(array_list_ele_t ele,int typ)402 int find_ele(array_list_ele_t ele, int typ) const
403 {
404 size_t i;
405 array_list_ele_t *p;
406
407 /* scan for the element */
408 for (i = 0, p = arr_ ; i < cnt_ ; ++i, ++p)
409 {
410 /* if this is the element, return the index */
411 if (p->equals(ele, typ))
412 return (int)i;
413 }
414
415 /* didn't find it */
416 return -1;
417 }
418
419 /* add a new element */
add_ele(int i)420 void add_ele(int i) { add_ele(array_list_ele_t(i)); }
add_ele(long l)421 void add_ele(long l) { add_ele(array_list_ele_t(l)); }
add_ele(void * p)422 void add_ele(void *p) { add_ele(array_list_ele_t(p)); }
423
424 /* add a new element */
add_ele(array_list_ele_t ele)425 void add_ele(array_list_ele_t ele)
426 {
427 /* expand the array if necessary */
428 if (arr_ == 0)
429 {
430 /* we don't have an array yet, so allocate at the initial size */
431 init();
432 }
433 if (cnt_ >= alloc_)
434 {
435 /* allocate at the new size */
436 arr_ = (array_list_ele_t *)
437 realloc_mem(arr_, alloc_ * sizeof(arr_[0]),
438 (alloc_ + inc_siz_) * sizeof(arr_[0]));
439
440 /* remember the new size */
441 alloc_ += inc_siz_;
442 }
443
444 /* add the new element */
445 arr_[cnt_++] = ele;
446 }
447
448 /* remove one element by value; returns true if found, false if not */
remove_ele(int i)449 void remove_ele(int i)
450 { remove_ele(array_list_ele_t(i), ARRAY_LIST_ELE_INT); }
remove_ele(long l)451 void remove_ele(long l)
452 { remove_ele(array_list_ele_t(l), ARRAY_LIST_ELE_LONG); }
remove_ele(void * p)453 void remove_ele(void *p)
454 { remove_ele(array_list_ele_t(p), ARRAY_LIST_ELE_PTR); }
455
456 /* remove one element by value; returns true if found, false if not */
remove_ele(array_list_ele_t ele,int typ)457 int remove_ele(array_list_ele_t ele, int typ)
458 {
459 size_t i;
460 array_list_ele_t *p;
461
462 /* scan for the element */
463 for (i = 0, p = arr_ ; i < cnt_ ; ++i, ++p)
464 {
465 /* if this is the element, remove it */
466 if (p->equals(ele, typ))
467 {
468 /* remove the element at this index */
469 remove_ele(i);
470
471 /* indicate that we found the element */
472 return TRUE;
473 }
474 }
475
476 /* we didn't find the element */
477 return FALSE;
478 }
479
480 /* remove the element at the given index */
remove_ele(size_t idx)481 void remove_ele(size_t idx)
482 {
483 array_list_ele_t *p;
484
485 /* move each following element down one slot */
486 for (p = arr_ + idx, ++idx ; idx < cnt_ ; ++idx, ++p)
487 *p = *(p + 1);
488
489 /* reduce the in-use count */
490 --cnt_;
491 }
492
493 /* clear the entire list */
clear()494 void clear() { cnt_ = 0; }
495
496 protected:
497 /*
498 * Initialize. This is called to set up the array at the initial size,
499 * stored in alloc_, when we first need memory. Note that we defer
500 * this until we actually need the memory for two reasons. First, we
501 * can't call it from the constructor, because the vtable won't be
502 * built at construction, and we need to call the virtual alloc_mem().
503 * Second, by waiting, we ensure that we won't allocate any memory if
504 * our list is never actually needed.
505 */
init()506 void init()
507 {
508 /* allocate the array */
509 arr_ = (array_list_ele_t *)alloc_mem(alloc_ * sizeof(arr_[0]));
510 }
511
512 /* memory management */
alloc_mem(size_t siz)513 virtual void *alloc_mem(size_t siz)
514 { return t3malloc(siz); }
realloc_mem(void * p,size_t oldsiz,size_t newsiz)515 virtual void *realloc_mem(void *p, size_t oldsiz, size_t newsiz)
516 { return t3realloc(p, newsiz); }
free_mem(void * p)517 virtual void free_mem(void *p)
518 { t3free(p); }
519
520 /* our array of elements */
521 array_list_ele_t *arr_;
522
523 /* number of elements allocated */
524 size_t alloc_;
525
526 /* number of elements currently in use */
527 size_t cnt_;
528
529 /* increment size */
530 size_t inc_siz_;
531 };
532
533 #endif /* T3_STD_INCLUDED */
534
535