This is utils.c in view mode; [Download] [Up]
/* * utils.c - Miscellaneous utility functions. * * Written by * Ettore Perazzoli (ettore@comm2000.it) * * This file is part of VICE, the Versatile Commodore Emulator. * See README for copyright notice. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA * 02111-1307 USA. * */ #include "vice.h" #include <ctype.h> #include <errno.h> #include <fcntl.h> #include <stdarg.h> #include <stdio.h> #include <string.h> #include <sys/stat.h> #include <sys/types.h> #include <sys/wait.h> #include <unistd.h> #ifdef HAVE_VFORK_H #include <vfork.h> #endif #ifdef __MSDOS__ #include <process.h> #include <dir.h> #include <io.h> #endif #include "utils.h" /* ------------------------------------------------------------------------- */ /* Like malloc, but abort if not enough memory is available. */ void *xmalloc(size_t size) { void *p = malloc(size); if (p == NULL) { fprintf(stderr, "Virtual memory exhausted: cannot allocate %lu bytes.\n", (unsigned long)size); exit(-1); } return p; } /* Like realloc, but abort if not enough memory is available. */ void *xrealloc(void *p, size_t size) { void *new_p = realloc(p, size); if (new_p == NULL) { fprintf(stderr, "Virtual memory exhausted: cannot allocate %lu bytes.\n", (unsigned long)size); exit(-1); } return new_p; } /* Malloc enough space for `str', copy `str' into it and return its address. */ char *stralloc(const char *str) { int l = strlen(str); char *p = (char *)xmalloc(l + 1); memcpy(p, str, l + 1); return p; } /* Malloc a new string whose contents concatenate the arguments until the first NULL pointer (max `_CONCAT_MAX_ARGS' arguments). */ char *concat(const char *s, ...) { #define _CONCAT_MAX_ARGS 128 const char *arg; char *new, *ptr; int arg_len[_CONCAT_MAX_ARGS], tot_len, num_args; int i; va_list ap; arg_len[0] = tot_len = strlen(s); va_start(ap, s); for (i = 1; i < _CONCAT_MAX_ARGS && (arg = va_arg(ap, const char *)) != NULL; i++) { arg_len[i] = strlen(arg); tot_len += arg_len[i]; } num_args = i; new = (char *) xmalloc(tot_len + 1); memcpy(new, s, arg_len[0]); ptr = new + arg_len[0]; va_start(ap, s); for (i = 1; i < num_args; i++) { memcpy(ptr, va_arg(ap, const char *), arg_len[i]); ptr += arg_len[i]; } *ptr = '\0'; va_end(ap); return new; } /* Add the first `src_size' bytes of `src' to the end of `buf', which is a malloc'ed block of `max_buf_size' bytes of which only the first `buf_size' ones are used. If the `buf' is not large enough, realloc it. Return a pointer to the new block. */ char *bufcat(char *buf, int *buf_size, int *max_buf_size, const char *src, int src_size) { #define BUFCAT_GRANULARITY 0x1000 if (*buf_size + src_size > *max_buf_size) { char *new_buf; *max_buf_size = (((*buf_size + src_size) / BUFCAT_GRANULARITY + 1) * BUFCAT_GRANULARITY); new_buf = (char *)xrealloc(buf, *max_buf_size); buf = new_buf; } memcpy(buf + *buf_size, src, src_size); *buf_size += src_size; return buf; } /* Remove spaces from start and end of string `s'. The string is not reallocated even if it becomes smaller. */ void remove_spaces(char *s) { char *p; int l = strlen(s); for (p = s; *p == ' '; p++) ; l -= (p - s); memmove(s, p, l + 1); if (l > 0) { for (p = s + l - 1; l > 0 && *p == ' '; l--, p--) ; *(p + 1) = '\0'; } } /* Set a new value to the dynamically allocated string *str. */ void string_set(char **str, const char *new_value) { if (*str == NULL) { if (new_value != NULL) *str = stralloc(new_value); } else if (new_value == NULL) { free(*str); *str = NULL; } else { *str = xrealloc(*str, strlen(new_value) + 1); strcpy(*str, new_value); } } /* ------------------------------------------------------------------------- */ int string_to_long(const char *str, const char **endptr, int base, long *result) { const char *sp, *ep; long weight, value; long sign; char last_letter = 0; /* Initialize to make compiler happy. */ char c; if (base > 10) last_letter = 'A' + base - 11; c = toupper((int) *str); if (!isspace((int)c) && !isdigit((int)c) && (base <= 10 || c > last_letter || c < 'A') && c != '+' && c != '-') return -1; if (*str == '+') { sign = +1; str++; } else if (*str == '-') { str++; sign = -1; } else sign = +1; for (sp = str; isspace((int)*sp); sp++) ; for (ep = sp; (isdigit((int)*ep) || (base > 10 && toupper((int)*ep) <= last_letter && toupper((int)*ep) >= 'A')); ep++) ; if (ep == sp) return -1; if (endptr != NULL) *endptr = (char *)ep; ep--; for (value = 0, weight = 1; ep >= sp; weight *= base, ep--) { if (base > 10 && toupper((int) *ep) >= 'A') value += weight * (toupper((int)*ep) - 'A' + 10); else value += weight * (int)(*ep - '0'); } *result = value * sign; return 0; } /* Replace every occurrence of `string' in `s' with `replacement' and return the result as a malloc'ed string. */ char *subst(const char *s, const char *string, const char *replacement) { int num_occurrences; int total_size; int s_len = strlen(s); int string_len = strlen(string); int replacement_len = strlen(replacement); const char *sp; char *dp; char *result; /* First, count the occurrences so that we avoid re-allocating every time. */ for (num_occurrences = 0, sp = s; (sp = strstr(sp, string)) != NULL; num_occurrences++, sp += string_len) ; total_size = s_len - (string_len - replacement_len) * num_occurrences + 1; result = (char *) xmalloc(total_size); sp = s; dp = result; do { char *f = strstr(sp, string); if (f == NULL) break; memcpy(dp, sp, f - sp); memcpy(dp + (f - sp), replacement, replacement_len); dp += (f - sp) + replacement_len; s_len -= (f - sp) + string_len; sp = f + string_len; num_occurrences--; } while (num_occurrences != 0); memcpy(dp, sp, s_len + 1); return result; } /* ------------------------------------------------------------------------- */ /* Return a malloc'ed backup file name for file `fname'. */ char *make_backup_filename(const char *fname) { #ifndef __MSDOS__ /* Just add a '~' to the end of the name. */ int l = strlen(fname); char *p = (char *)xmalloc(l + 2); memcpy(p, fname, l); *(p + l) = '~'; *(p + l + 1) = '\0'; return p; #else /* !__MSDOS__ */ /* FIXME: only works with 8+3 names. */ char d[MAXDRIVE], p[MAXDIR], f[MAXFILE], e[MAXEXT]; char new[MAXPATH]; fnsplit(fname, d, p, f, e); fnmerge(new, d, p, f, "BAK"); return stralloc(new); #endif /* !__MSDOS__ */ } /* Make a backup for file `fname'. */ int make_backup_file(const char *fname) { char *backup_name = make_backup_filename(fname); int retval; /* Cannot do it... */ if (backup_name == NULL) return -1; retval = rename(fname, backup_name); free(backup_name); return retval; } /* Get the current working directory as a malloc'ed string. */ char *get_current_dir(void) { static int len = 128; char *p = (char *) xmalloc(len); while (getcwd(p, len) == NULL) { if (errno == ERANGE) { len *= 2; p = (char *) xrealloc(p, len); } else return NULL; } return p; } /* ------------------------------------------------------------------------- */ /* Return the length of an open file in bytes. */ unsigned long file_length(int fd) { struct stat statbuf; if (fstat(fd, &statbuf) < 0) return -1; return statbuf.st_size; } /* Load the first `size' bytes of file named `name' into `dest'. Return 0 on success, -1 on failure. */ int load_file(const char *name, void *dest, int size) { int fd, r; fd = open(name, O_RDONLY); if (fd < 0) return -1; r = read(fd, (char *)dest, size); if (r != size) { if (r < 0) perror(name); close(fd); return -1; } else { close(fd); return 0; } } /* Write the first `size' bytes of `src' into a newly created file `name'. If `name' already exists, it is replaced by the new one. Returns 0 on success, -1 on failure. */ int save_file(const char *name, const void *src, int size) { int fd, r; fd = open(name, O_WRONLY | O_TRUNC | O_CREAT, 0666); if (fd < 0) return -1; r = write(fd, (char *)src, size); if (r != size) { if (r < 0) perror(name); close(fd); return -1; } else { close(fd); return 0; } } /* Input one line from the file descriptor `f'. FIXME: we need something better, line GNU `getline()'. */ int get_line(char *buf, int bufsize, FILE *f) { char *r; int len; r = fgets(buf, bufsize, f); if (r == NULL) return -1; len = strlen(buf); if (len > 0) { char *p; /* Remove trailing newline character. */ if (*(buf + len - 1) == '\n') len--; /* Remove useless spaces. */ while (*(buf + len - 1) == ' ') len--; for (p = buf; *p == ' '; p++, len--) ; memmove(buf, p, len + 1); *(buf + len) = '\0'; } return len; } /* Split `path' into a file name and a directory component. Unlike the MS-DOS `fnsplit', the directory does not have a trailing '/'. */ void fname_split(const char *path, char **directory_return, char **name_return) { const char *p; if (path == NULL) { *directory_return = *name_return = NULL; return; } p = strrchr(path, '/'); #if defined __MSDOS__ || defined WIN32 if (p == NULL) p = strrchr(path, '\\'); #endif if (p == NULL) { if (directory_return != NULL) *directory_return = NULL; if (name_return != NULL) *name_return = stralloc(path); return; } if (directory_return != NULL) { *directory_return = xmalloc(p - path + 1); memcpy(*directory_return, path, p - path); (*directory_return)[p - path] = '\0'; } if (name_return != NULL) *name_return = stralloc(p + 1); return; } /* ------------------------------------------------------------------------- */ /* Launch program `name' (searched via the PATH environment variable) passing `argv' as the parameters, wait for it to exit and return its exit status. If `stdout_redir' or `stderr_redir' are != NULL, redirect stdout or stderr to the corresponding file. */ int spawn(const char *name, char **argv, const char *stdout_redir, const char *stderr_redir) { #ifndef __MSDOS__ /* Unix version. */ pid_t child_pid; #ifndef NeXT int child_status; #else union wait child_status; #endif child_pid = vfork(); if (child_pid < 0) { perror("vfork"); return -1; } else if (child_pid == 0) { if (stdout_redir && freopen(stdout_redir, "w", stdout) == NULL) { perror(stdout_redir); _exit(-1); } if (stderr_redir && freopen(stderr_redir, "w", stderr) == NULL) { perror(stderr_redir); _exit(-1); } execvp(name, argv); _exit(-1); } #ifndef NeXT if (waitpid(child_pid, &child_status, 0) != child_pid) { #else if (wait4(child_pid, &child_status, 0, 0) != child_pid) { #endif perror("waitpid"); return -1; } if (WIFEXITED(child_status)) #ifndef NeXT return WEXITSTATUS(child_status); #else return child_status.w_retcode; #endif else return -1; #else /* MS-DOS version. */ int new_stdout, new_stderr; int old_stdout_mode, old_stderr_mode; int old_stdout, old_stderr; int retval; new_stdout = new_stderr = old_stdout = old_stderr = -1; /* Make sure we are in binary mode. */ old_stdout_mode = setmode(STDOUT_FILENO, O_BINARY); old_stderr_mode = setmode(STDERR_FILENO, O_BINARY); /* Redirect stdout and stderr as requested, saving the old descriptors. */ if (stdout_redir != NULL) { old_stdout = dup(STDOUT_FILENO); new_stdout = open(stdout_redir, O_WRONLY | O_TRUNC | O_CREAT, 0666); if (new_stdout == -1) { perror(stdout_redir); retval = -1; goto cleanup; } dup2(new_stdout, STDOUT_FILENO); } if (stderr_redir != NULL) { old_stderr = dup(STDERR_FILENO); new_stderr = open(stderr_redir, O_WRONLY | O_TRUNC | O_CREAT, 0666); if (new_stderr == -1) { perror(stderr_redir); retval = -1; goto cleanup; } dup2(new_stderr, STDERR_FILENO); } /* Spawn the child process. */ retval = spawnvp(P_WAIT, name, argv); cleanup: if (old_stdout >= 0) dup2(old_stdout, STDOUT_FILENO); if (old_stderr >= 0) dup2(old_stderr, STDERR_FILENO); if (old_stdout_mode >= 0) setmode(STDOUT_FILENO, old_stdout_mode); if (old_stderr_mode >= 0) setmode(STDERR_FILENO, old_stderr_mode); if (new_stdout >= 0) close(new_stdout); if (new_stderr >= 0) close(new_stderr); return retval; #endif } /* ------------------------------------------------------------------------- */ /* This code is grabbed from GNU make. It returns the maximum path length by using `pathconf'. */ #ifdef NEED_GET_PATH_MAX unsigned int get_path_max(void) { static unsigned int value; if (value == 0) { long int x = pathconf("/", _PC_PATH_MAX); if (x > 0) value = x; else return MAXPATHLEN; } return value; } #endif /* The following are replacements for libc functions that could be missing. */ #if !defined HAVE_MEMMOVE void *memmove(void *target, const void *source, unsigned int length) { char *tptr = (char *) target; const char *sptr = (const char *) source; if (tptr > sptr) { tptr += length; sptr += length; while (length--) *(--tptr) = *(--sptr); } else if (tptr < sptr) { while (length--) *(tptr++) = *(sptr++); } return target; } #endif /* !defined HAVE_MEMMOVE */ #if !defined HAVE_ATEXIT static void atexit_support_func(int status, void *arg) { void (*f)(void) =(void (*)(void)) arg; f(); } int atexit(void (*function)(void)) { return on_exit(atexit_support_func, (void *)function); } #endif /* !defined HAVE_ATEXIT */ /* ------------------------------------------------------------------------- */ int read_dword(int fd, DWORD *buf, int num) { int i; BYTE *tmpbuf; tmpbuf = xmalloc(num); if (read(fd, (char *)tmpbuf, num) < num) { free(tmpbuf); return -1; } for (i = 0; i < (num / 4); i++) buf[i] = tmpbuf[i * 4] + (tmpbuf[i * 4 + 1] << 8) + (tmpbuf[i * 4 + 2] << 16) + (tmpbuf[i * 4 + 3] << 24); free(tmpbuf); return 0; } int write_dword(int fd, DWORD *buf, int num) { int i; BYTE *tmpbuf; tmpbuf = xmalloc(num); for (i = 0; i < (num / 4); i++) { tmpbuf[i * 4] = buf[i] & 0xff; tmpbuf[i * 4 + 1] = (buf[i] >> 8) & 0xff; tmpbuf[i * 4 + 2] = (buf[i] >> 16) & 0xff; tmpbuf[i * 4 + 3] = (buf[i] >> 24) & 0xff; } if (write(fd, (char *)tmpbuf, num) < 0) { free(tmpbuf); return -1; } free(tmpbuf); return 0; }
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.