| /* |
| * File helper functions. |
| * |
| * Copyright (C) 2001-2006 Peter Johnson |
| * |
| * 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 AUTHOR AND OTHER 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 AUTHOR OR OTHER 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. |
| */ |
| #ifdef HAVE_CONFIG_H |
| #include <config.h> |
| #undef HAVE_CONFIG_H |
| #endif |
| |
| /* Need either unistd.h or direct.h (on Windows) to prototype getcwd() */ |
| #ifdef HAVE_UNISTD_H |
| #include <unistd.h> |
| #elif defined(WIN32) || defined(_WIN32) |
| #include <direct.h> |
| #endif |
| |
| #include <ctype.h> |
| |
| #define YASM_LIB_INTERNAL |
| #include "util.h" |
| /*@unused@*/ RCSID("$Id$"); |
| |
| #include "file.h" |
| |
| |
| size_t |
| yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail) |
| { |
| const char *s; |
| s = strrchr(path, '/'); |
| if (!s) { |
| /* No head */ |
| *tail = path; |
| return 0; |
| } |
| *tail = s+1; |
| /* Strip trailing ./ on path */ |
| while ((s-1)>=path && *(s-1) == '.' && *s == '/' |
| && !((s-2)>=path && *(s-2) == '.')) |
| s -= 2; |
| /* Strip trailing slashes on path (except leading) */ |
| while (s>path && *s == '/') |
| s--; |
| /* Return length of head */ |
| return s-path+1; |
| } |
| |
| size_t |
| yasm__splitpath_win(const char *path, /*@out@*/ const char **tail) |
| { |
| const char *basepath = path; |
| const char *s; |
| |
| /* split off drive letter first, if any */ |
| if (isalpha(path[0]) && path[1] == ':') |
| basepath += 2; |
| |
| s = basepath; |
| while (*s != '\0') |
| s++; |
| while (s >= basepath && *s != '\\' && *s != '/') |
| s--; |
| if (s < basepath) { |
| *tail = basepath; |
| if (path == basepath) |
| return 0; /* No head */ |
| else |
| return 2; /* Drive letter is head */ |
| } |
| *tail = s+1; |
| /* Strip trailing .\ or ./ on path */ |
| while ((s-1)>=basepath && *(s-1) == '.' && (*s == '/' || *s == '\\') |
| && !((s-2)>=basepath && *(s-2) == '.')) |
| s -= 2; |
| /* Strip trailing slashes on path (except leading) */ |
| while (s>basepath && (*s == '/' || *s == '\\')) |
| s--; |
| /* Return length of head */ |
| return s-path+1; |
| } |
| |
| /* FIXME: dumb way for now */ |
| char * |
| yasm__abspath_unix(const char *path) |
| { |
| char *curdir, *abspath; |
| static const char pathsep[2] = "/"; |
| |
| curdir = getcwd(NULL, 0); |
| |
| abspath = yasm_xmalloc(strlen(curdir) + strlen(path) + 2); |
| strcpy(abspath, curdir); |
| strcat(abspath, pathsep); |
| strcat(abspath, path); |
| |
| free(curdir); |
| |
| return abspath; |
| } |
| |
| /* FIXME: dumb way for now */ |
| char * |
| yasm__abspath_win(const char *path) |
| { |
| char *curdir, *abspath, *ch; |
| static const char pathsep[2] = "\\"; |
| |
| curdir = getcwd(NULL, 0); |
| |
| abspath = yasm_xmalloc(strlen(curdir) + strlen(path) + 2); |
| strcpy(abspath, curdir); |
| strcat(abspath, pathsep); |
| strcat(abspath, path); |
| |
| free(curdir); |
| |
| /* Replace all / with \ */ |
| ch = abspath; |
| while (*ch) { |
| if (*ch == '/') |
| *ch = '\\'; |
| ch++; |
| } |
| |
| return abspath; |
| } |
| |
| char * |
| yasm__combpath_unix(const char *from, const char *to) |
| { |
| const char *tail; |
| size_t pathlen, i, j; |
| char *out; |
| |
| if (to[0] == '/') { |
| /* absolute "to" */ |
| out = yasm_xmalloc(strlen(to)+1); |
| /* Combine any double slashes when copying */ |
| for (j=0; *to; to++) { |
| if (*to == '/' && *(to+1) == '/') |
| continue; |
| out[j++] = *to; |
| } |
| out[j++] = '\0'; |
| return out; |
| } |
| |
| /* Get path component; note this strips trailing slash */ |
| pathlen = yasm__splitpath_unix(from, &tail); |
| |
| out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */ |
| |
| /* Combine any double slashes when copying */ |
| for (i=0, j=0; i<pathlen; i++) { |
| if (i<pathlen-1 && from[i] == '/' && from[i+1] == '/') |
| continue; |
| out[j++] = from[i]; |
| } |
| pathlen = j; |
| |
| /* Add trailing slash back in */ |
| if (pathlen > 0 && out[pathlen-1] != '/') |
| out[pathlen++] = '/'; |
| |
| /* Now scan from left to right through "to", stripping off "." and ".."; |
| * if we see "..", back up one directory in out unless last directory in |
| * out is also "..". |
| * |
| * Note this does NOT back through ..'s in the "from" path; this is just |
| * as well as that could skip symlinks (e.g. "foo/bar/.." might not be |
| * the same as "foo"). |
| */ |
| for (;;) { |
| if (to[0] == '.' && to[1] == '/') { |
| to += 2; /* current directory */ |
| while (*to == '/') |
| to++; /* strip off any additional slashes */ |
| } else if (pathlen == 0) |
| break; /* no more "from" path left, we're done */ |
| else if (to[0] == '.' && to[1] == '.' && to[2] == '/') { |
| if (pathlen >= 3 && out[pathlen-1] == '/' && out[pathlen-2] == '.' |
| && out[pathlen-3] == '.') { |
| /* can't ".." against a "..", so we're done. */ |
| break; |
| } |
| |
| to += 3; /* throw away "../" */ |
| while (*to == '/') |
| to++; /* strip off any additional slashes */ |
| |
| /* and back out last directory in "out" if not already at root */ |
| if (pathlen > 1) { |
| pathlen--; /* strip off trailing '/' */ |
| while (pathlen > 0 && out[pathlen-1] != '/') |
| pathlen--; |
| } |
| } else |
| break; |
| } |
| |
| /* Copy "to" to tail of output, and we're done */ |
| /* Combine any double slashes when copying */ |
| for (j=pathlen; *to; to++) { |
| if (*to == '/' && *(to+1) == '/') |
| continue; |
| out[j++] = *to; |
| } |
| out[j++] = '\0'; |
| |
| return out; |
| } |
| |
| char * |
| yasm__combpath_win(const char *from, const char *to) |
| { |
| const char *tail; |
| size_t pathlen, i, j; |
| char *out; |
| |
| if ((isalpha(to[0]) && to[1] == ':') || (to[0] == '/' || to[0] == '\\')) { |
| /* absolute or drive letter "to" */ |
| out = yasm_xmalloc(strlen(to)+1); |
| /* Combine any double slashes when copying */ |
| for (j=0; *to; to++) { |
| if ((*to == '/' || *to == '\\') |
| && (*(to+1) == '/' || *(to+1) == '\\')) |
| continue; |
| if (*to == '/') |
| out[j++] = '\\'; |
| else |
| out[j++] = *to; |
| } |
| out[j++] = '\0'; |
| return out; |
| } |
| |
| /* Get path component; note this strips trailing slash */ |
| pathlen = yasm__splitpath_win(from, &tail); |
| |
| out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */ |
| |
| /* Combine any double slashes when copying */ |
| for (i=0, j=0; i<pathlen; i++) { |
| if (i<pathlen-1 && (from[i] == '/' || from[i] == '\\') |
| && (from[i+1] == '/' || from[i+1] == '\\')) |
| continue; |
| if (from[i] == '/') |
| out[j++] = '\\'; |
| else |
| out[j++] = from[i]; |
| } |
| pathlen = j; |
| |
| /* Add trailing slash back in, unless it's only a raw drive letter */ |
| if (pathlen > 0 && out[pathlen-1] != '\\' |
| && !(pathlen == 2 && isalpha(out[0]) && out[1] == ':')) |
| out[pathlen++] = '\\'; |
| |
| /* Now scan from left to right through "to", stripping off "." and ".."; |
| * if we see "..", back up one directory in out unless last directory in |
| * out is also "..". |
| * |
| * Note this does NOT back through ..'s in the "from" path; this is just |
| * as well as that could skip symlinks (e.g. "foo/bar/.." might not be |
| * the same as "foo"). |
| */ |
| for (;;) { |
| if (to[0] == '.' && (to[1] == '/' || to[1] == '\\')) { |
| to += 2; /* current directory */ |
| while (*to == '/' || *to == '\\') |
| to++; /* strip off any additional slashes */ |
| } else if (pathlen == 0 |
| || (pathlen == 2 && isalpha(out[0]) && out[1] == ':')) |
| break; /* no more "from" path left, we're done */ |
| else if (to[0] == '.' && to[1] == '.' |
| && (to[2] == '/' || to[2] == '\\')) { |
| if (pathlen >= 3 && out[pathlen-1] == '\\' |
| && out[pathlen-2] == '.' && out[pathlen-3] == '.') { |
| /* can't ".." against a "..", so we're done. */ |
| break; |
| } |
| |
| to += 3; /* throw away "../" (or "..\") */ |
| while (*to == '/' || *to == '\\') |
| to++; /* strip off any additional slashes */ |
| |
| /* and back out last directory in "out" if not already at root */ |
| if (pathlen > 1) { |
| pathlen--; /* strip off trailing '/' */ |
| while (pathlen > 0 && out[pathlen-1] != '\\') |
| pathlen--; |
| } |
| } else |
| break; |
| } |
| |
| /* Copy "to" to tail of output, and we're done */ |
| /* Combine any double slashes when copying */ |
| for (j=pathlen; *to; to++) { |
| if ((*to == '/' || *to == '\\') && (*(to+1) == '/' || *(to+1) == '\\')) |
| continue; |
| if (*to == '/') |
| out[j++] = '\\'; |
| else |
| out[j++] = *to; |
| } |
| out[j++] = '\0'; |
| |
| return out; |
| } |
| |
| FILE * |
| yasm__fopen_include(const char *iname, const char *from, const char **paths, |
| const char *mode, char **oname) |
| { |
| FILE *f; |
| char *combine; |
| const char *path; |
| |
| /* Try directly relative to from first, then each of the include paths */ |
| path = from; |
| while (path) { |
| combine = yasm__combpath(path, iname); |
| f = fopen(combine, mode); |
| if (f) { |
| *oname = combine; |
| return f; |
| } |
| yasm_xfree(combine); |
| if (!paths) |
| break; |
| path = *paths++; |
| } |
| |
| return NULL; |
| } |
| |
| size_t |
| yasm_fwrite_16_l(unsigned short val, FILE *f) |
| { |
| if (fputc(val & 0xFF, f) == EOF) |
| return 0; |
| if (fputc((val >> 8) & 0xFF, f) == EOF) |
| return 0; |
| return 1; |
| } |
| |
| size_t |
| yasm_fwrite_32_l(unsigned long val, FILE *f) |
| { |
| if (fputc((int)(val & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)((val >> 8) & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)((val >> 16) & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)((val >> 24) & 0xFF), f) == EOF) |
| return 0; |
| return 1; |
| } |
| |
| size_t |
| yasm_fwrite_16_b(unsigned short val, FILE *f) |
| { |
| if (fputc((val >> 8) & 0xFF, f) == EOF) |
| return 0; |
| if (fputc(val & 0xFF, f) == EOF) |
| return 0; |
| return 1; |
| } |
| |
| size_t |
| yasm_fwrite_32_b(unsigned long val, FILE *f) |
| { |
| if (fputc((int)((val >> 24) & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)((val >> 16) & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)((val >> 8) & 0xFF), f) == EOF) |
| return 0; |
| if (fputc((int)(val & 0xFF), f) == EOF) |
| return 0; |
| return 1; |
| } |