]> git.ipfire.org Git - thirdparty/squid.git/blame - lib/util.c
- Removed Join method. Range fields are not join-able.
[thirdparty/squid.git] / lib / util.c
CommitLineData
be335c22 1
30a4f2a8 2/*
ef9b7ce6 3 * $Id: util.c,v 1.56 1998/03/08 04:42:25 wessels Exp $
30a4f2a8 4 *
5 * DEBUG:
6 * AUTHOR: Harvest Derived
7 *
42c04c16 8 * SQUID Internet Object Cache http://squid.nlanr.net/Squid/
30a4f2a8 9 * --------------------------------------------------------
10 *
11 * Squid is the result of efforts by numerous individuals from the
12 * Internet community. Development is led by Duane Wessels of the
13 * National Laboratory for Applied Network Research and funded by
14 * the National Science Foundation.
15 *
16 * This program is free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * This program is distributed in the hope that it will be useful,
22 * but WITHOUT ANY WARRANTY; without even the implied warranty of
23 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
24 * GNU General Public License for more details.
25 *
26 * You should have received a copy of the GNU General Public License
27 * along with this program; if not, write to the Free Software
28 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
29 *
30 */
c8f322d5 31#define _etext etext
7fc9f088 32
30a4f2a8 33/*
34 * Copyright (c) 1994, 1995. All rights reserved.
35 *
36 * The Harvest software was developed by the Internet Research Task
37 * Force Research Group on Resource Discovery (IRTF-RD):
38 *
39 * Mic Bowman of Transarc Corporation.
40 * Peter Danzig of the University of Southern California.
41 * Darren R. Hardy of the University of Colorado at Boulder.
42 * Udi Manber of the University of Arizona.
43 * Michael F. Schwartz of the University of Colorado at Boulder.
44 * Duane Wessels of the University of Colorado at Boulder.
45 *
46 * This copyright notice applies to software in the Harvest
47 * ``src/'' directory only. Users should consult the individual
48 * copyright notices in the ``components/'' subdirectories for
49 * copyright information about other software bundled with the
50 * Harvest source code distribution.
51 *
52 * TERMS OF USE
53 *
54 * The Harvest software may be used and re-distributed without
55 * charge, provided that the software origin and research team are
56 * cited in any use of the system. Most commonly this is
57 * accomplished by including a link to the Harvest Home Page
58 * (http://harvest.cs.colorado.edu/) from the query page of any
59 * Broker you deploy, as well as in the query result pages. These
60 * links are generated automatically by the standard Broker
61 * software distribution.
62 *
63 * The Harvest software is provided ``as is'', without express or
64 * implied warranty, and with no support nor obligation to assist
65 * in its use, correction, modification or enhancement. We assume
66 * no liability with respect to the infringement of copyrights,
67 * trade secrets, or any patents, and are not responsible for
68 * consequential damages. Proper use of the Harvest software is
69 * entirely the responsibility of the user.
70 *
71 * DERIVATIVE WORKS
72 *
73 * Users may make derivative works from the Harvest software, subject
74 * to the following constraints:
75 *
76 * - You must include the above copyright notice and these
77 * accompanying paragraphs in all forms of derivative works,
78 * and any documentation and other materials related to such
79 * distribution and use acknowledge that the software was
80 * developed at the above institutions.
81 *
82 * - You must notify IRTF-RD regarding your distribution of
83 * the derivative work.
84 *
85 * - You must clearly notify users that your are distributing
86 * a modified version and not the original Harvest software.
87 *
88 * - Any derivative product is also subject to these copyright
89 * and use restrictions.
90 *
91 * Note that the Harvest software is NOT in the public domain. We
92 * retain copyright, as specified above.
93 *
94 * HISTORY OF FREE SOFTWARE STATUS
95 *
96 * Originally we required sites to license the software in cases
97 * where they were going to build commercial products/services
98 * around Harvest. In June 1995 we changed this policy. We now
99 * allow people to use the core Harvest software (the code found in
100 * the Harvest ``src/'' directory) for free. We made this change
101 * in the interest of encouraging the widest possible deployment of
102 * the technology. The Harvest software is really a reference
103 * implementation of a set of protocols and formats, some of which
104 * we intend to standardize. We encourage commercial
105 * re-implementations of code complying to this set of standards.
106 */
0d94e9fe 107
30a4f2a8 108#include "config.h"
109
110#if HAVE_STDIO_H
090089c4 111#include <stdio.h>
30a4f2a8 112#endif
113#if HAVE_STDLIB_H
090089c4 114#include <stdlib.h>
30a4f2a8 115#endif
116#if HAVE_STRING_H
090089c4 117#include <string.h>
30a4f2a8 118#endif
673d7a4d 119#if HAVE_CTYPE_H
120#include <ctype.h>
121#endif
30a4f2a8 122#if HAVE_UNISTD_H
090089c4 123#include <unistd.h>
30a4f2a8 124#endif
88738790 125#if HAVE_GNUMALLLOC_H
126#include <gnumalloc.h>
127#elif HAVE_MALLOC_H && !defined(_SQUID_FREEBSD_) && !defined(_SQUID_NEXT_)
090089c4 128#include <malloc.h>
983061ed 129#endif
30a4f2a8 130#if HAVE_ERRNO_H
090089c4 131#include <errno.h>
30a4f2a8 132#endif
02922e76 133#if HAVE_MATH_H
134#include <math.h>
135#endif
090089c4 136
473471f2 137#include "util.h"
5e2e108b 138#include "snprintf.h"
30a4f2a8 139
f5b8bbc4 140void (*failure_notify) (const char *) = NULL;
090089c4 141static char msg[128];
142
35570558 143extern int sys_nerr;
35570558 144
36a97e19 145#if MEM_GEN_TRACE
146
3213655a 147static FILE *tracefp = NULL;
36a97e19 148
149void
150log_trace_init(char *fn)
151{
3213655a 152 tracefp = fopen(fn, "a+");
153 if (!tracefp) {
154 perror("log_trace_init");
155 exit(1);
156 }
36a97e19 157}
158
159void
160log_trace_done()
161{
3213655a 162 fclose(tracefp);
163 tracefp = NULL;
36a97e19 164}
165
166#endif
167
30a4f2a8 168#if XMALLOC_STATISTICS
169#define DBG_MAXSIZE (1024*1024)
170#define DBG_GRAIN (16)
171#define DBG_MAXINDEX (DBG_MAXSIZE/DBG_GRAIN)
172#define DBG_INDEX(sz) (sz<DBG_MAXSIZE?(sz+DBG_GRAIN-1)/DBG_GRAIN:DBG_MAXINDEX)
173static int malloc_sizes[DBG_MAXINDEX + 1];
174static int dbg_stat_init = 0;
175
36a97e19 176
b8d8561b 177static void
0673c0ba 178stat_init(void)
30a4f2a8 179{
180 int i;
181 for (i = 0; i <= DBG_MAXINDEX; i++)
182 malloc_sizes[i] = 0;
183 dbg_stat_init = 1;
184}
185
b8d8561b 186static int
187malloc_stat(int sz)
30a4f2a8 188{
189 if (!dbg_stat_init)
190 stat_init();
191 return malloc_sizes[DBG_INDEX(sz)] += 1;
192}
193
b8d8561b 194void
5d3ec1a4 195malloc_statistics(void (*func) (int, int, void *), void *data)
30a4f2a8 196{
197 int i;
198 for (i = 0; i <= DBG_MAXSIZE; i += DBG_GRAIN)
199 func(i, malloc_sizes[DBG_INDEX(i)], data);
200}
201#endif /* XMALLOC_STATISTICS */
202
090089c4 203
45e93040 204
59272939 205#if XMALLOC_TRACE
33ab18e8 206char *xmalloc_file = "";
207int xmalloc_line = 0;
208char *xmalloc_func = "";
209static int xmalloc_count = 0;
210int xmalloc_trace = 0; /* Enable with -m option */
211size_t xmalloc_total = 0;
59272939 212#undef xmalloc
213#undef xfree
214#undef xxfree
215#undef xrealloc
216#undef xcalloc
217#undef xstrdup
218#endif
219
1d012b4c 220#if XMALLOC_DEBUG
68b468e5 221#define DBG_ARRY_SZ (1<<10)
222#define DBG_ARRY_BKTS (1<<8)
33ab18e8 223static void *(*malloc_ptrs)[DBG_ARRY_SZ];
8c6551ac 224static int malloc_size[DBG_ARRY_BKTS][DBG_ARRY_SZ];
59272939 225#if XMALLOC_TRACE
33ab18e8 226static char *malloc_file[DBG_ARRY_BKTS][DBG_ARRY_SZ];
227static short malloc_line[DBG_ARRY_BKTS][DBG_ARRY_SZ];
59272939 228static int malloc_count[DBG_ARRY_BKTS][DBG_ARRY_SZ];
229#endif
45e93040 230static int dbg_initd = 0;
45e93040 231
b8d8561b 232static void
0673c0ba 233check_init(void)
45e93040 234{
33ab18e8 235 int B = 0, I = 0;
236 /* calloc the ptrs so that we don't see them when hunting lost memory */
237 malloc_ptrs = calloc(DBG_ARRY_BKTS, sizeof(*malloc_ptrs));
68b468e5 238 for (B = 0; B < DBG_ARRY_BKTS; B++) {
30a4f2a8 239 for (I = 0; I < DBG_ARRY_SZ; I++) {
240 malloc_ptrs[B][I] = NULL;
241 malloc_size[B][I] = 0;
59272939 242#if XMALLOC_TRACE
243 malloc_file[B][I] = NULL;
244 malloc_line[B][I] = 0;
245 malloc_count[B][I] = 0;
246#endif
30a4f2a8 247 }
45e93040 248 }
249 dbg_initd = 1;
250}
251
b8d8561b 252static void
253check_free(void *s)
45e93040 254{
33ab18e8 255 int B, I;
8c6551ac 256 B = (((int) s) >> 4) & 0xFF;
45e93040 257 for (I = 0; I < DBG_ARRY_SZ; I++) {
8c6551ac 258 if (malloc_ptrs[B][I] != s)
45e93040 259 continue;
8c6551ac 260 malloc_ptrs[B][I] = NULL;
261 malloc_size[B][I] = 0;
59272939 262#if XMALLOC_TRACE
33ab18e8 263 malloc_file[B][I] = NULL;
264 malloc_line[B][I] = 0;
265 malloc_count[B][I] = 0;
59272939 266#endif
45e93040 267 break;
268 }
269 if (I == DBG_ARRY_SZ) {
25347664 270 snprintf(msg, 128, "xfree: ERROR: s=%p not found!", s);
45e93040 271 (*failure_notify) (msg);
272 }
273}
274
b8d8561b 275static void
276check_malloc(void *p, size_t sz)
45e93040 277{
33ab18e8 278 void *P, *Q;
279 int B, I;
45e93040 280 if (!dbg_initd)
281 check_init();
7fc9f088 282 B = (((int) p) >> 4) & 0xFF;
45e93040 283 for (I = 0; I < DBG_ARRY_SZ; I++) {
33ab18e8 284 if (!(P = malloc_ptrs[B][I]))
45e93040 285 continue;
8c6551ac 286 Q = P + malloc_size[B][I];
45e93040 287 if (P <= p && p < Q) {
25347664 288 snprintf(msg, 128, "xmalloc: ERROR: p=%p falls in P=%p+%d",
8c6551ac 289 p, P, malloc_size[B][I]);
45e93040 290 (*failure_notify) (msg);
291 }
292 }
293 for (I = 0; I < DBG_ARRY_SZ; I++) {
33ab18e8 294 if (malloc_ptrs[B][I])
45e93040 295 continue;
8c6551ac 296 malloc_ptrs[B][I] = p;
297 malloc_size[B][I] = (int) sz;
59272939 298#if XMALLOC_TRACE
299 malloc_file[B][I] = xmalloc_file;
300 malloc_line[B][I] = xmalloc_line;
301 malloc_count[B][I] = xmalloc_count;
302#endif
45e93040 303 break;
304 }
305 if (I == DBG_ARRY_SZ)
306 (*failure_notify) ("xmalloc: debug out of array space!");
307}
308#endif
309
59272939 310#if XMALLOC_TRACE && !HAVE_MALLOCBLKSIZE
5e5cb0fc 311size_t
312xmallocblksize(void *p)
7fc9f088 313{
33ab18e8 314 int B, I;
7fc9f088 315 B = (((int) p) >> 4) & 0xFF;
316 for (I = 0; I < DBG_ARRY_SZ; I++) {
317 if (malloc_ptrs[B][I] == p)
318 return malloc_size[B][I];
319 }
320 return 0;
321}
322#endif
323
59272939 324#ifdef XMALLOC_TRACE
325static char *
326malloc_file_name(void *p)
327{
33ab18e8 328 int B, I;
59272939 329 B = (((int) p) >> 4) & 0xFF;
330 for (I = 0; I < DBG_ARRY_SZ; I++) {
331 if (malloc_ptrs[B][I] == p)
332 return malloc_file[B][I];
333 }
334 return 0;
335}
336int
337malloc_line_number(void *p)
338{
33ab18e8 339 int B, I;
59272939 340 B = (((int) p) >> 4) & 0xFF;
341 for (I = 0; I < DBG_ARRY_SZ; I++) {
342 if (malloc_ptrs[B][I] == p)
343 return malloc_line[B][I];
344 }
345 return 0;
346}
347int
348malloc_number(void *p)
349{
33ab18e8 350 int B, I;
59272939 351 B = (((int) p) >> 4) & 0xFF;
352 for (I = 0; I < DBG_ARRY_SZ; I++) {
353 if (malloc_ptrs[B][I] == p)
354 return malloc_count[B][I];
355 }
356 return 0;
357}
b8d8561b 358static void
33ab18e8 359xmalloc_show_trace(void *p, int sign)
68b468e5 360{
e5f4e1b0 361 int statMemoryAccounted();
0e473d70 362 static size_t last_total = 0, last_accounted = 0, last_mallinfo = 0;
0e473d70 363 size_t accounted = statMemoryAccounted();
5e5cb0fc 364 size_t mi = 0;
7fc9f088 365 size_t sz;
5e5cb0fc 366#if HAVE_MALLINFO
367 struct mallinfo mp = mallinfo();
368 mi = mp.uordblks + mp.usmblks + mp.hblkhd;
369#endif
370 sz = xmallocblksize(p) * sign;
33ab18e8 371 xmalloc_total += sz;
372 xmalloc_count += sign > 0;
373 if (xmalloc_trace) {
374 fprintf(stderr, "%c%8p size=%5d/%d acc=%5d/%d mallinfo=%5d/%d %s:%d %s",
375 sign > 0 ? '+' : '-', p,
376 (int) xmalloc_total - last_total, (int) xmalloc_total,
377 (int) accounted - last_accounted, (int) accounted,
378 (int) mi - last_mallinfo, (int) mi,
379 xmalloc_file, xmalloc_line, xmalloc_func);
380 if (sign < 0)
381 fprintf(stderr, " (%d %s:%d)\n", malloc_number(p), malloc_file_name(p), malloc_line_number(p));
382 else
383 fprintf(stderr, " %d\n", xmalloc_count);
384 }
385 last_total = xmalloc_total;
0e473d70 386 last_accounted = accounted;
387 last_mallinfo = mi;
68b468e5 388}
7ce875eb 389
390short malloc_refs[DBG_ARRY_BKTS][DBG_ARRY_SZ];
33ab18e8 391#define XMALLOC_LEAK_ALIGN (4)
7ce875eb 392static void
393xmalloc_scan_region(void *start, int size, int depth)
33ab18e8 394{
395 int B, I;
396 char *ptr = start;
397 char *end = ptr + size - XMALLOC_LEAK_ALIGN;
7ce875eb 398 static int sum = 0;
33ab18e8 399 while (ptr <= end) {
400 void *p = *(void **) ptr;
401 if (p && p != start) {
402 B = (((int) p) >> 4) & 0xFF;
403 for (I = 0; I < DBG_ARRY_SZ; I++) {
404 if (malloc_ptrs[B][I] == p) {
7ce875eb 405 if (!malloc_refs[B][I]++) {
406 /* A new reference */
407 fprintf(stderr, "%*s%p %s:%d size %d allocation %d\n",
408 depth, "",
409 malloc_ptrs[B][I], malloc_file[B][I],
410 malloc_line[B][I], malloc_size[B][I],
411 malloc_count[B][I]);
412 sum += malloc_size[B][I];
413 xmalloc_scan_region(malloc_ptrs[B][I], malloc_size[B][I], depth + 1);
414 if (depth == 0) {
415 if (sum != malloc_size[B][I])
416 fprintf(stderr, "=== %d bytes\n", sum);
417 sum = 0;
418 }
419#if XMALLOC_SHOW_ALL_REFERENCES
420 } else {
421 /* We have already scanned this pointer... */
422 fprintf(stderr, "%*s%p %s:%d size %d allocation %d ... (%d)\n",
423 depth * 2, "",
424 malloc_ptrs[B][I], malloc_file[B][I],
425 malloc_line[B][I], malloc_size[B][I],
426 malloc_count[B][I], malloc_refs[B][I]);
427#endif
428 }
33ab18e8 429 }
430 }
431 }
432 ptr += XMALLOC_LEAK_ALIGN;
433 }
33ab18e8 434}
7ce875eb 435
33ab18e8 436void
437xmalloc_find_leaks(void)
438{
439 int B, I;
33ab18e8 440 int leak_sum = 0;
c8f322d5 441
7ce875eb 442 extern void _etext;
443 fprintf(stderr, "----- Memory map ----\n");
444 xmalloc_scan_region(&_etext, (void *) sbrk(0) - (void *) &_etext, 0);
33ab18e8 445 for (B = 0; B < DBG_ARRY_BKTS; B++) {
446 for (I = 0; I < DBG_ARRY_SZ; I++) {
447 if (malloc_ptrs[B][I] && malloc_refs[B][I] == 0) {
448 /* Found a leak... */
449 fprintf(stderr, "Leak found: %p", malloc_ptrs[B][I]);
450 fprintf(stderr, " %s", malloc_file[B][I]);
451 fprintf(stderr, ":%d", malloc_line[B][I]);
7ce875eb 452 fprintf(stderr, " size %d", malloc_size[B][I]);
453 fprintf(stderr, " allocation %d\n", malloc_count[B][I]);
33ab18e8 454 leak_sum += malloc_size[B][I];
455 }
456 }
457 }
458 if (leak_sum) {
459 fprintf(stderr, "Total leaked memory: %d\n", leak_sum);
460 } else {
461 fprintf(stderr, "No memory leaks detected\n");
462 }
33ab18e8 463 fprintf(stderr, "----------------------\n");
464}
59272939 465#endif /* XMALLOC_TRACE */
68b468e5 466
090089c4 467/*
468 * xmalloc() - same as malloc(3). Used for portability.
469 * Never returns NULL; fatal on error.
470 */
b8d8561b 471void *
472xmalloc(size_t sz)
090089c4 473{
474 static void *p;
475
476 if (sz < 1)
477 sz = 1;
36a97e19 478
090089c4 479 if ((p = malloc(sz)) == NULL) {
480 if (failure_notify) {
25347664 481 snprintf(msg, 128, "xmalloc: Unable to allocate %d bytes!\n",
090089c4 482 (int) sz);
483 (*failure_notify) (msg);
484 } else {
485 perror("malloc");
486 }
487 exit(1);
488 }
1d012b4c 489#if XMALLOC_DEBUG
45e93040 490 check_malloc(p, sz);
30a4f2a8 491#endif
492#if XMALLOC_STATISTICS
493 malloc_stat(sz);
68b468e5 494#endif
59272939 495#if XMALLOC_TRACE
33ab18e8 496 xmalloc_show_trace(p, 1);
36a97e19 497#endif
498#if MEM_GEN_TRACE
3213655a 499 if (tracefp)
500 fprintf(tracefp, "m:%d:%p\n", sz, p);
45e93040 501#endif
090089c4 502 return (p);
503}
504
505/*
506 * xfree() - same as free(3). Will not call free(3) if s == NULL.
507 */
b8d8561b 508void
509xfree(void *s)
090089c4 510{
59272939 511#if XMALLOC_TRACE
33ab18e8 512 xmalloc_show_trace(s, -1);
7fc9f088 513#endif
36a97e19 514
7fc9f088 515#if XMALLOC_DEBUG
516 check_free(s);
45e93040 517#endif
518 if (s != NULL)
090089c4 519 free(s);
36a97e19 520#if MEM_GEN_TRACE
3213655a 521 if (tracefp && s)
522 fprintf(tracefp, "f:%p\n", s);
36a97e19 523#endif
45e93040 524}
525
526/* xxfree() - like xfree(), but we already know s != NULL */
b8d8561b 527void
528xxfree(void *s)
45e93040 529{
59272939 530#if XMALLOC_TRACE
33ab18e8 531 xmalloc_show_trace(s, -1);
7fc9f088 532#endif
533#if XMALLOC_DEBUG
534 check_free(s);
45e93040 535#endif
536 free(s);
36a97e19 537#if MEM_GEN_TRACE
3213655a 538 if (tracefp && s)
539 fprintf(tracefp, "f:%p\n", s);
36a97e19 540#endif
090089c4 541}
542
543/*
544 * xrealloc() - same as realloc(3). Used for portability.
545 * Never returns NULL; fatal on error.
546 */
b8d8561b 547void *
548xrealloc(void *s, size_t sz)
090089c4 549{
550 static void *p;
551
59272939 552#if XMALLOC_TRACE
33ab18e8 553 xmalloc_show_trace(s, -1);
68b468e5 554#endif
555
090089c4 556 if (sz < 1)
557 sz = 1;
3213655a 558#if XMALLOC_DEBUG
559 if (s != NULL)
560 check_free(s);
561#endif
090089c4 562 if ((p = realloc(s, sz)) == NULL) {
563 if (failure_notify) {
25347664 564 snprintf(msg, 128, "xrealloc: Unable to reallocate %d bytes!\n",
090089c4 565 (int) sz);
566 (*failure_notify) (msg);
567 } else {
568 perror("realloc");
569 }
570 exit(1);
571 }
1d012b4c 572#if XMALLOC_DEBUG
ef9b7ce6 573 fprintf(stderr, "realloc: ``mallocing'' %p\n", s);
45e93040 574 check_malloc(p, sz);
30a4f2a8 575#endif
576#if XMALLOC_STATISTICS
577 malloc_stat(sz);
68b468e5 578#endif
59272939 579#if XMALLOC_TRACE
33ab18e8 580 xmalloc_show_trace(p, 1);
71a17702 581#endif
582#if MEM_GEN_TRACE
3213655a 583 if (tracefp) /* new ptr, old ptr, new size */
584 fprintf(tracefp, "r:%p:%p:%d\n", p, s, sz);
45e93040 585#endif
090089c4 586 return (p);
587}
588
589/*
590 * xcalloc() - same as calloc(3). Used for portability.
591 * Never returns NULL; fatal on error.
592 */
b8d8561b 593void *
594xcalloc(int n, size_t sz)
090089c4 595{
596 static void *p;
597
598 if (n < 1)
599 n = 1;
600 if (sz < 1)
601 sz = 1;
602 if ((p = calloc(n, sz)) == NULL) {
603 if (failure_notify) {
25347664 604 snprintf(msg, 128, "xcalloc: Unable to allocate %d blocks of %d bytes!\n",
090089c4 605 (int) n, (int) sz);
606 (*failure_notify) (msg);
607 } else {
608 perror("xcalloc");
609 }
610 exit(1);
611 }
1d012b4c 612#if XMALLOC_DEBUG
45e93040 613 check_malloc(p, sz * n);
30a4f2a8 614#endif
615#if XMALLOC_STATISTICS
616 malloc_stat(sz);
68b468e5 617#endif
59272939 618#if XMALLOC_TRACE
33ab18e8 619 xmalloc_show_trace(p, 1);
36a97e19 620#endif
621#if MEM_GEN_TRACE
3213655a 622 if (tracefp)
623 fprintf(tracefp, "c:%d:%d:%p\n", n, sz, p);
45e93040 624#endif
090089c4 625 return (p);
626}
627
628/*
629 * xstrdup() - same as strdup(3). Used for portability.
630 * Never returns NULL; fatal on error.
631 */
b8d8561b 632char *
0ee4272b 633xstrdup(const char *s)
090089c4 634{
635 static char *p = NULL;
30a4f2a8 636 size_t sz;
090089c4 637
638 if (s == NULL) {
639 if (failure_notify) {
640 (*failure_notify) ("xstrdup: tried to dup a NULL pointer!\n");
641 } else {
642 fprintf(stderr, "xstrdup: tried to dup a NULL pointer!\n");
643 }
644 exit(1);
645 }
3213655a 646 sz = strlen(s) + 1;
cb69b4c7 647 p = xmalloc(sz);
648 memcpy(p, s, sz); /* copy string, including terminating character */
649 return p;
090089c4 650}
651
090089c4 652/*
4d38fc7e 653 * xstrerror() - strerror() wrapper
090089c4 654 */
0ee4272b 655const char *
0673c0ba 656xstrerror(void)
090089c4 657{
35570558 658 static char xstrerror_buf[BUFSIZ];
35570558 659 if (errno < 0 || errno >= sys_nerr)
090089c4 660 return ("Unknown");
25347664 661 snprintf(xstrerror_buf, BUFSIZ, "(%d) %s", errno, strerror(errno));
35570558 662 return xstrerror_buf;
090089c4 663}
664
d591088d 665#if NOT_NEEDED
75cf00f4 666/*
667 * xbstrerror with argument for late notification */
668
669const char *
670xbstrerror(int err)
671{
672 static char xbstrerror_buf[BUFSIZ];
673 if (err < 0 || err >= sys_nerr)
6a54c60e 674 return ("Unknown");
25347664 675 snprintf(xbstrerror_buf, BUFSIZ, "(%d) %s", err, strerror(err));
75cf00f4 676 return xbstrerror_buf;
677}
d591088d 678#endif
75cf00f4 679
b8d8561b 680void
681Tolower(char *q)
673d7a4d 682{
683 char *s = q;
684 while (*s) {
b8d8561b 685 *s = tolower((unsigned char) *s);
686 s++;
673d7a4d 687 }
688}
9d90e665 689
690int
691tvSubMsec(struct timeval t1, struct timeval t2)
692{
693 return (t2.tv_sec - t1.tv_sec) * 1000 +
6759a5fb 694 (t2.tv_usec - t1.tv_usec) / 1000;
9d90e665 695}
d5aa0e3b 696
88738790 697int
698tvSubUsec(struct timeval t1, struct timeval t2)
699{
700 return (t2.tv_sec - t1.tv_sec) * 1000000 +
701 (t2.tv_usec - t1.tv_usec);
702}
703
260e56a3 704double
705tvSubDsec(struct timeval t1, struct timeval t2)
706{
707 return (double) (t2.tv_sec - t1.tv_sec) +
708 (double) (t2.tv_usec - t1.tv_usec) / 1000000.0;
709}
710
d5aa0e3b 711/*
712 * xstrncpy() - similar to strncpy(3) but terminates string
cb69b4c7 713 * always with '\0' if (n != 0 and dst != NULL),
714 * and doesn't do padding
d5aa0e3b 715 */
716char *
717xstrncpy(char *dst, const char *src, size_t n)
718{
cb69b4c7 719 if (!n || !dst)
c1764328 720 return dst;
cb69b4c7 721 if (src)
722 while (--n != 0 && *src != '\0')
723 *dst++ = *src++;
c1764328 724 *dst = '\0';
d5aa0e3b 725 return dst;
726}
cb69b4c7 727
728/* returns the number of leading white spaces in str; handy in skipping ws */
729size_t
730xcountws(const char *str)
731{
732 size_t count = 0;
733 if (str) {
734 while (isspace(*str)) {
735 str++;
736 count++;
737 }
738 }
739 return count;
740}
7021844c 741
742/* somewhat safer calculation of %s */
743double
744xpercent(double part, double whole)
745{
746 return xdiv(100 * part, whole);
747}
748
02922e76 749int
750xpercentInt(double part, double whole)
751{
ef9b7ce6 752 return (int) rint(xpercent(part, whole));
02922e76 753}
754
755
7021844c 756/* somewhat safer division */
757double
758xdiv(double nom, double denom)
759{
760 return (denom != 0.0) ? nom / denom : -1.0;
761}