# -*-makefile-*-
-# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.160 2003/03/29 11:31:51 petere Exp $
+# $Header: /cvsroot/pgsql/src/Makefile.global.in,v 1.161 2003/04/04 20:42:11 momjian Exp $
 
 #------------------------------------------------------------------------------
 # All PostgreSQL makefiles include this file and use the variables it sets,
 #
 # substitute implementations of the C library
 
-LIBOBJS = @LIBOBJS@
+LIBOBJS = @LIBOBJS@ path.o
 
 ifneq (,$(LIBOBJS))
 LIBS += -lpgport
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.190 2003/03/27 16:51:27 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/copy.c,v 1.191 2003/04/04 20:42:11 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
             * Prevent write to relative path ... too easy to shoot
             * oneself in the foot by overwriting a database file ...
             */
-           if (filename[0] != '/')
+           if (!is_absolute_path(filename))
                elog(ERROR, "Relative path not allowed for server side"
                     " COPY command");
 
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.111 2003/04/04 20:40:44 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/commands/dbcommands.c,v 1.112 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
    if (dbpath == NULL || dbpath[0] == '\0')
        return NULL;
 
-   if (strchr(dbpath, '/'))
+   if (first_path_separator(dbpath))
    {
-       if (dbpath[0] != '/')
+       if (!is_absolute_path(dbpath))
            elog(ERROR, "Relative paths are not allowed as database locations");
 #ifndef ALLOW_ABSOLUTE_DBPATHS
        elog(ERROR, "Absolute paths are not allowed as database locations");
 
        if (!var)
            elog(ERROR, "Postmaster environment variable '%s' not set", dbpath);
-       if (var[0] != '/')
+       if (!is_absolute_path(var))
            elog(ERROR, "Postmaster environment variable '%s' must be absolute path", dbpath);
        prefix = var;
    }
 
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.96 2003/03/27 16:51:29 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/storage/file/fd.c,v 1.97 2003/04/04 20:42:12 momjian Exp $
  *
  * NOTES:
  *
    char       *buf;
 
    /* Not an absolute path name? Then fill in with database path... */
-   if (*filename != '/')
+   if (!is_absolute_path(filename))
    {
        buf = (char *) palloc(strlen(DatabasePath) + strlen(filename) + 2);
        sprintf(buf, "%s/%s", DatabasePath, filename);
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.57 2002/09/02 02:47:05 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/fmgr/dfmgr.c,v 1.58 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
    AssertArg(name);
 
-   have_slash = (strchr(name, '/') != NULL);
+   have_slash = (first_path_separator(name) != NULL);
 
    if (!have_slash)
    {
    if (name[0] != '$')
        return pstrdup(name);
 
-   macroname_len = strcspn(name + 1, "/") + 1;
+   macroname_len = strcspn(name + 1,
+#ifndef WIN32
+       "/"
+#else
+       "/\\"
+#endif
+       ) + 1;
 
    if (strncmp(name, "$libdir", macroname_len) == 0)
        replacement = PKGLIBDIR;
    size_t      baselen;
 
    AssertArg(basename != NULL);
-   AssertArg(strchr(basename, '/') == NULL);
+   AssertArg(first_path_separator(basename) == NULL);
    AssertState(Dynamic_library_path != NULL);
 
    p = Dynamic_library_path;
        pfree(piece);
 
        /* only absolute paths */
-       if (mangled[0] != '/')
+       if (!is_absolute_path(mangled))
            elog(ERROR, "dynamic_library_path component is not absolute");
 
        full = palloc(strlen(mangled) + 1 + baselen + 1);
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/findbe.c,v 1.31 2002/11/02 15:54:13 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/Attic/findbe.c,v 1.32 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
     * (making sure that a relative path is made absolute before returning
     * it).
     */
-   if (argv0 && (p = strrchr(argv0, '/')) && *++p)
+   if (argv0 && (p = last_path_separator(argv0)) && *++p)
    {
-       if (*argv0 == '/' || !getcwd(buf, MAXPGPATH))
+       if (is_absolute_path(argv0) || !getcwd(buf, MAXPGPATH))
            buf[0] = '\0';
        else
            strcat(buf, "/");
        strcat(buf, argv0);
-       p = strrchr(buf, '/');
+       p = last_path_separator(buf);
        strcpy(++p, binary_name);
        if (ValidateBinary(buf) == 0)
        {
                continue;
            if (endp)
                *endp = '\0';
-           if (*startp == '/' || !getcwd(buf, MAXPGPATH))
+           if (is_absolute_path(startp) || !getcwd(buf, MAXPGPATH))
                buf[0] = '\0';
            else
                strcat(buf, "/");
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.101 2003/03/20 04:51:44 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/init/miscinit.c,v 1.102 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
    AssertArg(dir);
 
    /* If presented path is relative, convert to absolute */
-   if (dir[0] != '/')
+   if (!is_absolute_path(dir))
    {
        char       *buf;
        size_t      buflen;
     * generating funny-looking paths to individual files.
     */
    newlen = strlen(new);
-   if (newlen > 1 && new[newlen - 1] == '/')
+   if (newlen > 1 && new[newlen - 1] == '/'
+#ifdef WIN32
+       || new[newlen - 1] == '\\'
+#endif
+       )
        new[newlen - 1] = '\0';
 
    if (DataDir)
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.55 2003/03/10 22:28:19 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/backend/utils/misc/Attic/database.c,v 1.56 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
        return NULL;            /* ain't gonna fit nohow */
 
    /* leading path delimiter? then already absolute path */
-   if (*dbpath == '/')
+   if (is_absolute_path(dbpath))
    {
 #ifdef ALLOW_ABSOLUTE_DBPATHS
-       cp = strrchr(dbpath, '/');
+       cp = last_path_separator(dbpath);
        len = cp - dbpath;
        strncpy(buf, dbpath, len);
        snprintf(&buf[len], MAXPGPATH - len, "/base/%s", (cp + 1));
 #endif
    }
    /* path delimiter somewhere? then has leading environment variable */
-   else if ((cp = strchr(dbpath, '/')) != NULL)
+   else if ((cp = first_path_separator(dbpath)) != NULL)
    {
        const char *envvar;
 
 
  * licence: BSD
  *
- * $Header: /cvsroot/pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.8 2003/01/08 22:26:34 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_controldata/pg_controldata.c,v 1.9 2003/04/04 20:42:12 momjian Exp $
  */
 #include "postgres.h"
 
    textdomain("pg_controldata");
 #endif
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
 
  * by PostgreSQL
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.325 2003/03/31 20:48:45 momjian Exp $
+ *   $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dump.c,v 1.326 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
    dataOnly = schemaOnly = dumpData = attrNames = false;
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    /* Set default options based on progname */
    if (strcmp(progname, "pg_backup") == 0)
 
  * Portions Copyright (c) 1994, Regents of the University of California
  *
  *
- * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.16 2003/03/14 22:45:49 tgl Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_dumpall.c,v 1.17 2003/04/04 20:42:12 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
    textdomain("pg_dump");
 #endif
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
        return result;
 
    cmd = createPQExpBuffer();
-   last = strrchr(argv0, '/');
+   last = last_path_separator(argv0);
 
    if (!last)
        appendPQExpBuffer(cmd, "pg_dump");
 
  *
  *
  * IDENTIFICATION
- *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.44 2003/01/06 18:53:25 petere Exp $
+ *     $Header: /cvsroot/pgsql/src/bin/pg_dump/pg_restore.c,v 1.45 2003/04/04 20:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 
    opts = NewRestoreOptions();
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
 
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.8 2002/10/18 22:05:36 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/pg_resetxlog/pg_resetxlog.c,v 1.9 2003/04/04 20:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
    textdomain("pg_resetxlog");
 #endif
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
 
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.24 2003/03/20 15:39:53 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/prompt.c,v 1.25 2003/04/04 20:42:13 momjian Exp $
  */
 #include "postgres_fe.h"
 #include "prompt.h"
                        const char *host = PQhost(pset.db);
 
                        /* INET socket */
-                       if (host && host[0] && host[0] != '/')
+                       if (host && host[0] && !is_absolute_path(host))
                        {
                            strncpy(buf, host, MAX_PROMPT_SIZE);
                            if (*p == 'm')
 
  *
  * Copyright 2000 by PostgreSQL Global Development Group
  *
- * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.72 2003/03/20 06:43:35 momjian Exp $
+ * $Header: /cvsroot/pgsql/src/bin/psql/startup.c,v 1.73 2003/04/04 20:42:13 momjian Exp $
  */
 #include "postgres_fe.h"
 
    textdomain("psql");
 #endif
 
-   if (!strrchr(argv[0], '/'))
-       pset.progname = argv[0];
-   else
-       pset.progname = strrchr(argv[0], '/') + 1;
+   pset.progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
 
  * Portions Copyright (c) 1996-2003, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Header: /cvsroot/pgsql/src/bin/scripts/common.c,v 1.1 2003/03/18 22:19:46 petere Exp $
+ * $Header: /cvsroot/pgsql/src/bin/scripts/common.c,v 1.2 2003/04/04 20:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 }
 
 
-/*
- * Extracts the actual name of the program as called.
- */
-char *
-get_progname(char *argv0)
-{
-   if (!strrchr(argv0, '/'))
-       return argv0;
-   else
-       return strrchr(argv0, '/') + 1;
-}
-
-
 /*
  * Initialized NLS if enabled.
  */
 
 #endif
 
 const char *get_user_name(const char *progname);
-char *get_progname(char *argv0);
 
 #define _(x) gettext((x))
 void init_nls(void);
 
  * Portions Copyright (c) 1996-2002, PostgreSQL Global Development Group
  * Portions Copyright (c) 1994, Regents of the University of California
  *
- * $Id: c.h,v 1.135 2003/01/09 18:00:24 tgl Exp $
+ * $Id: c.h,v 1.136 2003/04/04 20:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
 #include <unistd.h>
 #endif
 
+/* Portable path handling for Unix/Win32 */
+bool is_absolute_path(const char *filename);
+char *first_path_separator(const char *filename);
+char *last_path_separator(const char *filename);
+char *get_progname(char *argv0);
+
 #if defined(bsdi) || defined(netbsd)
 int fseeko(FILE *stream, off_t offset, int whence);
 off_t ftello(FILE *stream);
 
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.1 2003/03/16 10:42:53 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/ecpglib/connect.c,v 1.2 2003/04/04 20:42:13 momjian Exp $ */
 
 #include "postgres_fe.h"
 
                *tmp = '\0';
            }
 
-           tmp = strrchr(dbname + offset, '/');
+           tmp = last_path_separator(dbname + offset);
            if (tmp != NULL)    /* database name given */
            {
                realname = strdup(tmp + 1);
 
-/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.64 2003/03/27 14:29:17 meskes Exp $ */
+/* $Header: /cvsroot/pgsql/src/interfaces/ecpg/preproc/ecpg.c,v 1.65 2003/04/04 20:42:13 momjian Exp $ */
 
 /* New main for ecpg, the PostgreSQL embedded SQL precompiler. */
    struct _include_path *ip;
    char       *progname;
 
-   if (!strrchr(argv[0], '/'))
-       progname = argv[0];
-   else
-       progname = strrchr(argv[0], '/') + 1;
+   progname = get_progname(argv[0]);
 
    if (argc > 1)
    {
            strcpy(input_filename, argv[fnr]);
 
            /* take care of relative paths */
-           ptr2ext = strrchr(input_filename, '/');
+           ptr2ext = last_path_separator(input_filename);
            ptr2ext = (ptr2ext ? strrchr(ptr2ext, '.') : strrchr(input_filename, '.'));
 
            /* no extension? */
 
  *
  *
  * IDENTIFICATION
- *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.230 2003/04/02 00:49:28 tgl Exp $
+ *   $Header: /cvsroot/pgsql/src/interfaces/libpq/fe-connect.c,v 1.231 2003/04/04 20:42:13 momjian Exp $
  *
  *-------------------------------------------------------------------------
  */
    /*
     * Allow unix socket specification in the host name
     */
-   if (conn->pghost && conn->pghost[0] == '/')
+   if (conn->pghost && is_absolute_path(conn->pghost))
    {
        if (conn->pgunixsocket)
            free(conn->pgunixsocket);
     * We don't allow unix socket path as a function parameter. This
     * allows unix socket specification in the host name.
     */
-   if (conn->pghost && conn->pghost[0] == '/')
+   if (conn->pghost && is_absolute_path(conn->pghost))
    {
        if (conn->pgunixsocket)
            free(conn->pgunixsocket);
                *tmp = '\0';
            }
 
-           tmp = strrchr(conn->dbName + offset, '/');
+           tmp = last_path_separator(conn->dbName + offset);
            if (tmp != NULL)    /* database name given */
            {
                if (conn->dbName)
 
--- /dev/null
+/* $Id: path.c,v 1.1 2003/04/04 20:42:13 momjian Exp $ */
+
+#include "c.h"
+#include <ctype.h>
+
+/*
+ * is_absolute_path
+ */
+bool is_absolute_path(const char *filename)
+{
+   return filename[0] == '/'
+#ifdef WIN32   /* WIN32 paths can either have forward or backward slashes */
+       || filename[0] == '\\'
+       || (isalpha(filename[0]) && filename[1] == ':'
+           && (filename[2] == '\\' || filename[2] == '/'))
+#endif
+       ;
+}
+
+
+   
+/*
+ * first_path_separator
+ */
+char *first_path_separator(const char *filename)
+{
+#ifndef WIN32
+   return strchr(filename, '/');
+#else
+   char *slash, *bslash;
+
+   /* How should we handle "C:file.c"? */
+   slash = strchr(filename, '/');
+   bslash = strchr(filename, '\\');
+   if (slash == NULL)
+       return bslash;
+   else if (bslash == NULL)
+       return slash;
+   else
+       return (slash < bslash) ? slash : bslash;
+#endif
+}
+
+
+/*
+ * last_path_separator
+ */
+char *last_path_separator(const char *filename)
+{
+#ifndef WIN32
+   return strrchr(filename, '/');
+#else
+   char *slash, *bslash;
+
+   /* How should we handle "C:file.c"? */
+   slash = strrchr(filename, '/');
+   bslash = strrchr(filename, '\\');
+   if (slash == NULL)
+       return bslash;
+   else if (bslash == NULL)
+       return slash;
+   else
+       return (slash > bslash) ? slash : bslash;
+#endif
+}
+
+
+/*
+ * Extracts the actual name of the program as called.
+ */
+char *
+get_progname(char *argv0)
+{
+   if (!last_path_separator(argv0))
+       return argv0;
+   else
+       return last_path_separator(argv0) + 1;
+}