Flush tracedump file after each `interesting' write.
[become] / src / utils.c
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
d0168b65 3 * $Id: utils.c,v 1.4 1997/09/08 13:43:54 mdw Exp $
c4f2d992 4 *
5 * Miscellaneous useful bits of code.
6 *
7 * (c) 1997 Mark Wooding
8 */
9
03f996bd 10/*----- Licensing notice --------------------------------------------------*
c4f2d992 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
03f996bd 25 * along with `become'; if not, write to the Free Software Foundation,
26 * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
c4f2d992 27 */
28
29/*----- Revision history --------------------------------------------------*
30 *
31 * $Log: utils.c,v $
d0168b65 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
deab2ee8 36 * Add some simple `malloc' tracking.
37 *
03f996bd 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
c4f2d992 42 * Initial revision
43 *
44 */
45
46/*----- Header files ------------------------------------------------------*/
47
48/* --- ANSI headers --- */
49
03f996bd 50#include <ctype.h>
c4f2d992 51#include <stdarg.h>
52#include <stdio.h>
53#include <stdlib.h>
03f996bd 54#include <string.h>
c4f2d992 55
56/* --- Local headers --- */
57
58#include "config.h"
59#include "utils.h"
60
03f996bd 61/*----- Program name handling ---------------------------------------------*/
c4f2d992 62
03f996bd 63/* --- Static data --- */
c4f2d992 64
03f996bd 65static const char *myname = 0; /* What's my name? */
c4f2d992 66
67/* --- @quis@ --- *
68 *
69 * Arguments: ---
70 *
71 * Returns: Pointer to the program name.
72 *
73 * Use: Returns the program name.
74 */
75
76const 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
100void 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
122void 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
143void 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
03f996bd 154/*----- Trace messages ----------------------------------------------------*/
155
156#if defined(TRACING) || !defined(NDEBUG)
157
158/* --- Static data --- */
159
160static FILE *tracefp = 0; /* Where does debugging go? */
161static 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
174void 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);
d0168b65 184 fflush(tracefp);
03f996bd 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
199void 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 }
d0168b65 234 fflush(tracefp);
03f996bd 235}
236
03f996bd 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
247void 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
263void 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
274unsigned int tracing(void) { return (tracefp ? tracelvl : 0u); }
275
276#endif
277
c4f2d992 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
290void *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
307char *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
326void *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
deab2ee8 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
342typedef 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
354static unsigned int memused = 0;
355static 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
366void *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
394void 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
425void *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
472unsigned 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
486void 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
c4f2d992 499/*----- That's all, folks -------------------------------------------------*/