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