Home | History | Annotate | Line # | Download | only in patch
util.c revision 1.28
      1  1.24     joerg /*
      2  1.24     joerg  * $OpenBSD: util.c,v 1.32 2006/03/11 19:41:30 otto Exp $
      3  1.24     joerg  * $DragonFly: src/usr.bin/patch/util.c,v 1.9 2007/09/29 23:11:10 swildner Exp $
      4  1.28  christos  * $NetBSD: util.c,v 1.28 2018/06/18 18:33:31 christos Exp $
      5  1.24     joerg  */
      6  1.16    itojun 
      7  1.16    itojun /*
      8  1.24     joerg  * patch - a program to apply diffs to original files
      9  1.24     joerg  *
     10  1.24     joerg  * Copyright 1986, Larry Wall
     11  1.24     joerg  *
     12  1.16    itojun  * Redistribution and use in source and binary forms, with or without
     13  1.24     joerg  * modification, are permitted provided that the following condition is met:
     14  1.24     joerg  * 1. Redistributions of source code must retain the above copyright notice,
     15  1.24     joerg  * this condition and the following disclaimer.
     16  1.24     joerg  *
     17  1.24     joerg  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND ANY
     18  1.24     joerg  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
     19  1.24     joerg  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
     20  1.24     joerg  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
     21  1.24     joerg  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     22  1.24     joerg  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
     23  1.24     joerg  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
     24  1.24     joerg  * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     25  1.16    itojun  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     26  1.16    itojun  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     27  1.16    itojun  * SUCH DAMAGE.
     28  1.24     joerg  *
     29  1.24     joerg  * -C option added in 1998, original code by Marc Espie, based on FreeBSD
     30  1.24     joerg  * behaviour
     31  1.16    itojun  */
     32  1.16    itojun 
     33   1.5  christos #include <sys/cdefs.h>
     34  1.28  christos __RCSID("$NetBSD: util.c,v 1.28 2018/06/18 18:33:31 christos Exp $");
     35   1.2   mycroft 
     36  1.12  kristerw #include <sys/param.h>
     37  1.24     joerg #include <sys/stat.h>
     38  1.24     joerg 
     39  1.24     joerg #include <ctype.h>
     40  1.24     joerg #include <errno.h>
     41  1.24     joerg #include <fcntl.h>
     42  1.24     joerg #include <libgen.h>
     43  1.24     joerg #include <signal.h>
     44  1.24     joerg #include <stdarg.h>
     45  1.24     joerg #include <stdlib.h>
     46  1.24     joerg #include <stdio.h>
     47  1.24     joerg #include <string.h>
     48  1.24     joerg #include <unistd.h>
     49  1.12  kristerw 
     50   1.1       cgd #include "common.h"
     51   1.1       cgd #include "util.h"
     52   1.1       cgd #include "backupfile.h"
     53  1.24     joerg #include "pathnames.h"
     54  1.10  kristerw 
     55  1.24     joerg /* Rename a file, copying it if necessary. */
     56   1.1       cgd 
     57   1.1       cgd int
     58  1.24     joerg move_file(const char *from, const char *to)
     59   1.1       cgd {
     60  1.24     joerg 	int	fromfd;
     61  1.24     joerg 	ssize_t	i;
     62  1.21       skd 
     63  1.11  kristerw 	/* to stdout? */
     64   1.1       cgd 
     65  1.11  kristerw 	if (strEQ(to, "-")) {
     66   1.1       cgd #ifdef DEBUGGING
     67  1.11  kristerw 		if (debug & 4)
     68  1.11  kristerw 			say("Moving %s to stdout.\n", from);
     69   1.1       cgd #endif
     70  1.24     joerg 		fromfd = open(from, O_RDONLY);
     71  1.11  kristerw 		if (fromfd < 0)
     72  1.11  kristerw 			pfatal("internal error, can't reopen %s", from);
     73  1.24     joerg 		while ((i = read(fromfd, buf, buf_len)) > 0)
     74  1.24     joerg 			if (write(STDOUT_FILENO, buf, i) != i)
     75  1.11  kristerw 				pfatal("write failed");
     76  1.24     joerg 		close(fromfd);
     77  1.11  kristerw 		return 0;
     78  1.11  kristerw 	}
     79  1.24     joerg 	if (backup_file(to) < 0) {
     80  1.24     joerg 		say("Can't backup %s, output is in %s: %s\n", to, from,
     81  1.24     joerg 		    strerror(errno));
     82  1.24     joerg 		return -1;
     83   1.1       cgd 	}
     84   1.1       cgd #ifdef DEBUGGING
     85   1.1       cgd 	if (debug & 4)
     86  1.11  kristerw 		say("Moving %s to %s.\n", from, to);
     87   1.1       cgd #endif
     88  1.24     joerg 	if (rename(from, to) < 0) {
     89  1.24     joerg 		if (errno != EXDEV || copy_file(from, to) < 0) {
     90  1.11  kristerw 			say("Can't create %s, output is in %s: %s\n",
     91  1.11  kristerw 			    to, from, strerror(errno));
     92  1.11  kristerw 			return -1;
     93  1.11  kristerw 		}
     94   1.1       cgd 	}
     95  1.24     joerg 	return 0;
     96  1.24     joerg }
     97  1.24     joerg 
     98  1.24     joerg /* Backup the original file.  */
     99  1.24     joerg 
    100  1.24     joerg int
    101  1.24     joerg backup_file(const char *orig)
    102  1.24     joerg {
    103  1.24     joerg 	struct stat	filestat;
    104  1.24     joerg 	char		bakname[MAXPATHLEN], *s, *simplename;
    105  1.24     joerg 	dev_t		orig_device;
    106  1.24     joerg 	ino_t		orig_inode;
    107  1.24     joerg 
    108  1.24     joerg 	if (backup_type == none || stat(orig, &filestat) != 0)
    109  1.24     joerg 		return 0;			/* nothing to do */
    110  1.24     joerg 	/*
    111  1.24     joerg 	 * If the user used zero prefixes or suffixes, then
    112  1.24     joerg 	 * he doesn't want backups.  Yet we have to remove
    113  1.24     joerg 	 * orig to break possible hardlinks.
    114  1.24     joerg 	 */
    115  1.24     joerg 	if ((origprae && *origprae == 0) || *simple_backup_suffix == 0) {
    116  1.24     joerg 		unlink(orig);
    117  1.24     joerg 		return 0;
    118  1.24     joerg 	}
    119  1.24     joerg 	orig_device = filestat.st_dev;
    120  1.24     joerg 	orig_inode = filestat.st_ino;
    121  1.24     joerg 
    122  1.24     joerg 	if (origprae) {
    123  1.24     joerg 		if (strlcpy(bakname, origprae, sizeof(bakname)) >= sizeof(bakname) ||
    124  1.24     joerg 		    strlcat(bakname, orig, sizeof(bakname)) >= sizeof(bakname))
    125  1.24     joerg 			fatal("filename %s too long for buffer\n", origprae);
    126  1.24     joerg 	} else {
    127  1.24     joerg 		if ((s = find_backup_file_name(orig)) == NULL)
    128  1.24     joerg 			fatal("out of memory\n");
    129  1.24     joerg 		if (strlcpy(bakname, s, sizeof(bakname)) >= sizeof(bakname))
    130  1.24     joerg 			fatal("filename %s too long for buffer\n", s);
    131  1.24     joerg 		free(s);
    132  1.24     joerg 	}
    133  1.24     joerg 
    134  1.24     joerg 	if ((simplename = strrchr(bakname, '/')) != NULL)
    135  1.24     joerg 		simplename = simplename + 1;
    136  1.24     joerg 	else
    137  1.24     joerg 		simplename = bakname;
    138  1.24     joerg 
    139  1.24     joerg 	/*
    140  1.24     joerg 	 * Find a backup name that is not the same file. Change the
    141  1.24     joerg 	 * first lowercase char into uppercase; if that isn't
    142  1.24     joerg 	 * sufficient, chop off the first char and try again.
    143  1.24     joerg 	 */
    144  1.24     joerg 	while (stat(bakname, &filestat) == 0 &&
    145  1.24     joerg 	    orig_device == filestat.st_dev && orig_inode == filestat.st_ino) {
    146  1.24     joerg 		/* Skip initial non-lowercase chars.  */
    147  1.24     joerg 		for (s = simplename; *s && !islower((unsigned char)*s); s++)
    148  1.24     joerg 			;
    149  1.24     joerg 		if (*s)
    150  1.24     joerg 			*s = toupper((unsigned char)*s);
    151  1.24     joerg 		else
    152  1.24     joerg 			memmove(simplename, simplename + 1,
    153  1.24     joerg 			    strlen(simplename + 1) + 1);
    154  1.24     joerg 	}
    155  1.24     joerg #ifdef DEBUGGING
    156  1.24     joerg 	if (debug & 4)
    157  1.24     joerg 		say("Moving %s to %s.\n", orig, bakname);
    158  1.24     joerg #endif
    159  1.24     joerg 	if (rename(orig, bakname) < 0) {
    160  1.24     joerg 		if (errno != EXDEV || copy_file(orig, bakname) < 0)
    161  1.24     joerg 			return -1;
    162  1.24     joerg 	}
    163  1.11  kristerw 	return 0;
    164  1.11  kristerw }
    165  1.11  kristerw 
    166  1.11  kristerw /*
    167  1.11  kristerw  * Copy a file.
    168  1.11  kristerw  */
    169  1.24     joerg int
    170  1.24     joerg copy_file(const char *from, const char *to)
    171  1.11  kristerw {
    172  1.24     joerg 	int	tofd, fromfd;
    173  1.24     joerg 	ssize_t	i;
    174  1.11  kristerw 
    175  1.24     joerg 	tofd = open(to, O_CREAT|O_TRUNC|O_WRONLY, 0666);
    176  1.11  kristerw 	if (tofd < 0)
    177  1.24     joerg 		return -1;
    178  1.24     joerg 	fromfd = open(from, O_RDONLY, 0);
    179   1.1       cgd 	if (fromfd < 0)
    180  1.11  kristerw 		pfatal("internal error, can't reopen %s", from);
    181  1.24     joerg 	while ((i = read(fromfd, buf, buf_len)) > 0)
    182  1.11  kristerw 		if (write(tofd, buf, i) != i)
    183  1.11  kristerw 			pfatal("write to %s failed", to);
    184  1.24     joerg 	close(fromfd);
    185  1.24     joerg 	close(tofd);
    186  1.24     joerg 	return 0;
    187  1.12  kristerw }
    188  1.12  kristerw 
    189  1.12  kristerw /*
    190  1.24     joerg  * Allocate a unique area for a string.
    191  1.11  kristerw  */
    192   1.1       cgd char *
    193  1.24     joerg savestr(const char *s)
    194   1.1       cgd {
    195  1.24     joerg 	char	*rv;
    196   1.1       cgd 
    197  1.24     joerg 	if (!s)
    198  1.24     joerg 		s = "Oops";
    199  1.24     joerg 	rv = strdup(s);
    200  1.24     joerg 	if (rv == NULL) {
    201  1.24     joerg 		if (using_plan_a)
    202  1.24     joerg 			out_of_mem = true;
    203  1.24     joerg 		else
    204  1.24     joerg 			fatal("out of memory\n");
    205  1.24     joerg 	}
    206  1.24     joerg 	return rv;
    207   1.1       cgd }
    208   1.1       cgd 
    209  1.11  kristerw /*
    210  1.24     joerg  * Vanilla terminal output (buffered).
    211  1.11  kristerw  */
    212   1.1       cgd void
    213  1.24     joerg say(const char *fmt, ...)
    214   1.1       cgd {
    215  1.24     joerg 	va_list	ap;
    216  1.24     joerg 
    217  1.24     joerg 	va_start(ap, fmt);
    218  1.24     joerg 	vfprintf(stderr, fmt, ap);
    219  1.11  kristerw 	va_end(ap);
    220  1.24     joerg 	fflush(stderr);
    221   1.1       cgd }
    222   1.1       cgd 
    223  1.11  kristerw /*
    224  1.11  kristerw  * Terminal output, pun intended.
    225  1.11  kristerw  */
    226  1.24     joerg void
    227  1.24     joerg fatal(const char *fmt, ...)
    228   1.1       cgd {
    229  1.24     joerg 	va_list	ap;
    230  1.24     joerg 
    231  1.24     joerg 	va_start(ap, fmt);
    232  1.11  kristerw 	fprintf(stderr, "patch: **** ");
    233  1.24     joerg 	vfprintf(stderr, fmt, ap);
    234  1.11  kristerw 	va_end(ap);
    235  1.24     joerg 	my_exit(2);
    236   1.1       cgd }
    237   1.1       cgd 
    238  1.11  kristerw /*
    239  1.24     joerg  * Say something from patch, something from the system, then silence . . .
    240  1.11  kristerw  */
    241  1.24     joerg void
    242  1.24     joerg pfatal(const char *fmt, ...)
    243   1.1       cgd {
    244  1.24     joerg 	va_list	ap;
    245  1.24     joerg 	int	errnum = errno;
    246  1.24     joerg 
    247  1.11  kristerw 	fprintf(stderr, "patch: **** ");
    248  1.24     joerg 	va_start(ap, fmt);
    249  1.24     joerg 	vfprintf(stderr, fmt, ap);
    250  1.24     joerg 	va_end(ap);
    251  1.11  kristerw 	fprintf(stderr, ": %s\n", strerror(errnum));
    252  1.24     joerg 	my_exit(2);
    253   1.1       cgd }
    254   1.1       cgd 
    255  1.11  kristerw /*
    256  1.24     joerg  * Get a response from the user via /dev/tty
    257  1.11  kristerw  */
    258   1.1       cgd void
    259  1.24     joerg ask(const char *fmt, ...)
    260   1.1       cgd {
    261  1.24     joerg 	va_list	ap;
    262  1.24     joerg 	ssize_t	nr = 0;
    263  1.24     joerg 	static	int ttyfd = -1;
    264  1.11  kristerw 
    265  1.24     joerg 	va_start(ap, fmt);
    266  1.24     joerg 	vfprintf(stdout, fmt, ap);
    267  1.11  kristerw 	va_end(ap);
    268  1.24     joerg 	fflush(stdout);
    269  1.24     joerg 	if (ttyfd < 0)
    270  1.24     joerg 		ttyfd = open(_PATH_TTY, O_RDONLY);
    271  1.24     joerg 	if (ttyfd >= 0) {
    272  1.24     joerg 		if ((nr = read(ttyfd, buf, buf_len)) > 0 &&
    273  1.24     joerg 		    buf[nr - 1] == '\n')
    274  1.24     joerg 			buf[nr - 1] = '\0';
    275  1.24     joerg 	}
    276  1.24     joerg 	if (ttyfd < 0 || nr <= 0) {
    277  1.24     joerg 		/* no tty or error reading, pretend user entered 'return' */
    278  1.24     joerg 		putchar('\n');
    279  1.24     joerg 		buf[0] = '\0';
    280  1.11  kristerw 	}
    281   1.1       cgd }
    282   1.1       cgd 
    283  1.11  kristerw /*
    284  1.11  kristerw  * How to handle certain events when not in a critical region.
    285  1.11  kristerw  */
    286   1.1       cgd void
    287   1.9  kristerw set_signals(int reset)
    288   1.1       cgd {
    289  1.24     joerg 	static sig_t	hupval, intval;
    290   1.1       cgd 
    291  1.11  kristerw 	if (!reset) {
    292  1.11  kristerw 		hupval = signal(SIGHUP, SIG_IGN);
    293  1.11  kristerw 		if (hupval != SIG_IGN)
    294  1.24     joerg 			hupval = my_exit;
    295  1.11  kristerw 		intval = signal(SIGINT, SIG_IGN);
    296  1.11  kristerw 		if (intval != SIG_IGN)
    297  1.24     joerg 			intval = my_exit;
    298  1.11  kristerw 	}
    299  1.24     joerg 	signal(SIGHUP, hupval);
    300  1.24     joerg 	signal(SIGINT, intval);
    301   1.1       cgd }
    302   1.1       cgd 
    303  1.11  kristerw /*
    304  1.11  kristerw  * How to handle certain events when in a critical region.
    305  1.11  kristerw  */
    306   1.1       cgd void
    307  1.24     joerg ignore_signals(void)
    308   1.1       cgd {
    309  1.24     joerg 	signal(SIGHUP, SIG_IGN);
    310  1.24     joerg 	signal(SIGINT, SIG_IGN);
    311   1.1       cgd }
    312   1.1       cgd 
    313  1.11  kristerw /*
    314  1.24     joerg  * Make sure we'll have the directories to create a file. If `striplast' is
    315  1.24     joerg  * true, ignore the last element of `filename'.
    316  1.11  kristerw  */
    317  1.24     joerg 
    318   1.1       cgd void
    319  1.24     joerg makedirs(const char *filename, bool striplast)
    320   1.1       cgd {
    321  1.24     joerg 	char	*tmpbuf;
    322  1.24     joerg 
    323  1.24     joerg 	if ((tmpbuf = strdup(filename)) == NULL)
    324  1.24     joerg 		fatal("out of memory\n");
    325  1.11  kristerw 
    326  1.24     joerg 	if (striplast) {
    327  1.24     joerg 		char	*s = strrchr(tmpbuf, '/');
    328  1.25     joerg 		if (s == NULL) {
    329  1.25     joerg 			free(tmpbuf);
    330  1.24     joerg 			return;	/* nothing to be done */
    331  1.25     joerg 		}
    332  1.24     joerg 		*s = '\0';
    333  1.24     joerg 	}
    334  1.24     joerg 	if (mkpath(tmpbuf) != 0)
    335  1.24     joerg 		pfatal("creation of %s failed", tmpbuf);
    336  1.24     joerg 	free(tmpbuf);
    337   1.1       cgd }
    338   1.1       cgd 
    339  1.11  kristerw /*
    340  1.11  kristerw  * Make filenames more reasonable.
    341  1.11  kristerw  */
    342   1.1       cgd char *
    343  1.24     joerg fetchname(const char *at, bool *exists, int strip_leading)
    344   1.1       cgd {
    345  1.24     joerg 	char		*fullname, *name, *t;
    346  1.24     joerg 	int		sleading, tab;
    347  1.24     joerg 	struct stat	filestat;
    348  1.11  kristerw 
    349  1.24     joerg 	if (at == NULL || *at == '\0')
    350  1.11  kristerw 		return NULL;
    351  1.11  kristerw 	while (isspace((unsigned char)*at))
    352  1.11  kristerw 		at++;
    353   1.1       cgd #ifdef DEBUGGING
    354  1.11  kristerw 	if (debug & 128)
    355  1.24     joerg 		say("fetchname %s %d\n", at, strip_leading);
    356   1.1       cgd #endif
    357  1.24     joerg 	/* So files can be created by diffing against /dev/null.  */
    358  1.24     joerg 	if (strnEQ(at, _PATH_DEVNULL, sizeof(_PATH_DEVNULL) - 1))
    359  1.11  kristerw 		return NULL;
    360  1.24     joerg 	name = fullname = t = savestr(at);
    361  1.11  kristerw 
    362  1.24     joerg 	tab = strchr(t, '\t') != NULL;
    363  1.24     joerg 	/* Strip off up to `strip_leading' path components and NUL terminate. */
    364  1.24     joerg 	for (sleading = strip_leading; *t != '\0' && ((tab && *t != '\t') ||
    365  1.24     joerg 	    !isspace((unsigned char)*t)); t++) {
    366  1.24     joerg 		if (t[0] == '/' && t[1] != '/' && t[1] != '\0')
    367  1.11  kristerw 			if (--sleading >= 0)
    368  1.11  kristerw 				name = t + 1;
    369  1.24     joerg 	}
    370  1.11  kristerw 	*t = '\0';
    371  1.11  kristerw 
    372  1.11  kristerw 	/*
    373  1.24     joerg 	 * If no -p option was given (957 is the default value!), we were
    374  1.24     joerg 	 * given a relative pathname, and the leading directories that we
    375  1.24     joerg 	 * just stripped off all exist, put them back on.
    376  1.11  kristerw 	 */
    377  1.11  kristerw 	if (strip_leading == 957 && name != fullname && *fullname != '/') {
    378  1.11  kristerw 		name[-1] = '\0';
    379  1.24     joerg 		if (stat(fullname, &filestat) == 0 && S_ISDIR(filestat.st_mode)) {
    380  1.11  kristerw 			name[-1] = '/';
    381  1.11  kristerw 			name = fullname;
    382  1.11  kristerw 		}
    383  1.11  kristerw 	}
    384  1.24     joerg 	name = savestr(name);
    385  1.24     joerg 	free(fullname);
    386  1.24     joerg 
    387  1.24     joerg 	*exists = stat(name, &filestat) == 0;
    388  1.24     joerg 	return name;
    389  1.24     joerg }
    390  1.24     joerg 
    391  1.24     joerg /*
    392  1.24     joerg  * Takes the name returned by fetchname and looks in RCS/SCCS directories
    393  1.24     joerg  * for a checked in version.
    394  1.24     joerg  */
    395  1.24     joerg char *
    396  1.24     joerg checked_in(char *file)
    397  1.24     joerg {
    398  1.24     joerg 	char		*filebase, *filedir, tmpbuf[MAXPATHLEN];
    399  1.24     joerg 	struct stat	filestat;
    400  1.11  kristerw 
    401  1.24     joerg 	filebase = basename(file);
    402  1.24     joerg 	filedir = dirname(file);
    403  1.24     joerg 
    404  1.24     joerg #define try(f, a1, a2, a3) \
    405  1.24     joerg (snprintf(tmpbuf, sizeof tmpbuf, f, a1, a2, a3), stat(tmpbuf, &filestat) == 0)
    406  1.24     joerg 
    407  1.24     joerg 	if (try("%s/RCS/%s%s", filedir, filebase, RCSSUFFIX) ||
    408  1.24     joerg 	    try("%s/RCS/%s%s", filedir, filebase, "") ||
    409  1.24     joerg 	    try("%s/%s%s", filedir, filebase, RCSSUFFIX) ||
    410  1.24     joerg 	    try("%s/SCCS/%s%s", filedir, SCCSPREFIX, filebase) ||
    411  1.24     joerg 	    try("%s/%s%s", filedir, SCCSPREFIX, filebase))
    412  1.24     joerg 		return file;
    413  1.24     joerg 
    414  1.24     joerg 	return NULL;
    415  1.24     joerg }
    416  1.11  kristerw 
    417  1.24     joerg void
    418  1.24     joerg version(void)
    419  1.24     joerg {
    420  1.26       wiz 	printf("Patch version 2.0-12u8-NetBSD\n");
    421  1.24     joerg 	my_exit(EXIT_SUCCESS);
    422  1.24     joerg }
    423   1.1       cgd 
    424  1.24     joerg /*
    425  1.24     joerg  * Exit with cleanup.
    426  1.24     joerg  */
    427  1.24     joerg void
    428  1.24     joerg my_exit(int status)
    429  1.24     joerg {
    430  1.24     joerg 	unlink(TMPINNAME);
    431  1.24     joerg 	if (!toutkeep)
    432  1.24     joerg 		unlink(TMPOUTNAME);
    433  1.24     joerg 	if (!trejkeep)
    434  1.24     joerg 		unlink(TMPREJNAME);
    435  1.24     joerg 	unlink(TMPPATNAME);
    436  1.24     joerg 	exit(status);
    437   1.1       cgd }
    438  1.28  christos 
    439  1.28  christos void *
    440  1.28  christos pch_realloc(void *ptr, size_t number, size_t size)
    441  1.28  christos {
    442  1.28  christos 	if (number > SIZE_MAX / size) {
    443  1.28  christos 		errno = EOVERFLOW;
    444  1.28  christos 		return NULL;
    445  1.28  christos 	}
    446  1.28  christos 	return realloc(ptr, number * size);
    447  1.28  christos }
    448