/src/netcdf-c/libdispatch/dpathmgr.c
| Line | Count | Source | 
| 1 |  | /* | 
| 2 |  |  * Copyright 2018, University Corporation for Atmospheric Research | 
| 3 |  |  * See netcdf/COPYRIGHT file for copying and redistribution conditions. | 
| 4 |  |  */ | 
| 5 |  |  | 
| 6 |  | #include "config.h" | 
| 7 |  | #include <stdlib.h> | 
| 8 |  | #include <stdio.h> | 
| 9 |  | #include <string.h> | 
| 10 |  | #include <assert.h> | 
| 11 |  | #include <errno.h> | 
| 12 |  | #ifdef HAVE_FCNTL_H | 
| 13 |  | #include <fcntl.h> | 
| 14 |  | #endif | 
| 15 |  | #ifdef HAVE_SYS_STAT_H | 
| 16 |  | #include <sys/stat.h> | 
| 17 |  | #endif | 
| 18 |  | #ifdef HAVE_UNISTD_H | 
| 19 |  | #include <unistd.h> | 
| 20 |  | #endif | 
| 21 |  | #ifdef HAVE_DIRENT_H | 
| 22 |  | #include <dirent.h> | 
| 23 |  | #endif | 
| 24 |  | #ifdef _WIN32 | 
| 25 |  | #include <windows.h> | 
| 26 |  | #include <io.h> | 
| 27 |  | #include <wchar.h> | 
| 28 |  | #include <direct.h> | 
| 29 |  | #endif | 
| 30 |  | #include <locale.h> | 
| 31 |  |  | 
| 32 |  | #include "netcdf.h" | 
| 33 |  | #include "ncpathmgr.h" | 
| 34 |  | #include "nclog.h" | 
| 35 |  | #include "nclist.h" | 
| 36 |  | #include "ncbytes.h" | 
| 37 |  | #include "ncuri.h" | 
| 38 |  | #include "ncutf8.h" | 
| 39 |  |  | 
| 40 |  | #undef DEBUGPATH | 
| 41 |  | static int pathdebug = -1; | 
| 42 |  | #undef DEBUG | 
| 43 |  |  | 
| 44 |  | #ifdef DEBUG | 
| 45 |  | #define REPORT(e,msg) report((e),(msg),__LINE__) | 
| 46 |  | #else | 
| 47 |  | #define REPORT(e,msg) | 
| 48 |  | #endif | 
| 49 |  |  | 
| 50 |  | #ifdef _WIN32 | 
| 51 |  | #define access _access | 
| 52 |  | #define mkdir _mkdir | 
| 53 |  | #define rmdir _rmdir | 
| 54 |  | #define getcwd _getcwd | 
| 55 |  |  | 
| 56 |  | #if WINVERMAJOR > 10 || (WINVERMAJOR == 10 && WINVERBUILD >= 17134) | 
| 57 |  | /* Should be possible to use UTF8 directly */ | 
| 58 |  | #define WINUTF8 | 
| 59 |  | #else | 
| 60 |  | #undef WINUTF8 | 
| 61 |  | #endif | 
| 62 |  |  | 
| 63 |  | #endif | 
| 64 |  |  | 
| 65 |  | #ifndef __OSX__ | 
| 66 |  | #if defined(__APPLE__) && defined(__MACH__) | 
| 67 |  | #define __OSX__ 1 | 
| 68 |  | #endif | 
| 69 |  | #endif | 
| 70 |  |  | 
| 71 |  | /* | 
| 72 |  | Code to provide some path conversion code so that | 
| 73 |  | paths in one format can be used on a platform that uses | 
| 74 |  | a different format. | 
| 75 |  | See the documentation in ncpathmgr.h for details. | 
| 76 |  | */ | 
| 77 |  |  | 
| 78 |  | /* Define legal windows drive letters */ | 
| 79 |  | static const char* windrive = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ/"; | 
| 80 |  |  | 
| 81 |  | static const char netdrive = '/'; | 
| 82 |  |  | 
| 83 |  | static const size_t cdlen = 10; /* strlen("/cygdrive/") */ | 
| 84 |  |  | 
| 85 |  | static int pathinitialized = 0; | 
| 86 |  |  | 
| 87 |  | static const char* cygwinspecial[] = | 
| 88 |  |     {"/bin/","/dev/","/etc/","/home/", | 
| 89 |  |      "/lib/","/proc/","/sbin/","/tmp/", | 
| 90 |  |      "/usr/","/var/",NULL}; | 
| 91 |  |  | 
| 92 |  | static const struct Path { | 
| 93 |  |     int kind; | 
| 94 |  |     char drive; | 
| 95 |  |     char* path; | 
| 96 |  | } empty = {NCPD_UNKNOWN,0,NULL}; | 
| 97 |  |  | 
| 98 |  | /* Keep the working directory kind and drive */ | 
| 99 |  | static char wdprefix[8192]; | 
| 100 |  |  | 
| 101 |  | /* The current codepage */ | 
| 102 |  | #ifdef _WIN32 | 
| 103 |  | static int acp = -1; | 
| 104 |  | #endif | 
| 105 |  |  | 
| 106 |  | /* Keep CYGWIN/MSYS2 mount point */ | 
| 107 |  | static struct MountPoint { | 
| 108 |  |     int defined; | 
| 109 |  |     char prefix[8192]; /*minus leading drive */ | 
| 110 |  |     char drive; | 
| 111 |  | } mountpoint; | 
| 112 |  |  | 
| 113 |  | /* Pick the platform kind for testing */ | 
| 114 |  | static int platform = 0; | 
| 115 |  | /* Do not treat /d/x as d:/x for msys */ | 
| 116 |  | static int env_msys_no_pathconv = 0; | 
| 117 |  |  | 
| 118 |  | static int parsepath(const char* inpath, struct Path* path); | 
| 119 |  | static int unparsepath(struct Path* p, char** pathp, int platform); | 
| 120 |  | static int getwdpath(void); | 
| 121 |  | static void clearPath(struct Path* path); | 
| 122 |  | static void pathinit(void); | 
| 123 |  | static int iscygwinspecial(const char* path); | 
| 124 |  | static int testurl(const char* path); | 
| 125 |  |  | 
| 126 |  | #ifdef WINPATH | 
| 127 |  | static int ansi2utf8(const char* local, char** u8p); | 
| 128 |  | static int ansi2wide(const char* local, wchar_t** u16p); | 
| 129 |  | static int utf82wide(const char* utf8, wchar_t** u16p); | 
| 130 |  | static int wide2utf8(const wchar_t* u16, char** u8p); | 
| 131 |  | #endif | 
| 132 |  |  | 
| 133 |  | /*Forward*/ | 
| 134 |  | #ifdef DEBUG | 
| 135 |  | static void report(int stat, const char* msg, int line); | 
| 136 |  | #endif | 
| 137 |  | static char* printPATH(struct Path* p); | 
| 138 |  |  | 
| 139 |  | EXTERNL | 
| 140 |  | char* /* caller frees */ | 
| 141 |  | NCpathcvt(const char* inpath) | 
| 142 | 0 | { | 
| 143 | 0 |     int stat = NC_NOERR; | 
| 144 | 0 |     char* tmp1 = NULL; | 
| 145 | 0 |     char* result = NULL; | 
| 146 | 0 |     struct Path inparsed = empty; | 
| 147 | 0 |     int platform= NCgetlocalpathkind(); | 
| 148 |  | 
 | 
| 149 | 0 |     if(inpath == NULL) goto done; /* defensive driving */ | 
| 150 |  |  | 
| 151 | 0 |     if(!pathinitialized) pathinit(); | 
| 152 |  | 
 | 
| 153 | 0 |     if(testurl(inpath)) { /* Pass thru URLs */ | 
| 154 | 0 |   if((result = strdup(inpath))==NULL) stat = NC_ENOMEM; | 
| 155 | 0 |   goto done; | 
| 156 | 0 |     } | 
| 157 |  |  | 
| 158 | 0 |     if((stat = parsepath(inpath,&inparsed))) | 
| 159 | 0 |   {REPORT(stat,"NCpathcvt: parsepath"); goto done;} | 
| 160 | 0 |     if(pathdebug > 0) | 
| 161 | 0 |         fprintf(stderr,">>> NCpathcvt: inparsed=%s\n",printPATH(&inparsed)); | 
| 162 |  | 
 | 
| 163 | 0 |     if((stat = unparsepath(&inparsed,&result,platform))) | 
| 164 | 0 |         {REPORT(stat,"NCpathcvt: unparsepath"); goto done;} | 
| 165 |  |  | 
| 166 | 0 | done: | 
| 167 | 0 |     if(pathdebug > 0) { | 
| 168 | 0 |         fprintf(stderr,">>> inpath=|%s| result=|%s|\n", | 
| 169 | 0 |             inpath?inpath:"NULL",result?result:"NULL"); | 
| 170 | 0 |         fflush(stderr); | 
| 171 | 0 |     } | 
| 172 | 0 |     if(stat) { | 
| 173 | 0 |         nullfree(result); result = NULL; | 
| 174 | 0 |   nclog(NCLOGERR,"NCpathcvt: stat=%d (%s)", | 
| 175 | 0 |     stat,nc_strerror(stat)); | 
| 176 | 0 |     } | 
| 177 | 0 |     nullfree(tmp1); | 
| 178 | 0 |     clearPath(&inparsed); | 
| 179 |  |     //fprintf(stderr,">>> ncpathcvt: inpath=%s result=%s\n",inpath,result); | 
| 180 | 0 |     return result; | 
| 181 | 0 | } | 
| 182 |  |  | 
| 183 |  | EXTERNL | 
| 184 |  | int | 
| 185 |  | NCpathcanonical(const char* srcpath, char** canonp) | 
| 186 | 1 | { | 
| 187 | 1 |     int stat = NC_NOERR; | 
| 188 | 1 |     char* canon = NULL; | 
| 189 | 1 |     struct Path path = empty; | 
| 190 |  |  | 
| 191 | 1 |     if(srcpath == NULL) goto done; | 
| 192 |  |  | 
| 193 | 1 |     if(!pathinitialized) pathinit(); | 
| 194 |  |  | 
| 195 |  |     /* parse the src path */ | 
| 196 | 1 |     if((stat = parsepath(srcpath,&path))) {goto done;} | 
| 197 |  |  | 
| 198 |  |     /* Convert to cygwin form */ | 
| 199 | 1 |     if((stat = unparsepath(&path,&canon, NCPD_CYGWIN))) | 
| 200 | 0 |         goto done; | 
| 201 |  |  | 
| 202 | 1 |     if(canonp) {*canonp = canon; canon = NULL;} | 
| 203 |  |  | 
| 204 | 1 | done: | 
| 205 | 1 |     nullfree(canon); | 
| 206 | 1 |     clearPath(&path); | 
| 207 | 1 |     return stat; | 
| 208 | 1 | } | 
| 209 |  |  | 
| 210 |  | EXTERNL | 
| 211 |  | char* /* caller frees */ | 
| 212 |  | NCpathabsolute(const char* relpath) | 
| 213 | 0 | { | 
| 214 | 0 |     int stat = NC_NOERR; | 
| 215 | 0 |     struct Path canon = empty; | 
| 216 | 0 |     char* tmp1 = NULL; | 
| 217 | 0 |     char* result = NULL; | 
| 218 | 0 |     size_t len; | 
| 219 |  | 
 | 
| 220 | 0 |     if(relpath == NULL) goto done; /* defensive driving */ | 
| 221 |  |  | 
| 222 | 0 |     if(!pathinitialized) pathinit(); | 
| 223 |  |  | 
| 224 |  |     /* Decompose path */ | 
| 225 | 0 |     if((stat = parsepath(relpath,&canon))) | 
| 226 | 0 |   {REPORT(stat,"pathabs: parsepath"); goto done;} | 
| 227 |  |  | 
| 228 |  |     /* See if relative */ | 
| 229 | 0 |     if(canon.kind == NCPD_REL) { | 
| 230 |  |   /* prepend the wd path to the inpath, including drive letter, if any */ | 
| 231 | 0 |   len = strlen(wdprefix)+strlen(canon.path)+1+1; | 
| 232 | 0 |   if((tmp1 = (char*)malloc(len))==NULL) | 
| 233 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 234 | 0 |   tmp1[0] = '\0'; | 
| 235 | 0 |   strlcat(tmp1,wdprefix,len); | 
| 236 | 0 |   strlcat(tmp1,"/",len); | 
| 237 | 0 |   strlcat(tmp1,canon.path,len); | 
| 238 | 0 |         nullfree(canon.path); | 
| 239 | 0 |         canon.path = NULL; | 
| 240 |  |   /* Reparse */ | 
| 241 | 0 |   result = NCpathabsolute(tmp1); | 
| 242 | 0 |   goto done; | 
| 243 | 0 |     } | 
| 244 |  |     /* rebuild */ | 
| 245 | 0 |     if((stat=unparsepath(&canon,&result,NCgetlocalpathkind()))) | 
| 246 | 0 |   {REPORT(stat,"pathabs: unparsepath"); goto done;} | 
| 247 | 0 | done: | 
| 248 | 0 |     if(pathdebug > 0) { | 
| 249 | 0 |         fprintf(stderr,">>> relpath=|%s| result=|%s|\n", | 
| 250 | 0 |             relpath?relpath:"NULL",result?result:"NULL"); | 
| 251 | 0 |         fflush(stderr); | 
| 252 | 0 |     } | 
| 253 | 0 |     if(stat) { | 
| 254 | 0 |         nullfree(tmp1); tmp1 = NULL; | 
| 255 | 0 |   nclog(NCLOGERR,"NCpathcvt: stat=%d (%s)", | 
| 256 | 0 |     stat,nc_strerror(stat)); | 
| 257 | 0 |     } | 
| 258 | 0 |     clearPath(&canon); | 
| 259 | 0 |     nullfree(tmp1); | 
| 260 | 0 |     return result; | 
| 261 | 0 | } | 
| 262 |  |  | 
| 263 |  |  | 
| 264 |  | /* Testing support */ | 
| 265 |  | EXTERNL | 
| 266 |  | char* /* caller frees */ | 
| 267 |  | NCpathcvt_test(const char* inpath, int ukind, int udrive) | 
| 268 | 0 | { | 
| 269 | 0 |     char* result = NULL; | 
| 270 | 0 |     struct MountPoint old; | 
| 271 |  | 
 | 
| 272 | 0 |     if(!pathinitialized) pathinit(); | 
| 273 |  | 
 | 
| 274 | 0 |     old = mountpoint; | 
| 275 | 0 |     memset(&mountpoint,0,sizeof(mountpoint)); | 
| 276 |  | 
 | 
| 277 | 0 |     mountpoint.drive = (char)udrive; | 
| 278 | 0 |     mountpoint.defined = (mountpoint.drive || nulllen(mountpoint.prefix) > 0); | 
| 279 | 0 |     platform = ukind; | 
| 280 | 0 |     result = NCpathcvt(inpath); | 
| 281 | 0 |     mountpoint = old; | 
| 282 | 0 |     return result; | 
| 283 | 0 | } | 
| 284 |  |  | 
| 285 |  | static void | 
| 286 |  | pathinit(void) | 
| 287 | 1 | { | 
| 288 | 1 |     if(pathinitialized) return; | 
| 289 | 1 |     pathinitialized = 1; /* avoid recursion */ | 
| 290 |  |  | 
| 291 |  |     /* Check for path debug env vars */ | 
| 292 | 1 |     if(pathdebug < 0) { | 
| 293 | 1 |   const char* s = getenv("NCPATHDEBUG"); | 
| 294 | 1 |         pathdebug = (s == NULL ? 0 : 1); | 
| 295 | 1 |     } | 
| 296 | 1 |     (void)getwdpath(); | 
| 297 |  |  | 
| 298 |  | #ifdef _WIN32 | 
| 299 |  |     /* Get the current code page */ | 
| 300 |  |     acp = GetACP(); | 
| 301 |  | #endif | 
| 302 |  |  | 
| 303 | 1 |     memset(&mountpoint,0,sizeof(mountpoint)); | 
| 304 |  | #ifdef REGEDIT | 
| 305 |  |     { /* See if we can get the MSYS2 prefix from the registry */ | 
| 306 |  |   if(getmountpoint(mountpoint.prefix,sizeof(mountpoint.prefix))) | 
| 307 |  |       goto next; | 
| 308 |  |   mountpoint.defined = 1; | 
| 309 |  | if(pathdebug > 0) | 
| 310 |  |   fprintf(stderr,">>>> registry: mountprefix=|%s|\n",mountpoint.prefix); | 
| 311 |  |     } | 
| 312 |  | next: | 
| 313 |  | #endif | 
| 314 | 1 |     if(!mountpoint.defined) { | 
| 315 | 1 |   mountpoint.prefix[0] = '\0'; | 
| 316 |  |         /* See if MSYS2_PREFIX is defined */ | 
| 317 | 1 |         if(getenv("MSYS2_PREFIX")) { | 
| 318 | 0 |       const char* m2 = getenv("MSYS2_PREFIX"); | 
| 319 | 0 |       mountpoint.prefix[0] = '\0'; | 
| 320 | 0 |             strlcat(mountpoint.prefix,m2,sizeof(mountpoint.prefix)); | 
| 321 | 0 |   } | 
| 322 | 1 |         if(pathdebug > 0) { | 
| 323 | 0 |             fprintf(stderr,">>>> prefix: mountprefix=|%s|\n",mountpoint.prefix); | 
| 324 | 0 |         } | 
| 325 | 1 |     } | 
| 326 | 1 |     if(mountpoint.defined) { | 
| 327 | 0 |   char* p; | 
| 328 | 0 |   size_t size = strlen(mountpoint.prefix); | 
| 329 | 0 |         for(p=mountpoint.prefix;*p;p++) {if(*p == '\\') *p = '/';} /* forward slash*/ | 
| 330 | 0 |   if(mountpoint.prefix[size-1] == '/') { | 
| 331 | 0 |       size--; | 
| 332 | 0 |       mountpoint.prefix[size] = '\0'; /* no trailing slash */ | 
| 333 | 0 |   } | 
| 334 |  |   /* Finally extract the drive letter, if any */ | 
| 335 |  |   /* assumes mount prefix is in windows form */ | 
| 336 | 0 |   mountpoint.drive = 0; | 
| 337 | 0 |   if(strchr(windrive,mountpoint.prefix[0]) != NULL | 
| 338 | 0 |            && mountpoint.prefix[1] == ':') { | 
| 339 | 0 |       char* q = mountpoint.prefix; | 
| 340 | 0 |       mountpoint.drive = mountpoint.prefix[0]; | 
| 341 |  |       /* Shift prefix left 2 chars */ | 
| 342 | 0 |             for(p=mountpoint.prefix+2;*p;p++) {*q++ = *p;} | 
| 343 | 0 |       *q = '\0'; | 
| 344 | 0 |   } | 
| 345 | 0 |     } | 
| 346 |  |  | 
| 347 |  |     /* Check for the MSYS_NO_PATHCONV env var */ | 
| 348 | 1 |     { | 
| 349 | 1 |   const char* s = getenv("MSYS_NO_PATHCONV"); | 
| 350 | 1 |   env_msys_no_pathconv = (s == NULL ? 0 : 1); | 
| 351 | 1 |     } | 
| 352 |  |  | 
| 353 | 1 |     pathinitialized = 1; | 
| 354 | 1 | } | 
| 355 |  |  | 
| 356 |  | static void | 
| 357 |  | clearPath(struct Path* path) | 
| 358 | 1 | { | 
| 359 | 1 |     nullfree(path->path); | 
| 360 | 1 |     path->path = NULL; | 
| 361 | 1 | } | 
| 362 |  |  | 
| 363 |  | /* Unfortunately, not all cygwin paths start with /cygdrive. | 
| 364 |  |    So see if the path starts with one of the special paths. | 
| 365 |  | */ | 
| 366 |  | static int | 
| 367 |  | iscygwinspecial(const char* path) | 
| 368 | 1 | { | 
| 369 | 1 |     const char** p; | 
| 370 | 1 |     if(path == NULL) return 0; | 
| 371 | 11 |     for(p=cygwinspecial;*p;p++) { | 
| 372 | 10 |         if(strncmp(*p,path,strlen(*p))==0) return 1; | 
| 373 | 10 |     } | 
| 374 | 1 |     return 0; | 
| 375 | 1 | } | 
| 376 |  |  | 
| 377 |  | /* return 1 if path looks like a url; 0 otherwise */ | 
| 378 |  | static int | 
| 379 |  | testurl(const char* path) | 
| 380 | 0 | { | 
| 381 | 0 |     int isurl = 0; | 
| 382 | 0 |     NCURI* tmpurl = NULL; | 
| 383 |  | 
 | 
| 384 | 0 |     if(path == NULL) return 0; | 
| 385 |  |  | 
| 386 |  |     /* Ok, try to parse as a url */ | 
| 387 | 0 |     ncuriparse(path,&tmpurl); | 
| 388 | 0 |     isurl = (tmpurl == NULL?0:1); | 
| 389 | 0 |     ncurifree(tmpurl); | 
| 390 | 0 |     return isurl; | 
| 391 | 0 | } | 
| 392 |  |  | 
| 393 |  | #ifdef WINPATH | 
| 394 |  |  | 
| 395 |  | /* | 
| 396 |  | Provide wrappers for Path-related functions | 
| 397 |  | */ | 
| 398 |  |  | 
| 399 |  | EXTERNL | 
| 400 |  | FILE* | 
| 401 |  | NCfopen(const char* path, const char* flags) | 
| 402 |  | { | 
| 403 |  |     int stat = NC_NOERR; | 
| 404 |  |     FILE* f = NULL; | 
| 405 |  |     char bflags[64]; | 
| 406 |  |     char* path8 = NULL; /* ACP -> UTF=8 */ | 
| 407 |  |     char* bflags8 = NULL; | 
| 408 |  |     char* cvtpath = NULL; | 
| 409 |  |     wchar_t* wpath = NULL; | 
| 410 |  |     wchar_t* wflags = NULL; | 
| 411 |  |     size_t flaglen = strlen(flags)+1+1; | 
| 412 |  |  | 
| 413 |  |     bflags[0] = '\0'; | 
| 414 |  |     strlcat(bflags, flags, sizeof(bflags)); | 
| 415 |  | #ifdef _WIN32 | 
| 416 |  |     strlcat(bflags,"b",sizeof(bflags)); | 
| 417 |  | #endif | 
| 418 |  |  | 
| 419 |  |     /* First, convert from current Code Page to utf8 */ | 
| 420 |  |     if((stat = ansi2utf8(path,&path8))) goto done; | 
| 421 |  |     if((stat = ansi2utf8(bflags,&bflags8))) goto done; | 
| 422 |  |  | 
| 423 |  |     /* Localize */ | 
| 424 |  |     if((cvtpath = NCpathcvt(path8))==NULL) goto done; | 
| 425 |  |  | 
| 426 |  | #ifdef WINUTF8 | 
| 427 |  |     if(acp == CP_UTF8) { | 
| 428 |  |         /* This should take utf8 directly */  | 
| 429 |  |         f = fopen(cvtpath,bflags8); | 
| 430 |  |     } else | 
| 431 |  | #endif | 
| 432 |  |     { | 
| 433 |  |         /* Convert from utf8 to wide */ | 
| 434 |  |         if((stat = utf82wide(cvtpath,&wpath))) goto done; | 
| 435 |  |         if((stat = utf82wide(bflags8,&wflags))) goto done; | 
| 436 |  |         f = _wfopen(wpath,wflags); | 
| 437 |  |     } | 
| 438 |  | done: | 
| 439 |  |     nullfree(cvtpath); | 
| 440 |  |     nullfree(path8); | 
| 441 |  |     nullfree(bflags8); | 
| 442 |  |     nullfree(wpath); | 
| 443 |  |     nullfree(wflags); | 
| 444 |  |     return f; | 
| 445 |  | } | 
| 446 |  |  | 
| 447 |  | EXTERNL | 
| 448 |  | int | 
| 449 |  | NCopen3(const char* path, int flags, int mode) | 
| 450 |  | { | 
| 451 |  |     int stat = NC_NOERR; | 
| 452 |  |     int fd = -1; | 
| 453 |  |     char* cvtpath = NULL; | 
| 454 |  |     char* path8 = NULL; | 
| 455 |  |     wchar_t* wpath = NULL; | 
| 456 |  |  | 
| 457 |  |     /* First, convert from current Code Page to utf8 */ | 
| 458 |  |     if((stat = ansi2utf8(path,&path8))) goto done; | 
| 459 |  |  | 
| 460 |  |     if((cvtpath = NCpathcvt(path8))==NULL) goto done; | 
| 461 |  |  | 
| 462 |  | #ifdef _WIN32 | 
| 463 |  |     flags |= O_BINARY; | 
| 464 |  | #endif | 
| 465 |  | #ifdef WINUTF8 | 
| 466 |  |     if(acp == CP_UTF8) { | 
| 467 |  |         /* This should take utf8 directly */  | 
| 468 |  |         fd = _open(cvtpath,flags,mode); | 
| 469 |  |     } else | 
| 470 |  | #endif | 
| 471 |  |     { | 
| 472 |  |         /* Convert from utf8 to wide */ | 
| 473 |  |         if((stat = utf82wide(cvtpath,&wpath))) goto done; | 
| 474 |  |         fd = _wopen(wpath,flags,mode); | 
| 475 |  |     } | 
| 476 |  |  | 
| 477 |  | done: | 
| 478 |  |     nullfree(cvtpath); | 
| 479 |  |     nullfree(path8); | 
| 480 |  |     nullfree(wpath); | 
| 481 |  |     return fd; | 
| 482 |  | } | 
| 483 |  |  | 
| 484 |  | EXTERNL | 
| 485 |  | int | 
| 486 |  | NCopen2(const char *path, int flags) | 
| 487 |  | { | 
| 488 |  |     return NCopen3(path,flags,0); | 
| 489 |  | } | 
| 490 |  |  | 
| 491 |  | #ifdef HAVE_DIRENT_H | 
| 492 |  | EXTERNL | 
| 493 |  | DIR* | 
| 494 |  | NCopendir(const char* path) | 
| 495 |  | { | 
| 496 |  |     DIR* ent = NULL; | 
| 497 |  |     char* cvtname = NCpathcvt(path); | 
| 498 |  |     if(cvtname == NULL) return NULL; | 
| 499 |  |     ent = opendir(cvtname); | 
| 500 |  |     nullfree(cvtname); | 
| 501 |  |     return ent; | 
| 502 |  | } | 
| 503 |  |  | 
| 504 |  | EXTERNL | 
| 505 |  | int | 
| 506 |  | NCclosedir(DIR* ent) | 
| 507 |  | { | 
| 508 |  |     int stat = NC_NOERR; | 
| 509 |  |     if(closedir(ent) < 0) stat = errno; | 
| 510 |  |     return stat; | 
| 511 |  | } | 
| 512 |  | #endif | 
| 513 |  |  | 
| 514 |  | /* | 
| 515 |  | Provide wrappers for other file system functions | 
| 516 |  | */ | 
| 517 |  |  | 
| 518 |  | /* Return access applied to path+mode */ | 
| 519 |  | EXTERNL | 
| 520 |  | int | 
| 521 |  | NCaccess(const char* path, int mode) | 
| 522 |  | { | 
| 523 |  |     int stat = 0; | 
| 524 |  |     char* cvtpath = NULL; | 
| 525 |  |     char* path8 = NULL; | 
| 526 |  |     wchar_t* wpath = NULL; | 
| 527 |  |  | 
| 528 |  |     /* First, convert from current Code Page to utf8 */ | 
| 529 |  |     if((stat = ansi2utf8(path,&path8))) goto done; | 
| 530 |  |  | 
| 531 |  |     if((cvtpath = NCpathcvt(path8)) == NULL) {stat = EINVAL; goto done;} | 
| 532 |  | #ifdef WINUTF8 | 
| 533 |  |     if(acp == CP_UTF8) { | 
| 534 |  |         /* This should take utf8 directly */  | 
| 535 |  |         if(_access(cvtpath,mode) < 0) {stat = errno; goto done;} | 
| 536 |  |     } else | 
| 537 |  | #endif | 
| 538 |  |     { | 
| 539 |  |         /* Convert from utf8 to wide */ | 
| 540 |  |         if((stat = utf82wide(cvtpath,&wpath))) goto done; | 
| 541 |  |         if(_waccess(wpath,mode) < 0) {stat = errno; goto done;} | 
| 542 |  |     } | 
| 543 |  |  | 
| 544 |  | done: | 
| 545 |  |     nullfree(cvtpath); | 
| 546 |  |     nullfree(path8); | 
| 547 |  |     nullfree(wpath); | 
| 548 |  |     errno = stat; | 
| 549 |  |     return (errno?-1:0); | 
| 550 |  | } | 
| 551 |  |  | 
| 552 |  | EXTERNL | 
| 553 |  | int | 
| 554 |  | NCremove(const char* path) | 
| 555 |  | { | 
| 556 |  |     int status = 0; | 
| 557 |  |     char* path8 = NULL; | 
| 558 |  |     char* cvtpath = NULL; | 
| 559 |  |     wchar_t* wpath = NULL; | 
| 560 |  |  | 
| 561 |  |     /* First, convert from current Code Page to utf8 */ | 
| 562 |  |     if((status = ansi2utf8(path,&path8))) goto done; | 
| 563 |  |  | 
| 564 |  |     if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;} | 
| 565 |  | #ifdef WINUTF8 | 
| 566 |  |     if(acp == CP_UTF8) { | 
| 567 |  |         /* This should take utf8 directly */  | 
| 568 |  |         if(remove(cvtpath) < 0) {status = errno; goto done;} | 
| 569 |  |     } else | 
| 570 |  | #endif | 
| 571 |  |     { | 
| 572 |  |         if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;} | 
| 573 |  |         if(_wremove(wpath) < 0) {status = errno; goto done;} | 
| 574 |  |     } | 
| 575 |  |  | 
| 576 |  | done: | 
| 577 |  |     nullfree(cvtpath); | 
| 578 |  |     nullfree(path8); | 
| 579 |  |     nullfree(wpath); | 
| 580 |  |     errno = status; | 
| 581 |  |     return (errno?-1:0); | 
| 582 |  | } | 
| 583 |  |  | 
| 584 |  | EXTERNL | 
| 585 |  | int | 
| 586 |  | NCmkdir(const char* path, int mode) | 
| 587 |  | { | 
| 588 |  |     int status = 0; | 
| 589 |  |     char* cvtpath = NULL; | 
| 590 |  |     char* path8 = NULL; | 
| 591 |  |     wchar_t* wpath = NULL; | 
| 592 |  |  | 
| 593 |  |     /* First, convert from current Code Page to utf8 */ | 
| 594 |  |     if((status = ansi2utf8(path,&path8))) goto done; | 
| 595 |  |  | 
| 596 |  |     if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;} | 
| 597 |  | #ifdef WINUTF8 | 
| 598 |  |     if(acp == CP_UTF8) { | 
| 599 |  |         /* This should take utf8 directly */  | 
| 600 |  |         if(_mkdir(cvtpath) < 0) {status = errno; goto done;} | 
| 601 |  |     } else | 
| 602 |  | #endif | 
| 603 |  |     { | 
| 604 |  |         if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;} | 
| 605 |  |         if(_wmkdir(wpath) < 0) {status = errno; goto done;} | 
| 606 |  |     } | 
| 607 |  |  | 
| 608 |  | done: | 
| 609 |  |     nullfree(cvtpath); | 
| 610 |  |     nullfree(path8); | 
| 611 |  |     nullfree(wpath); | 
| 612 |  |     errno = status; | 
| 613 |  |     return (errno?-1:0); | 
| 614 |  | } | 
| 615 |  |  | 
| 616 |  | EXTERNL | 
| 617 |  | int | 
| 618 |  | NCrmdir(const char* path) | 
| 619 |  | { | 
| 620 |  |     int status = 0; | 
| 621 |  |     char* cvtname = NULL; | 
| 622 |  |     char* path8 = NULL; | 
| 623 |  |  | 
| 624 |  |     /* First, convert from current Code Page to utf8 */ | 
| 625 |  |     if((status = ansi2utf8(path,&path8))) goto done; | 
| 626 |  |    | 
| 627 |  |     cvtname = NCpathcvt(path8); | 
| 628 |  |     if(cvtname == NULL) {errno = ENOENT; status = -1;} | 
| 629 |  |     status = rmdir(cvtname); | 
| 630 |  | done: | 
| 631 |  |     nullfree(cvtname); | 
| 632 |  |     nullfree(path8); | 
| 633 |  |     return status; | 
| 634 |  | } | 
| 635 |  |  | 
| 636 |  | EXTERNL | 
| 637 |  | char* | 
| 638 |  | NCgetcwd(char* cwdbuf, size_t cwdlen) | 
| 639 |  | { | 
| 640 |  |     int status = NC_NOERR; | 
| 641 |  |     char* path = NULL; | 
| 642 |  |     size_t len; | 
| 643 |  |     struct Path wd; | 
| 644 |  |  | 
| 645 |  |     errno = 0; | 
| 646 |  |     if(cwdlen == 0) {status = ENAMETOOLONG; goto done;} | 
| 647 |  |     if(!pathinitialized) pathinit(); | 
| 648 |  |     if((status = getwdpath())) {status = ENOENT; goto done;} | 
| 649 |  |     if((status = parsepath(wdprefix,&wd))) {status = EINVAL; goto done;} | 
| 650 |  |     if((status = unparsepath(&wd,&path,NCgetlocalpathkind()))) {status = EINVAL; goto done;} | 
| 651 |  |     len = strlen(path); | 
| 652 |  |     if(len >= cwdlen) {status = ENAMETOOLONG; goto done;} | 
| 653 |  |     if(cwdbuf == NULL) { | 
| 654 |  |   if((cwdbuf = malloc(cwdlen))==NULL) | 
| 655 |  |       {status = NCTHROW(ENOMEM); goto done;} | 
| 656 |  |     } | 
| 657 |  |     memcpy(cwdbuf,path,len+1); | 
| 658 |  | done: | 
| 659 |  |     clearPath(&wd); | 
| 660 |  |     nullfree(path); | 
| 661 |  |     errno = status; | 
| 662 |  |     return cwdbuf; | 
| 663 |  | } | 
| 664 |  |  | 
| 665 |  | EXTERNL | 
| 666 |  | int | 
| 667 |  | NCmkstemp(char* base) | 
| 668 |  | { | 
| 669 |  |     int stat = 0; | 
| 670 |  |     int fd, rno; | 
| 671 |  |     char* tmp = NULL; | 
| 672 |  |     size_t len; | 
| 673 |  |     char* xp = NULL; | 
| 674 |  |     char* cvtpath = NULL; | 
| 675 |  |     int attempts; | 
| 676 |  |  | 
| 677 |  |     cvtpath = NCpathcvt(base); | 
| 678 |  |     len = strlen(cvtpath); | 
| 679 |  |     xp = cvtpath+(len-6); | 
| 680 |  |     assert(memcmp(xp,"XXXXXX",6)==0); | 
| 681 |  |     for(attempts=10;attempts>0;attempts--) { | 
| 682 |  |         /* The Windows version of mkstemp does not work right; | 
| 683 |  |            it only allows for 26 possible XXXXXX values */ | 
| 684 |  |         /* Need to simulate by using some kind of pseudo-random number */ | 
| 685 |  |         rno = rand(); | 
| 686 |  |         if(rno < 0) rno = -rno; | 
| 687 |  |         snprintf(xp,7,"%06d",rno); | 
| 688 |  |         fd=NCopen3(cvtpath,O_RDWR|O_BINARY|O_CREAT, _S_IREAD|_S_IWRITE); | 
| 689 |  |         if(fd >= 0) break; | 
| 690 |  |     } | 
| 691 |  |     if(fd < 0) { | 
| 692 |  |        nclog(NCLOGERR, "Could not create temp file: %s",tmp); | 
| 693 |  |        stat = EACCES; | 
| 694 |  |        goto done; | 
| 695 |  |     } | 
| 696 |  | done: | 
| 697 |  |     nullfree(cvtpath); | 
| 698 |  |     if(stat && fd >= 0) {close(fd);} | 
| 699 |  |     return (stat?-1:fd); | 
| 700 |  | } | 
| 701 |  |  | 
| 702 |  | #ifdef HAVE_SYS_STAT_H | 
| 703 |  | EXTERNL | 
| 704 |  | int | 
| 705 |  | NCstat(const char* path, STAT buf) | 
| 706 |  | { | 
| 707 |  |     int status = 0; | 
| 708 |  |     char* cvtpath = NULL; | 
| 709 |  |     char* path8 = NULL; | 
| 710 |  |     wchar_t* wpath = NULL; | 
| 711 |  |  | 
| 712 |  |     if((status = ansi2utf8(path,&path8))) goto done; | 
| 713 |  |  | 
| 714 |  |     if((cvtpath = NCpathcvt(path8)) == NULL) {status=ENOMEM; goto done;} | 
| 715 |  | #ifdef WINUTF8 | 
| 716 |  |     if(acp == CP_UTF8) { | 
| 717 |  |         if(_stat64(cvtpath,buf) < 0) {status = errno; goto done;} | 
| 718 |  |     } else | 
| 719 |  | #endif | 
| 720 |  |     { | 
| 721 |  |         if((status = utf82wide(cvtpath,&wpath))) {status = ENOENT; goto done;} | 
| 722 |  |         if(_wstat64(wpath,buf) < 0) {status = errno; goto done;} | 
| 723 |  |     } | 
| 724 |  |  | 
| 725 |  | done: | 
| 726 |  |     nullfree(cvtpath); | 
| 727 |  |     nullfree(path8); | 
| 728 |  |     nullfree(wpath); | 
| 729 |  |     errno = status; | 
| 730 |  |     return (errno?-1:0); | 
| 731 |  | } | 
| 732 |  | #endif /*HAVE_SYS_STAT_H*/ | 
| 733 |  |  | 
| 734 |  | int | 
| 735 |  | NCpath2utf8(const char* s, char** u8p) | 
| 736 |  | { | 
| 737 |  |     return ansi2utf8(s,u8p); | 
| 738 |  | } | 
| 739 |  |  | 
| 740 |  | int | 
| 741 |  | NCstdbinary(void) | 
| 742 |  | { | 
| 743 |  |     int fd; | 
| 744 |  |     fd = _fileno(stdin); | 
| 745 |  |     if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; | 
| 746 |  |     fd = _fileno(stdout); | 
| 747 |  |     if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; | 
| 748 |  |     fd = _fileno(stderr); | 
| 749 |  |     if(_setmode(fd,_O_BINARY)<0) return NC_EINVAL; | 
| 750 |  |     return NC_NOERR;         | 
| 751 |  | } | 
| 752 |  |  | 
| 753 |  | #else /*!WINPATH*/ | 
| 754 |  |  | 
| 755 |  | int | 
| 756 |  | NCpath2utf8(const char* path, char** u8p) | 
| 757 | 0 | { | 
| 758 | 0 |     int stat = NC_NOERR; | 
| 759 | 0 |     char* u8 = NULL; | 
| 760 | 0 |     if(path != NULL) { | 
| 761 | 0 |         u8 = strdup(path); | 
| 762 | 0 |   if(u8 == NULL) {stat =  NC_ENOMEM; goto done;} | 
| 763 | 0 |     } | 
| 764 | 0 |     if(u8p) {*u8p = u8; u8 = NULL;} | 
| 765 | 0 | done: | 
| 766 | 0 |     return stat; | 
| 767 | 0 | } | 
| 768 |  |  | 
| 769 |  | int | 
| 770 |  | NCstdbinary(void) | 
| 771 | 0 | { | 
| 772 | 0 |     return NC_NOERR; | 
| 773 | 0 | } | 
| 774 |  |  | 
| 775 |  | #endif /*!WINPATH*/ | 
| 776 |  |  | 
| 777 |  | EXTERNL int | 
| 778 |  | NChasdriveletter(const char* path) | 
| 779 | 0 | { | 
| 780 | 0 |     int stat = NC_NOERR; | 
| 781 | 0 |     int hasdl = 0; | 
| 782 | 0 |     struct Path canon = empty; | 
| 783 |  | 
 | 
| 784 | 0 |     if(!pathinitialized) pathinit(); | 
| 785 |  | 
 | 
| 786 | 0 |     if((stat = parsepath(path,&canon))) goto done; | 
| 787 | 0 |     hasdl = (canon.drive != 0); | 
| 788 | 0 | done: | 
| 789 | 0 |     clearPath(&canon); | 
| 790 | 0 |     return hasdl; | 
| 791 | 0 | } | 
| 792 |  |  | 
| 793 |  | EXTERNL int | 
| 794 |  | NCisnetworkpath(const char* path) | 
| 795 | 0 | { | 
| 796 | 0 |     int stat = NC_NOERR; | 
| 797 | 0 |     int isnp = 0; | 
| 798 | 0 |     struct Path canon = empty; | 
| 799 |  | 
 | 
| 800 | 0 |     if(!pathinitialized) pathinit(); | 
| 801 |  | 
 | 
| 802 | 0 |     if((stat = parsepath(path,&canon))) goto done; | 
| 803 | 0 |     isnp = (canon.drive == netdrive); | 
| 804 | 0 | done: | 
| 805 | 0 |     clearPath(&canon); | 
| 806 | 0 |     return isnp; | 
| 807 | 0 | } | 
| 808 |  |  | 
| 809 |  | /**************************************************/ | 
| 810 |  | /* Utilities */ | 
| 811 |  |  | 
| 812 |  | /* Parse a path */ | 
| 813 |  | static int | 
| 814 |  | parsepath(const char* inpath, struct Path* path) | 
| 815 | 1 | { | 
| 816 | 1 |     int stat = NC_NOERR; | 
| 817 | 1 |     char* tmp1 = NULL; | 
| 818 | 1 |     size_t len; | 
| 819 | 1 |     char* p; | 
| 820 | 1 |     int platform = NCgetlocalpathkind(); | 
| 821 |  |  | 
| 822 | 1 |     assert(path); | 
| 823 | 1 |     memset(path,0,sizeof(struct Path)); | 
| 824 |  |  | 
| 825 | 1 |     if(inpath == NULL) goto done; /* defensive driving */ | 
| 826 | 1 |     if(!pathinitialized) pathinit(); | 
| 827 |  |  | 
| 828 |  | #if 0 | 
| 829 |  |     /* Convert to UTF8 */ | 
| 830 |  |     if((stat = NCpath2utf8(inpath,&tmp1))) goto done; | 
| 831 |  | #else | 
| 832 | 1 |     tmp1 = strdup(inpath); | 
| 833 | 1 | #endif | 
| 834 |  |     /* Convert to forward slash to simplify later code */ | 
| 835 | 6 |     for(p=tmp1;*p;p++) {if(*p == '\\') *p = '/';} | 
| 836 |  |  | 
| 837 |  |     /* parse all paths to 2 parts: | 
| 838 |  |   1. drive letter (optional) | 
| 839 |  |   2. path after drive letter | 
| 840 |  |     */ | 
| 841 |  |  | 
| 842 | 1 |     len = strlen(tmp1); | 
| 843 |  |  | 
| 844 |  |     /* 1. look for Windows network path //...; drive letter is faked using | 
| 845 |  |           the character '/' */ | 
| 846 | 1 |     if(len >= 2 && (tmp1[0] == '/') && (tmp1[1] == '/')) { | 
| 847 | 0 |   path->drive = netdrive; | 
| 848 |  |   /* Remainder */ | 
| 849 | 0 |   if(tmp1[2] == '\0') | 
| 850 | 0 |       path->path = NULL; | 
| 851 | 0 |   else | 
| 852 | 0 |       path->path = strdup(tmp1+1); /*keep first '/' */ | 
| 853 | 0 |   if(path == NULL) | 
| 854 | 0 |       {stat = NC_ENOMEM; goto done;} | 
| 855 | 0 |   path->kind = NCPD_WIN; | 
| 856 | 0 |     } | 
| 857 |  |     /* 2. Look for leading /cygdrive/D where D is a single-char drive letter */ | 
| 858 | 1 |     else if(len >= (cdlen+1) | 
| 859 | 0 |   && memcmp(tmp1,"/cygdrive/",cdlen)==0 | 
| 860 | 0 |   && strchr(windrive,tmp1[cdlen]) != NULL | 
| 861 | 0 |   && (tmp1[cdlen+1] == '/' | 
| 862 | 0 |       || tmp1[cdlen+1] == '\0')) { | 
| 863 |  |   /* Assume this is a cygwin path */ | 
| 864 | 0 |   path->drive = tmp1[cdlen]; | 
| 865 |  |   /* Remainder */ | 
| 866 | 0 |   if(tmp1[cdlen+1] == '\0') | 
| 867 | 0 |       path->path = NULL; | 
| 868 | 0 |   else | 
| 869 | 0 |       path->path = strdup(tmp1+cdlen+1); | 
| 870 | 0 |   if(path == NULL) | 
| 871 | 0 |       {stat = NC_ENOMEM; goto done;} | 
| 872 | 0 |   path->kind = NCPD_CYGWIN; | 
| 873 | 0 |     } | 
| 874 |  |     /* 4. Look for windows path:  D:/... where D is a single-char | 
| 875 |  |           drive letter */ | 
| 876 | 1 |     else if(len >= 2 | 
| 877 | 1 |   && strchr(windrive,tmp1[0]) != NULL | 
| 878 | 1 |   && tmp1[1] == ':' | 
| 879 | 0 |   && (tmp1[2] == '\0' || tmp1[2] == '/')) { | 
| 880 |  |   /* Assume this is a windows path */ | 
| 881 | 0 |   path->drive = tmp1[0]; | 
| 882 |  |   /* Remainder */ | 
| 883 | 0 |   if(tmp1[2] == '\0') | 
| 884 | 0 |       path->path = NULL; | 
| 885 | 0 |   else | 
| 886 | 0 |       path->path = strdup(tmp1+2); | 
| 887 | 0 |   if(path == NULL) | 
| 888 | 0 |       {stat = NC_ENOMEM; goto done;} | 
| 889 | 0 |   path->kind = NCPD_WIN; /* Might be MINGW */ | 
| 890 | 0 |     } | 
| 891 |  |     /* The /D/x/y/z MSYS paths cause much parsing confusion. | 
| 892 |  |        So only use it if the current platform is msys and MSYS_NO_PATHCONV | 
| 893 |  |        is undefined and NCpathsetplatform was called. Otherwise use windows | 
| 894 |  |        paths. | 
| 895 |  |     */ | 
| 896 |  |     /* X. look for MSYS path /D/... */ | 
| 897 | 1 |     else if(platform == NCPD_MSYS | 
| 898 | 0 |   && !env_msys_no_pathconv | 
| 899 | 0 |         && len >= 2 | 
| 900 | 0 |   && (tmp1[0] == '/') | 
| 901 | 0 |   && strchr(windrive,tmp1[1]) != NULL | 
| 902 | 0 |   && (tmp1[2] == '/' || tmp1[2] == '\0')) { | 
| 903 |  |   /* Assume this is that stupid MSYS path format */ | 
| 904 | 0 |   path->drive = tmp1[1]; | 
| 905 |  |   /* Remainder */ | 
| 906 | 0 |   if(tmp1[2] == '\0') | 
| 907 | 0 |       path->path = NULL; | 
| 908 | 0 |   else | 
| 909 | 0 |       path->path = strdup(tmp1+2); | 
| 910 | 0 |   if(path == NULL) | 
| 911 | 0 |       {stat = NC_ENOMEM; goto done;} | 
| 912 | 0 |   path->kind = NCPD_MSYS; | 
| 913 | 0 |     } | 
| 914 |  |     /* 5. look for *nix* path; note this includes MSYS2 paths as well */ | 
| 915 | 1 |     else if(len >= 1 && tmp1[0] == '/') { | 
| 916 |  |   /* Assume this is a *nix path */ | 
| 917 | 1 |   path->drive = 0; /* no drive letter */ | 
| 918 |  |   /* Remainder */ | 
| 919 | 1 |   path->path = tmp1; tmp1 = NULL; | 
| 920 | 1 |   path->kind = NCPD_NIX; | 
| 921 | 1 |     } else {/* 6. Relative path of unknown type */ | 
| 922 | 0 |   path->kind = NCPD_REL; | 
| 923 | 0 |   path->path = tmp1; tmp1 = NULL; | 
| 924 | 0 |     } | 
| 925 |  |  | 
| 926 | 1 | done: | 
| 927 | 1 |     nullfree(tmp1); | 
| 928 | 1 |     if(stat) {clearPath(path);} | 
| 929 | 1 |     return stat; | 
| 930 | 1 | } | 
| 931 |  |  | 
| 932 |  | static int | 
| 933 |  | unparsepath(struct Path* xp, char** pathp, int platform) | 
| 934 | 1 | { | 
| 935 | 1 |     int stat = NC_NOERR; | 
| 936 | 1 |     size_t len; | 
| 937 | 1 |     char* path = NULL; | 
| 938 | 1 |     char sdrive[4] = "\0\0\0\0"; | 
| 939 | 1 |     char* p = NULL; | 
| 940 | 1 |     int cygspecial = 0; | 
| 941 | 1 |     char drive = 0; | 
| 942 |  |  | 
| 943 |  |     /* Short circuit a relative path */ | 
| 944 | 1 |     if(xp->kind == NCPD_REL) { | 
| 945 |  |   /* Pass thru relative paths, but with proper slashes */ | 
| 946 | 0 |   if((path = strdup(xp->path))==NULL) stat = NC_ENOMEM; | 
| 947 | 0 |   if(platform == NCPD_WIN || platform == NCPD_MSYS) { | 
| 948 | 0 |       char* p; | 
| 949 | 0 |             for(p=path;*p;p++) {if(*p == '/') *p = '\\';} /* back slash*/ | 
| 950 | 0 |   } | 
| 951 | 0 |   goto exit; | 
| 952 | 0 |     } | 
| 953 |  |  | 
| 954 |  |     /* We need a two level switch with an arm | 
| 955 |  |        for every pair of (xp->kind,platform) | 
| 956 |  |     */ | 
| 957 |  |  | 
| 958 | 1 | #define CASE(k,t) case ((k)*10+(t)) | 
| 959 |  |  | 
| 960 | 1 |     switch (xp->kind*10 + platform) { | 
| 961 | 0 |     CASE(NCPD_NIX,NCPD_NIX): | 
| 962 | 0 |   assert(xp->drive == 0); | 
| 963 | 0 |   len = nulllen(xp->path)+1; | 
| 964 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 965 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 966 | 0 |   path[0] = '\0'; | 
| 967 | 0 |   if(xp->path != NULL) | 
| 968 | 0 |       strlcat(path,xp->path,len); | 
| 969 | 0 |   break; | 
| 970 | 0 |     CASE(NCPD_NIX,NCPD_MSYS): | 
| 971 | 0 |     CASE(NCPD_NIX,NCPD_WIN): | 
| 972 | 0 |   assert(xp->drive == 0); | 
| 973 | 0 |   len = nulllen(xp->path)+1; | 
| 974 | 0 |   if(!mountpoint.defined) | 
| 975 | 0 |       {stat = NC_EINVAL; goto done;} /* drive required */ | 
| 976 | 0 |   len += (strlen(mountpoint.prefix) + 2); | 
| 977 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 978 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 979 | 0 |   path[0] = '\0'; | 
| 980 | 0 |   assert(mountpoint.drive != 0); | 
| 981 | 0 |   sdrive[0] = mountpoint.drive; | 
| 982 | 0 |   sdrive[1] = ':'; | 
| 983 | 0 |   sdrive[2] = '\0'; | 
| 984 | 0 |   strlcat(path,sdrive,len); | 
| 985 | 0 |   strlcat(path,mountpoint.prefix,len); | 
| 986 | 0 |   if(xp->path != NULL) strlcat(path,xp->path,len); | 
| 987 | 0 |         for(p=path;*p;p++) {if(*p == '/') *p = '\\';} /* restore back slash */ | 
| 988 | 0 |   break; | 
| 989 | 1 |     CASE(NCPD_NIX,NCPD_CYGWIN): | 
| 990 | 1 |   assert(xp->drive == 0); | 
| 991 |  |   /* Is this one of the special cygwin paths? */ | 
| 992 | 1 |   cygspecial = iscygwinspecial(xp->path); | 
| 993 | 1 |   len = 0; | 
| 994 | 1 |   if(!cygspecial && mountpoint.drive != 0) { | 
| 995 | 0 |       len = cdlen + 1+1; /* /cygdrive/D */ | 
| 996 | 0 |       len += nulllen(mountpoint.prefix); | 
| 997 | 0 |   } | 
| 998 | 1 |   if(xp->path) | 
| 999 | 1 |       len += strlen(xp->path); | 
| 1000 | 1 |   len++; /* nul term */ | 
| 1001 | 1 |         if((path = (char*)malloc(len))==NULL) | 
| 1002 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1003 | 1 |   path[0] = '\0'; | 
| 1004 | 1 |   if(!cygspecial && mountpoint.drive != 0) { | 
| 1005 | 0 |             strlcat(path,"/cygdrive/",len); | 
| 1006 | 0 |       sdrive[0] = mountpoint.drive; | 
| 1007 | 0 |       sdrive[1] = '\0'; | 
| 1008 | 0 |             strlcat(path,sdrive,len); | 
| 1009 | 0 |             strlcat(path,mountpoint.prefix,len); | 
| 1010 | 0 |   } | 
| 1011 | 1 |     if(xp->path) | 
| 1012 | 1 |       strlcat(path,xp->path,len); | 
| 1013 | 1 |   break; | 
| 1014 |  |  | 
| 1015 | 0 |     CASE(NCPD_CYGWIN,NCPD_NIX): | 
| 1016 | 0 |         len = nulllen(xp->path); | 
| 1017 | 0 |         if(xp->drive != 0) | 
| 1018 | 0 |       len += (cdlen + 1); /* strlen("/cygdrive/D") */ | 
| 1019 | 0 |   len++; /* nul term */ | 
| 1020 | 0 |         if((path = (char*)malloc(len))==NULL) | 
| 1021 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1022 | 0 |   path[0] = '\0'; | 
| 1023 | 0 |   if(xp->drive != 0) { | 
| 1024 |  |       /* There is no good/standard way to map a windows | 
| 1025 |  |                drive letter to a *nix* path.*/ | 
| 1026 |  | #if 0 | 
| 1027 |  |             strlcat(path,"/cygdrive/",len); | 
| 1028 |  | #else | 
| 1029 |  |       /* so, just use "/D" where D is the drive letter */ | 
| 1030 | 0 |       strlcat(path,"/",len); | 
| 1031 | 0 | #endif | 
| 1032 | 0 |       sdrive[0] = xp->drive; sdrive[1] = '\0'; | 
| 1033 | 0 |             strlcat(path,sdrive,len); | 
| 1034 | 0 |   } | 
| 1035 | 0 |     if(xp->path) | 
| 1036 | 0 |       strlcat(path,xp->path,len); | 
| 1037 | 0 |   break; | 
| 1038 |  |  | 
| 1039 | 0 |     CASE(NCPD_CYGWIN,NCPD_WIN): | 
| 1040 | 0 |     CASE(NCPD_CYGWIN,NCPD_MSYS): | 
| 1041 | 0 |   len = nulllen(xp->path)+1; | 
| 1042 | 0 |   if(xp->drive == 0 && !mountpoint.defined) | 
| 1043 | 0 |       {stat = NC_EINVAL; goto done;} /* drive required */ | 
| 1044 | 0 |         if (xp->drive == 0) | 
| 1045 | 0 |             len += (strlen(mountpoint.prefix) + 2); | 
| 1046 | 0 |         else | 
| 1047 | 0 |             len += sizeof(sdrive); | 
| 1048 | 0 |         len++; | 
| 1049 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 1050 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1051 | 0 |   path[0] = '\0'; | 
| 1052 | 0 |   if(xp->drive != 0) | 
| 1053 | 0 |       drive = xp->drive; | 
| 1054 | 0 |   else | 
| 1055 | 0 |       drive = mountpoint.drive; | 
| 1056 | 0 |   sdrive[0] = drive; sdrive[1] = ':'; sdrive[2] = '\0'; | 
| 1057 | 0 |         strlcat(path,sdrive,len); | 
| 1058 | 0 |   if(xp->path != NULL) | 
| 1059 | 0 |             strlcat(path,xp->path,len); | 
| 1060 | 0 |         for(p=path;*p;p++) {if(*p == '/') *p = '\\';} /* restore back slash */ | 
| 1061 | 0 |   break; | 
| 1062 |  |  | 
| 1063 | 0 |     CASE(NCPD_CYGWIN,NCPD_CYGWIN): | 
| 1064 | 0 |   len = nulllen(xp->path)+1; | 
| 1065 | 0 |   if(xp->drive != 0) | 
| 1066 | 0 |       len += (cdlen + 2); | 
| 1067 | 0 |   len++; | 
| 1068 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 1069 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1070 | 0 |   path[0] = '\0'; | 
| 1071 | 0 |   if(xp->drive != 0) { | 
| 1072 | 0 |       sdrive[0] = xp->drive; sdrive[1] = '\0'; | 
| 1073 | 0 |       strlcat(path,"/cygdrive/",len); | 
| 1074 | 0 |       strlcat(path,sdrive,len); | 
| 1075 | 0 |   } | 
| 1076 | 0 |   if(xp->path != NULL) | 
| 1077 | 0 |       strlcat(path,xp->path,len); | 
| 1078 | 0 |   break; | 
| 1079 |  |  | 
| 1080 | 0 |     CASE(NCPD_WIN, NCPD_WIN) : | 
| 1081 | 0 |     CASE(NCPD_MSYS, NCPD_MSYS) : | 
| 1082 | 0 |     CASE(NCPD_WIN, NCPD_MSYS) : | 
| 1083 | 0 |     CASE(NCPD_MSYS, NCPD_WIN) : | 
| 1084 | 0 |   if(xp->drive == 0 && !mountpoint.defined) | 
| 1085 | 0 |       {stat = NC_EINVAL; goto done;} /* drive required */ | 
| 1086 | 0 |         len = nulllen(xp->path) + 1 + sizeof(sdrive); | 
| 1087 | 0 |   if(xp->drive == 0) | 
| 1088 | 0 |       len += strlen(mountpoint.prefix); | 
| 1089 | 0 |   len++; | 
| 1090 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 1091 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1092 | 0 |   path[0] = '\0'; | 
| 1093 | 0 |   if(xp->drive != 0) | 
| 1094 | 0 |       drive = xp->drive; | 
| 1095 | 0 |   else | 
| 1096 | 0 |       drive = mountpoint.drive; | 
| 1097 | 0 |   sdrive[0] = drive; | 
| 1098 | 0 |   sdrive[1] = (drive == netdrive ? '\0' : ':'); | 
| 1099 | 0 |   sdrive[2] = '\0'; | 
| 1100 | 0 |         strlcat(path,sdrive,len); | 
| 1101 | 0 |   if(xp->path != NULL) | 
| 1102 | 0 |             strlcat(path,xp->path,len); | 
| 1103 | 0 |         for(p=path;*p;p++) {if(*p == '/') *p = '\\';} /* restore back slash */ | 
| 1104 | 0 |   break; | 
| 1105 |  |  | 
| 1106 | 0 |     CASE(NCPD_WIN,NCPD_NIX): | 
| 1107 | 0 |     CASE(NCPD_MSYS,NCPD_NIX): | 
| 1108 | 0 |   assert(xp->drive != 0); | 
| 1109 | 0 |   len = nulllen(xp->path)+1; | 
| 1110 | 0 |   if(xp->drive != 0) | 
| 1111 | 0 |             len += sizeof(sdrive); | 
| 1112 | 0 |   len++; | 
| 1113 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 1114 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1115 | 0 |   path[0] = '\0'; | 
| 1116 | 0 |   if(xp->drive != 0) { | 
| 1117 | 0 |       sdrive[0] = '/'; sdrive[1] = xp->drive; sdrive[2] = '\0'; | 
| 1118 | 0 |             strlcat(path,sdrive,len); | 
| 1119 | 0 |   } | 
| 1120 | 0 |   if(xp->path != NULL) strlcat(path,xp->path,len); | 
| 1121 | 0 |   break; | 
| 1122 |  |  | 
| 1123 | 0 |     CASE(NCPD_MSYS,NCPD_CYGWIN): | 
| 1124 | 0 |     CASE(NCPD_WIN,NCPD_CYGWIN): | 
| 1125 | 0 |   assert(xp->drive != 0); | 
| 1126 | 0 |   len = nulllen(xp->path)+1; | 
| 1127 | 0 |         len += (cdlen + 2); | 
| 1128 | 0 |   len++; | 
| 1129 | 0 |   if((path = (char*)malloc(len))==NULL) | 
| 1130 | 0 |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1131 | 0 |   path[0] = '\0'; | 
| 1132 | 0 |         sdrive[0] = xp->drive; sdrive[1] = '\0'; | 
| 1133 | 0 |   strlcat(path,"/cygdrive/",len); | 
| 1134 | 0 |         strlcat(path,sdrive,len); | 
| 1135 | 0 |   if(xp->path != NULL) strlcat(path,xp->path,len); | 
| 1136 | 0 |   break; | 
| 1137 |  |  | 
| 1138 | 0 |     default: stat = NC_EINTERNAL; goto done; | 
| 1139 | 1 |     } | 
| 1140 |  |  | 
| 1141 | 1 |     if(pathdebug > 0) | 
| 1142 | 0 |   fprintf(stderr,">>> unparse: platform=%s xp=%s path=|%s|\n",NCgetkindname(platform),printPATH(xp),path); | 
| 1143 |  |  | 
| 1144 | 1 | exit: | 
| 1145 | 1 |     if(pathp) {*pathp = path; path = NULL;} | 
| 1146 | 1 | done: | 
| 1147 | 1 |     nullfree(path); | 
| 1148 | 1 |     return stat; | 
| 1149 | 1 | } | 
| 1150 |  |  | 
| 1151 |  | static int | 
| 1152 |  | getwdpath(void) | 
| 1153 | 1 | { | 
| 1154 | 1 |     int stat = NC_NOERR; | 
| 1155 | 1 |     char* path = NULL; | 
| 1156 |  |  | 
| 1157 | 1 |     wdprefix[0] = '\0'; | 
| 1158 |  | #ifdef _WIN32 | 
| 1159 |  |     { | 
| 1160 |  |         wchar_t* wcwd = NULL; | 
| 1161 |  |         wchar_t* wpath = NULL; | 
| 1162 |  |         wcwd = (wchar_t*)calloc(8192, sizeof(wchar_t)); | 
| 1163 |  |         wpath = _wgetcwd(wcwd, 8192); | 
| 1164 |  |         path = NULL; | 
| 1165 |  |         stat = wide2utf8(wpath, &path); | 
| 1166 |  |         nullfree(wcwd); | 
| 1167 |  |         if (stat) return stat; | 
| 1168 |  |   strlcat(wdprefix,path,sizeof(wdprefix)); | 
| 1169 |  |     } | 
| 1170 |  | #else | 
| 1171 | 1 |     { | 
| 1172 | 1 |         getcwd(wdprefix, sizeof(wdprefix)); | 
| 1173 | 1 |     } | 
| 1174 | 1 | #endif | 
| 1175 | 1 |     nullfree(path); path = NULL; | 
| 1176 | 1 |     return stat; | 
| 1177 | 1 | } | 
| 1178 |  |  | 
| 1179 |  | int | 
| 1180 |  | NCgetinputpathkind(const char* inpath) | 
| 1181 | 0 | { | 
| 1182 | 0 |     struct Path p; | 
| 1183 | 0 |     int result = NCPD_UNKNOWN; | 
| 1184 |  | 
 | 
| 1185 | 0 |     memset(&p,0,sizeof(p)); | 
| 1186 | 0 |     if(inpath == NULL) goto done; /* defensive driving */ | 
| 1187 | 0 |     if(testurl(inpath)) goto done; | 
| 1188 | 0 |     if(!pathinitialized) pathinit(); | 
| 1189 | 0 |     if(parsepath(inpath,&p)) goto done; | 
| 1190 |  |  | 
| 1191 | 0 | done: | 
| 1192 | 0 |     result = p.kind; | 
| 1193 | 0 |     clearPath(&p); | 
| 1194 | 0 |     return result; | 
| 1195 | 0 | } | 
| 1196 |  |  | 
| 1197 |  | int | 
| 1198 |  | NCgetlocalpathkind(void) | 
| 1199 | 3 | { | 
| 1200 | 3 |     int kind = NCPD_UNKNOWN; | 
| 1201 | 3 |     if(platform) return platform; | 
| 1202 |  | #ifdef __CYGWIN__ | 
| 1203 |  |   kind = NCPD_CYGWIN; | 
| 1204 |  | #elif defined _MSC_VER /* not _WIN32 */ | 
| 1205 |  |   kind = NCPD_WIN; | 
| 1206 |  | #elif defined __MSYS__ | 
| 1207 |  |   kind = NCPD_MSYS; | 
| 1208 |  | #elif defined __MINGW32__ | 
| 1209 |  |   kind = NCPD_WIN; /* alias */ | 
| 1210 |  | #else | 
| 1211 | 3 |   kind = NCPD_NIX; | 
| 1212 | 3 | #endif | 
| 1213 | 3 |     return kind; | 
| 1214 | 3 | } | 
| 1215 |  |  | 
| 1216 |  | /* Signal that input paths should be treated as inputtype. | 
| 1217 |  |    NCPD_UNKNOWN resets to default. | 
| 1218 |  | */ | 
| 1219 |  | void | 
| 1220 |  | NCpathsetplatform(int inputtype) | 
| 1221 | 0 | { | 
| 1222 | 0 |     switch (inputtype) { | 
| 1223 | 0 |     case NCPD_NIX: platform = NCPD_NIX; break; | 
| 1224 | 0 |     case NCPD_MSYS: platform = NCPD_MSYS; break; | 
| 1225 | 0 |     case NCPD_CYGWIN: platform = NCPD_CYGWIN; break; | 
| 1226 | 0 |     case NCPD_WIN: platform = NCPD_WIN; break; | 
| 1227 | 0 |     default: platform = NCPD_UNKNOWN; break; /* reset */ | 
| 1228 | 0 |     } | 
| 1229 | 0 | } | 
| 1230 |  |  | 
| 1231 |  | /* Force the platform based on various CPP flags */ | 
| 1232 |  | void | 
| 1233 |  | NCpathforceplatform(void) | 
| 1234 | 0 | { | 
| 1235 |  | #ifdef __CYGWIN__ | 
| 1236 |  |     NCpathsetplatform(NCPD_CYGWIN); | 
| 1237 |  | #elif defined _MSC_VER /* not _WIN32 */ | 
| 1238 |  |     NCpathsetplatform(NCPD_WIN); | 
| 1239 |  | #elif defined __MSYS__ | 
| 1240 |  |     NCpathsetplatform(NCPD_MSYS); | 
| 1241 |  | #elif defined __MINGW32__ | 
| 1242 |  |     NCpathsetplatform(NCPD_MSYS); | 
| 1243 |  | #elif defined(__linux__) || defined(__unix__) || defined(__unix) || defined(__OSX__) | 
| 1244 | 0 |     NCpathsetplatform(NCPD_NIX); | 
| 1245 |  | #else | 
| 1246 |  |     NCpathsetplatform(NCPD_UNKNOWN); | 
| 1247 |  | #endif | 
| 1248 | 0 | } | 
| 1249 |  |  | 
| 1250 |  | const char* | 
| 1251 |  | NCgetkindname(int kind) | 
| 1252 | 0 | { | 
| 1253 | 0 |     switch (kind) { | 
| 1254 | 0 |     case NCPD_UNKNOWN: return "NCPD_UNKNOWN"; | 
| 1255 | 0 |     case NCPD_NIX: return "NCPD_NIX"; | 
| 1256 | 0 |     case NCPD_MSYS: return "NCPD_MSYS"; | 
| 1257 | 0 |     case NCPD_CYGWIN: return "NCPD_CYGWIN"; | 
| 1258 | 0 |     case NCPD_WIN: return "NCPD_WIN"; | 
| 1259 |  |     /* same as WIN case NCPD_MINGW: return "NCPD_MINGW";*/ | 
| 1260 | 0 |     case NCPD_REL: return "NCPD_REL"; | 
| 1261 | 0 |     default: break; | 
| 1262 | 0 |     } | 
| 1263 | 0 |     return "NCPD_UNKNOWN"; | 
| 1264 | 0 | } | 
| 1265 |  |  | 
| 1266 |  | #ifdef WINPATH | 
| 1267 |  | /** | 
| 1268 |  |  * Converts the file path from current character set (presumably some | 
| 1269 |  |  * ANSI character set like ISO-Latin-1 or UTF-8 to UTF-8 | 
| 1270 |  |  * @param local Pointer to a nul-terminated string in current char set. | 
| 1271 |  |  * @param u8p Pointer for returning the output utf8 string | 
| 1272 |  |  * | 
| 1273 |  |  * @return NC_NOERR return converted filename | 
| 1274 |  |  * @return NC_EINVAL if conversion fails | 
| 1275 |  |  * @return NC_ENOMEM if no memory available | 
| 1276 |  |  * | 
| 1277 |  |  */ | 
| 1278 |  | static int | 
| 1279 |  | ansi2utf8(const char* path, char** u8p) | 
| 1280 |  | { | 
| 1281 |  |     int stat=NC_NOERR; | 
| 1282 |  |     char* u8 = NULL; | 
| 1283 |  |     int n; | 
| 1284 |  |     wchar_t* u16 = NULL; | 
| 1285 |  |  | 
| 1286 |  |     if(path == NULL) goto done; | 
| 1287 |  |  | 
| 1288 |  |     if(!pathinitialized) pathinit(); | 
| 1289 |  |  | 
| 1290 |  | #ifdef WINUTF8 | 
| 1291 |  |     if(acp == CP_UTF8) { /* Current code page is UTF8 and Windows supports */ | 
| 1292 |  |         u8 = strdup(path); | 
| 1293 |  |   if(u8 == NULL) stat = NC_ENOMEM; | 
| 1294 |  |     } else | 
| 1295 |  | #endif | 
| 1296 |  |     /* Use wide character conversion plus current code page*/ | 
| 1297 |  |     { | 
| 1298 |  |         /* Get length of the converted string */ | 
| 1299 |  |         n = MultiByteToWideChar(acp, 0, path, -1, NULL, 0); | 
| 1300 |  |         if (!n) {stat = NC_EINVAL; goto done;} | 
| 1301 |  |         if((u16 = malloc(sizeof(wchar_t) * (n)))==NULL) | 
| 1302 |  |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1303 |  |         /* do the conversion */ | 
| 1304 |  |         if (!MultiByteToWideChar(CP_ACP, 0, path, -1, u16, n)) | 
| 1305 |  |             {stat = NC_EINVAL; goto done;} | 
| 1306 |  |         /* Now reverse the process to produce utf8 */ | 
| 1307 |  |         n = WideCharToMultiByte(CP_UTF8, 0, u16, -1, NULL, 0, NULL, NULL); | 
| 1308 |  |         if (!n) {stat = NC_EINVAL; goto done;} | 
| 1309 |  |         if((u8 = malloc(sizeof(char) * n))==NULL) | 
| 1310 |  |       {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1311 |  |         if (!WideCharToMultiByte(CP_UTF8, 0, u16, -1, u8, n, NULL, NULL)) | 
| 1312 |  |             {stat = NC_EINVAL; goto done;} | 
| 1313 |  |     } | 
| 1314 |  | done: | 
| 1315 |  |     if(u8p) {*u8p = u8; u8 = NULL;} | 
| 1316 |  |     nullfree(u8); | 
| 1317 |  |     nullfree(u16); | 
| 1318 |  |     return stat; | 
| 1319 |  | } | 
| 1320 |  |  | 
| 1321 |  | static int | 
| 1322 |  | ansi2wide(const char* local, wchar_t** u16p) | 
| 1323 |  | { | 
| 1324 |  |     int stat=NC_NOERR; | 
| 1325 |  |     wchar_t* u16 = NULL; | 
| 1326 |  |     int n; | 
| 1327 |  |  | 
| 1328 |  |     if(!pathinitialized) pathinit(); | 
| 1329 |  |  | 
| 1330 |  |     /* Get length of the converted string */ | 
| 1331 |  |     n = MultiByteToWideChar(CP_ACP, 0,  local, -1, NULL, 0); | 
| 1332 |  |     if (!n) {stat = NC_EINVAL; goto done;} | 
| 1333 |  |     if((u16 = malloc(sizeof(wchar_t) * n))==NULL) | 
| 1334 |  |   {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1335 |  |     /* do the conversion */ | 
| 1336 |  |     if (!MultiByteToWideChar(CP_ACP, 0, local, -1, u16, n)) | 
| 1337 |  |         {stat = NC_EINVAL; goto done;} | 
| 1338 |  |     if(u16p) {*u16p = u16; u16 = NULL;} | 
| 1339 |  | done: | 
| 1340 |  |     nullfree(u16); | 
| 1341 |  |     return stat; | 
| 1342 |  | } | 
| 1343 |  |  | 
| 1344 |  | static int | 
| 1345 |  | utf82wide(const char* utf8, wchar_t** u16p) | 
| 1346 |  | { | 
| 1347 |  |     int stat=NC_NOERR; | 
| 1348 |  |     wchar_t* u16 = NULL; | 
| 1349 |  |     int n; | 
| 1350 |  |  | 
| 1351 |  |     if(!pathinitialized) pathinit(); | 
| 1352 |  |  | 
| 1353 |  |     /* Get length of the converted string */ | 
| 1354 |  |     n = MultiByteToWideChar(CP_UTF8, 0,  utf8, -1, NULL, 0); | 
| 1355 |  |     if (!n) {stat = NC_EINVAL; goto done;} | 
| 1356 |  |     if((u16 = malloc(sizeof(wchar_t) * n))==NULL) | 
| 1357 |  |   {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1358 |  |     /* do the conversion */ | 
| 1359 |  |     if (!MultiByteToWideChar(CP_UTF8, 0, utf8, -1, u16, n)) | 
| 1360 |  |         {stat = NC_EINVAL; goto done;} | 
| 1361 |  |     if(u16p) {*u16p = u16; u16 = NULL;} | 
| 1362 |  | done: | 
| 1363 |  |     nullfree(u16); | 
| 1364 |  |     return stat; | 
| 1365 |  | } | 
| 1366 |  |  | 
| 1367 |  | static int | 
| 1368 |  | wide2utf8(const wchar_t* u16, char** u8p) | 
| 1369 |  | { | 
| 1370 |  |     int stat=NC_NOERR; | 
| 1371 |  |     char* u8 = NULL; | 
| 1372 |  |     int n; | 
| 1373 |  |  | 
| 1374 |  |     if(!pathinitialized) pathinit(); | 
| 1375 |  |  | 
| 1376 |  |     /* Get length of the converted string */ | 
| 1377 |  |     n = WideCharToMultiByte(CP_UTF8, 0,  u16, -1, NULL, 0, NULL, NULL); | 
| 1378 |  |     if (!n) {stat = NC_EINVAL; goto done;} | 
| 1379 |  |     if((u8 = malloc(sizeof(char) * n))==NULL) | 
| 1380 |  |   {stat = NCTHROW(NC_ENOMEM); goto done;} | 
| 1381 |  |     /* do the conversion */ | 
| 1382 |  |     if (!WideCharToMultiByte(CP_UTF8, 0, u16, -1, u8, n, NULL, NULL)) | 
| 1383 |  |         {stat = NC_EINVAL; goto done;} | 
| 1384 |  |     if(u8p) {*u8p = u8; u8 = NULL;} | 
| 1385 |  | done: | 
| 1386 |  |     nullfree(u8); | 
| 1387 |  |     return stat; | 
| 1388 |  | } | 
| 1389 |  |  | 
| 1390 |  | #endif /*WINPATH*/ | 
| 1391 |  |  | 
| 1392 |  | static char* | 
| 1393 |  | printPATH(struct Path* p) | 
| 1394 | 0 | { | 
| 1395 | 0 |     static char buf[4096]; | 
| 1396 | 0 |     buf[0] = '\0'; | 
| 1397 | 0 |     snprintf(buf,sizeof(buf),"Path{kind=%d drive='%c' path=|%s|}", | 
| 1398 | 0 |   p->kind,(p->drive > 0?p->drive:'0'),p->path); | 
| 1399 | 0 |     return buf; | 
| 1400 | 0 | } | 
| 1401 |  |  | 
| 1402 |  | #if 0 | 
| 1403 |  | static int | 
| 1404 |  | hexfor(int c) | 
| 1405 |  | { | 
| 1406 |  |     if(c >= '0' && c <= '9') return c - '0'; | 
| 1407 |  |     if(c >= 'a' && c <= 'f') return (c - 'a')+10; | 
| 1408 |  |     if(c >= 'A' && c <= 'F') return (c - 'A')+10; | 
| 1409 |  |     return -1; | 
| 1410 |  | } | 
| 1411 |  | #endif | 
| 1412 |  |  | 
| 1413 |  | static char hexdigit[] = "0123456789abcdef"; | 
| 1414 |  |  | 
| 1415 |  | EXTERNL void | 
| 1416 |  | printutf8hex(const char* s, char* sx) | 
| 1417 | 0 | { | 
| 1418 | 0 |     const char* p; | 
| 1419 | 0 |     char* q; | 
| 1420 | 0 |     for(q=sx,p=s;*p;p++) { | 
| 1421 | 0 |   unsigned int c = (unsigned char)*p; | 
| 1422 | 0 |   if(c >= ' ' && c <= 127) | 
| 1423 | 0 |       *q++ = (char)c; | 
| 1424 | 0 |   else { | 
| 1425 | 0 |       *q++ = '\\'; | 
| 1426 | 0 |       *q++ = 'x'; | 
| 1427 | 0 |       *q++ = hexdigit[(c>>4)&0xf]; | 
| 1428 | 0 |       *q++ = hexdigit[(c)&0xf]; | 
| 1429 | 0 |   } | 
| 1430 | 0 |     } | 
| 1431 | 0 |     *q = '\0'; | 
| 1432 | 0 | } | 
| 1433 |  |  | 
| 1434 |  | #ifdef DEBUG | 
| 1435 |  | static void | 
| 1436 |  | report(int stat, const char* msg, int line) | 
| 1437 |  | { | 
| 1438 |  |     if(stat) { | 
| 1439 |  |   nclog(NCLOGERR,"NCpathcvt(%d): %s: stat=%d (%s)", | 
| 1440 |  |     line,msg,stat,nc_strerror(stat)); | 
| 1441 |  |     } | 
| 1442 |  | } | 
| 1443 |  | #endif |