chiark / gitweb /
Make it build\!
[become] / src / utils.c
CommitLineData
c4f2d992 1/* -*-c-*-
2 *
c758e654 3 * $Id: utils.c,v 1.6 1998/01/12 16:46:47 mdw Exp $
c4f2d992 4 *
5 * Miscellaneous useful bits of code.
6 *
c758e654 7 * (c) 1998 Mark Wooding
c4f2d992 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 $
c758e654 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
88c62e21 36 * Flush output before and after writing memory tracking information.
37 *
38 * Revision 1.4 1997/09/08 13:43:54 mdw
d0168b65 39 * Flush tracedump file after each `interesting' write.
40 *
41 * Revision 1.3 1997/08/20 16:25:37 mdw
deab2ee8 42 * Add some simple `malloc' tracking.
43 *
03f996bd 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
c4f2d992 48 * Initial revision
49 *
50 */
51
52/*----- Header files ------------------------------------------------------*/
53
54/* --- ANSI headers --- */
55
03f996bd 56#include <ctype.h>
c4f2d992 57#include <stdarg.h>
58#include <stdio.h>
59#include <stdlib.h>
03f996bd 60#include <string.h>
c4f2d992 61
62/* --- Local headers --- */
63
64#include "config.h"
65#include "utils.h"
66
03f996bd 67/*----- Program name handling ---------------------------------------------*/
c4f2d992 68
03f996bd 69/* --- Static data --- */
c4f2d992 70
03f996bd 71static const char *myname = 0; /* What's my name? */
c4f2d992 72
73/* --- @quis@ --- *
74 *
75 * Arguments: ---
76 *
77 * Returns: Pointer to the program name.
78 *
79 * Use: Returns the program name.
80 */
81
82const 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
106void 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
128void 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
149void 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
03f996bd 160/*----- Trace messages ----------------------------------------------------*/
161
162#if defined(TRACING) || !defined(NDEBUG)
163
164/* --- Static data --- */
165
166static FILE *tracefp = 0; /* Where does debugging go? */
167static 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
180void 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);
d0168b65 190 fflush(tracefp);
03f996bd 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
205void 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 }
d0168b65 240 fflush(tracefp);
03f996bd 241}
242
03f996bd 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
253void 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
269void 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
280unsigned int tracing(void) { return (tracefp ? tracelvl : 0u); }
281
282#endif
283
c4f2d992 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
296void *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
313char *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
332void *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
deab2ee8 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
348typedef 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
360static unsigned int memused = 0;
361static 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
372void *track_malloc(size_t sz)
373{
374 szblock *q = (malloc)(sz + sizeof(szblock));
375 if (q) {
376 memused += sz;
377#ifdef TRACK_VERBOSE
88c62e21 378 fflush(0);
deab2ee8 379 printf("[%p] allocated %lu\n", (void *)(q + 1), (unsigned long)sz);
88c62e21 380 fflush(stdout);
deab2ee8 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
402void track_free(void *p)
403{
404 szblock *q;
405
406 if (!p)
407 return;
408 q = (szblock *)p - 1;
409#ifdef TRACK_VERBOSE
88c62e21 410 fflush(0);
deab2ee8 411 printf("[%p] freed %lu\n", (void *)(q + 1), (unsigned long)q->x.sz);
88c62e21 412 fflush(stdout);
deab2ee8 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
435void *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
88c62e21 455 fflush(0);
deab2ee8 456 printf("[%p->%p] reallocated %lu -> %lu\n",
457 (void *)(q + 1), (void *)(qq + 1),
458 (unsigned long)osz, (unsigned long)sz);
88c62e21 459 fflush(stdout);
deab2ee8 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
484unsigned 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
498void track_memlist(void)
499{
500 szblock *q = memlist;
88c62e21 501 fflush(0);
deab2ee8 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");
88c62e21 508 fflush(stdout);
deab2ee8 509}
510
511#endif
512
c4f2d992 513/*----- That's all, folks -------------------------------------------------*/