2 * File helper functions.
4 * Copyright (C) 2001-2007 Peter Johnson
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
19 * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
20 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
21 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
22 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
23 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
24 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
25 * POSSIBILITY OF SUCH DAMAGE.
29 /* Need either unistd.h or direct.h to prototype getcwd() and mkdir() */
42 #ifdef HAVE_SYS_STAT_H
52 #define BSIZE 8192 /* Fill block size */
56 yasm_scanner_initialize(yasm_scanner *s)
68 yasm_scanner_delete(yasm_scanner *s)
77 yasm_fill_helper(yasm_scanner *s, unsigned char **cursor,
78 size_t (*input_func) (void *d, unsigned char *buf,
80 void *input_func_data)
88 cnt = s->tok - s->bot;
90 memmove(s->bot, s->tok, (size_t)(s->lim - s->tok));
98 if ((s->top - s->lim) < BSIZE) {
99 unsigned char *buf = yasm_xmalloc((size_t)(s->lim - s->bot) + BSIZE);
100 memcpy(buf, s->tok, (size_t)(s->lim - s->tok));
102 s->ptr = &buf[s->ptr - s->bot];
103 *cursor = &buf[*cursor - s->bot];
104 s->lim = &buf[s->lim - s->bot];
105 s->top = &s->lim[BSIZE];
110 if ((cnt = input_func(input_func_data, s->lim, BSIZE)) == 0) {
111 s->eof = &s->lim[cnt];
119 yasm_unescape_cstring(unsigned char *str, size_t *len)
121 unsigned char *s = str;
122 unsigned char *o = str;
125 while ((size_t)(s-str)<*len) {
126 if (*s == '\\' && (size_t)(&s[1]-str)<*len) {
129 case 'b': *o = '\b'; s++; break;
130 case 'f': *o = '\f'; s++; break;
131 case 'n': *o = '\n'; s++; break;
132 case 'r': *o = '\r'; s++; break;
133 case 't': *o = '\t'; s++; break;
135 /* hex escape; grab last two digits */
137 while ((size_t)(&s[2]-str)<*len && isxdigit(s[0])
138 && isxdigit(s[1]) && isxdigit(s[2]))
140 if ((size_t)(s-str)<*len && isxdigit(*s)) {
144 if ((size_t)(s-str)<*len && isxdigit(*s))
146 *o = (unsigned char)strtoul((char *)t, NULL, 16);
157 if ((size_t)(s-str)<*len && isdigit(*s)) {
162 if ((size_t)(s-str)<*len && isdigit(*s)) {
170 yasm_warn_set(YASM_WARN_GENERAL,
171 N_("octal value out of range"));
184 yasm__splitpath_unix(const char *path, /*@out@*/ const char **tail)
187 s = strrchr(path, '/');
194 /* Strip trailing ./ on path */
195 while ((s-1)>=path && *(s-1) == '.' && *s == '/'
196 && !((s-2)>=path && *(s-2) == '.'))
198 /* Strip trailing slashes on path (except leading) */
199 while (s>path && *s == '/')
201 /* Return length of head */
206 yasm__splitpath_win(const char *path, /*@out@*/ const char **tail)
208 const char *basepath = path;
211 /* split off drive letter first, if any */
212 if (isalpha(path[0]) && path[1] == ':')
218 while (s >= basepath && *s != '\\' && *s != '/')
222 if (path == basepath)
223 return 0; /* No head */
225 return 2; /* Drive letter is head */
228 /* Strip trailing .\ or ./ on path */
229 while ((s-1)>=basepath && *(s-1) == '.' && (*s == '/' || *s == '\\')
230 && !((s-2)>=basepath && *(s-2) == '.'))
232 /* Strip trailing slashes on path (except leading) */
233 while (s>basepath && (*s == '/' || *s == '\\'))
235 /* Return length of head */
246 buf = yasm_xmalloc(size);
248 if (getenv("YASM_TEST_SUITE")) {
253 while (getcwd(buf, size-1) == NULL) {
254 if (errno != ERANGE) {
255 yasm__fatal(N_("could not determine current working directory"));
260 buf = yasm_xrealloc(buf, size);
263 /* append a '/' if not already present */
265 if (buf[size-1] != '\\' && buf[size-1] != '/') {
273 yasm__abspath(const char *path)
275 char *curdir, *abspath;
277 curdir = yasm__getcwd();
278 abspath = yasm__combpath(curdir, path);
285 yasm__combpath_unix(const char *from, const char *to)
288 size_t pathlen, i, j;
293 out = yasm_xmalloc(strlen(to)+1);
294 /* Combine any double slashes when copying */
295 for (j=0; *to; to++) {
296 if (*to == '/' && *(to+1) == '/')
304 /* Get path component; note this strips trailing slash */
305 pathlen = yasm__splitpath_unix(from, &tail);
307 out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */
309 /* Combine any double slashes when copying */
310 for (i=0, j=0; i<pathlen; i++) {
311 if (i<pathlen-1 && from[i] == '/' && from[i+1] == '/')
317 /* Add trailing slash back in */
318 if (pathlen > 0 && out[pathlen-1] != '/')
319 out[pathlen++] = '/';
321 /* Now scan from left to right through "to", stripping off "." and "..";
322 * if we see "..", back up one directory in out unless last directory in
325 * Note this does NOT back through ..'s in the "from" path; this is just
326 * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
327 * the same as "foo").
330 if (to[0] == '.' && to[1] == '/') {
331 to += 2; /* current directory */
333 to++; /* strip off any additional slashes */
334 } else if (pathlen == 0)
335 break; /* no more "from" path left, we're done */
336 else if (to[0] == '.' && to[1] == '.' && to[2] == '/') {
337 if (pathlen >= 3 && out[pathlen-1] == '/' && out[pathlen-2] == '.'
338 && out[pathlen-3] == '.') {
339 /* can't ".." against a "..", so we're done. */
343 to += 3; /* throw away "../" */
345 to++; /* strip off any additional slashes */
347 /* and back out last directory in "out" if not already at root */
349 pathlen--; /* strip off trailing '/' */
350 while (pathlen > 0 && out[pathlen-1] != '/')
357 /* Copy "to" to tail of output, and we're done */
358 /* Combine any double slashes when copying */
359 for (j=pathlen; *to; to++) {
360 if (*to == '/' && *(to+1) == '/')
370 yasm__combpath_win(const char *from, const char *to)
373 size_t pathlen, i, j;
376 if ((isalpha(to[0]) && to[1] == ':') || (to[0] == '/' || to[0] == '\\')) {
377 /* absolute or drive letter "to" */
378 out = yasm_xmalloc(strlen(to)+1);
379 /* Combine any double slashes when copying */
380 for (j=0; *to; to++) {
381 if ((*to == '/' || *to == '\\')
382 && (*(to+1) == '/' || *(to+1) == '\\'))
393 /* Get path component; note this strips trailing slash */
394 pathlen = yasm__splitpath_win(from, &tail);
396 out = yasm_xmalloc(pathlen+strlen(to)+2); /* worst case maximum len */
398 /* Combine any double slashes when copying */
399 for (i=0, j=0; i<pathlen; i++) {
400 if (i<pathlen-1 && (from[i] == '/' || from[i] == '\\')
401 && (from[i+1] == '/' || from[i+1] == '\\'))
410 /* Add trailing slash back in, unless it's only a raw drive letter */
411 if (pathlen > 0 && out[pathlen-1] != '\\'
412 && !(pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
413 out[pathlen++] = '\\';
415 /* Now scan from left to right through "to", stripping off "." and "..";
416 * if we see "..", back up one directory in out unless last directory in
419 * Note this does NOT back through ..'s in the "from" path; this is just
420 * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
421 * the same as "foo").
424 if (to[0] == '.' && (to[1] == '/' || to[1] == '\\')) {
425 to += 2; /* current directory */
426 while (*to == '/' || *to == '\\')
427 to++; /* strip off any additional slashes */
428 } else if (pathlen == 0
429 || (pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
430 break; /* no more "from" path left, we're done */
431 else if (to[0] == '.' && to[1] == '.'
432 && (to[2] == '/' || to[2] == '\\')) {
433 if (pathlen >= 3 && out[pathlen-1] == '\\'
434 && out[pathlen-2] == '.' && out[pathlen-3] == '.') {
435 /* can't ".." against a "..", so we're done. */
439 to += 3; /* throw away "../" (or "..\") */
440 while (*to == '/' || *to == '\\')
441 to++; /* strip off any additional slashes */
443 /* and back out last directory in "out" if not already at root */
445 pathlen--; /* strip off trailing '/' */
446 while (pathlen > 0 && out[pathlen-1] != '\\')
453 /* Copy "to" to tail of output, and we're done */
454 /* Combine any double slashes when copying */
455 for (j=pathlen; *to; to++) {
456 if ((*to == '/' || *to == '\\') && (*(to+1) == '/' || *(to+1) == '\\'))
469 yasm__createpath_common(const char *path, int win)
471 const char *pp = path, *pe;
475 lth = len = strlen(path);
476 ts = tp = (char *) malloc(len + 1);
479 if ((win && *pe == '\\') || *pe == '/')
486 if (pp == pe || (win && *pp == '\\') || *pp == '/') {
488 struct _finddata_t fi;
490 #elif defined(HAVE_SYS_STAT_H)
496 h = _findfirst(ts, &fi);
498 if (fi.attrib != _A_SUBDIR) {
502 } else if (errno == ENOENT) {
503 if (_mkdir(ts) == -1) {
510 #elif defined(HAVE_SYS_STAT_H)
511 if (stat(ts, &fi) != -1) {
512 if (!S_ISDIR(fi.st_mode))
514 } else if (errno == ENOENT) {
515 if (mkdir(ts, 0755) == -1) {
530 typedef struct incpath {
531 STAILQ_ENTRY(incpath) link;
532 /*@owned@*/ char *path;
535 STAILQ_HEAD(incpath_head, incpath) incpaths = STAILQ_HEAD_INITIALIZER(incpaths);
538 yasm_fopen_include(const char *iname, const char *from, const char *mode,
545 /* Try directly relative to from first, then each of the include paths */
547 combine = yasm__combpath(from, iname);
548 f = fopen(combine, mode);
559 STAILQ_FOREACH(np, &incpaths, link) {
560 combine = yasm__combpath(np->path, iname);
561 f = fopen(combine, mode);
578 yasm_delete_include_paths(void)
582 n1 = STAILQ_FIRST(&incpaths);
584 n2 = STAILQ_NEXT(n1, link);
585 yasm_xfree(n1->path);
589 STAILQ_INIT(&incpaths);
593 yasm_get_include_dir(void **iter)
595 incpath *p = (incpath *)*iter;
598 p = STAILQ_FIRST(&incpaths);
600 p = STAILQ_NEXT(p, link);
610 yasm_add_include_path(const char *path)
612 incpath *np = yasm_xmalloc(sizeof(incpath));
613 size_t len = strlen(path);
615 np->path = yasm_xmalloc(len+2);
616 memcpy(np->path, path, len+1);
617 /* Add trailing slash if it is missing */
618 if (path[len-1] != '\\' && path[len-1] != '/') {
620 np->path[len+1] = '\0';
623 STAILQ_INSERT_TAIL(&incpaths, np, link);
627 yasm_fwrite_16_l(unsigned short val, FILE *f)
629 if (fputc(val & 0xFF, f) == EOF)
631 if (fputc((val >> 8) & 0xFF, f) == EOF)
637 yasm_fwrite_32_l(unsigned long val, FILE *f)
639 if (fputc((int)(val & 0xFF), f) == EOF)
641 if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
643 if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
645 if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
651 yasm_fwrite_16_b(unsigned short val, FILE *f)
653 if (fputc((val >> 8) & 0xFF, f) == EOF)
655 if (fputc(val & 0xFF, f) == EOF)
661 yasm_fwrite_32_b(unsigned long val, FILE *f)
663 if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
665 if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
667 if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
669 if (fputc((int)(val & 0xFF), f) == EOF)