145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org/*
245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * File helper functions.
345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *  Copyright (C) 2001-2007  Peter Johnson
545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * Redistribution and use in source and binary forms, with or without
745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * modification, are permitted provided that the following conditions
845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * are met:
945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 1. Redistributions of source code must retain the above copyright
1045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer.
1145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * 2. Redistributions in binary form must reproduce the above copyright
1245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    notice, this list of conditions and the following disclaimer in the
1345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *    documentation and/or other materials provided with the distribution.
1445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org *
1545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND OTHER CONTRIBUTORS ``AS IS''
1645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
1745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
1845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR OTHER CONTRIBUTORS BE
1945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
2545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org * POSSIBILITY OF SUCH DAMAGE.
2645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org */
2745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <util.h>
2845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
29d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org/* Need either unistd.h or direct.h to prototype getcwd() and mkdir() */
30d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org#ifdef HAVE_UNISTD_H
3145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <unistd.h>
32d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org#endif
33d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org
34d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org#ifdef HAVE_DIRECT_H
3545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <direct.h>
3645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#endif
3745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
38a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#ifdef _WIN32
39a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#include <io.h>
40a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#endif
41a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
42a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#ifdef HAVE_SYS_STAT_H
43a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#include <sys/stat.h>
44a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#endif
45a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
4645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <ctype.h>
4745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include <errno.h>
4845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
4945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "errwarn.h"
5045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#include "file.h"
5145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org#define BSIZE   8192        /* Fill block size */
5345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
5545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
5645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_scanner_initialize(yasm_scanner *s)
5745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
5845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->bot = NULL;
5945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->tok = NULL;
6045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->ptr = NULL;
6145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->cur = NULL;
6245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->lim = NULL;
6345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->top = NULL;
6445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->eof = NULL;
6545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
6645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
6745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
6845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_scanner_delete(yasm_scanner *s)
6945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
7045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (s->bot) {
7145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(s->bot);
7245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->bot = NULL;
7345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
7445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
7545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
7645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgint
7745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fill_helper(yasm_scanner *s, unsigned char **cursor,
7845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 size_t (*input_func) (void *d, unsigned char *buf,
7945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                       size_t max),
8045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 void *input_func_data)
8145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
8245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size_t cnt;
8345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    int first = 0;
8445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (s->eof)
8645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
8745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
8845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    cnt = s->tok - s->bot;
8945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (cnt > 0) {
9045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        memmove(s->bot, s->tok, (size_t)(s->lim - s->tok));
9145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->tok = s->bot;
9245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->ptr -= cnt;
9345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *cursor -= cnt;
9445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->lim -= cnt;
9545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
9645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!s->bot)
9745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        first = 1;
9845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((s->top - s->lim) < BSIZE) {
9945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        unsigned char *buf = yasm_xmalloc((size_t)(s->lim - s->bot) + BSIZE);
10045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        memcpy(buf, s->tok, (size_t)(s->lim - s->tok));
10145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->tok = buf;
10245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->ptr = &buf[s->ptr - s->bot];
10345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *cursor = &buf[*cursor - s->bot];
10445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->lim = &buf[s->lim - s->bot];
10545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->top = &s->lim[BSIZE];
10645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (s->bot)
10745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(s->bot);
10845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->bot = buf;
10945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
11045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((cnt = input_func(input_func_data, s->lim, BSIZE)) == 0) {
11145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s->eof = &s->lim[cnt];
11245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *s->eof++ = '\n';
11345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
11445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s->lim += cnt;
11545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return first;
11645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
11745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
11845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
11945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_unescape_cstring(unsigned char *str, size_t *len)
12045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
12145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char *s = str;
12245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char *o = str;
12345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    unsigned char t[4];
12445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
12545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while ((size_t)(s-str)<*len) {
12645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (*s == '\\' && (size_t)(&s[1]-str)<*len) {
12745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            s++;
12845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            switch (*s) {
12945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 'b': *o = '\b'; s++; break;
13045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 'f': *o = '\f'; s++; break;
13145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 'n': *o = '\n'; s++; break;
13245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 'r': *o = '\r'; s++; break;
13345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 't': *o = '\t'; s++; break;
13445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                case 'x':
13545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    /* hex escape; grab last two digits */
13645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    s++;
13745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    while ((size_t)(&s[2]-str)<*len && isxdigit(s[0])
13845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                           && isxdigit(s[1]) && isxdigit(s[2]))
13945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        s++;
14045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if ((size_t)(s-str)<*len && isxdigit(*s)) {
14145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        t[0] = *s++;
14245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        t[1] = '\0';
14345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        t[2] = '\0';
14445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if ((size_t)(s-str)<*len && isxdigit(*s))
14545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            t[1] = *s++;
14645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        *o = (unsigned char)strtoul((char *)t, NULL, 16);
14745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    } else
14845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        *o = '\0';
14945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;
15045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                default:
15145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    if (isdigit(*s)) {
15245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        int warn = 0;
15345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        /* octal escape */
15445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if (*s > '7')
15545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            warn = 1;
15645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        *o = *s++ - '0';
15745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if ((size_t)(s-str)<*len && isdigit(*s)) {
15845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            if (*s > '7')
15945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                warn = 1;
16045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            *o <<= 3;
16145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            *o += *s++ - '0';
16245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            if ((size_t)(s-str)<*len && isdigit(*s)) {
16345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                if (*s > '7')
16445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                    warn = 1;
16545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                *o <<= 3;
16645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                *o += *s++ - '0';
16745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            }
16845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        }
16945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        if (warn)
17045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                            yasm_warn_set(YASM_WARN_GENERAL,
17145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                                          N_("octal value out of range"));
17245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    } else
17345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                        *o = *s++;
17445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    break;
17545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
17645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            o++;
17745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
17845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            *o++ = *s++;
17945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
18045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *len = o-str;
18145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
18245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
18345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
18445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__splitpath_unix(const char *path, /*@out@*/ const char **tail)
18545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
18645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *s;
18745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s = strrchr(path, '/');
18845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!s) {
18945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* No head */
19045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *tail = path;
19145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
19245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
19345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *tail = s+1;
19445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Strip trailing ./ on path */
19545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while ((s-1)>=path && *(s-1) == '.' && *s == '/'
19645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org           && !((s-2)>=path && *(s-2) == '.'))
19745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s -= 2;
19845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Strip trailing slashes on path (except leading) */
19945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (s>path && *s == '/')
20045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s--;
20145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Return length of head */
20245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return s-path+1;
20345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
20445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
20545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
20645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__splitpath_win(const char *path, /*@out@*/ const char **tail)
20745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
20845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *basepath = path;
20945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *s;
21045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* split off drive letter first, if any */
21245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (isalpha(path[0]) && path[1] == ':')
21345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        basepath += 2;
21445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
21545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    s = basepath;
21645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (*s != '\0')
21745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s++;
21845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (s >= basepath && *s != '\\' && *s != '/')
21945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s--;
22045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (s < basepath) {
22145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *tail = basepath;
22245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (path == basepath)
22345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 0;   /* No head */
22445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        else
22545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return 2;   /* Drive letter is head */
22645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
22745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *tail = s+1;
22845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Strip trailing .\ or ./ on path */
22945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while ((s-1)>=basepath && *(s-1) == '.' && (*s == '/' || *s == '\\')
23045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org           && !((s-2)>=basepath && *(s-2) == '.'))
23145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s -= 2;
23245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Strip trailing slashes on path (except leading) */
23345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (s>basepath && (*s == '/' || *s == '\\'))
23445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        s--;
23545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Return length of head */
23645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return s-path+1;
23745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
23845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
23945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgchar *
24045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__getcwd(void)
24145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
24245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char *buf;
24345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size_t size;
24445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
24545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size = 1024;
24645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    buf = yasm_xmalloc(size);
247d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org
248d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    if (getenv("YASM_TEST_SUITE")) {
249d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        strcpy(buf, "./");
250d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org        return buf;
251d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org    }
252d65182f1818d1c19e6f3866ab6e68a262fad5185hbono@chromium.org
253a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    while (getcwd(buf, size-1) == NULL) {
25445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (errno != ERANGE) {
25545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm__fatal(N_("could not determine current working directory"));
25645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            yasm_xfree(buf);
25745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return NULL;
25845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
25945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        size *= 2;
26045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        buf = yasm_xrealloc(buf, size);
26145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
262a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
263a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    /* append a '/' if not already present */
264a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    size = strlen(buf);
265a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    if (buf[size-1] != '\\' && buf[size-1] != '/') {
266a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        buf[size] = '/';
267a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        buf[size+1] = '\0';
268a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    }
26945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return buf;
27045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
27145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
27245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgchar *
27345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__abspath(const char *path)
27445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
27545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char *curdir, *abspath;
27645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
27745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    curdir = yasm__getcwd();
27845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    abspath = yasm__combpath(curdir, path);
27945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    yasm_xfree(curdir);
28045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
28145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return abspath;
28245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
28345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
28445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgchar *
28545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__combpath_unix(const char *from, const char *to)
28645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
28745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *tail;
28845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size_t pathlen, i, j;
28945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char *out;
29045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
29145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (to[0] == '/') {
29245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* absolute "to" */
29345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out = yasm_xmalloc(strlen(to)+1);
29445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Combine any double slashes when copying */
29545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (j=0; *to; to++) {
29645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (*to == '/' && *(to+1) == '/')
29745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                continue;
29845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            out[j++] = *to;
29945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
30045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[j++] = '\0';
30145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return out;
30245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
30345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
30445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Get path component; note this strips trailing slash */
30545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    pathlen = yasm__splitpath_unix(from, &tail);
30645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
30745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    out = yasm_xmalloc(pathlen+strlen(to)+2);   /* worst case maximum len */
30845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
30945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Combine any double slashes when copying */
31045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0, j=0; i<pathlen; i++) {
31145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (i<pathlen-1 && from[i] == '/' && from[i+1] == '/')
31245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
31345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[j++] = from[i];
31445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
31545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    pathlen = j;
31645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
31745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Add trailing slash back in */
31845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (pathlen > 0 && out[pathlen-1] != '/')
31945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[pathlen++] = '/';
32045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
32145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Now scan from left to right through "to", stripping off "." and "..";
32245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * if we see "..", back up one directory in out unless last directory in
32345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * out is also "..".
32445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     *
32545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Note this does NOT back through ..'s in the "from" path; this is just
32645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
32745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * the same as "foo").
32845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
32945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (;;) {
33045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (to[0] == '.' && to[1] == '/') {
33145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            to += 2;        /* current directory */
33245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            while (*to == '/')
33345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                to++;           /* strip off any additional slashes */
33445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if (pathlen == 0)
33545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;          /* no more "from" path left, we're done */
33645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        else if (to[0] == '.' && to[1] == '.' && to[2] == '/') {
33745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (pathlen >= 3 && out[pathlen-1] == '/' && out[pathlen-2] == '.'
33845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                && out[pathlen-3] == '.') {
33945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* can't ".." against a "..", so we're done. */
34045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
34145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
34245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
34345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            to += 3;    /* throw away "../" */
34445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            while (*to == '/')
34545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                to++;           /* strip off any additional slashes */
34645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
34745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* and back out last directory in "out" if not already at root */
34845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (pathlen > 1) {
34945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                pathlen--;      /* strip off trailing '/' */
35045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                while (pathlen > 0 && out[pathlen-1] != '/')
35145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    pathlen--;
35245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
35345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
35445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
35545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
35645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
35745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Copy "to" to tail of output, and we're done */
35845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Combine any double slashes when copying */
35945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (j=pathlen; *to; to++) {
36045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (*to == '/' && *(to+1) == '/')
36145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
36245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[j++] = *to;
36345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
36445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    out[j++] = '\0';
36545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return out;
36745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
36845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
36945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgchar *
37045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm__combpath_win(const char *from, const char *to)
37145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
37245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    const char *tail;
37345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size_t pathlen, i, j;
37445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char *out;
37545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
37645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if ((isalpha(to[0]) && to[1] == ':') || (to[0] == '/' || to[0] == '\\')) {
37745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* absolute or drive letter "to" */
37845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out = yasm_xmalloc(strlen(to)+1);
37945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        /* Combine any double slashes when copying */
38045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        for (j=0; *to; to++) {
38145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if ((*to == '/' || *to == '\\')
38245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                && (*(to+1) == '/' || *(to+1) == '\\'))
38345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                continue;
38445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (*to == '/')
38545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                out[j++] = '\\';
38645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
38745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                out[j++] = *to;
38845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
38945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[j++] = '\0';
39045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return out;
39145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
39245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Get path component; note this strips trailing slash */
39445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    pathlen = yasm__splitpath_win(from, &tail);
39545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    out = yasm_xmalloc(pathlen+strlen(to)+2);   /* worst case maximum len */
39745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
39845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Combine any double slashes when copying */
39945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (i=0, j=0; i<pathlen; i++) {
40045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (i<pathlen-1 && (from[i] == '/' || from[i] == '\\')
40145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            && (from[i+1] == '/' || from[i+1] == '\\'))
40245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
40345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (from[i] == '/')
40445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            out[j++] = '\\';
40545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        else
40645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            out[j++] = from[i];
40745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
40845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    pathlen = j;
40945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
41045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Add trailing slash back in, unless it's only a raw drive letter */
41145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (pathlen > 0 && out[pathlen-1] != '\\'
41245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        && !(pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
41345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        out[pathlen++] = '\\';
41445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
41545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Now scan from left to right through "to", stripping off "." and "..";
41645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * if we see "..", back up one directory in out unless last directory in
41745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * out is also "..".
41845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     *
41945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * Note this does NOT back through ..'s in the "from" path; this is just
42045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * as well as that could skip symlinks (e.g. "foo/bar/.." might not be
42145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     * the same as "foo").
42245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org     */
42345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (;;) {
42445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (to[0] == '.' && (to[1] == '/' || to[1] == '\\')) {
42545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            to += 2;        /* current directory */
42645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            while (*to == '/' || *to == '\\')
42745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                to++;           /* strip off any additional slashes */
42845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else if (pathlen == 0
42945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 || (pathlen == 2 && isalpha(out[0]) && out[1] == ':'))
43045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;          /* no more "from" path left, we're done */
43145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        else if (to[0] == '.' && to[1] == '.'
43245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                 && (to[2] == '/' || to[2] == '\\')) {
43345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (pathlen >= 3 && out[pathlen-1] == '\\'
43445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                && out[pathlen-2] == '.' && out[pathlen-3] == '.') {
43545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                /* can't ".." against a "..", so we're done. */
43645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                break;
43745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
43845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
43945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            to += 3;    /* throw away "../" (or "..\") */
44045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            while (*to == '/' || *to == '\\')
44145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                to++;           /* strip off any additional slashes */
44245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
44345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            /* and back out last directory in "out" if not already at root */
44445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (pathlen > 1) {
44545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                pathlen--;      /* strip off trailing '/' */
44645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                while (pathlen > 0 && out[pathlen-1] != '\\')
44745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                    pathlen--;
44845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            }
44945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        } else
45045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            break;
45145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
45245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
45345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Copy "to" to tail of output, and we're done */
45445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Combine any double slashes when copying */
45545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    for (j=pathlen; *to; to++) {
45645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if ((*to == '/' || *to == '\\') && (*(to+1) == '/' || *(to+1) == '\\'))
45745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            continue;
45845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (*to == '/')
45945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            out[j++] = '\\';
46045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        else
46145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            out[j++] = *to;
46245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
46345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    out[j++] = '\0';
46445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
46545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return out;
46645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
46745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
468a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgsize_t
469a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgyasm__createpath_common(const char *path, int win)
470a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org{
471a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    const char *pp = path, *pe;
472a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    char *ts, *tp;
473a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    size_t len, lth;
474a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
475a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    lth = len = strlen(path);
476a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    ts = tp = (char *) malloc(len + 1);
477a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    pe = pp + len;
478a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    while (pe > pp) {
479a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        if ((win && *pe == '\\') || *pe == '/')
480a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            break;
481a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        --pe;
482a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        --lth;
483a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    }
484a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
485a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    while (pp <= pe) {
486a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        if (pp == pe || (win && *pp == '\\') || *pp == '/') {
487a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#ifdef _WIN32
488a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            struct _finddata_t fi;
489a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            intptr_t h;
490a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#elif defined(HAVE_SYS_STAT_H)
491a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            struct stat fi;
492a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#endif
493a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            *tp = '\0';
494a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
495a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#ifdef _WIN32
496a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            h = _findfirst(ts, &fi);
497a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            if (h != -1) {
498a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                if (fi.attrib != _A_SUBDIR) {
499a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    _findclose(h);
500a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    break;
501a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                }
502a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            } else if (errno == ENOENT) {
503a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                if (_mkdir(ts) == -1) {
504a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    _findclose(h);
505a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    lth = -1;
506a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    break;
507a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                }
508a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            }
509a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            _findclose(h);
510a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#elif defined(HAVE_SYS_STAT_H)
511a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            if (stat(ts, &fi) != -1) {
512a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                if (!S_ISDIR(fi.st_mode))
513a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    break;
514a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            } else if (errno == ENOENT) {
515a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                if (mkdir(ts, 0755) == -1) {
516a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    lth = 0;
517a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                    break;
518a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org                }
519a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            }
520a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#else
521a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org            break;
522a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org#endif
523a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        }
524a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org        *tp++ = *pp++;
525a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    }
526a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    free(ts);
527a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org    return lth;
528a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org}
529a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.org
53045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgtypedef struct incpath {
53145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    STAILQ_ENTRY(incpath) link;
53245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /*@owned@*/ char *path;
53345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org} incpath;
53445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
535a1b5233e6d340f45f4846131fec9d0b92e203ce4hbono@chromium.orgSTAILQ_HEAD(incpath_head, incpath) incpaths = STAILQ_HEAD_INITIALIZER(incpaths);
53645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
53745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgFILE *
53845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fopen_include(const char *iname, const char *from, const char *mode,
53945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                   char **oname)
54045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
54145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    FILE *f;
54245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    char *combine;
54345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    incpath *np;
54445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
54545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Try directly relative to from first, then each of the include paths */
54645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (from) {
54745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        combine = yasm__combpath(from, iname);
54845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        f = fopen(combine, mode);
54945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (f) {
55045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (oname)
55145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                *oname = combine;
55245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
55345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_xfree(combine);
55445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return f;
55545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
55645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(combine);
55745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
55845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
55945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    STAILQ_FOREACH(np, &incpaths, link) {
56045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        combine = yasm__combpath(np->path, iname);
56145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        f = fopen(combine, mode);
56245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        if (f) {
56345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            if (oname)
56445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                *oname = combine;
56545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            else
56645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org                yasm_xfree(combine);
56745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org            return f;
56845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        }
56945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(combine);
57045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
57145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
57245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (oname)
57345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        *oname = NULL;
57445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return NULL;
57545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
57645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
57745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
57845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_delete_include_paths(void)
57945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
58045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    incpath *n1, *n2;
58145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
58245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    n1 = STAILQ_FIRST(&incpaths);
58345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    while (n1) {
58445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        n2 = STAILQ_NEXT(n1, link);
58545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(n1->path);
58645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        yasm_xfree(n1);
58745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        n1 = n2;
58845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
58945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    STAILQ_INIT(&incpaths);
59045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
59145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgconst char *
59345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_get_include_dir(void **iter)
59445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
59545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    incpath *p = (incpath *)*iter;
59645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
59745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (!p)
59845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        p = STAILQ_FIRST(&incpaths);
59945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
60045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        p = STAILQ_NEXT(p, link);
60145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
60245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    *iter = p;
60345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (p)
60445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return p->path;
60545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    else
60645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return NULL;
60745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
60845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
60945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgvoid
61045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_add_include_path(const char *path)
61145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
61245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    incpath *np = yasm_xmalloc(sizeof(incpath));
61345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    size_t len = strlen(path);
61445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
61545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    np->path = yasm_xmalloc(len+2);
61645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    memcpy(np->path, path, len+1);
61745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    /* Add trailing slash if it is missing */
61845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (path[len-1] != '\\' && path[len-1] != '/') {
61945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        np->path[len] = '/';
62045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        np->path[len+1] = '\0';
62145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    }
62245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    STAILQ_INSERT_TAIL(&incpaths, np, link);
62445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
62545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
62645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
62745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fwrite_16_l(unsigned short val, FILE *f)
62845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
62945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc(val & 0xFF, f) == EOF)
63045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
63145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((val >> 8) & 0xFF, f) == EOF)
63245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
63345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
63445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
63545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
63645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
63745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fwrite_32_l(unsigned long val, FILE *f)
63845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
63945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)(val & 0xFF), f) == EOF)
64045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
64145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
64245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
64345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
64445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
64545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
64645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
64745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
64845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
64945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
65045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
65145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fwrite_16_b(unsigned short val, FILE *f)
65245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
65345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((val >> 8) & 0xFF, f) == EOF)
65445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
65545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc(val & 0xFF, f) == EOF)
65645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
65745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
65845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
65945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org
66045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgsize_t
66145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.orgyasm_fwrite_32_b(unsigned long val, FILE *f)
66245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org{
66345afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 24) & 0xFF), f) == EOF)
66445afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
66545afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 16) & 0xFF), f) == EOF)
66645afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
66745afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)((val >> 8) & 0xFF), f) == EOF)
66845afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
66945afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    if (fputc((int)(val & 0xFF), f) == EOF)
67045afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org        return 0;
67145afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org    return 1;
67245afe016bed87b9c6946184709058b39ede3f77ajwong@chromium.org}
673