Coverage Report

Created: 2025-07-11 06:50

/src/xpdf-4.05/goo/gfile.cc
Line
Count
Source (jump to first uncovered line)
1
//========================================================================
2
//
3
// gfile.cc
4
//
5
// Miscellaneous file and directory name manipulation.
6
//
7
// Copyright 1996-2003 Glyph & Cog, LLC
8
//
9
//========================================================================
10
11
#include <aconf.h>
12
13
#ifdef _WIN32
14
#  undef WIN32_LEAN_AND_MEAN
15
#  include <windows.h>
16
#  include <time.h>
17
#  include <direct.h>
18
#  include <shobjidl.h>
19
#  include <shlguid.h>
20
#else
21
#  if !defined(ACORN)
22
#    include <sys/types.h>
23
#    include <sys/stat.h>
24
#    include <fcntl.h>
25
#  endif
26
#  include <time.h>
27
#  include <limits.h>
28
#  include <string.h>
29
#  if !defined(VMS) && !defined(ACORN)
30
#    include <pwd.h>
31
#  endif
32
#  if defined(VMS) && (__DECCXX_VER < 50200000)
33
#    include <unixlib.h>
34
#  endif
35
#endif // _WIN32
36
#include "gmem.h"
37
#include "gmempp.h"
38
#include "GString.h"
39
#include "gfile.h"
40
41
// Some systems don't define this, so just make it something reasonably
42
// large.
43
#ifndef PATH_MAX
44
#define PATH_MAX 1024
45
#endif
46
47
//------------------------------------------------------------------------
48
49
11.5k
GString *getHomeDir() {
50
#ifdef VMS
51
  //---------- VMS ----------
52
  return new GString("SYS$LOGIN:");
53
54
#elif defined(_WIN32)
55
  //---------- Win32 ----------
56
  char *s;
57
  GString *ret;
58
59
  if ((s = getenv("USERPROFILE")))
60
    ret = new GString(s);
61
  else
62
    ret = new GString(".");
63
  return ret;
64
65
#elif defined(__EMX__)
66
  //---------- OS/2+EMX ----------
67
  char *s;
68
  GString *ret;
69
70
  if ((s = getenv("HOME")))
71
    ret = new GString(s);
72
  else
73
    ret = new GString(".");
74
  return ret;
75
76
#elif defined(ACORN)
77
  //---------- RISCOS ----------
78
  return new GString("@");
79
80
#else
81
  //---------- Unix ----------
82
11.5k
  char *s;
83
11.5k
  struct passwd *pw;
84
11.5k
  GString *ret;
85
86
11.5k
  if ((s = getenv("HOME"))) {
87
11.5k
    ret = new GString(s);
88
11.5k
  } else {
89
0
    if ((s = getenv("USER")))
90
0
      pw = getpwnam(s);
91
0
    else
92
0
      pw = getpwuid(getuid());
93
0
    if (pw)
94
0
      ret = new GString(pw->pw_dir);
95
0
    else
96
0
      ret = new GString(".");
97
0
  }
98
11.5k
  return ret;
99
11.5k
#endif
100
11.5k
}
101
102
0
GString *getCurrentDir() {
103
0
  char buf[PATH_MAX+1];
104
105
#if defined(__EMX__)
106
  if (_getcwd2(buf, sizeof(buf)))
107
#elif defined(_WIN32)
108
  if (GetCurrentDirectoryA(sizeof(buf), buf))
109
#elif defined(ACORN)
110
  if (strcpy(buf, "@"))
111
#else
112
0
  if (getcwd(buf, sizeof(buf)))
113
0
#endif
114
0
    return new GString(buf);
115
0
  return new GString();
116
0
}
117
118
172k
GString *appendToPath(GString *path, const char *fileName) {
119
#if defined(VMS)
120
  //---------- VMS ----------
121
  //~ this should handle everything necessary for file
122
  //~ requesters, but it's certainly not complete
123
  char *p0, *p1, *p2;
124
  char *q1;
125
126
  p0 = path->getCString();
127
  p1 = p0 + path->getLength() - 1;
128
  if (!strcmp(fileName, "-")) {
129
    if (*p1 == ']') {
130
      for (p2 = p1; p2 > p0 && *p2 != '.' && *p2 != '['; --p2) ;
131
      if (*p2 == '[')
132
  ++p2;
133
      path->del(p2 - p0, p1 - p2);
134
    } else if (*p1 == ':') {
135
      path->append("[-]");
136
    } else {
137
      path->clear();
138
      path->append("[-]");
139
    }
140
  } else if ((q1 = strrchr(fileName, '.')) && !strncmp(q1, ".DIR;", 5)) {
141
    if (*p1 == ']') {
142
      path->insert(p1 - p0, '.');
143
      path->insert(p1 - p0 + 1, fileName, q1 - fileName);
144
    } else if (*p1 == ':') {
145
      path->append('[');
146
      path->append(']');
147
      path->append(fileName, q1 - fileName);
148
    } else {
149
      path->clear();
150
      path->append(fileName, q1 - fileName);
151
    }
152
  } else {
153
    if (*p1 != ']' && *p1 != ':')
154
      path->clear();
155
    path->append(fileName);
156
  }
157
  return path;
158
159
#elif defined(_WIN32)
160
  //---------- Win32 ----------
161
  GString *tmp;
162
  char buf[256];
163
  char *fp;
164
165
  tmp = new GString(path);
166
  tmp->append('/');
167
  tmp->append(fileName);
168
  GetFullPathNameA(tmp->getCString(), sizeof(buf), buf, &fp);
169
  delete tmp;
170
  path->clear();
171
  path->append(buf);
172
  return path;
173
174
#elif defined(ACORN)
175
  //---------- RISCOS ----------
176
  char *p;
177
  int i;
178
179
  path->append(".");
180
  i = path->getLength();
181
  path->append(fileName);
182
  for (p = path->getCString() + i; *p; ++p) {
183
    if (*p == '/') {
184
      *p = '.';
185
    } else if (*p == '.') {
186
      *p = '/';
187
    }
188
  }
189
  return path;
190
191
#elif defined(__EMX__)
192
  //---------- OS/2+EMX ----------
193
  int i;
194
195
  // appending "." does nothing
196
  if (!strcmp(fileName, "."))
197
    return path;
198
199
  // appending ".." goes up one directory
200
  if (!strcmp(fileName, "..")) {
201
    for (i = path->getLength() - 2; i >= 0; --i) {
202
      if (path->getChar(i) == '/' || path->getChar(i) == '\\' ||
203
    path->getChar(i) == ':')
204
  break;
205
    }
206
    if (i <= 0) {
207
      if (path->getChar(0) == '/' || path->getChar(0) == '\\') {
208
  path->del(1, path->getLength() - 1);
209
      } else if (path->getLength() >= 2 && path->getChar(1) == ':') {
210
  path->del(2, path->getLength() - 2);
211
      } else {
212
  path->clear();
213
  path->append("..");
214
      }
215
    } else {
216
      if (path->getChar(i-1) == ':')
217
  ++i;
218
      path->del(i, path->getLength() - i);
219
    }
220
    return path;
221
  }
222
223
  // otherwise, append "/" and new path component
224
  if (path->getLength() > 0 &&
225
      path->getChar(path->getLength() - 1) != '/' &&
226
      path->getChar(path->getLength() - 1) != '\\')
227
    path->append('/');
228
  path->append(fileName);
229
  return path;
230
231
#else
232
  //---------- Unix ----------
233
172k
  int i;
234
235
  // appending "." does nothing
236
172k
  if (!strcmp(fileName, "."))
237
0
    return path;
238
239
  // appending ".." goes up one directory
240
172k
  if (!strcmp(fileName, "..")) {
241
0
    for (i = path->getLength() - 2; i >= 0; --i) {
242
0
      if (path->getChar(i) == '/')
243
0
  break;
244
0
    }
245
0
    if (i <= 0) {
246
0
      if (path->getChar(0) == '/') {
247
0
  path->del(1, path->getLength() - 1);
248
0
      } else {
249
0
  path->clear();
250
0
  path->append("..");
251
0
      }
252
0
    } else {
253
0
      path->del(i, path->getLength() - i);
254
0
    }
255
0
    return path;
256
0
  }
257
258
  // otherwise, append "/" and new path component
259
172k
  if (path->getLength() > 0 &&
260
172k
      path->getChar(path->getLength() - 1) != '/')
261
172k
    path->append('/');
262
172k
  path->append(fileName);
263
172k
  return path;
264
172k
#endif
265
172k
}
266
267
0
GString *grabPath(char *fileName) {
268
#ifdef VMS
269
  //---------- VMS ----------
270
  char *p;
271
272
  if ((p = strrchr(fileName, ']')))
273
    return new GString(fileName, p + 1 - fileName);
274
  if ((p = strrchr(fileName, ':')))
275
    return new GString(fileName, p + 1 - fileName);
276
  return new GString();
277
278
#elif defined(__EMX__) || defined(_WIN32)
279
  //---------- OS/2+EMX and Win32 ----------
280
  char *p;
281
282
  if ((p = strrchr(fileName, '/')))
283
    return new GString(fileName, (int)(p - fileName));
284
  if ((p = strrchr(fileName, '\\')))
285
    return new GString(fileName, (int)(p - fileName));
286
  if ((p = strrchr(fileName, ':')))
287
    return new GString(fileName, (int)(p + 1 - fileName));
288
  return new GString();
289
290
#elif defined(ACORN)
291
  //---------- RISCOS ----------
292
  char *p;
293
294
  if ((p = strrchr(fileName, '.')))
295
    return new GString(fileName, p - fileName);
296
  return new GString();
297
298
#else
299
  //---------- Unix ----------
300
0
  char *p;
301
302
0
  if ((p = strrchr(fileName, '/')))
303
0
    return new GString(fileName, (int)(p - fileName));
304
0
  return new GString();
305
0
#endif
306
0
}
307
308
0
GBool isAbsolutePath(char *path) {
309
#ifdef VMS
310
  //---------- VMS ----------
311
  return strchr(path, ':') ||
312
   (path[0] == '[' && path[1] != '.' && path[1] != '-');
313
314
#elif defined(__EMX__) || defined(_WIN32)
315
  //---------- OS/2+EMX and Win32 ----------
316
  return path[0] == '/' || path[0] == '\\' || path[1] == ':';
317
318
#elif defined(ACORN)
319
  //---------- RISCOS ----------
320
  return path[0] == '$';
321
322
#else
323
  //---------- Unix ----------
324
0
  return path[0] == '/';
325
0
#endif
326
0
}
327
328
0
GString *makePathAbsolute(GString *path) {
329
#ifdef VMS
330
  //---------- VMS ----------
331
  char buf[PATH_MAX+1];
332
333
  if (!isAbsolutePath(path->getCString())) {
334
    if (getcwd(buf, sizeof(buf))) {
335
      path->insert(0, buf);
336
    }
337
  }
338
  return path;
339
340
#elif defined(_WIN32)
341
  //---------- Win32 ----------
342
  char buf[MAX_PATH];
343
  char *fp;
344
345
  buf[0] = '\0';
346
  if (!GetFullPathNameA(path->getCString(), MAX_PATH, buf, &fp)) {
347
    path->clear();
348
    return path;
349
  }
350
  path->clear();
351
  path->append(buf);
352
  return path;
353
354
#elif defined(ACORN)
355
  //---------- RISCOS ----------
356
  path->insert(0, '@');
357
  return path;
358
359
#else
360
  //---------- Unix and OS/2+EMX ----------
361
0
  struct passwd *pw;
362
0
  char buf[PATH_MAX+1];
363
0
  GString *s;
364
0
  char *p1, *p2;
365
0
  int n;
366
367
0
  if (path->getChar(0) == '~') {
368
0
    if (path->getChar(1) == '/' ||
369
#ifdef __EMX__
370
  path->getChar(1) == '\\' ||
371
#endif
372
0
  path->getLength() == 1) {
373
0
      path->del(0, 1);
374
0
      s = getHomeDir();
375
0
      path->insert(0, s);
376
0
      delete s;
377
0
    } else {
378
0
      p1 = path->getCString() + 1;
379
#ifdef __EMX__
380
      for (p2 = p1; *p2 && *p2 != '/' && *p2 != '\\'; ++p2) ;
381
#else
382
0
      for (p2 = p1; *p2 && *p2 != '/'; ++p2) ;
383
0
#endif
384
0
      if ((n = (int)(p2 - p1)) > PATH_MAX)
385
0
  n = PATH_MAX;
386
0
      strncpy(buf, p1, n);
387
0
      buf[n] = '\0';
388
0
      if ((pw = getpwnam(buf))) {
389
0
  path->del(0, (int)(p2 - p1 + 1));
390
0
  path->insert(0, pw->pw_dir);
391
0
      }
392
0
    }
393
0
  } else if (!isAbsolutePath(path->getCString())) {
394
0
    if (getcwd(buf, sizeof(buf))) {
395
0
#ifndef __EMX__
396
0
      path->insert(0, '/');
397
0
#endif
398
0
      path->insert(0, buf);
399
0
    }
400
0
  }
401
0
  return path;
402
0
#endif
403
0
}
404
405
0
GBool pathIsFile(const char *path) {
406
#ifdef _WIN32
407
  wchar_t wPath[winMaxLongPath + 1];
408
  fileNameToUCS2(path, wPath, winMaxLongPath + 1);
409
  DWORD attr = GetFileAttributesW(wPath);
410
  return attr != INVALID_FILE_ATTRIBUTES &&
411
         !(attr & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE));
412
#else
413
0
  struct stat statBuf;
414
0
  return stat(path, &statBuf) == 0 && S_ISREG(statBuf.st_mode);
415
0
#endif
416
0
}
417
418
0
GBool pathIsDir(const char *path) {
419
#ifdef _WIN32
420
  wchar_t wPath[winMaxLongPath + 1];
421
  fileNameToUCS2(path, wPath, winMaxLongPath + 1);
422
  DWORD attr = GetFileAttributesW(wPath);
423
  return attr != INVALID_FILE_ATTRIBUTES && (attr & FILE_ATTRIBUTE_DIRECTORY);
424
#else
425
0
  struct stat statBuf;
426
0
  return stat(path, &statBuf) == 0 && S_ISDIR(statBuf.st_mode);
427
0
#endif
428
0
}
429
430
0
time_t getModTime(char *fileName) {
431
#ifdef _WIN32
432
  //~ should implement this, but it's (currently) only used in xpdf
433
  return 0;
434
#else
435
0
  struct stat statBuf;
436
437
0
  if (stat(fileName, &statBuf)) {
438
0
    return 0;
439
0
  }
440
0
  return statBuf.st_mtime;
441
0
#endif
442
0
}
443
444
GBool openTempFile(GString **name, FILE **f,
445
0
       const char *mode, const char *ext) {
446
#if defined(_WIN32)
447
  //---------- Win32 ----------
448
  char tempPath[MAX_PATH + 1];
449
  GString *s, *s2;
450
  FILE *f2;
451
  DWORD n;
452
  int t, i;
453
454
  // this has the standard race condition problem, but I haven't found
455
  // a better way to generate temp file names with extensions on
456
  // Windows
457
  n = GetTempPathA(sizeof(tempPath), tempPath);
458
  if (n > 0 && n <= sizeof(tempPath)) {
459
    s = new GString(tempPath);
460
    if (tempPath[n-1] != '\\') {
461
      s->append('\\');
462
    }
463
  } else {
464
    s = new GString(".\\");
465
  }
466
  s->appendf("xpdf_{0:d}_{1:d}_",
467
       (int)GetCurrentProcessId(), (int)GetCurrentThreadId());
468
  t = (int)time(NULL);
469
  for (i = 0; i < 1000; ++i) {
470
    s2 = GString::format("{0:t}{1:d}", s, t + i);
471
    if (ext) {
472
      s2->append(ext);
473
    }
474
    if (!(f2 = fopen(s2->getCString(), "r"))) {
475
      if (!(f2 = fopen(s2->getCString(), mode))) {
476
  delete s2;
477
  delete s;
478
  return gFalse;
479
      }
480
      *name = s2;
481
      *f = f2;
482
      delete s;
483
      return gTrue;
484
    }
485
    fclose(f2);
486
    delete s2;
487
  }
488
  delete s;
489
  return gFalse;
490
#elif defined(VMS) || defined(__EMX__) || defined(ACORN)
491
  //---------- non-Unix ----------
492
  char *s;
493
494
  // There is a security hole here: an attacker can create a symlink
495
  // with this file name after the tmpnam call and before the fopen
496
  // call.  I will happily accept fixes to this function for non-Unix
497
  // OSs.
498
  if (!(s = tmpnam(NULL))) {
499
    return gFalse;
500
  }
501
  *name = new GString(s);
502
  if (ext) {
503
    (*name)->append(ext);
504
  }
505
  if (!(*f = fopen((*name)->getCString(), mode))) {
506
    delete (*name);
507
    *name = NULL;
508
    return gFalse;
509
  }
510
  return gTrue;
511
#else
512
  //---------- Unix ----------
513
0
  char *s;
514
0
  int fd;
515
516
0
  if (ext) {
517
0
#if HAVE_MKSTEMPS
518
0
    if ((s = getenv("TMPDIR"))) {
519
0
      *name = new GString(s);
520
0
    } else {
521
0
      *name = new GString("/tmp");
522
0
    }
523
0
    (*name)->append("/XXXXXX")->append(ext);
524
0
    fd = mkstemps((*name)->getCString(), (int)strlen(ext));
525
#else
526
    if (!(s = tmpnam(NULL))) {
527
      return gFalse;
528
    }
529
    *name = new GString(s);
530
    (*name)->append(ext);
531
    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
532
#endif
533
0
  } else {
534
0
#if HAVE_MKSTEMP
535
0
    if ((s = getenv("TMPDIR"))) {
536
0
      *name = new GString(s);
537
0
    } else {
538
0
      *name = new GString("/tmp");
539
0
    }
540
0
    (*name)->append("/XXXXXX");
541
0
    fd = mkstemp((*name)->getCString());
542
#else // HAVE_MKSTEMP
543
    if (!(s = tmpnam(NULL))) {
544
      return gFalse;
545
    }
546
    *name = new GString(s);
547
    fd = open((*name)->getCString(), O_WRONLY | O_CREAT | O_EXCL, 0600);
548
#endif // HAVE_MKSTEMP
549
0
  }
550
0
  if (fd < 0 || !(*f = fdopen(fd, mode))) {
551
0
    delete *name;
552
0
    *name = NULL;
553
0
    return gFalse;
554
0
  }
555
0
  return gTrue;
556
0
#endif
557
0
}
558
559
0
GBool createDir(char *path, int mode) {
560
#ifdef _WIN32
561
  return !_mkdir(path);
562
#else
563
0
  return !mkdir(path, mode);
564
0
#endif
565
0
}
566
567
0
GBool executeCommand(char *cmd) {
568
#ifdef VMS
569
  return system(cmd) ? gTrue : gFalse;
570
#else
571
0
  return system(cmd) ? gFalse : gTrue;
572
0
#endif
573
0
}
574
575
#ifdef _WIN32
576
GString *fileNameToUTF8(char *path) {
577
  GString *s;
578
  char *p;
579
580
  s = new GString();
581
  for (p = path; *p; ++p) {
582
    if (*p & 0x80) {
583
      s->append((char)(0xc0 | ((*p >> 6) & 0x03)));
584
      s->append((char)(0x80 | (*p & 0x3f)));
585
    } else {
586
      s->append(*p);
587
    }
588
  }
589
  return s;
590
}
591
592
GString *fileNameToUTF8(wchar_t *path) {
593
  GString *s;
594
  wchar_t *p;
595
596
  s = new GString();
597
  for (p = path; *p; ++p) {
598
    if (*p < 0x80) {
599
      s->append((char)*p);
600
    } else if (*p < 0x800) {
601
      s->append((char)(0xc0 | ((*p >> 6) & 0x1f)));
602
      s->append((char)(0x80 | (*p & 0x3f)));
603
    } else {
604
      s->append((char)(0xe0 | ((*p >> 12) & 0x0f)));
605
      s->append((char)(0x80 | ((*p >> 6) & 0x3f)));
606
      s->append((char)(0x80 | (*p & 0x3f)));
607
    }
608
  }
609
  return s;
610
}
611
612
GString *fileNameMultiByteToUTF8(char *path) {
613
  wchar_t fileNameW[winMaxLongPath + 1];
614
  if (MultiByteToWideChar(CP_OEMCP, 0, path, -1,
615
         fileNameW, sizeof(fileNameW) / sizeof(wchar_t))) {
616
    return fileNameToUTF8(fileNameW);
617
  } else {
618
    // shouldn't happen, but just in case...
619
    return new GString(path);
620
  }
621
}
622
623
wchar_t *fileNameToUCS2(const char *path, wchar_t *out, size_t outSize) {
624
  const char *p;
625
  size_t i;
626
627
  for (p = path, i = 0; *p && i < outSize - 1; ++i) {
628
    if ((p[0] & 0xe0) == 0xc0 &&
629
  p[1] && (p[1] & 0xc0) == 0x80) {
630
      out[i] = (wchar_t)(((p[0] & 0x1f) << 6) |
631
        (p[1] & 0x3f));
632
      p += 2;
633
    } else if ((p[0] & 0xf0) == 0xe0 &&
634
         (p[1] & 0xc0) == 0x80 &&
635
         (p[2] & 0xc0) == 0x80) {
636
      out[i] = (wchar_t)(((p[0] & 0x0f) << 12) |
637
       ((p[1] & 0x3f) << 6) |
638
        (p[2] & 0x3f));
639
      p += 3;
640
    } else {
641
      out[i] = (wchar_t)(p[0] & 0xff);
642
      p += 1;
643
    }
644
  }
645
  out[i] = (wchar_t)0;
646
  return out;
647
}
648
#endif
649
650
0
FILE *openFile(const char *path, const char *mode) {
651
#if defined(_WIN32)
652
  wchar_t wPath[winMaxLongPath + 1];
653
  wchar_t wMode[8];
654
  int i;
655
656
  fileNameToUCS2(path, wPath, winMaxLongPath + 1);
657
  for (i = 0; mode[i] && i < sizeof(wMode)/sizeof(wchar_t) - 1; ++i) {
658
    wMode[i] = (wchar_t)(mode[i] & 0xff);
659
  }
660
  wMode[i] = (wchar_t)0;
661
  readWindowsShortcut(wPath, winMaxLongPath + 1);
662
  return _wfopen(wPath, wMode);
663
#elif defined(VMS)
664
  return fopen(path, mode, "ctx=stm");
665
#else
666
0
  return fopen(path, mode);
667
0
#endif
668
0
}
669
670
#ifdef _WIN32
671
void readWindowsShortcut(wchar_t *wPath, size_t wPathSize) {
672
  size_t n = wcslen(wPath);
673
  if (n < 4 || wcscmp(wPath + n - 4, L".lnk")) {
674
    return;
675
  }
676
  IShellLinkW *shellLink;
677
  HRESULT hres;
678
  hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
679
        IID_IShellLinkW, (LPVOID *)&shellLink);
680
  bool needCoUninit = false;
681
  if (hres == CO_E_NOTINITIALIZED) {
682
    CoInitialize(NULL);
683
    needCoUninit = true;
684
    hres = CoCreateInstance(CLSID_ShellLink, NULL, CLSCTX_INPROC_SERVER,
685
          IID_IShellLinkW, (LPVOID *)&shellLink);
686
  }
687
  if (FAILED(hres)) {
688
    return;
689
  }
690
  IPersistFile *persistFile;
691
  hres = shellLink->QueryInterface(IID_IPersistFile, (LPVOID *)&persistFile);
692
  if (FAILED(hres)) {
693
    return;
694
  }
695
  hres = persistFile->Load(wPath, STGM_READ);
696
  if (FAILED(hres)) {
697
    fprintf(stderr, "IPersistFile.Load failed: 0x%08lx\n", hres);
698
    exit(1);
699
  }
700
  wchar_t target[winMaxLongPath + 1];
701
  hres = shellLink->GetPath(target, winMaxLongPath + 1, NULL, 0);
702
  if (FAILED(hres)) {
703
    return;
704
  }
705
  shellLink->Release();
706
  if (needCoUninit) {
707
    CoUninitialize();
708
  }
709
  if (wcslen(target) > wPathSize - 1) {
710
    return;
711
  }
712
  wcscpy(wPath, target);
713
}
714
#endif
715
716
0
int makeDir(const char *path, int mode) {
717
#ifdef _WIN32
718
  wchar_t wPath[winMaxLongPath + 1];
719
  return _wmkdir(fileNameToUCS2(path, wPath, winMaxLongPath + 1));
720
#else
721
0
  return mkdir(path, (mode_t)mode);
722
0
#endif
723
0
}
724
725
0
char *getLine(char *buf, int size, FILE *f) {
726
0
  int c, i;
727
728
0
  i = 0;
729
0
  while (i < size - 1) {
730
0
    if ((c = fgetc(f)) == EOF) {
731
0
      break;
732
0
    }
733
0
    buf[i++] = (char)c;
734
0
    if (c == '\x0a') {
735
0
      break;
736
0
    }
737
0
    if (c == '\x0d') {
738
0
      c = fgetc(f);
739
0
      if (c == '\x0a' && i < size - 1) {
740
0
  buf[i++] = (char)c;
741
0
      } else if (c != EOF) {
742
0
  ungetc(c, f);
743
0
      }
744
0
      break;
745
0
    }
746
0
  }
747
0
  buf[i] = '\0';
748
0
  if (i == 0) {
749
0
    return NULL;
750
0
  }
751
0
  return buf;
752
0
}
753
754
0
int gfseek(FILE *f, GFileOffset offset, int whence) {
755
0
#if HAVE_FSEEKO
756
0
  return fseeko(f, offset, whence);
757
#elif HAVE_FSEEK64
758
  return fseek64(f, offset, whence);
759
#elif HAVE_FSEEKI64
760
  return _fseeki64(f, offset, whence);
761
#else
762
  return fseek(f, offset, whence);
763
#endif
764
0
}
765
766
0
GFileOffset gftell(FILE *f) {
767
0
#if HAVE_FSEEKO
768
0
  return ftello(f);
769
#elif HAVE_FSEEK64
770
  return ftell64(f);
771
#elif HAVE_FSEEKI64
772
  return _ftelli64(f);
773
#else
774
  return ftell(f);
775
#endif
776
0
}
777
778
0
void fixCommandLine(int *argc, char **argv[]) {
779
#ifdef _WIN32
780
  int argcw;
781
  wchar_t **argvw;
782
  GString *arg;
783
  int i;
784
785
  argvw = CommandLineToArgvW(GetCommandLineW(), &argcw);
786
  if (!argvw || argcw < 0) {
787
    return;
788
  }
789
790
  *argc = argcw;
791
792
  *argv = (char **)gmallocn(argcw + 1, sizeof(char *));
793
  for (i = 0; i < argcw; ++i) {
794
    arg = fileNameToUTF8(argvw[i]);
795
    (*argv)[i] = copyString(arg->getCString());
796
    delete arg;
797
  }
798
  (*argv)[argcw] = NULL;
799
800
  LocalFree(argvw);
801
#endif
802
0
}