830e037ae85482e57b155188bf2a81cadec6ce69
[become] / src / utils.c
1 /* -*-c-*-
2 *
3 * $Id: utils.c,v 1.3 1997/08/20 16:25:37 mdw Exp $
4 *
5 * Miscellaneous useful bits of code.
6 *
7 * (c) 1997 Mark Wooding
8 */
9
10 /*----- Licensing notice --------------------------------------------------*
11 *
12 * This file is part of `become'
13 *
14 * `Become' is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License as published by
16 * the Free Software Foundation; either version 2 of the License, or
17 * (at your option) any later version.
18 *
19 * `Become' is distributed in the hope that it will be useful,
20 * but WITHOUT ANY WARRANTY; without even the implied warranty of
21 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
22 * GNU General Public License for more details.
23 *
24 * You should have received a copy of the GNU General Public License
25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
27 */
28
29 /*----- Revision history --------------------------------------------------*
30 *
31 * $Log: utils.c,v $
32 * Revision 1.3 1997/08/20 16:25:37 mdw
33 * Add some simple `malloc' tracking.
34 *
35 * Revision 1.2 1997/08/04 10:24:26 mdw
36 * Sources placed under CVS control.
37 *
38 * Revision 1.1 1997/07/21 13:47:42 mdw
39 * Initial revision
40 *
41 */
42
43 /*----- Header files ------------------------------------------------------*/
44
45 /* --- ANSI headers --- */
46
47 #include <ctype.h>
48 #include <stdarg.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52
53 /* --- Local headers --- */
54
55 #include "config.h"
56 #include "utils.h"
57
58 /*----- Program name handling ---------------------------------------------*/
59
60 /* --- Static data --- */
61
62 static const char *myname = 0; /* What's my name? */
63
64 /* --- @quis@ --- *
65 *
66 * Arguments: ---
67 *
68 * Returns: Pointer to the program name.
69 *
70 * Use: Returns the program name.
71 */
72
73 const char *quis(void)
74 {
75 return (myname);
76 }
77
78 /* --- @ego@ --- *
79 *
80 * Arguments: @const char *p@ = pointer to program name
81 *
82 * Returns: ---
83 *
84 * Use: Tells the utils library what the program's name is.
85 */
86
87 #ifndef PATHSEP
88 # if defined(__riscos)
89 # define PATHSEP '.'
90 # elif defined(__unix) || defined(unix)
91 # define PATHSEP '/'
92 # else
93 # define PATHSEP '\\'
94 # endif
95 #endif
96
97 void ego(const char *p)
98 {
99 const char *q = p;
100 while (*q) {
101 if (*q++ == PATHSEP)
102 p = q;
103 }
104 myname = p;
105 }
106
107 /*----- Error reporting ---------------------------------------------------*/
108
109 /* --- @moan@ --- *
110 *
111 * Arguments: @const char *f@ = a @printf@-style format string
112 * @...@ = other arguments
113 *
114 * Returns: ---
115 *
116 * Use: Reports an error.
117 */
118
119 void moan(const char *f, ...)
120 {
121 va_list ap;
122 va_start(ap, f);
123 fprintf(stderr, "%s: ", myname);
124 vfprintf(stderr, f, ap);
125 va_end(ap);
126 putc('\n', stderr);
127 }
128
129 /* --- @die@ --- *
130 *
131 * Arguments: @const char *f@ = a @printf@-style format string
132 * @...@ = other arguments
133 *
134 * Returns: Never.
135 *
136 * Use: Reports an error and hari-kiris. Like @moan@ above, only
137 * more permanent.
138 */
139
140 void die(const char *f, ...)
141 {
142 va_list ap;
143 va_start(ap, f);
144 fprintf(stderr, "%s: ", myname);
145 vfprintf(stderr, f, ap);
146 va_end(ap);
147 putc('\n', stderr);
148 exit(EXIT_FAILURE);
149 }
150
151 /*----- Trace messages ----------------------------------------------------*/
152
153 #if defined(TRACING) || !defined(NDEBUG)
154
155 /* --- Static data --- */
156
157 static FILE *tracefp = 0; /* Where does debugging go? */
158 static unsigned int tracelvl = 0; /* How much tracing gets done? */
159
160 /* --- @trace@ --- *
161 *
162 * Arguments: @unsigned int lvl@ = trace level for output
163 * @const char *f@ = a @printf@-style format string
164 * @...@ = other arguments
165 *
166 * Returns: ---
167 *
168 * Use: Reports a message to the trace output.
169 */
170
171 void trace(unsigned int lvl, const char *f, ...)
172 {
173 va_list ap;
174 if ((lvl & tracing()) == 0)
175 return;
176 va_start(ap, f);
177 fprintf(tracefp, "*** %s: ", myname);
178 vfprintf(tracefp, f, ap);
179 va_end(ap);
180 putc('\n', tracefp);
181 }
182
183 /* --- @traceblk@ --- *
184 *
185 * Arguments: @unsigned int lvl@ = trace level for output
186 * @const char *hdr@ = some header string to write
187 * @const void *blk@ = pointer to a block of memory to dump
188 * @size_t sz@ = size of the block of memory
189 *
190 * Returns: ---
191 *
192 * Use: Dumps the contents of a block to the trace output.
193 */
194
195 void traceblk(unsigned int lvl, const char *hdr, const void *blk, size_t sz)
196 {
197 const unsigned char *p = blk;
198 size_t i;
199 unsigned long o = 0;
200 size_t c;
201
202 /* --- Skip if the trace level is too high --- */
203
204 if ((lvl & tracing()) == 0)
205 return;
206
207 /* --- Now start work --- */
208
209 fprintf(tracefp, "*** %s: %s\n", myname, hdr);
210
211 while (sz) {
212 fprintf(tracefp, "*** %s: %08lu : ", myname, o);
213 for (i = 0; i < 8; i++) {
214 if (i < sz)
215 fprintf(tracefp, "%02x ", p[i]);
216 else
217 fputs("** ", tracefp);
218 }
219 fputs(": ", tracefp);
220 for (i = 0; i < 8; i++) {
221 if (i < sz)
222 fputc(isprint(p[i]) ? p[i] : '.', tracefp);
223 else
224 fputc('*', tracefp);
225 }
226 fputc('\n', tracefp);
227 c = (sz >= 8) ? 8 : sz;
228 sz -= c, p += c, o += c;
229 }
230 }
231
232
233 /* --- @traceon@ --- *
234 *
235 * Arguments: @FILE *fp@ = a file to trace on
236 * @unsigned int lvl@ = trace level to set
237 *
238 * Returns: ---
239 *
240 * Use: Enables tracing to a file.
241 */
242
243 void traceon(FILE *fp, unsigned int lvl)
244 {
245 tracefp = fp;
246 if (!tracelvl)
247 tracelvl = lvl;
248 }
249
250 /* --- @tracesetlvl@ --- *
251 *
252 * Arguments: @unsigned int lvl@ = trace level to set
253 *
254 * Returns: ---
255 *
256 * Use: Sets the tracing level.
257 */
258
259 void tracesetlvl(unsigned int lvl) { tracelvl = lvl; }
260
261 /* --- @tracing@ --- *
262 *
263 * Arguments: ---
264 *
265 * Returns: Zero if not tracing, tracing level if tracing.
266 *
267 * Use: Informs the caller whether tracing is enabled.
268 */
269
270 unsigned int tracing(void) { return (tracefp ? tracelvl : 0u); }
271
272 #endif
273
274 /*----- Memory management functions ---------------------------------------*/
275
276 /* --- @xmalloc@ --- *
277 *
278 * Arguments: @size_t sz@ = size of block to allocate
279 *
280 * Returns: Pointer to allocated block.
281 *
282 * Use: Allocates memory. If the memory isn't available, we don't
283 * hang aroung long enough for a normal function return.
284 */
285
286 void *xmalloc(size_t sz)
287 {
288 void *p = malloc(sz);
289 if (!p)
290 die("not enough memory");
291 return (p);
292 }
293
294 /* --- @xstrdup@ --- *
295 *
296 * Arguments: @const char *s@ = pointer to a string
297 *
298 * Returns: Pointer to a copy of the string.
299 *
300 * Use: Copies a string (like @strdup@ would, if it existed).
301 */
302
303 char *xstrdup(const char *s)
304 {
305 size_t sz = strlen(s) + 1;
306 char *p = xmalloc(sz);
307 memcpy(p, s, sz);
308 return (p);
309 }
310
311 /* --- @xrealloc@ --- *
312 *
313 * Arguments: @void *p@ = pointer to a block of memory
314 * @size_t sz@ = new size desired for the block
315 *
316 * Returns: Pointer to the resized memory block (which is almost
317 * certainly not in the same place any more).
318 *
319 * Use: Resizes a memory block.
320 */
321
322 void *xrealloc(void *p, size_t sz)
323 {
324 p = realloc(p, sz);
325 if (!p)
326 die("not enough memory");
327 return (p);
328 }
329
330 /*----- Simple memory use tracking ----------------------------------------*/
331
332 #ifdef TRACK_MALLOC
333
334 /*#define TRACK_VERBOSE*/
335
336 /* --- A type to record a size and have a nice alignment --- */
337
338 typedef union szblock {
339 struct {
340 union szblock *next;
341 union szblock *prev;
342 size_t sz;
343 } x;
344 long double _ld;
345 void *_p;
346 } szblock;
347
348 /* --- Static data --- */
349
350 static unsigned int memused = 0;
351 static szblock *memlist;
352
353 /* --- @track_malloc@ --- *
354 *
355 * Arguments: @size_t sz@ = size requested
356 *
357 * Returns: Pointer to allocated space, or null
358 *
359 * Use: Allocates memory, and tracks how much is allocated.
360 */
361
362 void *track_malloc(size_t sz)
363 {
364 szblock *q = (malloc)(sz + sizeof(szblock));
365 if (q) {
366 memused += sz;
367 #ifdef TRACK_VERBOSE
368 printf("[%p] allocated %lu\n", (void *)(q + 1), (unsigned long)sz);
369 #endif
370 q->x.sz = sz;
371 q->x.next = memlist;
372 q->x.prev = 0;
373 if (q->x.next)
374 q->x.next->x.prev = q;
375 memlist = q;
376 return (q + 1);
377 }
378 return (0);
379 }
380
381 /* --- @track_free@ --- *
382 *
383 * Arguments: @void *p@ = pointer to an allocated block
384 *
385 * Returns: ---
386 *
387 * Use: Frees memory, and tracks how much is still allocated.
388 */
389
390 void track_free(void *p)
391 {
392 szblock *q;
393
394 if (!p)
395 return;
396 q = (szblock *)p - 1;
397 #ifdef TRACK_VERBOSE
398 printf("[%p] freed %lu\n", (void *)(q + 1), (unsigned long)q->x.sz);
399 #endif
400 if (q->x.next)
401 q->x.next->x.prev = q->x.prev;
402 if (q->x.prev)
403 q->x.prev->x.next = q->x.next;
404 else
405 memlist = q->x.next;
406 memused -= q->x.sz;
407 (free)(q);
408 }
409
410 /* --- @track_realloc@ --- *
411 *
412 * Arguments: @void *p@ = pointer to an allocated block
413 * @size_t sz@ = how big it wants to be
414 *
415 * Returns: Pointer to the new block.
416 *
417 * Use: Reallocates a block, tracking how much memory is still
418 * available.
419 */
420
421 void *track_realloc(void *p, size_t sz)
422 {
423 size_t osz;
424 szblock *q, *qq;
425 if (p) {
426 q = (szblock *)p - 1;
427 osz = q->x.sz;
428 if (q->x.next)
429 q->x.next->x.prev = q->x.prev;
430 if (q->x.prev)
431 q->x.prev->x.next = q->x.next;
432 else
433 memlist = q->x.next;
434 } else {
435 q = 0;
436 osz = 0;
437 }
438 qq = (realloc)(q, sz + sizeof(szblock));
439 if (qq) {
440 #ifdef TRACK_VERBOSE
441 printf("[%p->%p] reallocated %lu -> %lu\n",
442 (void *)(q + 1), (void *)(qq + 1),
443 (unsigned long)osz, (unsigned long)sz);
444 #endif
445 qq->x.sz = sz;
446 qq->x.next = memlist;
447 qq->x.prev = 0;
448 if (qq->x.next)
449 qq->x.next->x.prev = qq;
450 memlist = qq;
451 memused += sz - osz;
452 qq->x.sz = sz;
453 return (qq + 1);
454 }
455 return (0);
456 }
457
458 /* --- @track_memused@ --- *
459 *
460 * Arguments: ---
461 *
462 * Returns: A count of how much memory is used currently.
463 *
464 * Use: Returns the amount of memory which the @track_@-functions
465 * above have counted as being currently allocated.
466 */
467
468 unsigned long track_memused(void)
469 {
470 return (memused);
471 }
472
473 /* --- @track_memlist@ --- *
474 *
475 * Arguments: ---
476 *
477 * Returns: ---
478 *
479 * Use: Dumps a list of allocated blocks to standard output.
480 */
481
482 void track_memlist(void)
483 {
484 szblock *q = memlist;
485 printf("listing blocks:\n");
486 while (q) {
487 printf("... [%p] %lu\n", (void *)(q + 1), (unsigned long)q->x.sz);
488 q = q->x.next;
489 }
490 printf("done\n");
491 }
492
493 #endif
494
495 /*----- That's all, folks -------------------------------------------------*/