chiark / gitweb /
Complete rewrite to support class trees. Makes the behaviour of the set
[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 -------------------------------------------------*/