VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/path.cpp@ 14515

Last change on this file since 14515 was 14324, checked in by vboxsync, 16 years ago

RTPathStripFilename root fix.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 22.7 KB
Line 
1/* $Id: path.cpp 14324 2008-11-18 19:09:34Z vboxsync $ */
2/** @file
3 * IPRT - Path Manipulation.
4 */
5
6/*
7 * Copyright (C) 2006-2007 Sun Microsystems, Inc.
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 *
17 * The contents of this file may alternatively be used under the terms
18 * of the Common Development and Distribution License Version 1.0
19 * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
20 * VirtualBox OSE distribution, in which case the provisions of the
21 * CDDL are applicable instead of those of the GPL.
22 *
23 * You may elect to license modified versions of this file under the
24 * terms and conditions of either the GPL or the CDDL or both.
25 *
26 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
27 * Clara, CA 95054 USA or visit http://www.sun.com if you need
28 * additional information or have any questions.
29 */
30
31
32/*******************************************************************************
33* Header Files *
34*******************************************************************************/
35#include <iprt/path.h>
36#include <iprt/dir.h>
37#include <iprt/param.h>
38#include <iprt/string.h>
39#include <iprt/assert.h>
40#include <iprt/string.h>
41#include <iprt/ctype.h>
42#include <iprt/err.h>
43#include <iprt/uni.h>
44#include "internal/fs.h"
45#include "internal/path.h"
46#include "internal/process.h"
47
48
49/**
50 * Strips the filename from a path.
51 *
52 * @param pszPath Path which filename should be extracted from.
53 * If only filename in the string a '.' will be returned.
54 *
55 */
56RTDECL(void) RTPathStripFilename(char *pszPath)
57{
58 char *psz = pszPath;
59 char *pszLastSep = NULL;
60
61
62 for (;; psz++)
63 {
64 switch (*psz)
65 {
66 /* handle separators. */
67#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
68 case ':':
69 pszLastSep = psz + 1;
70 if (RTPATH_IS_SLASH(psz[1]))
71 pszPath = psz + 1;
72 else
73 pszPath = psz;
74 break;
75
76 case '\\':
77#endif
78 case '/':
79 pszLastSep = psz;
80 break;
81
82 /* the end */
83 case '\0':
84 if (!pszLastSep)
85 {
86 /* no directory component */
87 pszPath[0] = '.';
88 pszPath[1] = '\0';
89 }
90 else if (pszLastSep == pszPath)
91 {
92 /* only root. */
93 pszLastSep[1] = '\0';
94 }
95 else
96 pszLastSep[0] = '\0';
97 return;
98 }
99 }
100 /* will never get here */
101}
102
103
104/**
105 * Strips the extension from a path.
106 *
107 * @param pszPath Path which extension should be stripped.
108 */
109RTDECL(void) RTPathStripExt(char *pszPath)
110{
111 char *pszDot = NULL;
112 for (;; pszPath++)
113 {
114 switch (*pszPath)
115 {
116 /* handle separators. */
117#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
118 case ':':
119 case '\\':
120#endif
121 case '/':
122 pszDot = NULL;
123 break;
124 case '.':
125 pszDot = pszPath;
126 break;
127
128 /* the end */
129 case '\0':
130 if (pszDot)
131 *pszDot = '\0';
132 return;
133 }
134 }
135 /* will never get here */
136}
137
138
139/**
140 * Parses a path.
141 *
142 * It figures the length of the directory component, the offset of
143 * the file name and the location of the suffix dot.
144 *
145 * @returns The path length.
146 *
147 * @param pszPath Path to find filename in.
148 * @param pcbDir Where to put the length of the directory component.
149 * If no directory, this will be 0. Optional.
150 * @param poffName Where to store the filename offset.
151 * If empty string or if it's ending with a slash this
152 * will be set to -1. Optional.
153 * @param poffSuff Where to store the suffix offset (the last dot).
154 * If empty string or if it's ending with a slash this
155 * will be set to -1. Optional.
156 * @param pfFlags Where to set flags returning more information about
157 * the path. For the future. Optional.
158 */
159RTDECL(size_t) RTPathParse(const char *pszPath, size_t *pcchDir, ssize_t *poffName, ssize_t *poffSuff)
160{
161 const char *psz = pszPath;
162 ssize_t offRoot = 0;
163 const char *pszName = pszPath;
164 const char *pszLastDot = NULL;
165
166 for (;; psz++)
167 {
168 switch (*psz)
169 {
170 /* handle separators. */
171#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
172 case ':':
173 pszName = psz + 1;
174 offRoot = pszName - psz;
175 break;
176
177 case '\\':
178#endif
179 case '/':
180 pszName = psz + 1;
181 break;
182
183 case '.':
184 pszLastDot = psz;
185 break;
186
187 /*
188 * The end. Complete the results.
189 */
190 case '\0':
191 {
192 ssize_t offName = *pszName != '\0' ? pszName - pszPath : -1;
193 if (poffName)
194 *poffName = offName;
195
196 if (poffSuff)
197 {
198 ssize_t offSuff = -1;
199 if (pszLastDot)
200 {
201 offSuff = pszLastDot - pszPath;
202 if (offSuff <= offName)
203 offSuff = -1;
204 }
205 *poffSuff = offSuff;
206 }
207
208 if (pcchDir)
209 {
210 ssize_t off = offName - 1;
211 while (off >= offRoot && RTPATH_IS_SLASH(pszPath[off]))
212 off--;
213 *pcchDir = RT_MAX(off, offRoot) + 1;
214 }
215
216 return psz - pszPath;
217 }
218 }
219 }
220
221 /* will never get here */
222 return 0;
223}
224
225
226/**
227 * Finds the filename in a path.
228 *
229 * @returns Pointer to filename within pszPath.
230 * @returns NULL if no filename (i.e. empty string or ends with a slash).
231 * @param pszPath Path to find filename in.
232 */
233RTDECL(char *) RTPathFilename(const char *pszPath)
234{
235 const char *psz = pszPath;
236 const char *pszName = pszPath;
237
238 for (;; psz++)
239 {
240 switch (*psz)
241 {
242 /* handle separators. */
243#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
244 case ':':
245 pszName = psz + 1;
246 break;
247
248 case '\\':
249#endif
250 case '/':
251 pszName = psz + 1;
252 break;
253
254 /* the end */
255 case '\0':
256 if (*pszName)
257 return (char *)(void *)pszName;
258 return NULL;
259 }
260 }
261
262 /* will never get here */
263 return NULL;
264}
265
266
267/**
268 * Strips the trailing slashes of a path name.
269 *
270 * @param pszPath Path to strip.
271 *
272 * @todo This isn't safe for a root element! Needs fixing.
273 */
274RTDECL(void) RTPathStripTrailingSlash(char *pszPath)
275{
276 char *pszEnd = strchr(pszPath, '\0');
277 while (pszEnd-- > pszPath)
278 {
279 switch (*pszEnd)
280 {
281 case '/':
282#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
283 case '\\':
284#endif
285 *pszEnd = '\0';
286 break;
287 default:
288 return;
289 }
290 }
291 return;
292}
293
294
295/**
296 * Finds the extension part of in a path.
297 *
298 * @returns Pointer to extension within pszPath.
299 * @returns NULL if no extension.
300 * @param pszPath Path to find extension in.
301 */
302RTDECL(char *) RTPathExt(const char *pszPath)
303{
304 const char *psz = pszPath;
305 const char *pszExt = NULL;
306
307 for (;; psz++)
308 {
309 switch (*psz)
310 {
311 /* handle separators. */
312#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
313 case ':':
314 pszExt = NULL;
315 break;
316
317 case '\\':
318#endif
319 case '/':
320 pszExt = NULL;
321 break;
322 case '.':
323 pszExt = psz;
324 break;
325
326 /* the end */
327 case '\0':
328 if (pszExt)
329 return (char *)(void *)pszExt;
330 return NULL;
331 }
332 }
333
334 /* will never get here */
335 return NULL;
336}
337
338
339/**
340 * Checks if a path have an extension.
341 *
342 * @returns true if extension present.
343 * @returns false if no extension.
344 * @param pszPath Path to check.
345 */
346RTDECL(bool) RTPathHaveExt(const char *pszPath)
347{
348 return RTPathExt(pszPath) != NULL;
349}
350
351
352/**
353 * Checks if a path includes more than a filename.
354 *
355 * @returns true if path present.
356 * @returns false if no path.
357 * @param pszPath Path to check.
358 */
359RTDECL(bool) RTPathHavePath(const char *pszPath)
360{
361#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
362 return strpbrk(pszPath, "/\\:") != NULL;
363#else
364 return strpbrk(pszPath, "/") != NULL;
365#endif
366}
367
368
369/**
370 * Helper for RTPathCompare() and RTPathStartsWith().
371 *
372 * @returns similar to strcmp.
373 * @param pszPath1 Path to compare.
374 * @param pszPath2 Path to compare.
375 * @param fLimit Limit the comparison to the length of \a pszPath2
376 * @internal
377 */
378static int rtPathCompare(const char *pszPath1, const char *pszPath2, bool fLimit)
379{
380 if (pszPath1 == pszPath2)
381 return 0;
382 if (!pszPath1)
383 return -1;
384 if (!pszPath2)
385 return 1;
386
387#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
388 PRTUNICP puszPath1;
389 int rc = RTStrToUni(pszPath1, &puszPath1);
390 if (RT_FAILURE(rc))
391 return -1;
392 PRTUNICP puszPath2;
393 rc = RTStrToUni(pszPath2, &puszPath2);
394 if (RT_FAILURE(rc))
395 {
396 RTUniFree(puszPath1);
397 return 1;
398 }
399
400 int iDiff = 0;
401 PRTUNICP puszTmpPath1 = puszPath1;
402 PRTUNICP puszTmpPath2 = puszPath2;
403 for (;;)
404 {
405 register RTUNICP uc1 = *puszTmpPath1;
406 register RTUNICP uc2 = *puszTmpPath2;
407 if (uc1 != uc2)
408 {
409 if (uc1 == '\\')
410 uc1 = '/';
411 else
412 uc1 = RTUniCpToUpper(uc1);
413 if (uc2 == '\\')
414 uc2 = '/';
415 else
416 uc2 = RTUniCpToUpper(uc2);
417 if (uc1 != uc2)
418 {
419 iDiff = uc1 > uc2 ? 1 : -1; /* (overflow/underflow paranoia) */
420 if (fLimit && uc2 == '\0')
421 iDiff = 0;
422 break;
423 }
424 }
425 if (!uc1)
426 break;
427 puszTmpPath1++;
428 puszTmpPath2++;
429
430 }
431
432 RTUniFree(puszPath2);
433 RTUniFree(puszPath1);
434 return iDiff;
435
436#else
437 if (!fLimit)
438 return strcmp(pszPath1, pszPath2);
439 return strncmp(pszPath1, pszPath2, strlen(pszPath2));
440#endif
441}
442
443
444/**
445 * Compares two paths.
446 *
447 * The comparison takes platform-dependent details into account,
448 * such as:
449 * <ul>
450 * <li>On DOS-like platforms, both |\| and |/| separator chars are considered
451 * to be equal.
452 * <li>On platforms with case-insensitive file systems, mismatching characters
453 * are uppercased and compared again.
454 * </ul>
455 *
456 * @remark
457 *
458 * File system details are currently ignored. This means that you won't get
459 * case-insentive compares on unix systems when a path goes into a case-insensitive
460 * filesystem like FAT, HPFS, HFS, NTFS, JFS, or similar. For NT, OS/2 and similar
461 * you'll won't get case-sensitve compares on a case-sensitive file system.
462 *
463 * @param pszPath1 Path to compare (must be an absolute path).
464 * @param pszPath2 Path to compare (must be an absolute path).
465 *
466 * @returns @< 0 if the first path less than the second path.
467 * @returns 0 if the first path identical to the second path.
468 * @returns @> 0 if the first path greater than the second path.
469 */
470RTDECL(int) RTPathCompare(const char *pszPath1, const char *pszPath2)
471{
472 return rtPathCompare(pszPath1, pszPath2, false /* full path lengths */);
473}
474
475
476/**
477 * Checks if a path starts with the given parent path.
478 *
479 * This means that either the path and the parent path matches completely, or that
480 * the path is to some file or directory residing in the tree given by the parent
481 * directory.
482 *
483 * The path comparison takes platform-dependent details into account,
484 * see RTPathCompare() for details.
485 *
486 * @param pszPath Path to check, must be an absolute path.
487 * @param pszParentPath Parent path, must be an absolute path.
488 * No trailing directory slash!
489 *
490 * @returns |true| when \a pszPath starts with \a pszParentPath (or when they
491 * are identical), or |false| otherwise.
492 *
493 * @remark This API doesn't currently handle root directory compares in a manner
494 * consistant with the other APIs. RTPathStartsWith(pszSomePath, "/") will
495 * not work if pszSomePath isn't "/".
496 */
497RTDECL(bool) RTPathStartsWith(const char *pszPath, const char *pszParentPath)
498{
499 if (pszPath == pszParentPath)
500 return true;
501 if (!pszPath || !pszParentPath)
502 return false;
503
504 if (rtPathCompare(pszPath, pszParentPath, true /* limited by path 2 */) != 0)
505 return false;
506
507 const size_t cchParentPath = strlen(pszParentPath);
508 return RTPATH_IS_SLASH(pszPath[cchParentPath])
509 || pszPath[cchParentPath] == '\0';
510}
511
512
513/**
514 * Same as RTPathReal only the result is RTStrDup()'ed.
515 *
516 * @returns Pointer to real path. Use RTStrFree() to free this string.
517 * @returns NULL if RTPathReal() or RTStrDup() fails.
518 * @param pszPath
519 */
520RTDECL(char *) RTPathRealDup(const char *pszPath)
521{
522 char szPath[RTPATH_MAX];
523 int rc = RTPathReal(pszPath, szPath, sizeof(szPath));
524 if (RT_SUCCESS(rc))
525 return RTStrDup(szPath);
526 return NULL;
527}
528
529
530/**
531 * Same as RTPathAbs only the result is RTStrDup()'ed.
532 *
533 * @returns Pointer to real path. Use RTStrFree() to free this string.
534 * @returns NULL if RTPathAbs() or RTStrDup() fails.
535 * @param pszPath The path to resolve.
536 */
537RTDECL(char *) RTPathAbsDup(const char *pszPath)
538{
539 char szPath[RTPATH_MAX];
540 int rc = RTPathAbs(pszPath, szPath, sizeof(szPath));
541 if (RT_SUCCESS(rc))
542 return RTStrDup(szPath);
543 return NULL;
544}
545
546
547/**
548 * Returns the length of the volume name specifier of the given path.
549 * If no such specifier zero is returned.
550 */
551size_t rtPathVolumeSpecLen(const char *pszPath)
552{
553#if defined (RT_OS_OS2) || defined (RT_OS_WINDOWS)
554 if (pszPath && *pszPath)
555 {
556 /* UTC path. */
557 if ( (pszPath[0] == '\\' || pszPath[0] == '/')
558 && (pszPath[1] == '\\' || pszPath[1] == '/'))
559 return strcspn(pszPath + 2, "\\/") + 2;
560
561 /* Drive letter. */
562 if ( pszPath[1] == ':'
563 && toupper(pszPath[0]) >= 'A' && toupper(pszPath[0]) <= 'Z')
564 return 2;
565 }
566 return 0;
567
568#else
569 /* This isn't quite right when looking at the above stuff, but it works assuming that '//' does not mean UNC. */
570 /// @todo (dmik) well, it's better to consider there's no volume name
571 // at all on *nix systems
572 return 0;
573// return pszPath && pszPath[0] == '/';
574#endif
575}
576
577
578/**
579 * Get the absolute path (no symlinks, no . or .. components), assuming the
580 * given base path as the current directory. The resulting path doesn't have
581 * to exist.
582 *
583 * @returns iprt status code.
584 * @param pszBase The base path to act like a current directory.
585 * When NULL, the actual cwd is used (i.e. the call
586 * is equivalent to RTPathAbs(pszPath, ...).
587 * @param pszPath The path to resolve.
588 * @param pszAbsPath Where to store the absolute path.
589 * @param cchAbsPath Size of the buffer.
590 */
591RTDECL(int) RTPathAbsEx(const char *pszBase, const char *pszPath, char *pszAbsPath, size_t cchAbsPath)
592{
593 if (pszBase && pszPath && !rtPathVolumeSpecLen(pszPath))
594 {
595#if defined(RT_OS_WINDOWS)
596 /* The format for very long paths is not supported. */
597 if ( (pszBase[0] == '/' || pszBase[0] == '\\')
598 && (pszBase[1] == '/' || pszBase[1] == '\\')
599 && pszBase[2] == '?'
600 && (pszBase[3] == '/' || pszBase[3] == '\\'))
601 return VERR_INVALID_NAME;
602#endif
603
604 /** @todo there are a couple of things which isn't 100% correct, although the
605 * current code will have to work for now - I don't have time to fix it right now.
606 *
607 * 1) On Windows & OS/2 we confuse '/' with an abspath spec and will
608 * not necessarily resolve it on the right drive.
609 * 2) A trailing slash in the base might cause UNC names to be created.
610 * 3) The lengths total doesn't have to be less than max length
611 * if the pszPath starts with a slash.
612 */
613 size_t cchBase = strlen(pszBase);
614 size_t cchPath = strlen(pszPath);
615 if (cchBase + cchPath >= RTPATH_MAX)
616 return VERR_FILENAME_TOO_LONG;
617
618 bool fRootSpec = pszPath[0] == '/'
619#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
620 || pszPath[0] == '\\'
621#endif
622 ;
623 size_t cchVolSpec = rtPathVolumeSpecLen(pszBase);
624 char szPath[RTPATH_MAX];
625 if (fRootSpec)
626 {
627 /* join the disk name from base and the path */
628 memcpy(szPath, pszBase, cchVolSpec);
629 strcpy(&szPath[cchVolSpec], pszPath);
630 }
631 else
632 {
633 /* join the base path and the path */
634 strcpy(szPath, pszBase);
635 szPath[cchBase] = RTPATH_DELIMITER;
636 strcpy(&szPath[cchBase + 1], pszPath);
637 }
638 return RTPathAbs(szPath, pszAbsPath, cchAbsPath);
639 }
640
641 /* Fallback to the non *Ex version */
642 return RTPathAbs(pszPath, pszAbsPath, cchAbsPath);
643}
644
645
646/**
647 * Same as RTPathAbsEx only the result is RTStrDup()'ed.
648 *
649 * @returns Pointer to the absolute path. Use RTStrFree() to free this string.
650 * @returns NULL if RTPathAbsEx() or RTStrDup() fails.
651 * @param pszBase The base path to act like a current directory.
652 * When NULL, the actual cwd is used (i.e. the call
653 * is equivalent to RTPathAbs(pszPath, ...).
654 * @param pszPath The path to resolve.
655 */
656RTDECL(char *) RTPathAbsExDup(const char *pszBase, const char *pszPath)
657{
658 char szPath[RTPATH_MAX];
659 int rc = RTPathAbsEx(pszBase, pszPath, szPath, sizeof(szPath));
660 if (RT_SUCCESS(rc))
661 return RTStrDup(szPath);
662 return NULL;
663}
664
665
666#ifndef RT_MINI
667
668RTDECL(int) RTPathProgram(char *pszPath, size_t cchPath)
669{
670 AssertReturn(g_szrtProcExePath[0], VERR_WRONG_ORDER);
671
672 /*
673 * Calc the length and check if there is space before copying.
674 */
675 size_t cch = g_cchrtProcDir;
676 if (cch <= cchPath)
677 {
678 memcpy(pszPath, g_szrtProcExePath, cch);
679 pszPath[cch] = '\0';
680 return VINF_SUCCESS;
681 }
682
683 AssertMsgFailed(("Buffer too small (%zu <= %zu)\n", cchPath, cch));
684 return VERR_BUFFER_OVERFLOW;
685}
686
687
688/**
689 * Gets the directory for architecture-independent application data, for
690 * example NLS files, module sources, ...
691 *
692 * Linux: /usr/shared/@<application@>
693 * Windows: @<program files directory@>/@<application@>
694 * Old path: same as RTPathProgram()
695 *
696 */
697RTDECL(int) RTPathAppPrivateNoArch(char *pszPath, size_t cchPath)
698{
699#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE)
700 char *pszUtf8Path;
701 int rc;
702 rc = rtPathFromNative(&pszUtf8Path, RTPATH_APP_PRIVATE);
703 if (RT_SUCCESS(rc))
704 {
705 size_t cchPathPrivateNoArch = strlen(pszUtf8Path);
706 if (cchPathPrivateNoArch < cchPath)
707 memcpy(pszPath, pszUtf8Path, cchPathPrivateNoArch + 1);
708 else
709 rc = VERR_BUFFER_OVERFLOW;
710 RTStrFree(pszUtf8Path);
711 }
712 return rc;
713#else
714 return RTPathProgram(pszPath, cchPath);
715#endif
716}
717
718
719/**
720 * Gets the directory for architecture-dependent application data, for
721 * example modules which can be loaded at runtime.
722 *
723 * Linux: /usr/lib/@<application@>
724 * Windows: @<program files directory@>/@<application@>
725 * Old path: same as RTPathProgram()
726 *
727 * @returns iprt status code.
728 * @param pszPath Buffer where to store the path.
729 * @param cchPath Buffer size in bytes.
730 */
731RTDECL(int) RTPathAppPrivateArch(char *pszPath, size_t cchPath)
732{
733#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_PRIVATE_ARCH)
734 char *pszUtf8Path;
735 int rc;
736 rc = rtPathFromNative(&pszUtf8Path, RTPATH_APP_PRIVATE_ARCH);
737 if (RT_SUCCESS(rc))
738 {
739 size_t cchPathPrivateArch = strlen(pszUtf8Path);
740 if (cchPathPrivateArch < cchPath)
741 memcpy(pszPath, pszUtf8Path, cchPathPrivateArch + 1);
742 else
743 rc = VERR_BUFFER_OVERFLOW;
744 RTStrFree(pszUtf8Path);
745 }
746 return rc;
747#else
748 return RTPathProgram(pszPath, cchPath);
749#endif
750}
751
752
753/**
754 * Gets the directory of shared libraries. This is not the same as
755 * RTPathAppPrivateArch() as Linux depends all shared libraries in
756 * a common global directory where ld.so can found them.
757 *
758 * Linux: /usr/lib
759 * Windows: @<program files directory@>/@<application@>
760 * Old path: same as RTPathProgram()
761 *
762 * @returns iprt status code.
763 * @param pszPath Buffer where to store the path.
764 * @param cchPath Buffer size in bytes.
765 */
766RTDECL(int) RTPathSharedLibs(char *pszPath, size_t cchPath)
767{
768#if !defined(RT_OS_WINDOWS) && defined(RTPATH_SHARED_LIBS)
769 char *pszUtf8Path;
770 int rc;
771 rc = rtPathFromNative(&pszUtf8Path, RTPATH_SHARED_LIBS);
772 if (RT_SUCCESS(rc))
773 {
774 size_t cchPathSharedLibs = strlen(pszUtf8Path);
775 if (cchPathSharedLibs < cchPath)
776 memcpy(pszPath, pszUtf8Path, cchPathSharedLibs + 1);
777 else
778 rc = VERR_BUFFER_OVERFLOW;
779 RTStrFree(pszUtf8Path);
780 }
781 return rc;
782#else
783 return RTPathProgram(pszPath, cchPath);
784#endif
785}
786
787
788/**
789 * Gets the directory for documentation.
790 *
791 * Linux: /usr/share/doc/@<application@>
792 * Windows: @<program files directory@>/@<application@>
793 * Old path: same as RTPathProgram()
794 *
795 * @returns iprt status code.
796 * @param pszPath Buffer where to store the path.
797 * @param cchPath Buffer size in bytes.
798 */
799RTDECL(int) RTPathAppDocs(char *pszPath, size_t cchPath)
800{
801#if !defined(RT_OS_WINDOWS) && defined(RTPATH_APP_DOCS)
802 char *pszUtf8Path;
803 int rc;
804 rc = rtPathFromNative(&pszUtf8Path, RTPATH_APP_DOCS);
805 if (RT_SUCCESS(rc))
806 {
807 size_t cchPathAppDocs = strlen(pszUtf8Path);
808 if (cchPathAppDocs < cchPath)
809 memcpy(pszPath, pszUtf8Path, cchPathAppDocs + 1);
810 else
811 rc = VERR_BUFFER_OVERFLOW;
812 RTStrFree(pszUtf8Path);
813 }
814 return rc;
815#else
816 return RTPathProgram(pszPath, cchPath);
817#endif
818}
819
820#endif /* !RT_MINI */
821
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette