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