/*
* Copyright (c) 2005 - 2006, Nils R. Weller
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <errno.h>
#include <ctype.h>
#include <unistd.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
#include "preprocess.h"
#include "n_libc.h"
static size_t n_xmalloc_guard;
void
n_xmalloc_set_guard(size_t nbytes) {
n_xmalloc_guard = nbytes;
}
void *
(n_xmalloc)(size_t nbytes) {
void *ret;
if ((ret = malloc(nbytes+n_xmalloc_guard)) == NULL) {
perror("malloc");
exit(EXIT_FAILURE);
}
return ret;
}
void *
(n_xrealloc)(void *block, size_t nbytes) {
void *ret;
if ((ret = realloc(block, nbytes)) == NULL) {
perror("realloc");
exit(EXIT_FAILURE);
}
return ret;
}
char *
(n_strdup)(const char *msg) {
char *ret;
size_t len = strlen(msg) + 1;
if ((ret = malloc(len)) == NULL) {
return NULL;
}
memcpy(ret, msg, len);
return ret;
}
char *
(n_xstrdup)(const char *msg) {
char *ret;
if ((ret = n_strdup(msg)) == NULL) {
perror("n_strdup");
exit(EXIT_FAILURE);
}
return ret;
}
void *
(n_memdup)(const void *data, size_t len) {
void *ret;
if ((ret = malloc(len)) == NULL) {
return NULL;
}
memcpy(ret, data, len);
return ret;
}
void *
(n_xmemdup)(const void *data, size_t len) {
void *ret;
if ((ret = n_memdup(data, len)) == NULL) {
perror("n_memdup");
exit(EXIT_FAILURE);
}
return ret;
}
void
(x_fprintf)(FILE *fd, const char *fmt, ...) {
va_list va;
int rc;
if (g_ignore_text) return;
va_start(va, fmt);
rc = vfprintf(fd, fmt, va);
va_end(va);
if (rc < 0) {
perror("vfprintf");
exit(EXIT_FAILURE);
}
}
void
(x_fflush)(FILE *fd) {
if (fflush(fd) == EOF) {
perror("fflush");
exit(EXIT_FAILURE);
}
}
void
(x_fputc)(int ch, FILE *fd) {
if (g_ignore_text && ch != '\n') {
return;
}
if (fputc(ch, fd) == EOF) {
perror("x_fputc");
exit(EXIT_FAILURE);
}
}
/*
* If some data is modified unexpectedly by someone unknown, just
* do
* ptr = debug_malloc_pages(bufsiz);
* memcpy(ptr, buf, bufsiz);
* mprotect(ptr, bufsiz, PROT_READ);
* buf = ptr;
* ... then a bus error or segfault will be caused when someone
* attempts to change buf, and gdb gives us a backtrace
*/
void *
debug_malloc_pages(size_t nbytes) {
long psize = sysconf(_SC_PAGESIZE);
size_t npages = nbytes / psize;
void *ret;
if (npages * psize < nbytes) {
++npages;
}
#ifdef MAP_ANON
ret = mmap(0, npages * psize, PROT_READ|PROT_WRITE,
MAP_ANON|MAP_SHARED, -1, 0);
if (ret == MAP_FAILED) {
perror("mmap");
exit(EXIT_FAILURE);
}
#else
puts("debug_malloc_pages() does not work on this system");
exit(1);
#endif
return ret;
}
void
(dounimpl)(const char *f, int line) {
printf("In function `%s', line %d:\n", f, line);
puts("WHOOPS! This code path should not have been executed");
puts("because it is unimplemented. Sorry about that. Rest");
puts("assured that I'll work on this soon.");
puts("");
puts("How about a game of snake in the meantime? [y/n] ");
if (isatty(1) && tolower(getchar()) == 'y') {
struct stat sbuf;
char *path;
if (stat("/usr/local/nwcc/bin/snake", &sbuf) == 0) {
path = "/usr/local/nwcc/bin/snake";
} else {
path = "./snake";
}
(void) execl(path, "snake", (char *)NULL);
perror(path);
exit(EXIT_FAILURE);
}
puts("Calling abort() ...");
abort();
}
/* XXX remove */
void
make_room(char **p, size_t *size, size_t nbytes) {
if (nbytes > *size) {
if (*size == 0) *size = 128;
else *size *= 2;
*p = n_xrealloc(*p, *size);
}
}
int n_optind;
char *n_optarg;
#define NEXT_ARG() do { \
if (++curind >= argc || \
(argv[curind][0] == '-' \
&& argv[curind][1] != 0)) { \
(void) fprintf(stderr, "No argument given for " \
"option `%s'\n", argv[curind-1]); \
return '?'; \
} \
n_optind = curind; \
} while (0)
/*
* This mostly resembles getopt() but doesn't stop processing when there is a
* non-option argument, as BSD implementations do, and supports long arguments.
*
* XXX this should probably mess with argv to make n_optind meaningful when
* normal arguments are mixed with options, as does GNU getopt()
*/
int
nw_get_arg(int argc, char **argv, struct ga_option *options,int nopts,int*idx) {
static int curind;
char *p;
char *p2 = NULL;
int i;
*idx = 0;
if (n_optind == 0) {
n_optind = 1; /* XXX ?!?! */
}
#if 0
do {
if (++curind >= argc) {
return -1;
}
p = argv[curind];
} while (*p != '-');
#endif
if (++curind >= argc) {
return -1;
}
p = argv[curind];
if (*p != '-') {
n_optarg = argv[curind];
n_optind = curind;
return '!';
}
n_optind = curind;
if (strcmp(p+1, "-") == 0) {
/* Done */
curind = argc;
return -1;
} else if (p[1] == 0) {
return '-';
} else if (p[2] == 0) {
/* Single char option */
++p;
do_single:
for (i = 0; i < nopts; ++i) {
if (options[i].ch == *p) {
if (!options[i].takesarg && p[1] != 0) {
if (*p == 'W'
|| *p == 'f'
|| *p == 'm') {
/* XXX gcc compatibility... */
return '!';
}
(void) fprintf(stderr,
"Option %c does not take an argument\n",
*p);
return '?';
}
break;
}
}
} else {
int is_long = 0;
if (*++p == '-') {
/* --long-option */
++p;
is_long = 1;
}
p2 = strchr(p, '=');
for (i = 0; i < nopts; ++i) {
if (options[i].name != NULL) {
if (p2 != NULL) {
/* -opt=val */
if (strncmp(p, options[i].name,
p2 - p) == 0) {
break;
}
} else {
if (strcmp(p, options[i].name) == 0) {
break;
}
}
}
}
if (i == nopts && !is_long) {
/*
* This may be a single-char option plus argument, as
* in;
* -lfoo equals -l foo
*/
goto do_single;
}
}
if (i == nopts) {
(void) fprintf(stderr, "Unknown option -- %s\n", argv[curind]);
return '?';
}
if (options[i].takesarg) {
if (options[i].name != NULL) {
if (p2 == NULL) {
/* Argument must be next string */
NEXT_ARG();
n_optarg = argv[curind];
} else {
n_optarg = p2+1;
}
} else {
if (p[1] != 0) {
n_optarg = p+1;
} else {
NEXT_ARG();
n_optarg = argv[curind];
}
}
} else {
n_optind = curind+1;
}
*idx = i; /* XXXX !!!!!!!!!!!!!!!!!!!! should set to -1 :-( */
if (options[i].name == NULL) {
return options[i].ch;
} else {
return '?';
}
}
/*
* gdb on IRIX usually doesn't seem to work with abort()-generated
* core dumps :-( I do not know why :-(
* :-( :-(
*/
void
irix_abort(void) {
fflush(NULL);
*(char *)0 = 0;
}
static int
search_dir(const char *path, const char *name) {
DIR *d;
struct dirent *dir;
if ((d = opendir(path)) == NULL) {
perror(path);
return -1;
}
while ((dir = readdir(d)) != NULL) {
if (strcmp(dir->d_name, name) == 0) {
/* Found command */
closedir(d);
return 0;
}
}
closedir(d);
return -1;
}
int
find_cmd(const char *name, char *output, size_t outsiz) {
char *path;
char *saved_path;
char *p;
if ((path = getenv("PATH")) == NULL) {
(void) fprintf(stderr,
"find_cmd: No PATH environment variable set!\n");
return -1;
}
saved_path = path = n_xstrdup(path);
for (;;) {
p = strchr(path, ':');
if (p != NULL) *p = 0;
if (search_dir(path, name) == 0) {
/* Found */
if (output != NULL) {
if ((strlen(path) + strlen(name) + 2)
> outsiz) {
(void) fprintf(stderr,
"find_cmd: Path too long for buffer\n");
free(saved_path);
return -1;
} else {
sprintf(output, "%s/%s", path, name);
}
}
free(saved_path);
return 0;
}
if (p == NULL) break;
else path = p + 1;
}
free(saved_path);
return -1;
}
FILE *
get_tmp_file(char *temp, char *output, char *postfix) {
FILE *ret;
int fd;
size_t i;
i = 0;
do {
sprintf(output, "%s%lu.%s", temp, (unsigned long)i++, postfix);
fd = open(output, O_CREAT | O_EXCL | O_RDWR, S_IRWXU);
} while (fd == -1 && errno == EEXIST);
if (fd == -1) {
perror(output);
return NULL;
}
if ((ret = fdopen(fd, "w+")) == NULL) {
perror("fdopen");
close(fd);
remove(output);
return NULL;
}
return ret;
}
#ifdef TEST_GET_ARG
int
main(int argc, char **argv) {
int ch;
int idx;
struct ga_option opts[] = {
{ 'x', NULL, 0 },
{ 'y', NULL, 1 },
{ 0, "zm", 1 },
{ 0, "zorg", 0 },
{ 0, "hehe", 1 }
};
int nopts = sizeof opts / sizeof opts[0];
while ((ch = nw_get_arg(argc, argv, opts, nopts, &idx)) != -1) {
switch (ch) {
case 'x':
printf("read x!\n");
break;
case 'y':
printf("read y! arg=%s\n", n_optarg);
break;
case '!':
printf("read normal argument `%s'\n", n_optarg);
break;
case '?':
if (idx) {
printf("read option %s!\n", opts[idx].name);
if (opts[idx].takesarg) {
printf("arg=%s\n", n_optarg);
}
} else {
puts("hm");
}
}
}
argc -= n_optind;
argv += n_optind;
while (argc--) {
printf("%s\n", *argv++);
}
return 0;
}
#endif
syntax highlighted by Code2HTML, v. 0.9.1