pathLib.c
上传用户:nvosite88
上传日期:2007-01-17
资源大小:4983k
文件大小:19k
源码类别:

VxWorks

开发平台:

C/C++

  1. /* pathLib.c - file/directory path library */
  2. /* Copyright 1984-1992 Wind River Systems, Inc. */
  3. #include "copyright_wrs.h"
  4. /*
  5. modification history
  6. --------------------
  7. 02b,01oct93,jmm  removed the last change (02a)
  8. 02a,20jul93,jmm  changed pathArrayReduce() to cope with "../../../..."
  9. 01z,18jul92,smb  Changed errno.h to errnoLib.h.
  10. 01y,04jul92,jcf  scalable/ANSI/cleanup effort.
  11. 01x,26may92,rrr  the tree shuffle
  12. 01w,20jan92,jmm  changed pathBuild to check for null dereference
  13. 01v,13dec91,gae  ANSI fixes.
  14. 01u,04oct91,rrr  passed through the ansification filter
  15.                   -changed functions to ansi style
  16.   -changed includes to have absolute path from h/
  17.   -changed VOID to void
  18.   -changed copyright notice
  19. 01t,01oct90,dnw  fixed pathCat().
  20.  made entire library and all routines NOMANUAL.
  21. 01s,30jul90,dnw  changed pathLastName() back to 4.0.2 calling sequence and
  22.    added pathLastNamePtr() with new calling sequence.
  23.  added forward declaration of void routines.
  24. 01r,19jul90,kdl  mangen fixes for backslashes.
  25. 01q,19jul90,dnw  deleted unused pathSlashIndex(); made pathSlashRindex() LOCAL
  26. 01p,18may90,llk  small tweaks to pathCat().
  27. 01o,01may90,llk  changed pathBuild() and pathCat() to check that the path names
  28.    they construct are within MAX_FILENAME_LENGTH chars.
  29.    They both return STATUS now.
  30.  small documentation improvements.
  31.  lint reduction.
  32. 01n,01apr90,llk  added buffer parameter to pathParse to improve mem usage.
  33.  removed pathArrayFree().
  34. 01m,14mar90,kdl  allow "" as well as "/" for path separator, for MS-DOS.
  35. 01l,22feb90,jdi  documentation cleanup.
  36. 01k,12oct89,llk  fixed pathArrayReduce.  "../.." only went up 1 directory.
  37. 01j,12jul89,llk  lint.
  38. 01i,06jul89,llk  cut down number of malloc's to 1 in pathParse.
  39.  rewrote many routines.
  40.  changed parameters to pathBuild().
  41.  added pathArrayFree(), pathArrayReduce().
  42.  deleted pathAppend(), pathRemoveTail().
  43.  got NOMANUAL and LOCAL straightened out.
  44.  made pathLastName() return char *.
  45.  delinted.
  46. 01h,19oct88,llk  changed pathCat to insert a slash between a device name
  47.    and file name if no '/' or ':' is already there.
  48. 01g,23sep88,gae  documentation touchup.
  49. 01f,07jul88,jcf  fixed malloc to match new declaration.
  50. 01e,30jun88,llk  added pathBuild().
  51. 01d,16jun88,llk  moved pathSplit() here.
  52. 01c,04jun88,llk  cleaned a little.
  53. 01b,30may88,dnw  changed to v4 names.
  54. 01a,25may88,llk  written.
  55. */
  56. /*
  57. This library provides functions for manipulating and parsing directory
  58. and file path names for heirarchical file systems.
  59. The path names are UNIX style, with directory names separated by a "/".
  60. (Optionally, a "\" may be used; this is primarily useful for MS-DOS
  61. files.)
  62. The directory "." refers to the current directory.
  63. The directory ".." refers to the parent directory.
  64. Path names are handled in two forms:
  65. as a null-terminated string (such as "/abc/dir/file"), or
  66. as an array of directory names
  67. (such as a f2char**fP array with the entries "abc", "dir", "file", and NULL).
  68. SEE ALSO
  69. ioLib(1), iosDevFind(2)
  70. NOMANUAL
  71. */
  72. /* LINTLIBRARY */
  73. #include "vxWorks.h"
  74. #include "iosLib.h"
  75. #include "ioLib.h"
  76. #include "errnoLib.h"
  77. #include "string.h"
  78. #include "memLib.h"
  79. #include "pathLib.h"
  80. /* forward static functions */
  81. static void pathArrayReduce (char ** nameArray);
  82. static char *strcatlim (char *s1, char *s2, int limit);
  83. static char *pathSlashRindex (char *pString);
  84. /*******************************************************************************
  85. *
  86. * pathParse - parse a full pathname into an array of directory/file names
  87. *
  88. * Parses a UNIX style directory or file name which has directory names
  89. * separated by '/'s.  It copies the directory and file names, separated by
  90. * EOSs, into the user supplied buffer. The buffer is filled with "." for a
  91. * null path name.
  92. * The last entry in the returned array will be set to NULL.
  93. * It is assumed that the caller has created a buffer large enough to
  94. * contain the parsed pathname.
  95. *
  96. * For instance, "/usr/vw/dir/file" gets parsed into
  97. *
  98. *                          nameArray
  99. *                         |---------|
  100. *   ---------------------------o    |
  101. *   |                     |---------|
  102. *   |   -----------------------o    |
  103. *   |   |                 |---------|
  104. *   |   |  --------------------o    |
  105. *   |   |  |              |---------|
  106. *   |   |  |   ----------------o    |
  107. *   |   |  |   |          |---------|
  108. *   v   v  v   v          |   NULL  |
  109. *  |----------------|     |---------|
  110. *  |usr vw dir file |
  111. *  |----------------|
  112. *    nameBuf
  113. *
  114. * RETURNS: parsed directory name returned in `nameBuf' pointed to by `nameArray'
  115. *
  116. * NOMANUAL
  117. */
  118. void pathParse
  119.     (
  120.     char *longName,     /* full path name */
  121.     char **nameArray,   /* resulting array of pointers to directory names */
  122.     char *nameBuf       /* buffer containing resulting dir names pointed
  123.                               to by nameArray pointers */
  124.     )
  125.     {
  126.     FAST char *pName = nameBuf; /* ptr to name in nameArray */
  127.     FAST char *p0; /* ptr to character in longName */
  128.     FAST char *p1; /* ptr to character in longName */
  129.     int nameCount = 0; /* # of names encountered so far */
  130.     int nChars; /* # of characters in a name */
  131.     p0 = p1 = longName;
  132.     /*
  133.      * Copy names delimitted by '/'s and ''s to array of strings.
  134.      * nameArray entries point to strings
  135.      */
  136.     while (*p0 != EOS)
  137.         {
  138.         while ((*p1 != '/') && (*p1 != '\') && (*p1 != EOS))
  139.             p1++;
  140.         if (p0 == p1)   /* p1 hasn't moved forward, probably hit another '/' */
  141.             {
  142.             p0++; p1++;
  143.             continue;
  144.             }
  145.         nChars = p1 - p0; /* how many characters in dir name? */
  146.         bcopy (p0, pName, nChars); /* copy dir name to buffer */
  147.         pName [nChars] = EOS; /* terminate with EOS */
  148.         nameArray [nameCount] = pName; /* index into buffer with nameArray */
  149. pName += nChars + 1; /* move ptr to next open spot in buf */
  150.         if ((*p1 == '/') || (*p1 == '\'))
  151.             p1++;
  152.         p0 = p1;
  153.         nameCount++;
  154.         } /* while */
  155.     /* return "." (current directory) if no directories were specified */
  156.     if (nameCount == 0)
  157.         {
  158.         (void) strcpy (nameBuf, ".");
  159.         *nameArray = nameBuf;
  160.         nameCount++;
  161.         }
  162.     nameArray [nameCount] = NULL;
  163.     }
  164. /*******************************************************************************
  165. *
  166. * pathCondense - condense a file or directory path
  167. *
  168. * This routine condenses a path name by removing any occurrences of:
  169. *
  170. * .RS
  171. *  /../
  172. *  /./
  173. *  //
  174. * .RE
  175. *
  176. * NOMANUAL
  177. */
  178. void pathCondense
  179.     (
  180.     FAST char *pathName         /* directory or file path */
  181.     )
  182.     {
  183.     char *nameArray  [MAX_DIRNAMES];
  184.     char nameBuf     [MAX_FILENAME_LENGTH];
  185.     char newPathName [MAX_FILENAME_LENGTH];
  186.     char *pTail;
  187.     /* parse the stuff after the device name */
  188.     (void) iosDevFind (pathName, &pTail);
  189.     /* parse path name into individual dir names -- has the added
  190.      * benefit of eliminating "//"s */
  191.     pathParse (pTail, nameArray, nameBuf);
  192.     /* reduce occurances of ".." and "." */
  193.     pathArrayReduce (nameArray);
  194.     /*
  195.      * Rebuild path name.  Start with an empty path name.
  196.      * Preserve initial '/' if necessary
  197.      */
  198.     if ((*pTail == '/') || (*pTail == '\'))
  199. {
  200. newPathName [0] = *pTail;
  201. newPathName [1] = EOS;
  202. }
  203.     else
  204. newPathName [0] = EOS;
  205.     /*
  206.      * pathBuild() will return ERROR if newPathName gets too big.
  207.      * We're assuming it won't here, since it has either stayed the
  208.      * same size or been reduced.
  209.      */
  210.     (void) pathBuild (nameArray, (char **) NULL, newPathName);
  211.     /* newPathName should be the same size or smaller than pathName */
  212.     (void) strcpy (pTail, newPathName);
  213.     }
  214. /*******************************************************************************
  215. *
  216. * pathArrayReduce - reduce the number of entries in a nameArray by
  217. *                   eliminating occurances of "." and "..".
  218. *
  219. * pathArrayReduce eliminates occurances of "." and ".." in a nameArray.
  220. * Each instance of "." is set to EOS.  Each instance of ".." and the previous
  221. * directory name is set to EOS.
  222. */
  223. LOCAL void pathArrayReduce
  224.     (
  225.     char **nameArray    /* array of directory names, last entry is NULL */
  226.     )
  227.     {
  228.     FAST char **pArray = nameArray;
  229.     FAST char **ppPrevString;
  230.     FAST char *pString;
  231.     while ((pString = *pArray) != NULL)
  232.         {
  233.         if (strcmp (pString, ".") == 0)
  234.             {
  235.             /* "." means same directory, ignore */
  236.             *pString = EOS;
  237.             }
  238.         else if (strcmp (pString, "..") == 0)
  239.             {
  240.             /* up one directory and down one,
  241.              * ignore this directory and previous non-nullified directory
  242.              */
  243.             *pString = EOS; /* clear out this directory name */
  244.     ppPrevString = pArray - 1;
  245.     while (ppPrevString >= nameArray)
  246. {
  247. /* find last non-nullified string */
  248. if (**ppPrevString == EOS)
  249.     ppPrevString--;
  250. else
  251.     {
  252.     **ppPrevString = EOS;
  253.     break;
  254.     }
  255. }
  256.             }
  257.         pArray++;
  258.         } /* while */
  259.     }
  260. /*******************************************************************************
  261. *
  262. * pathBuild - generate path name by concatenating a list of directory names
  263. *
  264. * This routine uses an array of names to build a path name.  It appends the
  265. * names in nameArray to the given destination name destString.  It
  266. * successively uses the names in nameArray up to but not including
  267. * nameArrayEnd, or up to a * NULL entry in the nameArray, whichever
  268. * comes first.
  269. *
  270. * To use the entire path name array, pass NULL for nameArrayEnd.
  271. * destString must be NULL terminated before calling pathBuild.
  272. *
  273. * It assumes that destString should end up no longer than MAX_FILENAME_LENGTH.
  274. *
  275. * RETURNS:
  276. * OK    and copies resulting path name to <destString>
  277. * ERROR if resulting path name would have more than MAX_FILENAME_LENGTH chars.
  278. *
  279. * NOMANUAL
  280. */
  281. STATUS pathBuild
  282.     (
  283.     FAST char **nameArray,      /* array of directory names */
  284.     char **nameArrayEnd,        /* ptr to first name in array which should
  285.                                  * NOT be added to path     */
  286.     FAST char *destString       /* destination string       */
  287.     )
  288.     {
  289.     FAST char **pp;
  290.     int len = strlen (destString);
  291.     int newlen = 0;
  292.     BOOL slashEnd = FALSE; /* Does destString end with a slash? */
  293.     if (len >= MAX_FILENAME_LENGTH)
  294. {
  295. errnoSet (S_ioLib_NAME_TOO_LONG);
  296. return (ERROR);
  297. }
  298.     if ((len > 0) && (destString [len - 1] != '/')
  299. && (destString [len - 1] != '\'))
  300. {
  301. /* if string contains part of a path name and it doesn't end with a '/'
  302.  * or '', then slash terminate it */
  303. destString [len] = '/';
  304. destString [len + 1] = EOS;
  305. slashEnd = TRUE;
  306. }
  307.     /*
  308.      * Added a test to make sure pp is non-NULL before checking
  309.      * that *pp is not EOS.
  310.      */
  311.     for (pp = nameArray; (pp != NULL) && (*pp != NULL)
  312.  && (pp != nameArrayEnd); pp++)
  313. {
  314. if (**pp != EOS)
  315.     {
  316.     if (newlen = (len + strlen (*pp) + 1) > MAX_FILENAME_LENGTH)
  317. {
  318. errnoSet (S_ioLib_NAME_TOO_LONG);
  319. return (ERROR);
  320. }
  321.     (void) strcat (destString, *pp);
  322.     (void) strcat (destString, "/");
  323.     slashEnd = TRUE;
  324.     len = newlen;
  325.     }
  326. }
  327.     /* final string should not end with '/' */
  328.     if (slashEnd)
  329. destString [strlen (destString) - 1] = EOS;
  330.     return (OK);
  331.     }
  332. /*******************************************************************************
  333. *
  334. * pathCat - concatenate directory path to filename
  335. *
  336. * This routine constructs a valid filename from a directory path and a filename.
  337. * The resultant path name is put into <result>.
  338. *
  339. * The following arcane rules are used to derive the concatenated result.
  340. *
  341. * 1. if <fileName> begins with a device name, then <result> will just be
  342. *    <fileName>.
  343. * 2. if <dirName> begins with a device name that does NOT start with a "/",
  344. *    then that device name is first part of <result>.
  345. * 3. if <fileName> is a relative path name, i.e. does not start with
  346. *    '/', '\', '~', or '$', then <dirName> (less the device name of rule 2,
  347. *    if any) is the appended to <result>.  A '/' is appended to the result
  348. *    unless <dirName> already ends with one.
  349. * 4. <fileName> is appended to <result>.
  350. *
  351. * Thus, if the following are the only devices in the system:
  352. *
  353. *     dev:
  354. *     /usr
  355. *     /rt11/
  356. *
  357. * Then the following results would be obtained:
  358. *
  359. * dirName fileName result rule
  360. * ------- --------- ------------- ---------------------------
  361. * (any) yuba:blah yuba:blah fileName starts with device
  362. * (any) /usr/blah /usr/blah fileName starts with device
  363. * dev: blah dev:blah <dev><file>
  364. * dev: /blah dev:/blah <dev><file>
  365. * dev:foo blah dev:foo/blah <dev><dir>/<file>
  366. * dev:foo /blah dev:/blah <dev><file>
  367. * /usr blah /usr/blah </dir>/<file>
  368. * /usr /blah /blah <file>
  369. * /rt11/ blah /rt11/blah </dir/><file>
  370. * /rt11/ /blah /blah <file>
  371. *
  372. * <dirName> and <fileName> should be less than MAX_FILENAME_LENGTH chars long.
  373. *
  374. * RETURNS: OK
  375. *
  376. * RATIONALE
  377. *
  378. * These rules are intended to make pathnames work as in UNIX for devices
  379. * that start with "/", but also to allow DOS-like device prefixes and
  380. * rcp-like host prefixes, and also to retain compatibility with old
  381. * rt-11 conventions.
  382. * That these rules are so complex suggests that adopting a simpler,
  383. * more UNIX-like model would be better in the future.
  384. * For example, if device names were required to start with '/' and NOT
  385. * end in '/', then the following simple UNIX-like rules would suffice:
  386. *
  387. * 1. if <fileName> starts with "/" (i.e. is an absolute pathname), then
  388. *    the result is <filename>
  389. * 2. otherwise the result is <dirName>/<fileName>
  390. *
  391. * NOMANUAL
  392. */
  393. STATUS pathCat
  394.     (
  395.     FAST char *dirName,         /* directory path */
  396.     FAST char *fileName,        /* filename to be added to end of path */
  397.     FAST char *result           /* where to form concatenated name */
  398.     )
  399.     {
  400.     char *pTail;
  401.     if ((fileName == NULL) || (fileName[0] == EOS))
  402. {
  403. strcpy (result, dirName);
  404. return (OK);
  405. }
  406.     if ((dirName == NULL) || (dirName[0] == EOS))
  407. {
  408. strcpy (result, fileName);
  409. return (OK);
  410. }
  411.     /* if filename starts with a device name, result is just filename */
  412.     (void) iosDevFind (fileName, &pTail);
  413.     if (pTail != fileName)
  414. {
  415. strcpy (result, fileName);
  416. return (OK);
  417. }
  418.     /* if dirName starts with a device name that does NOT start with "/",
  419.      * then prepend that device name
  420.      */
  421.     *result = EOS;
  422.     if (dirName[0] != '/')
  423. {
  424. (void) iosDevFind (dirName, &pTail);
  425. if (pTail != dirName)
  426.     {
  427.     strncat (result, dirName, pTail - dirName);
  428.     dirName = pTail;
  429.     }
  430. }
  431.     /* if filename is relative path, prepend directory if any */
  432.     if ((index ("/\~$", fileName [0]) == NULL) && (dirName[0] != EOS))
  433. {
  434. strcatlim (result, dirName, PATH_MAX);
  435. if (dirName [strlen (dirName) - 1] != '/')
  436.     strcatlim (result, "/", PATH_MAX);
  437. }
  438.     /* concatenate filename */
  439.     strcatlim (result, fileName, PATH_MAX);
  440.     return (OK);
  441.     }
  442. /*******************************************************************************
  443. *
  444. * strcatlim - append characters of one string onto another up to limit
  445. *
  446. * This routine appends characters from string <s2> to the end of string <s1>,
  447. * limiting the resulting length of <s1> to <limit> characters, not including
  448. * the EOS.  The resulting <s1> will always be NULL terminated.
  449. * Thus <s1> must be big enough to hold <limit> + 1 characters.
  450. *
  451. * INTERNAL
  452. * Perhaps should be in strLib.
  453. *
  454. * RETURNS: A pointer to null-terminated <s1>.
  455. *
  456. */
  457. LOCAL char *strcatlim
  458.     (
  459.     FAST char *s1,      /* string to be appended to */
  460.     FAST char *s2,      /* string to append to s1 */
  461.     int limit           /* max number of chars in resulting s1, excluding EOS */
  462.     )
  463.     {
  464.     int n1;
  465.     int n2;
  466.     n1 = strlen (s1);
  467.     if (n1 < limit)
  468. {
  469. n2 = strlen (s2);
  470. n2 = min (n2, limit - n1);
  471. bcopy (s2, &s1 [n1], n2);
  472. s1 [n1 + n2] = EOS;
  473. }
  474.     return (s1);
  475.     }
  476. /*******************************************************************************
  477. *
  478. * pathLastNamePtr - return last name in a path name
  479. *
  480. * This routine returns a pointer to the character after the last slash
  481. * ("/" or "\") in the path name.  Note that if the directory name ends
  482. * with a slash, the returned pointer will point to a null string.
  483. *
  484. * RETURNS: A pointer to the last name in path.
  485. *
  486. * NOMANUAL
  487. */
  488. char *pathLastNamePtr
  489.     (
  490.     char *pathName
  491.     )
  492.     {
  493.     char *p;
  494.     if ((p = pathSlashRindex (pathName)) == NULL)
  495. return (pathName);
  496.     else
  497. return ((char *) (p + 1));
  498.     }
  499. /*******************************************************************************
  500. *
  501. * pathLastName - return last name in a path name
  502. *
  503. * This routine returns a pointer to the character after the last slash
  504. * ("/" or "\") in the path name.  Note that if the directory name ends
  505. * with a slash, the returned pointer will point to a null string.
  506. *
  507. * This routine is provided in addition to pathLastNamePtr() just for
  508. * backward compatibility with 4.0.2.  pathLastNamePtr() is the preferred
  509. * routine now.
  510. *
  511. * RETURNS: pointer to last name in location pointed to by <pLastName>
  512. *
  513. * NOMANUAL
  514. */
  515. void pathLastName
  516.     (
  517.     char *pathName,
  518.     char **pLastName
  519.     )
  520.     {
  521.     *pLastName = pathLastNamePtr (pathName);
  522.     }
  523. /*******************************************************************************
  524. *
  525. * pathSlashRindex - find last occurance of '/' or '' in string
  526. *
  527. * This routine searches a string for the last occurance of '/' or ''.
  528. * It returns a pointer to the last slash character.
  529. *
  530. * RETURNS:
  531. *    pointer to last '/' or '', or
  532. *    NULL if no slashes in string
  533. */
  534. LOCAL char *pathSlashRindex
  535.     (
  536.     char *pString               /* string to search */
  537.     )
  538.     {
  539.     FAST char *pForward; /* ptr to forward slash */
  540.     FAST char *pBack; /* ptr to back slash */
  541.     pForward = rindex (pString, '/');
  542.     pBack    = rindex (pString, '\');
  543.     return (max (pForward, pBack));
  544.     }
  545. /*******************************************************************************
  546. *
  547. * pathSplit - split a path name into its directory and file parts
  548. *
  549. * This routine splits a valid UNIX-style path name into its directory
  550. * and file parts by finding the last slash ("/" or "\").  The results are
  551. * copied into <dirName> and <fileName>.
  552. *
  553. * NOMANUAL
  554. */
  555. void pathSplit
  556.     (
  557.     FAST char *fullFileName,    /* full file name being parsed */
  558.     FAST char *dirName,         /* result, directory name */
  559.     char *fileName              /* result, simple file name */
  560.     )
  561.     {
  562.     FAST int nChars;
  563.     if (fullFileName != NULL)
  564. {
  565. char *p = pathSlashRindex (fullFileName);
  566. if (p == NULL)
  567.     {
  568.     (void) strcpy (fileName, fullFileName);
  569.     (void) strcpy (dirName, "");
  570.     }
  571. else
  572.     {
  573.     nChars = p - fullFileName;
  574.     (void) strncpy (dirName, fullFileName, nChars);
  575.     dirName [nChars] = EOS;
  576.     (void) strcpy (fileName, ++p);
  577.     }
  578. }
  579.     else
  580. {
  581. (void) strcpy (fileName, "");
  582. (void) strcpy (dirName, "");
  583. }
  584.     }