chiark / gitweb /
c6e1313c96f23846566e690a28e5f84fda442bf5
[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 -------------------------------------------------*/