Webserver+3d print

Dependents:   Nucleo

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers path.c Source File

path.c

Go to the documentation of this file.
00001 /**
00002  * @file path.c
00003  * @brief Path manipulation helper functions
00004  *
00005  * @section License
00006  *
00007  * Copyright (C) 2010-2017 Oryx Embedded SARL. All rights reserved.
00008  *
00009  * This program is free software; you can redistribute it and/or
00010  * modify it under the terms of the GNU General Public License
00011  * as published by the Free Software Foundation; either version 2
00012  * of the License, or (at your option) any later version.
00013  *
00014  * This program is distributed in the hope that it will be useful,
00015  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00016  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00017  * GNU General Public License for more details.
00018  *
00019  * You should have received a copy of the GNU General Public License
00020  * along with this program; if not, write to the Free Software Foundation,
00021  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
00022  *
00023  * @author Oryx Embedded SARL (www.oryx-embedded.com)
00024  * @version 1.7.6
00025  **/
00026 
00027 //Dependencies
00028 #include <string.h>
00029 #include <ctype.h>
00030 #include "path.h"
00031 
00032 
00033 /**
00034  * @brief Test if the path is absolute
00035  * @param[in] path NULL-terminated string that contains the path
00036  * @return TRUE is the path is absolute, else FALSE
00037  **/
00038 
00039 bool_t pathIsAbsolute(const char_t *path)
00040 {
00041    //Determine if the path is absolute or relative
00042    if(path[0] == '/' || path[0] == '\\')
00043       return TRUE;
00044    else
00045       return FALSE;
00046 }
00047 
00048 
00049 /**
00050  * @brief Test if the path is relative
00051  * @param[in] path NULL-terminated string that contains the path
00052  * @return TRUE is the path is relative, else FALSE
00053  **/
00054 
00055 bool_t pathIsRelative(const char_t *path)
00056 {
00057    //Determine if the path is absolute or relative
00058    if(path[0] == '/' || path[0] == '\\')
00059       return FALSE;
00060    else
00061       return TRUE;
00062 }
00063 
00064 
00065 /**
00066  * @brief Search a path for a file name
00067  * @param[in] path NULL-terminated string that contains the path to search
00068  * @return Pointer to the file name
00069  **/
00070 
00071 const char_t *pathFindFileName(const char_t *path)
00072 {
00073    size_t n;
00074 
00075    //Retrieve the length of the path
00076    n = strlen(path);
00077 
00078    //Skip trailing slash or backslash characters
00079    while(n > 0)
00080    {
00081       //Forward slash or backslash character found?
00082       if(path[n - 1] != '/' && path[n - 1] != '\\')
00083          break;
00084 
00085       //Previous character
00086       n--;
00087    }
00088 
00089    //Search the string for the last separator
00090    while(n > 0)
00091    {
00092       //Forward slash or backslash character found?
00093       if(path[n - 1] == '/' || path[n - 1] == '\\')
00094          break;
00095 
00096       //Previous character
00097       n--;
00098    }
00099 
00100    //Return a pointer to the file name
00101    return path + n;
00102 }
00103 
00104 
00105 /**
00106  * @brief Simplify a path
00107  * @param[in] path NULL-terminated string containing the path to be canonicalized
00108  **/
00109 
00110 void pathCanonicalize(char_t *path)
00111 {
00112    size_t i;
00113    size_t j;
00114    size_t k;
00115 
00116    //Move to the beginning of the string
00117    i = 0;
00118    k = 0;
00119 
00120    //Replace backslashes with forward slashes
00121    while(path[i] != '\0')
00122    {
00123       //Forward slash or backslash separator found?
00124       if(path[i] == '/' || path[i] == '\\')
00125       {
00126          path[k++] = '/';
00127          while(path[i] == '/' || path[i] == '\\') i++;
00128       }
00129       else
00130       {
00131          path[k++] = path[i++];
00132       }
00133    }
00134 
00135    //Properly terminate the string with a NULL character
00136    path[k] = '\0';
00137 
00138    //Move back to the beginning of the string
00139    i = 0;
00140    j = 0;
00141    k = 0;
00142 
00143    //Parse the entire string
00144    do
00145    {
00146       //Forward slash separator found?
00147       if(path[i] == '/' || path[i] == '\0')
00148       {
00149          //"." element found?
00150          if((i - j) == 1 && !strncmp(path + j, ".", 1))
00151          {
00152             //Check whether the pathname is empty?
00153             if(k == 0)
00154             {
00155                if(path[i] == '\0')
00156                {
00157                   path[k++] = '.';
00158                }
00159                else if(path[i] == '/' && path[i + 1] == '\0')
00160                {
00161                   path[k++] = '.';
00162                   path[k++] = '/';
00163                }
00164             }
00165             else if(k > 1)
00166             {
00167                //Remove the final slash if necessary
00168                if(path[i] == '\0')
00169                   k--;
00170             }
00171          }
00172          //".." element found?
00173          else if((i - j) == 2 && !strncmp(path + j, "..", 2))
00174          {
00175             //Check whether the pathname is empty?
00176             if(k == 0)
00177             {
00178                path[k++] = '.';
00179                path[k++] = '.';
00180 
00181                //Append a slash if necessary
00182                if(path[i] == '/')
00183                   path[k++] = '/';
00184             }
00185             else if(k > 1)
00186             {
00187                //Search the path for the previous slash
00188                for(j = 1; j < k; j++)
00189                {
00190                   if(path[k - j - 1] == '/')
00191                      break;
00192                }
00193 
00194                //Slash separator found?
00195                if(j < k)
00196                {
00197                   if(!strncmp(path + k - j, "..", 2))
00198                   {
00199                      path[k++] = '.';
00200                      path[k++] = '.';
00201                   }
00202                   else
00203                   {
00204                      k = k - j - 1;
00205                   }
00206 
00207                   //Append a slash if necessary
00208                   if(k == 0 && path[0] == '/')
00209                      path[k++] = '/';
00210                   else if(path[i] == '/')
00211                      path[k++] = '/';
00212                }
00213                //No slash separator found?
00214                else
00215                {
00216                   if(k == 3 && !strncmp(path, "..", 2))
00217                   {
00218                      path[k++] = '.';
00219                      path[k++] = '.';
00220 
00221                      //Append a slash if necessary
00222                      if(path[i] == '/')
00223                         path[k++] = '/';
00224                   }
00225                   else if(path[i] == '\0')
00226                   {
00227                      k = 0;
00228                      path[k++] = '.';
00229                   }
00230                   else if(path[i] == '/' && path[i + 1] == '\0')
00231                   {
00232                      k = 0;
00233                      path[k++] = '.';
00234                      path[k++] = '/';
00235                   }
00236                   else
00237                   {
00238                      k = 0;
00239                   }
00240                }
00241             }
00242          }
00243          else
00244          {
00245             //Copy directory name
00246             memmove(path + k, path + j, i - j);
00247             //Advance write pointer
00248             k += i - j;
00249 
00250             //Append a slash if necessary
00251             if(path[i] == '/')
00252                path[k++] = '/';
00253          }
00254 
00255          //Move to the next token
00256          while(path[i] == '/') i++;
00257          j = i;
00258       }
00259    } while(path[i++] != '\0');
00260 
00261    //Properly terminate the string with a NULL character
00262    path[k] = '\0';
00263 }
00264 
00265 
00266 /**
00267  * @brief Add a slash to the end of a string
00268  * @param[in,out] path NULL-terminated string that represents the path
00269  * @param[in] maxLen Maximum pathname length
00270  **/
00271 
00272 void pathAddSlash(char_t *path, size_t maxLen)
00273 {
00274    size_t n;
00275 
00276    //Retrieve the length of the string
00277    n = strlen(path);
00278 
00279    //Add a slash character only if necessary
00280    if(!n)
00281    {
00282       //Check the length of the resulting string
00283       if(maxLen >= 1)
00284          strcpy(path, "/");
00285    }
00286    else if(path[n - 1] != '/' && path[n - 1] != '\\')
00287    {
00288       //Check the length of the resulting string
00289       if(maxLen >= (n + 1))
00290          strcat(path, "/");
00291    }
00292 }
00293 
00294 
00295 /**
00296  * @brief Remove the trailing slash from a given path
00297  * @param[in,out] path NULL-terminated string that contains the path
00298  **/
00299 
00300 void pathRemoveSlash(char_t *path)
00301 {
00302    char_t *end;
00303 
00304    //Skip the leading slash character
00305    if(pathIsAbsolute(path))
00306       path++;
00307 
00308    //Search for the first slash character to be removed
00309    for(end = NULL; *path != '\0'; path++)
00310    {
00311       if(*path != '/' && *path != '\\')
00312          end = NULL;
00313       else if(!end)
00314          end = path;
00315    }
00316 
00317    //Remove the trailing slash characters
00318    if(end) *end = '\0';
00319 }
00320 
00321 
00322 /**
00323  * @brief Concatenate two paths
00324  * @param[in,out] path NULL-terminated string containing the first path
00325  * @param[in] more NULL-terminated string containing the second path
00326  * @param[in] maxLen Maximum pathname length
00327  **/
00328 
00329 void pathCombine(char_t *path, const char_t *more, size_t maxLen)
00330 {
00331    size_t n1;
00332    size_t n2;
00333 
00334    //Append a slash character to the first path
00335    if(*path != '\0')
00336       pathAddSlash(path, maxLen);
00337 
00338    //Skip any slash character at the beginning of the second path
00339    while(*more == '/' || *more == '\\') more++;
00340 
00341    //Retrieve the length of the first path
00342    n1 = strlen(path);
00343    //Retrieve the length of second path
00344    n2 = strlen(more);
00345 
00346    //Check the length of the resulting string
00347    if(n1 < maxLen)
00348    {
00349       //Limit the number of characters to be copied
00350       n2 = MIN(n2, maxLen - n1);
00351       //Concatenate the resulting string
00352       strncpy(path + n1, more, n2);
00353       //Properly terminate the string with a NULL character
00354       path[n1 + n2] = '\0';
00355    }
00356 }
00357 
00358 
00359 /**
00360  * @brief Check whether a file name matches the specified pattern
00361  * @param[in] path NULL-terminated string that contains the path to be matched
00362  * @param[in] pattern NULL-terminated string that contains the pattern for
00363  *   which to search. The pattern may contain wildcard characters
00364  * @return TRUE if the path matches the specified pattern, else FALSE
00365  **/
00366 
00367 bool_t pathMatch(const char_t *path, const char_t* pattern)
00368 {
00369    size_t i = 0;
00370    size_t j = 0;
00371 
00372    //Parse the pattern string
00373    while(pattern[j] != '\0')
00374    {
00375       //Any wildcard character found?
00376       if(pattern[j] == '?')
00377       {
00378          //The question mark matches a single character
00379          if(path[i] == '\0')
00380          {
00381             return FALSE;
00382          }
00383          else
00384          {
00385             //Advance position in pathname
00386             i++;
00387             //Advance position in pattern string
00388             j++;
00389          }
00390       }
00391       else if(pattern[j] == '*')
00392       {
00393          //The asterisk sign matches zero or more characters
00394          if(path[i] == '\0')
00395          {
00396             //Advance position in pattern string
00397             j++;
00398          }
00399          else if(pathMatch(path + i, pattern + j + 1))
00400          {
00401             return TRUE;
00402          }
00403          else
00404          {
00405             //Advance position in pathname
00406             i++;
00407          }
00408       }
00409       else
00410       {
00411          //Case insensitive comparison
00412          if(tolower((uint8_t) path[i]) != tolower((uint8_t) pattern[j]))
00413          {
00414             return FALSE;
00415          }
00416          else
00417          {
00418             //Advance position in pathname
00419             i++;
00420             //Advance position in pattern string
00421             j++;
00422          }
00423       }
00424    }
00425 
00426    //Check whether the file name matches the specified pattern
00427    if(path[i] == '\0' && pattern[j] == '\0')
00428       return TRUE;
00429    else
00430       return FALSE;
00431 }
00432