Sync with OpenBSD
This brings: - check for integer overflows in custom allocs - fix potential integer overflows in memory allocation - annotate regexp error messages with source string - better error handling in mkstemp/unlink/fdopen logic
This commit is contained in:
parent
dee9ff9658
commit
4d9c8bc174
@ -1,4 +1,4 @@
|
||||
# $OpenBSD: Makefile,v 1.10 2002/04/26 13:13:41 espie Exp $
|
||||
# $OpenBSD: Makefile,v 1.13 2014/05/12 19:11:19 espie Exp $
|
||||
# $FreeBSD$
|
||||
|
||||
# -DEXTENDED
|
||||
@ -15,10 +15,7 @@ NO_WMISSING_VARIABLE_DECLARATIONS=
|
||||
|
||||
SRCS= eval.c expr.c look.c main.c misc.c gnum4.c trace.c parser.y tokenizer.l
|
||||
.PATH: ${.CURDIR}/lib
|
||||
SRCS+= ohash_create_entry.c ohash_delete.c ohash_do.c ohash_entries.c \
|
||||
ohash_enum.c ohash_init.c ohash_int.h ohash_interval.c \
|
||||
ohash_lookup_interval.c ohash_lookup_memory.c ohash_qlookup.c \
|
||||
ohash_qlookupi.c
|
||||
SRCS+= ohash.c
|
||||
|
||||
tokenizer.o: parser.h
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: eval.c,v 1.70 2012/04/12 17:00:11 espie Exp $ */
|
||||
/* $OpenBSD: eval.c,v 1.73 2014/07/11 21:04:17 espie Exp $ */
|
||||
/* $NetBSD: eval.c,v 1.7 1996/11/10 21:21:29 pk Exp $ */
|
||||
|
||||
/*
|
||||
@ -267,7 +267,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
doesyscmd(argv[2]);
|
||||
break;
|
||||
case INCLTYPE:
|
||||
if (argc > 2)
|
||||
if (argc > 2) {
|
||||
if (!doincl(argv[2])) {
|
||||
if (mimic_gnu) {
|
||||
warn("%s at line %lu: include(%s)",
|
||||
@ -277,6 +277,7 @@ expand_builtin(const char *argv[], int argc, int td)
|
||||
err(1, "%s at line %lu: include(%s)",
|
||||
CURRENT_NAME, CURRENT_LINE, argv[2]);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SINCTYPE:
|
||||
@ -794,7 +795,7 @@ dom4wrap(const char *text)
|
||||
maxwraps = 16;
|
||||
else
|
||||
maxwraps *= 2;
|
||||
m4wraps = xrealloc(m4wraps, maxwraps * sizeof(*m4wraps),
|
||||
m4wraps = xreallocarray(m4wraps, maxwraps, sizeof(*m4wraps),
|
||||
"too many m4wraps");
|
||||
}
|
||||
m4wraps[wrapindex++] = xstrdup(text);
|
||||
@ -821,11 +822,10 @@ dodiv(int n)
|
||||
if (outfile[n] == NULL) {
|
||||
char fname[] = _PATH_DIVNAME;
|
||||
|
||||
if ((fd = mkstemp(fname)) < 0 ||
|
||||
(outfile[n] = fdopen(fd, "w+")) == NULL)
|
||||
err(1, "%s: cannot divert", fname);
|
||||
if (unlink(fname) == -1)
|
||||
err(1, "%s: cannot unlink", fname);
|
||||
if ((fd = mkstemp(fname)) < 0 ||
|
||||
unlink(fname) == -1 ||
|
||||
(outfile[n] = fdopen(fd, "w+")) == NULL)
|
||||
err(1, "%s: cannot divert", fname);
|
||||
}
|
||||
active = outfile[n];
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: extern.h,v 1.52 2012/04/12 17:00:11 espie Exp $ */
|
||||
/* $OpenBSD: extern.h,v 1.54 2014/05/12 19:11:19 espie Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.3 1996/01/13 23:25:24 pk Exp $ */
|
||||
|
||||
/*-
|
||||
@ -104,8 +104,10 @@ extern void pbnumbase(int, int, int);
|
||||
extern void pbunsigned(unsigned long);
|
||||
extern void pbstr(const char *);
|
||||
extern void pushback(int);
|
||||
extern void *xalloc(size_t, const char *fmt, ...);
|
||||
extern void *xrealloc(void *, size_t, const char *fmt, ...);
|
||||
extern void *xalloc(size_t, const char *, ...);
|
||||
extern void *xcalloc(size_t, size_t, const char *, ...);
|
||||
extern void *xrealloc(void *, size_t, const char *, ...);
|
||||
extern void *xreallocarray(void *, size_t, size_t, const char *, ...);
|
||||
extern char *xstrdup(const char *);
|
||||
extern void usage(void);
|
||||
extern void resizedivs(int);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: gnum4.c,v 1.42 2011/11/06 12:25:43 espie Exp $ */
|
||||
/* $OpenBSD: gnum4.c,v 1.46 2014/07/10 14:12:31 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1999 Marc Espie
|
||||
@ -196,10 +196,12 @@ static void addchars(const char *, size_t);
|
||||
static void addchar(int);
|
||||
static char *twiddle(const char *);
|
||||
static char *getstring(void);
|
||||
static void exit_regerror(int, regex_t *);
|
||||
static void do_subst(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void do_regexpindex(const char *, regex_t *, regmatch_t *);
|
||||
static void do_regexp(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void exit_regerror(int, regex_t *, const char *);
|
||||
static void do_subst(const char *, regex_t *, const char *, const char *,
|
||||
regmatch_t *);
|
||||
static void do_regexpindex(const char *, regex_t *, const char *, regmatch_t *);
|
||||
static void do_regexp(const char *, regex_t *, const char *, const char *,
|
||||
regmatch_t *);
|
||||
static void add_sub(int, const char *, regex_t *, regmatch_t *);
|
||||
static void add_replace(const char *, regex_t *, const char *, regmatch_t *);
|
||||
#define addconstantstring(s) addchars((s), sizeof(s)-1)
|
||||
@ -243,7 +245,7 @@ getstring(void)
|
||||
|
||||
|
||||
static void
|
||||
exit_regerror(int er, regex_t *re)
|
||||
exit_regerror(int er, regex_t *re, const char *source)
|
||||
{
|
||||
size_t errlen;
|
||||
char *errbuf;
|
||||
@ -252,7 +254,7 @@ exit_regerror(int er, regex_t *re)
|
||||
errbuf = xalloc(errlen,
|
||||
"malloc in regerror: %lu", (unsigned long)errlen);
|
||||
regerror(er, re, errbuf, errlen);
|
||||
m4errx(1, "regular expression error: %s.", errbuf);
|
||||
m4errx(1, "regular expression error in %s: %s.", source, errbuf);
|
||||
}
|
||||
|
||||
static void
|
||||
@ -296,7 +298,7 @@ add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm
|
||||
p++;
|
||||
continue;
|
||||
}
|
||||
if (isdigit(p[1])) {
|
||||
if (isdigit((unsigned char)p[1])) {
|
||||
add_sub(*(++p) - '0', string, re, pm);
|
||||
continue;
|
||||
}
|
||||
@ -306,7 +308,8 @@ add_replace(const char *string, regex_t *re, const char *replace, regmatch_t *pm
|
||||
}
|
||||
|
||||
static void
|
||||
do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
do_subst(const char *string, regex_t *re, const char *source,
|
||||
const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
int flags = 0;
|
||||
@ -341,12 +344,13 @@ do_subst(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
string += pm[0].rm_eo;
|
||||
}
|
||||
if (error != REG_NOMATCH)
|
||||
exit_regerror(error, re);
|
||||
exit_regerror(error, re, source);
|
||||
pbstr(string);
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
do_regexp(const char *string, regex_t *re, const char *source,
|
||||
const char *replace, regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -358,12 +362,13 @@ do_regexp(const char *string, regex_t *re, const char *replace, regmatch_t *pm)
|
||||
case REG_NOMATCH:
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re);
|
||||
exit_regerror(error, re, source);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
do_regexpindex(const char *string, regex_t *re, regmatch_t *pm)
|
||||
do_regexpindex(const char *string, regex_t *re, const char *source,
|
||||
regmatch_t *pm)
|
||||
{
|
||||
int error;
|
||||
|
||||
@ -375,7 +380,7 @@ do_regexpindex(const char *string, regex_t *re, regmatch_t *pm)
|
||||
pbnum(-1);
|
||||
break;
|
||||
default:
|
||||
exit_regerror(error, re);
|
||||
exit_regerror(error, re, source);
|
||||
}
|
||||
}
|
||||
|
||||
@ -459,6 +464,7 @@ dopatsubst(const char *argv[], int argc)
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
int mode = REG_EXTENDED;
|
||||
const char *source;
|
||||
size_t l = strlen(argv[3]);
|
||||
|
||||
if (!mimic_gnu ||
|
||||
@ -466,13 +472,14 @@ dopatsubst(const char *argv[], int argc)
|
||||
(l > 0 && argv[3][l-1] == '$'))
|
||||
mode |= REG_NEWLINE;
|
||||
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
mode);
|
||||
source = mimic_gnu ? twiddle(argv[3]) : argv[3];
|
||||
error = regcomp(&re, source, mode);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
exit_regerror(error, &re, source);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL);
|
||||
do_subst(argv[2], &re,
|
||||
pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t),
|
||||
NULL);
|
||||
do_subst(argv[2], &re, source,
|
||||
argc > 4 && argv[4] != NULL ? argv[4] : "", pmatch);
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
@ -486,6 +493,7 @@ doregexp(const char *argv[], int argc)
|
||||
int error;
|
||||
regex_t re;
|
||||
regmatch_t *pmatch;
|
||||
const char *source;
|
||||
|
||||
if (argc <= 3) {
|
||||
warnx("Too few arguments to regexp");
|
||||
@ -498,16 +506,16 @@ doregexp(const char *argv[], int argc)
|
||||
else
|
||||
pbstr(argv[4]);
|
||||
}
|
||||
error = regcomp(&re, mimic_gnu ? twiddle(argv[3]) : argv[3],
|
||||
REG_EXTENDED|REG_NEWLINE);
|
||||
source = mimic_gnu ? twiddle(argv[3]) : argv[3];
|
||||
error = regcomp(&re, source, REG_EXTENDED|REG_NEWLINE);
|
||||
if (error != 0)
|
||||
exit_regerror(error, &re);
|
||||
exit_regerror(error, &re, source);
|
||||
|
||||
pmatch = xalloc(sizeof(regmatch_t) * (re.re_nsub+1), NULL);
|
||||
pmatch = xreallocarray(NULL, re.re_nsub+1, sizeof(regmatch_t), NULL);
|
||||
if (argc == 4 || argv[4] == NULL)
|
||||
do_regexpindex(argv[2], &re, pmatch);
|
||||
do_regexpindex(argv[2], &re, source, pmatch);
|
||||
else
|
||||
do_regexp(argv[2], &re, argv[4], pmatch);
|
||||
do_regexp(argv[2], &re, source, argv[4], pmatch);
|
||||
free(pmatch);
|
||||
regfree(&re);
|
||||
}
|
||||
|
330
usr.bin/m4/lib/ohash.c
Normal file
330
usr.bin/m4/lib/ohash.c
Normal file
@ -0,0 +1,330 @@
|
||||
/* $OpenBSD: src/lib/libutil/ohash.c,v 1.1 2014/06/02 18:52:03 deraadt Exp $ */
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
#include "ohash.h"
|
||||
|
||||
struct _ohash_record {
|
||||
uint32_t hv;
|
||||
const char *p;
|
||||
};
|
||||
|
||||
#define DELETED ((const char *)h)
|
||||
#define NONE (h->size)
|
||||
|
||||
/* Don't bother changing the hash table if the change is small enough. */
|
||||
#define MINSIZE (1UL << 4)
|
||||
#define MINDELETED 4
|
||||
|
||||
static void ohash_resize(struct ohash *);
|
||||
|
||||
|
||||
/* This handles the common case of variable length keys, where the
|
||||
* key is stored at the end of the record.
|
||||
*/
|
||||
void *
|
||||
ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!*end)
|
||||
*end = start + strlen(start);
|
||||
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
|
||||
if (p) {
|
||||
memcpy(p+i->key_offset, start, *end-start);
|
||||
p[i->key_offset + (*end - start)] = '\0';
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
||||
|
||||
/* hash_delete only frees the hash structure. Use hash_first/hash_next
|
||||
* to free entries as well. */
|
||||
void
|
||||
ohash_delete(struct ohash *h)
|
||||
{
|
||||
(h->info.free)(h->t, h->info.data);
|
||||
#ifndef NDEBUG
|
||||
h->t = NULL;
|
||||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
ohash_resize(struct ohash *h)
|
||||
{
|
||||
struct _ohash_record *n;
|
||||
size_t ns;
|
||||
unsigned int j;
|
||||
unsigned int i, incr;
|
||||
|
||||
if (4 * h->deleted < h->total) {
|
||||
if (h->size >= (UINT_MAX >> 1U))
|
||||
ns = UINT_MAX;
|
||||
else
|
||||
ns = h->size << 1U;
|
||||
} else if (3 * h->deleted > 2 * h->total)
|
||||
ns = h->size >> 1U;
|
||||
else
|
||||
ns = h->size;
|
||||
if (ns < MINSIZE)
|
||||
ns = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_EXPAND++;
|
||||
STAT_HASH_SIZE += ns - h->size;
|
||||
#endif
|
||||
|
||||
n = (h->info.calloc)(ns, sizeof(struct _ohash_record), h->info.data);
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
for (j = 0; j < h->size; j++) {
|
||||
if (h->t[j].p != NULL && h->t[j].p != DELETED) {
|
||||
i = h->t[j].hv % ns;
|
||||
incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
|
||||
while (n[i].p != NULL) {
|
||||
i += incr;
|
||||
if (i >= ns)
|
||||
i -= ns;
|
||||
}
|
||||
n[i].hv = h->t[j].hv;
|
||||
n[i].p = h->t[j].p;
|
||||
}
|
||||
}
|
||||
(h->info.free)(h->t, h->info.data);
|
||||
h->t = n;
|
||||
h->size = ns;
|
||||
h->total -= h->deleted;
|
||||
h->deleted = 0;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_remove(struct ohash *h, unsigned int i)
|
||||
{
|
||||
void *result = (void *)h->t[i].p;
|
||||
|
||||
if (result == NULL || result == DELETED)
|
||||
return NULL;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES--;
|
||||
#endif
|
||||
h->t[i].p = DELETED;
|
||||
h->deleted++;
|
||||
if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
|
||||
ohash_resize(h);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_find(struct ohash *h, unsigned int i)
|
||||
{
|
||||
if (h->t[i].p == DELETED)
|
||||
return NULL;
|
||||
else
|
||||
return (void *)h->t[i].p;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_insert(struct ohash *h, unsigned int i, void *p)
|
||||
{
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
h->deleted--;
|
||||
h->t[i].p = p;
|
||||
} else {
|
||||
h->t[i].p = p;
|
||||
/* Arbitrary resize boundary. Tweak if not efficient enough. */
|
||||
if (++h->total * 4 > h->size * 3)
|
||||
ohash_resize(h);
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_entries(struct ohash *h)
|
||||
{
|
||||
return h->total - h->deleted;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_first(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
*pos = 0;
|
||||
return ohash_next(h, pos);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_next(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
for (; *pos < h->size; (*pos)++)
|
||||
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
|
||||
return (void *)h->t[(*pos)++].p;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
|
||||
{
|
||||
h->size = 1UL << size;
|
||||
if (h->size < MINSIZE)
|
||||
h->size = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_CREATION++;
|
||||
STAT_HASH_SIZE += h->size;
|
||||
#endif
|
||||
/* Copy info so that caller may free it. */
|
||||
h->info.key_offset = info->key_offset;
|
||||
h->info.calloc = info->calloc;
|
||||
h->info.free = info->free;
|
||||
h->info.alloc = info->alloc;
|
||||
h->info.data = info->data;
|
||||
h->t = (h->info.calloc)(h->size, sizeof(struct _ohash_record),
|
||||
h->info.data);
|
||||
h->total = h->deleted = 0;
|
||||
}
|
||||
|
||||
uint32_t
|
||||
ohash_interval(const char *s, const char **e)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
if (!*e)
|
||||
*e = s + strlen(s);
|
||||
if (s == *e)
|
||||
k = 0;
|
||||
else
|
||||
k = *s++;
|
||||
while (s != *e)
|
||||
k = ((k << 2) | (k >> 30)) ^ *s++;
|
||||
return k;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
|
||||
uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
strncmp(h->t[i].p+h->info.key_offset, start,
|
||||
end - start) == 0 &&
|
||||
(h->t[i].p+h->info.key_offset)[end-start] == '\0') {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
} return i;
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_qlookup(struct ohash *h, const char *s)
|
||||
{
|
||||
const char *e = NULL;
|
||||
return ohash_qlookupi(h, s, &e);
|
||||
}
|
||||
|
||||
unsigned int
|
||||
ohash_qlookupi(struct ohash *h, const char *s, const char **e)
|
||||
{
|
||||
uint32_t hv;
|
||||
|
||||
hv = ohash_interval(s, e);
|
||||
return ohash_lookup_interval(h, s, *e, hv);
|
||||
}
|
@ -1,8 +1,4 @@
|
||||
#ifndef OHASH_H
|
||||
#define OHASH_H
|
||||
/* $OpenBSD: ohash.h,v 1.8 2005/12/29 18:54:47 jaredy Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
/* $OpenBSD: src/lib/libutil/ohash.h,v 1.2 2014/06/02 18:52:03 deraadt Exp $ */
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
@ -21,21 +17,26 @@
|
||||
* $FreeBSD$
|
||||
*/
|
||||
|
||||
#ifndef OHASH_H
|
||||
#define OHASH_H
|
||||
|
||||
/* Open hashing support.
|
||||
* Open hashing was chosen because it is much lighter than other hash
|
||||
* techniques, and more efficient in most cases.
|
||||
*/
|
||||
|
||||
/* user-visible data structure */
|
||||
struct ohash_info {
|
||||
ptrdiff_t key_offset;
|
||||
void *data; /* user data */
|
||||
void *(*halloc)(size_t, void *);
|
||||
void (*hfree)(void *, size_t, void *);
|
||||
void *(*calloc)(size_t, size_t, void *);
|
||||
void (*free)(void *, void *);
|
||||
void *(*alloc)(size_t, void *);
|
||||
};
|
||||
|
||||
struct _ohash_record;
|
||||
|
||||
/* private structure. It's there just so you can do a sizeof */
|
||||
struct ohash {
|
||||
struct _ohash_record *t;
|
||||
struct ohash_info info;
|
||||
@ -55,9 +56,10 @@ void ohash_init(struct ohash *, unsigned, struct ohash_info *);
|
||||
void ohash_delete(struct ohash *);
|
||||
|
||||
unsigned int ohash_lookup_interval(struct ohash *, const char *,
|
||||
const char *, u_int32_t);
|
||||
const char *, uint32_t);
|
||||
unsigned int ohash_lookup_memory(struct ohash *, const char *,
|
||||
size_t, u_int32_t);
|
||||
size_t, uint32_t)
|
||||
__attribute__ ((__bounded__(__string__,2,3)));
|
||||
void *ohash_find(struct ohash *, unsigned int);
|
||||
void *ohash_remove(struct ohash *, unsigned int);
|
||||
void *ohash_insert(struct ohash *, unsigned int, void *);
|
||||
@ -66,10 +68,9 @@ void *ohash_next(struct ohash *, unsigned int *);
|
||||
unsigned int ohash_entries(struct ohash *);
|
||||
|
||||
void *ohash_create_entry(struct ohash_info *, const char *, const char **);
|
||||
u_int32_t ohash_interval(const char *, const char **);
|
||||
uint32_t ohash_interval(const char *, const char **);
|
||||
|
||||
unsigned int ohash_qlookupi(struct ohash *, const char *, const char **);
|
||||
unsigned int ohash_qlookup(struct ohash *, const char *);
|
||||
__END_DECLS
|
||||
#endif
|
||||
|
||||
|
@ -1,40 +0,0 @@
|
||||
/* $OpenBSD: ohash_create_entry.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
/* This handles the common case of variable length keys, where the
|
||||
* key is stored at the end of the record.
|
||||
*/
|
||||
void *
|
||||
ohash_create_entry(struct ohash_info *i, const char *start, const char **end)
|
||||
{
|
||||
char *p;
|
||||
|
||||
if (!*end)
|
||||
*end = start + strlen(start);
|
||||
p = (i->alloc)(i->key_offset + (*end - start) + 1, i->data);
|
||||
if (p) {
|
||||
memcpy(p+i->key_offset, start, *end-start);
|
||||
p[i->key_offset + (*end - start)] = '\0';
|
||||
}
|
||||
return (void *)p;
|
||||
}
|
@ -1,33 +0,0 @@
|
||||
/* $OpenBSD: ohash_delete.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
/* hash_delete only frees the hash structure. Use hash_first/hash_next
|
||||
* to free entries as well. */
|
||||
void
|
||||
ohash_delete(struct ohash *h)
|
||||
{
|
||||
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
#ifndef NDEBUG
|
||||
h->t = NULL;
|
||||
#endif
|
||||
}
|
@ -1,113 +0,0 @@
|
||||
/* $OpenBSD: ohash_do.c,v 1.4 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
static void ohash_resize(struct ohash *);
|
||||
|
||||
static void
|
||||
ohash_resize(struct ohash *h)
|
||||
{
|
||||
struct _ohash_record *n;
|
||||
unsigned int ns, j;
|
||||
unsigned int i, incr;
|
||||
|
||||
if (4 * h->deleted < h->total)
|
||||
ns = h->size << 1;
|
||||
else if (3 * h->deleted > 2 * h->total)
|
||||
ns = h->size >> 1;
|
||||
else
|
||||
ns = h->size;
|
||||
if (ns < MINSIZE)
|
||||
ns = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_EXPAND++;
|
||||
STAT_HASH_SIZE += ns - h->size;
|
||||
#endif
|
||||
n = (h->info.halloc)(sizeof(struct _ohash_record) * ns, h->info.data);
|
||||
if (!n)
|
||||
return;
|
||||
|
||||
for (j = 0; j < h->size; j++) {
|
||||
if (h->t[j].p != NULL && h->t[j].p != DELETED) {
|
||||
i = h->t[j].hv % ns;
|
||||
incr = ((h->t[j].hv % (ns - 2)) & ~1) + 1;
|
||||
while (n[i].p != NULL) {
|
||||
i += incr;
|
||||
if (i >= ns)
|
||||
i -= ns;
|
||||
}
|
||||
n[i].hv = h->t[j].hv;
|
||||
n[i].p = h->t[j].p;
|
||||
}
|
||||
}
|
||||
(h->info.hfree)(h->t, sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
h->t = n;
|
||||
h->size = ns;
|
||||
h->total -= h->deleted;
|
||||
h->deleted = 0;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_remove(struct ohash *h, unsigned int i)
|
||||
{
|
||||
void *result = __DECONST(void *, h->t[i].p);
|
||||
|
||||
if (result == NULL || result == DELETED)
|
||||
return NULL;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES--;
|
||||
#endif
|
||||
h->t[i].p = DELETED;
|
||||
h->deleted++;
|
||||
if (h->deleted >= MINDELETED && 4 * h->deleted > h->total)
|
||||
ohash_resize(h);
|
||||
return result;
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_find(struct ohash *h, unsigned int i)
|
||||
{
|
||||
if (h->t[i].p == DELETED)
|
||||
return NULL;
|
||||
else
|
||||
return __DECONST(void *, h->t[i].p);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_insert(struct ohash *h, unsigned int i, void *p)
|
||||
{
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_ENTRIES++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
h->deleted--;
|
||||
h->t[i].p = p;
|
||||
} else {
|
||||
h->t[i].p = p;
|
||||
/* Arbitrary resize boundary. Tweak if not efficient enough. */
|
||||
if (++h->total * 4 > h->size * 3)
|
||||
ohash_resize(h);
|
||||
}
|
||||
return p;
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
/* $OpenBSD: ohash_entries.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_entries(struct ohash *h)
|
||||
{
|
||||
return h->total - h->deleted;
|
||||
}
|
@ -1,38 +0,0 @@
|
||||
/* $OpenBSD: ohash_enum.c,v 1.3 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
void *
|
||||
ohash_first(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
*pos = 0;
|
||||
return ohash_next(h, pos);
|
||||
}
|
||||
|
||||
void *
|
||||
ohash_next(struct ohash *h, unsigned int *pos)
|
||||
{
|
||||
for (; *pos < h->size; (*pos)++)
|
||||
if (h->t[*pos].p != DELETED && h->t[*pos].p != NULL)
|
||||
return __DECONST(void *, h->t[(*pos)++].p);
|
||||
return NULL;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: ohash_init.3,v 1.14 2007/05/31 19:19:30 jmc Exp $
|
||||
.\" $OpenBSD: ohash_init.3,v 1.2 2014/05/13 14:01:41 jmc Exp $
|
||||
.\" Copyright (c) 1999 Marc Espie <espie@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
@ -15,8 +15,8 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.Dt OPEN_HASH 3
|
||||
.Dd May 12 2014
|
||||
.Dt OHASH_INIT 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ohash_init ,
|
||||
@ -71,11 +71,46 @@ initializes the table to store roughly 2 to the power
|
||||
.Fa size
|
||||
elements.
|
||||
.Fa info
|
||||
holds the position of the key in each record, and two pointers to
|
||||
is a pointer to a
|
||||
.Fa struct ohash_info .
|
||||
.Bd -literal -offset indent
|
||||
struct ohash_info {
|
||||
ptrdiff_t key_offset;
|
||||
void *data; /* user data */
|
||||
void *(*calloc)(size_t, size_t, void *);
|
||||
void (*free)(void *, void *);
|
||||
void *(*alloc)(size_t, void *);
|
||||
};
|
||||
.Ed
|
||||
.Pp
|
||||
The
|
||||
.Va offset
|
||||
field holds the position of the key in each record;
|
||||
the
|
||||
.Va calloc
|
||||
and
|
||||
.Va free
|
||||
fields are pointers to
|
||||
.Xr calloc 3
|
||||
and
|
||||
.Xr free 3 Ns -like
|
||||
functions, to use for managing the table internal storage.
|
||||
functions, used for managing the table internal storage;
|
||||
the
|
||||
.Va alloc
|
||||
field is only used by the utility function
|
||||
.Xr ohash_create_entry 3 .
|
||||
.Pp
|
||||
Each of these functions are called similarly to their standard counterpart,
|
||||
but with an extra
|
||||
.Ft void *
|
||||
parameter corresponding to the content of the field
|
||||
.Fa data ,
|
||||
which can be used to communicate specific information to the functions.
|
||||
.Pp
|
||||
.Fn ohash_init
|
||||
stores a copy of those fields internally, so
|
||||
.Fa info
|
||||
can be reclaimed after initialization.
|
||||
.Pp
|
||||
.Fn ohash_delete
|
||||
frees storage internal to
|
||||
@ -166,7 +201,7 @@ for (n = ohash_first(h, &i); n != NULL; n = ohash_next(h, &i))
|
||||
points to an auxiliary unsigned integer used to record the current position
|
||||
in the ohash table.
|
||||
Those functions are safe to use even while entries are added to/removed
|
||||
from the table, but in such a case they do not guarantee that new entries
|
||||
from the table, but in such a case they don't guarantee that new entries
|
||||
will be returned.
|
||||
As a special case, they can safely be used to free elements in the table.
|
||||
.Pp
|
||||
@ -179,7 +214,13 @@ Only
|
||||
.Fn ohash_remove
|
||||
and
|
||||
.Fn ohash_delete
|
||||
may call the user-supplied memory functions.
|
||||
may call the user-supplied memory functions:
|
||||
.Bd -literal -offset indent
|
||||
p = (*info->calloc)(n, sizeof_record, info->data);
|
||||
/* copy data from old to p */
|
||||
(*info->free)(old, info->data);
|
||||
.Ed
|
||||
.Pp
|
||||
It is the responsibility of the user memory allocation code to verify
|
||||
that those calls did not fail.
|
||||
.Pp
|
||||
@ -213,6 +254,7 @@ call.
|
||||
.Pp
|
||||
Multi-threaded applications should explicitly protect ohash table access.
|
||||
.Sh SEE ALSO
|
||||
.Xr hcreate 3 ,
|
||||
.Xr ohash_interval 3
|
||||
.Rs
|
||||
.%A Donald E. Knuth
|
||||
|
@ -1,43 +0,0 @@
|
||||
/* $OpenBSD: ohash_init.c,v 1.2 2004/06/22 20:00:16 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
void
|
||||
ohash_init(struct ohash *h, unsigned int size, struct ohash_info *info)
|
||||
{
|
||||
h->size = 1UL << size;
|
||||
if (h->size < MINSIZE)
|
||||
h->size = MINSIZE;
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_CREATION++;
|
||||
STAT_HASH_SIZE += h->size;
|
||||
#endif
|
||||
/* Copy info so that caller may free it. */
|
||||
h->info.key_offset = info->key_offset;
|
||||
h->info.halloc = info->halloc;
|
||||
h->info.hfree = info->hfree;
|
||||
h->info.alloc = info->alloc;
|
||||
h->info.data = info->data;
|
||||
h->t = (h->info.halloc)(sizeof(struct _ohash_record) * h->size,
|
||||
h->info.data);
|
||||
h->total = h->deleted = 0;
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
.\" $OpenBSD: ohash_interval.3,v 1.11 2007/05/31 19:19:30 jmc Exp $
|
||||
.\" $OpenBSD: ohash_interval.3,v 1.1 2014/05/12 19:09:00 espie Exp $
|
||||
.\" Copyright (c) 2001 Marc Espie <espie@openbsd.org>
|
||||
.\"
|
||||
.\" Permission to use, copy, modify, and distribute this software for any
|
||||
@ -15,8 +15,8 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd $Mdocdate: May 31 2007 $
|
||||
.Dt OPEN_HASH_HELPER 3
|
||||
.Dd June 5 2013
|
||||
.Dt OHASH_INTERVAL 3
|
||||
.Os
|
||||
.Sh NAME
|
||||
.Nm ohash_interval ,
|
||||
@ -68,7 +68,10 @@ the alloc field of
|
||||
.Fa info
|
||||
should point to a
|
||||
.Xr malloc 3 Ns -like
|
||||
function to allocate the storage.
|
||||
function to allocate the storage:
|
||||
.Bd -literal -offset indent
|
||||
p = (*info->alloc)(sz, info->data);
|
||||
.Ed
|
||||
.Pp
|
||||
.Fn ohash_qlookupi
|
||||
is a wrapper function that simply calls
|
||||
|
@ -1,38 +0,0 @@
|
||||
/* $OpenBSD: ohash_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
uint32_t
|
||||
ohash_interval(const char *s, const char **e)
|
||||
{
|
||||
uint32_t k;
|
||||
|
||||
if (!*e)
|
||||
*e = s + strlen(s);
|
||||
if (s == *e)
|
||||
k = 0;
|
||||
else
|
||||
k = *s++;
|
||||
while (s != *e)
|
||||
k = ((k << 2) | (k >> 30)) ^ *s++;
|
||||
return k;
|
||||
}
|
@ -1,70 +0,0 @@
|
||||
/* $OpenBSD: ohash_lookup_interval.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_interval(struct ohash *h, const char *start, const char *end,
|
||||
uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
strncmp(h->t[i].p+h->info.key_offset, start,
|
||||
end - start) == 0 &&
|
||||
(h->t[i].p+h->info.key_offset)[end-start] == '\0') {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
return i;
|
||||
}
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
@ -1,66 +0,0 @@
|
||||
/* $OpenBSD: ohash_lookup_memory.c,v 1.3 2006/01/16 15:52:25 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_lookup_memory(struct ohash *h, const char *k, size_t size, uint32_t hv)
|
||||
{
|
||||
unsigned int i, incr;
|
||||
unsigned int empty;
|
||||
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LOOKUP++;
|
||||
#endif
|
||||
empty = NONE;
|
||||
i = hv % h->size;
|
||||
incr = ((hv % (h->size-2)) & ~1) + 1;
|
||||
while (h->t[i].p != NULL) {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_LENGTH++;
|
||||
#endif
|
||||
if (h->t[i].p == DELETED) {
|
||||
if (empty == NONE)
|
||||
empty = i;
|
||||
} else if (h->t[i].hv == hv &&
|
||||
memcmp(h->t[i].p+h->info.key_offset, k, size) == 0) {
|
||||
if (empty != NONE) {
|
||||
h->t[empty].hv = hv;
|
||||
h->t[empty].p = h->t[i].p;
|
||||
h->t[i].p = DELETED;
|
||||
return empty;
|
||||
} else {
|
||||
#ifdef STATS_HASH
|
||||
STAT_HASH_POSITIVE++;
|
||||
#endif
|
||||
} return i;
|
||||
}
|
||||
i += incr;
|
||||
if (i >= h->size)
|
||||
i -= h->size;
|
||||
}
|
||||
|
||||
/* Found an empty position. */
|
||||
if (empty != NONE)
|
||||
i = empty;
|
||||
h->t[i].hv = hv;
|
||||
return i;
|
||||
}
|
@ -1,29 +0,0 @@
|
||||
/* $OpenBSD: ohash_qlookup.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_qlookup(struct ohash *h, const char *s)
|
||||
{
|
||||
const char *e = NULL;
|
||||
return ohash_qlookupi(h, s, &e);
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
/* $OpenBSD: ohash_qlookupi.c,v 1.2 2004/06/22 20:00:17 espie Exp $ */
|
||||
/* ex:ts=8 sw=4:
|
||||
*/
|
||||
|
||||
/* Copyright (c) 1999, 2004 Marc Espie <espie@openbsd.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
#include "ohash_int.h"
|
||||
|
||||
unsigned int
|
||||
ohash_qlookupi(struct ohash *h, const char *s, const char **e)
|
||||
{
|
||||
u_int32_t hv;
|
||||
|
||||
hv = ohash_interval(s, e);
|
||||
return ohash_lookup_interval(h, s, *e, hv);
|
||||
}
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: look.c,v 1.22 2010/09/07 19:58:09 marco Exp $ */
|
||||
/* $OpenBSD: look.c,v 1.23 2014/05/12 19:11:19 espie Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1989, 1993
|
||||
@ -51,36 +51,34 @@ __FBSDID("$FreeBSD$");
|
||||
#include "stdd.h"
|
||||
#include "extern.h"
|
||||
|
||||
static void *hash_alloc(size_t, void *);
|
||||
static void hash_free(void *, size_t, void *);
|
||||
static void *hash_calloc(size_t, size_t, void *);
|
||||
static void hash_free(void *, void *);
|
||||
static void *element_alloc(size_t, void *);
|
||||
static void setup_definition(struct macro_definition *, const char *,
|
||||
const char *);
|
||||
|
||||
static struct ohash_info macro_info = {
|
||||
offsetof(struct ndblock, name),
|
||||
NULL, hash_alloc, hash_free, element_alloc };
|
||||
NULL, hash_calloc, hash_free, element_alloc };
|
||||
|
||||
struct ohash macros;
|
||||
|
||||
/* Support routines for hash tables. */
|
||||
void *
|
||||
hash_alloc(size_t s, __unused void *u)
|
||||
hash_calloc(size_t n, size_t s, void *u __unused)
|
||||
{
|
||||
void *storage = xalloc(s, "hash alloc");
|
||||
if (storage)
|
||||
memset(storage, 0, s);
|
||||
void *storage = xcalloc(n, s, "hash alloc");
|
||||
return storage;
|
||||
}
|
||||
|
||||
void
|
||||
hash_free(void *p, __unused size_t s, __unused void *u)
|
||||
hash_free(void *p, void *u __unused)
|
||||
{
|
||||
free(p);
|
||||
}
|
||||
|
||||
void *
|
||||
element_alloc(size_t s, __unused void *u)
|
||||
element_alloc(size_t s, void *u __unused)
|
||||
{
|
||||
return xalloc(s, "element alloc");
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
.\" $NetBSD: m4.1,v 1.23 2012/04/08 22:00:39 wiz Exp $
|
||||
.\" @(#) $OpenBSD: m4.1,v 1.59 2010/10/21 13:20:51 jmc Exp $
|
||||
.\" @(#) $OpenBSD: m4.1,v 1.62 2014/04/14 07:00:47 jmc Exp $
|
||||
.\"
|
||||
.\" Copyright (c) 1989, 1993
|
||||
.\" The Regents of the University of California. All rights reserved.
|
||||
@ -33,7 +33,7 @@
|
||||
.\"
|
||||
.\" $FreeBSD$
|
||||
.\"
|
||||
.Dd October 21, 2010
|
||||
.Dd January 12 2014 $
|
||||
.Dt M4 1
|
||||
.Os
|
||||
.Sh NAME
|
||||
@ -88,9 +88,7 @@ In arguments to macros, leading unquoted space, tab, and newline
|
||||
.Pq Sq \en
|
||||
characters are ignored.
|
||||
To quote strings, use left and right single quotes
|
||||
.Po e.g.,\ \&
|
||||
.Sq "\ this is a string with a leading space"
|
||||
.Pc .
|
||||
.Pq e.g., Sq \ \&this is a string with a leading space .
|
||||
You can change the quote characters with the
|
||||
.Ic changequote
|
||||
built-in macro.
|
||||
@ -258,15 +256,17 @@ Prints the first argument on the standard error output stream.
|
||||
Passes its first argument to a shell and returns the shell's standard output.
|
||||
Note that the shell shares its standard input and standard error with
|
||||
.Nm .
|
||||
.It Fn eval expr
|
||||
.It Fn eval expr[,radix[,minimum]]
|
||||
Computes the first argument as an arithmetic expression using 32-bit
|
||||
arithmetic.
|
||||
Operators are the standard C ternary, arithmetic, logical,
|
||||
shift, relational, bitwise, and parentheses operators.
|
||||
You can specify
|
||||
octal, decimal, and hexadecimal numbers as in C.
|
||||
The second argument (if any)
|
||||
specifies the radix for the result and the third argument (if any)
|
||||
The optional second argument
|
||||
.Fa radix
|
||||
specifies the radix for the result and the optional third argument
|
||||
.Fa minimum
|
||||
specifies the minimum number of digits in the result.
|
||||
.It Fn expr expr
|
||||
This is an alias for
|
||||
@ -441,12 +441,12 @@ macro can modify the exit status.
|
||||
.Sh STANDARDS
|
||||
The
|
||||
.Nm
|
||||
utility is mostly compliant with the
|
||||
utility is compliant with the
|
||||
.St -p1003.1-2008
|
||||
specification.
|
||||
.Pp
|
||||
The flags
|
||||
.Op Fl dgIot
|
||||
.Op Fl dgIPot
|
||||
and the macros
|
||||
.Ic builtin ,
|
||||
.Ic esyscmd ,
|
||||
@ -467,9 +467,13 @@ are extensions to that specification.
|
||||
is not supposed to be a synonym for
|
||||
.Ic mkstemp ,
|
||||
but instead to be an insecure temporary file name creation function.
|
||||
The change causes no known compatibility issues.
|
||||
It is marked by
|
||||
.St -p1003.1-2008
|
||||
as being obsolescent and should not be used if portability is a concern.
|
||||
.Pp
|
||||
The output format of tracing and of
|
||||
The output format of
|
||||
.Ic traceon
|
||||
and
|
||||
.Ic dumpdef
|
||||
are not specified in any standard,
|
||||
are likely to change and should not be relied upon.
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: main.c,v 1.81 2012/04/12 17:00:11 espie Exp $ */
|
||||
/* $OpenBSD: main.c,v 1.83 2014/05/12 19:11:19 espie Exp $ */
|
||||
/* $NetBSD: main.c,v 1.12 1997/02/08 23:54:49 cgd Exp $ */
|
||||
|
||||
/*-
|
||||
@ -180,8 +180,8 @@ main(int argc, char *argv[])
|
||||
initspaces();
|
||||
STACKMAX = INITSTACKMAX;
|
||||
|
||||
mstack = (stae *)xalloc(sizeof(stae) * STACKMAX, NULL);
|
||||
sstack = (char *)xalloc(STACKMAX, NULL);
|
||||
mstack = xreallocarray(NULL, STACKMAX, sizeof(stae), NULL);
|
||||
sstack = xalloc(STACKMAX, NULL);
|
||||
|
||||
maxout = 0;
|
||||
outfile = NULL;
|
||||
@ -415,7 +415,8 @@ macro(void)
|
||||
}
|
||||
}
|
||||
} else if (t == EOF) {
|
||||
if (sp > -1 && ilevel <= 0) {
|
||||
if (!mimic_gnu /* you can puke right there */
|
||||
&& sp > -1 && ilevel <= 0) {
|
||||
warnx( "unexpected end of input, unclosed parenthesis:");
|
||||
dump_stack(paren, PARLEV);
|
||||
exit(1);
|
||||
@ -625,7 +626,7 @@ static void
|
||||
enlarge_stack(void)
|
||||
{
|
||||
STACKMAX += STACKMAX/2;
|
||||
mstack = xrealloc(mstack, sizeof(stae) * STACKMAX,
|
||||
mstack = xreallocarray(mstack, STACKMAX, sizeof(stae),
|
||||
"Evaluation stack overflow (%lu)",
|
||||
(unsigned long)STACKMAX);
|
||||
sstack = xrealloc(sstack, STACKMAX,
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $OpenBSD: misc.c,v 1.42 2010/09/07 19:58:09 marco Exp $ */
|
||||
/* $OpenBSD: misc.c,v 1.44 2014/05/12 19:11:19 espie Exp $ */
|
||||
/* $NetBSD: misc.c,v 1.6 1995/09/28 05:37:41 tls Exp $ */
|
||||
|
||||
/*
|
||||
@ -32,6 +32,7 @@
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__FBSDID("$FreeBSD$");
|
||||
|
||||
@ -40,6 +41,7 @@ __FBSDID("$FreeBSD$");
|
||||
#include <unistd.h>
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <stdint.h>
|
||||
#include <stdlib.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
@ -165,7 +167,7 @@ initspaces(void)
|
||||
strspace = xalloc(strsize+1, NULL);
|
||||
ep = strspace;
|
||||
endest = strspace+strsize;
|
||||
buf = (unsigned char *)xalloc(bufsize, NULL);
|
||||
buf = xalloc(bufsize, NULL);
|
||||
bufbase = buf;
|
||||
bp = buf;
|
||||
endpbb = buf + bufsize;
|
||||
@ -239,7 +241,7 @@ getdiv(int n)
|
||||
}
|
||||
|
||||
void
|
||||
onintr(__unused int signo)
|
||||
onintr(int signo __unused)
|
||||
{
|
||||
#define intrmessage "m4: interrupted.\n"
|
||||
write(STDERR_FILENO, intrmessage, sizeof(intrmessage)-1);
|
||||
@ -263,7 +265,7 @@ killdiv(void)
|
||||
extern char *__progname;
|
||||
|
||||
void
|
||||
m4errx(int evaluation, const char *fmt, ...)
|
||||
m4errx(int eval, const char *fmt, ...)
|
||||
{
|
||||
fprintf(stderr, "%s: ", __progname);
|
||||
fprintf(stderr, "%s at line %lu: ", CURRENT_NAME, CURRENT_LINE);
|
||||
@ -275,7 +277,7 @@ m4errx(int evaluation, const char *fmt, ...)
|
||||
va_end(ap);
|
||||
}
|
||||
fprintf(stderr, "\n");
|
||||
exit(evaluation);
|
||||
exit(eval);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -285,7 +287,7 @@ resizedivs(int n)
|
||||
{
|
||||
int i;
|
||||
|
||||
outfile = (FILE **)xrealloc(outfile, sizeof(FILE *) * n,
|
||||
outfile = xreallocarray(outfile, n, sizeof(FILE *),
|
||||
"too many diverts %d", n);
|
||||
for (i = maxout; i < n; i++)
|
||||
outfile[i] = NULL;
|
||||
@ -311,6 +313,25 @@ xalloc(size_t n, const char *fmt, ...)
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xcalloc(size_t n, size_t s, const char *fmt, ...)
|
||||
{
|
||||
void *p = calloc(n, s);
|
||||
|
||||
if (p == NULL) {
|
||||
if (fmt == NULL)
|
||||
err(1, "calloc");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
void *
|
||||
xrealloc(void *old, size_t n, const char *fmt, ...)
|
||||
{
|
||||
@ -331,6 +352,43 @@ xrealloc(void *old, size_t n, const char *fmt, ...)
|
||||
return p;
|
||||
}
|
||||
|
||||
/*
|
||||
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
|
||||
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
|
||||
*/
|
||||
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
|
||||
|
||||
static void *
|
||||
reallocarray(void *optr, size_t nmemb, size_t size)
|
||||
{
|
||||
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
|
||||
nmemb > 0 && SIZE_MAX / nmemb < size) {
|
||||
errno = ENOMEM;
|
||||
return NULL;
|
||||
}
|
||||
return realloc(optr, size * nmemb);
|
||||
}
|
||||
|
||||
void *
|
||||
xreallocarray(void *old, size_t s1, size_t s2, const char *fmt, ...)
|
||||
{
|
||||
void *p = reallocarray(old, s1, s2);
|
||||
|
||||
if (p == NULL) {
|
||||
free(old);
|
||||
if (fmt == NULL)
|
||||
err(1, "reallocarray");
|
||||
else {
|
||||
va_list va;
|
||||
|
||||
va_start(va, fmt);
|
||||
verr(1, fmt, va);
|
||||
va_end(va);
|
||||
}
|
||||
}
|
||||
return p;
|
||||
}
|
||||
|
||||
char *
|
||||
xstrdup(const char *s)
|
||||
{
|
||||
|
Loading…
Reference in New Issue
Block a user