UbixOS  2.0
fat_string.c
Go to the documentation of this file.
1 //-----------------------------------------------------------------------------
2 //-----------------------------------------------------------------------------
3 // FAT16/32 File IO Library
4 // V2.6
5 // Ultra-Embedded.com
6 // Copyright 2003 - 2012
7 //
8 // Email: admin@ultra-embedded.com
9 //
10 // License: GPL
11 // If you would like a version with a more permissive license for use in
12 // closed source commercial applications please contact me for details.
13 //-----------------------------------------------------------------------------
14 //
15 // This file is part of FAT File IO Library.
16 //
17 // FAT File IO Library is free software; you can redistribute it and/or modify
18 // it under the terms of the GNU General Public License as published by
19 // the Free Software Foundation; either version 2 of the License, or
20 // (at your option) any later version.
21 //
22 // FAT File IO Library is distributed in the hope that it will be useful,
23 // but WITHOUT ANY WARRANTY; without even the implied warranty of
24 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 // GNU General Public License for more details.
26 //
27 // You should have received a copy of the GNU General Public License
28 // along with FAT File IO Library; if not, write to the Free Software
29 // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
30 //-----------------------------------------------------------------------------
31 //-----------------------------------------------------------------------------
32 #include <string.h>
33 #include <assert.h>
34 #include "fat_string.h"
35 
36 //-----------------------------------------------------------------------------
37 // fatfs_total_path_levels: Take a filename and path and count the sub levels
38 // of folders. E.g. C:\folder\file.zip = 1 level
39 // Acceptable input formats are:
40 // c:\folder\file.zip
41 // /dev/etc/samba.conf
42 // Returns: -1 = Error, 0 or more = Ok
43 //-----------------------------------------------------------------------------
44 int fatfs_total_path_levels(char *path)
45 {
46  int levels = 0;
47  char expectedchar;
48 
49  if (!path)
50  return -1;
51 
52  // Acceptable formats:
53  // c:\folder\file.zip
54  // /dev/etc/samba.conf
55  if (*path == '/')
56  {
57  expectedchar = '/';
58  path++;
59  }
60  else if (path[1] == ':' || path[2] == '\\')
61  {
62  expectedchar = '\\';
63  path += 3;
64  }
65  else
66  return -1;
67 
68  // Count levels in path string
69  while (*path)
70  {
71  // Fast forward through actual subdir text to next slash
72  for (; *path; )
73  {
74  // If slash detected escape from for loop
75  if (*path == expectedchar) { path++; break; }
76  path++;
77  }
78 
79  // Increase number of subdirs founds
80  levels++;
81  }
82 
83  // Subtract the file itself
84  return levels-1;
85 }
86 //-----------------------------------------------------------------------------
87 // fatfs_get_substring: Get a substring from 'path' which contains the folder
88 // (or file) at the specified level.
89 // E.g. C:\folder\file.zip : Level 0 = C:\folder, Level 1 = file.zip
90 // Returns: -1 = Error, 0 = Ok
91 //-----------------------------------------------------------------------------
92 int fatfs_get_substring(char *path, int levelreq, char *output, int max_len)
93 {
94  int i;
95  int pathlen=0;
96  int levels=0;
97  int copypnt=0;
98  char expectedchar;
99 
100  if (!path || max_len <= 0)
101  return -1;
102 
103  // Acceptable formats:
104  // c:\folder\file.zip
105  // /dev/etc/samba.conf
106  if (*path == '/')
107  {
108  expectedchar = '/';
109  path++;
110  }
111  else if (path[1] == ':' || path[2] == '\\')
112  {
113  expectedchar = '\\';
114  path += 3;
115  }
116  else
117  return -1;
118 
119  // Get string length of path
120  pathlen = (int)strlen (path);
121 
122  // Loop through the number of times as characters in 'path'
123  for (i = 0; i<pathlen; i++)
124  {
125  // If a '\' is found then increase level
126  if (*path == expectedchar) levels++;
127 
128  // If correct level and the character is not a '\' or '/' then copy text to 'output'
129  if ( (levels == levelreq) && (*path != expectedchar) && (copypnt < (max_len-1)))
130  output[copypnt++] = *path;
131 
132  // Increment through path string
133  path++;
134  }
135 
136  // Null Terminate
137  output[copypnt] = '\0';
138 
139  // If a string was copied return 0 else return 1
140  if (output[0] != '\0')
141  return 0; // OK
142  else
143  return -1; // Error
144 }
145 //-----------------------------------------------------------------------------
146 // fatfs_split_path: Full path contains the passed in string.
147 // Returned is the path string and file Name string
148 // E.g. C:\folder\file.zip -> path = C:\folder filename = file.zip
149 // E.g. C:\file.zip -> path = [blank] filename = file.zip
150 //-----------------------------------------------------------------------------
151 int fatfs_split_path(char *full_path, char *path, int max_path, char *filename, int max_filename)
152 {
153  int strindex;
154 
155  // Count the levels to the filepath
156  int levels = fatfs_total_path_levels(full_path);
157  if (levels == -1)
158  return -1;
159 
160  // Get filename part of string
161  if (fatfs_get_substring(full_path, levels, filename, max_filename) != 0)
162  return -1;
163 
164  // If root file
165  if (levels == 0)
166  path[0] = '\0';
167  else
168  {
169  strindex = (int)strlen(full_path) - (int)strlen(filename);
170  if (strindex > max_path)
171  strindex = max_path;
172 
173  memcpy(path, full_path, strindex);
174  path[strindex-1] = '\0';
175  }
176 
177  return 0;
178 }
179 //-----------------------------------------------------------------------------
180 // FileString_StrCmpNoCase: Compare two strings case with case sensitivity
181 //-----------------------------------------------------------------------------
182 static int FileString_StrCmpNoCase(char *s1, char *s2, int n)
183 {
184  int diff;
185  char a,b;
186 
187  while (n--)
188  {
189  a = *s1;
190  b = *s2;
191 
192  // Make lower case if uppercase
193  if ((a>='A') && (a<='Z'))
194  a+= 32;
195  if ((b>='A') && (b<='Z'))
196  b+= 32;
197 
198  diff = a - b;
199 
200  // If different
201  if (diff)
202  return diff;
203 
204  // If run out of strings
205  if ( (*s1 == 0) || (*s2 == 0) )
206  break;
207 
208  s1++;
209  s2++;
210  }
211  return 0;
212 }
213 //-----------------------------------------------------------------------------
214 // FileString_GetExtension: Get index to extension within filename
215 // Returns -1 if not found or index otherwise
216 //-----------------------------------------------------------------------------
217 static int FileString_GetExtension(char *str)
218 {
219  int dotPos = -1;
220  char *strSrc = str;
221 
222  // Find last '.' in string (if at all)
223  while (*strSrc)
224  {
225  if (*strSrc=='.')
226  dotPos = (int)(strSrc-str);
227 
228  strSrc++;
229  }
230 
231  return dotPos;
232 }
233 //-----------------------------------------------------------------------------
234 // FileString_TrimLength: Get length of string excluding trailing spaces
235 // Returns -1 if not found or index otherwise
236 //-----------------------------------------------------------------------------
237 static int FileString_TrimLength(char *str, int strLen)
238 {
239  int length = strLen;
240  char *strSrc = str+strLen-1;
241 
242  // Find last non white space
243  while (strLen != 0)
244  {
245  if (*strSrc == ' ')
246  length = (int)(strSrc - str);
247  else
248  break;
249 
250  strSrc--;
251  strLen--;
252  }
253 
254  return length;
255 }
256 //-----------------------------------------------------------------------------
257 // fatfs_compare_names: Compare two filenames (without copying or changing origonals)
258 // Returns 1 if match, 0 if not
259 //-----------------------------------------------------------------------------
260 int fatfs_compare_names(char* strA, char* strB)
261 {
262  char *ext1 = NULL;
263  char *ext2 = NULL;
264  int ext1Pos, ext2Pos;
265  int file1Len, file2Len;
266 
267  // Get both files extension
268  ext1Pos = FileString_GetExtension(strA);
269  ext2Pos = FileString_GetExtension(strB);
270 
271  // NOTE: Extension position can be different for matching
272  // filename if trailing space are present before it!
273  // Check that if one has an extension, so does the other
274  if ((ext1Pos==-1) && (ext2Pos!=-1))
275  return 0;
276  if ((ext2Pos==-1) && (ext1Pos!=-1))
277  return 0;
278 
279  // If they both have extensions, compare them
280  if (ext1Pos!=-1)
281  {
282  // Set pointer to start of extension
283  ext1 = strA+ext1Pos+1;
284  ext2 = strB+ext2Pos+1;
285 
286  // Verify that the file extension lengths match!
287  if (strlen(ext1) != strlen(ext2))
288  return 0;
289 
290  // If they dont match
291  if (FileString_StrCmpNoCase(ext1, ext2, (int)strlen(ext1))!=0)
292  return 0;
293 
294  // Filelength is upto extensions
295  file1Len = ext1Pos;
296  file2Len = ext2Pos;
297  }
298  // No extensions
299  else
300  {
301  // Filelength is actual filelength
302  file1Len = (int)strlen(strA);
303  file2Len = (int)strlen(strB);
304  }
305 
306  // Find length without trailing spaces (before ext)
307  file1Len = FileString_TrimLength(strA, file1Len);
308  file2Len = FileString_TrimLength(strB, file2Len);
309 
310  // Check the file lengths match
311  if (file1Len!=file2Len)
312  return 0;
313 
314  // Compare main part of filenames
315  if (FileString_StrCmpNoCase(strA, strB, file1Len)!=0)
316  return 0;
317  else
318  return 1;
319 }
320 //-----------------------------------------------------------------------------
321 // fatfs_string_ends_with_slash: Does the string end with a slash (\ or /)
322 //-----------------------------------------------------------------------------
324 {
325  if (path)
326  {
327  while (*path)
328  {
329  // Last character?
330  if (!(*(path+1)))
331  {
332  if (*path == '\\' || *path == '/')
333  return 1;
334  }
335 
336  path++;
337  }
338  }
339 
340  return 0;
341 }
342 //-----------------------------------------------------------------------------
343 // fatfs_get_sfn_display_name: Get display name for SFN entry
344 //-----------------------------------------------------------------------------
345 int fatfs_get_sfn_display_name(char* out, char* in)
346 {
347  int len = 0;
348  while (*in && len <= 11)
349  {
350  char a = *in++;
351 
352  if (a == ' ')
353  continue;
354  // Make lower case if uppercase
355  else if ((a>='A') && (a<='Z'))
356  a+= 32;
357 
358  *out++ = a;
359  len++;
360  }
361 
362  *out = '\0';
363  return 1;
364 }
365 //-----------------------------------------------------------------------------
366 // fatfs_get_extension: Get extension of filename passed in 'filename'.
367 // Returned extension is always lower case.
368 // Returns: 1 if ok, 0 if not.
369 //-----------------------------------------------------------------------------
370 int fatfs_get_extension(char* filename, char* out, int maxlen)
371 {
372  int len = 0;
373 
374  // Get files extension offset
375  int ext_pos = FileString_GetExtension(filename);
376 
377  if (ext_pos > 0 && out && maxlen)
378  {
379  filename += ext_pos + 1;
380 
381  while (*filename && len < (maxlen-1))
382  {
383  char a = *filename++;
384 
385  // Make lowercase if uppercase
386  if ((a>='A') && (a<='Z'))
387  a+= 32;
388 
389  *out++ = a;
390  len++;
391  }
392 
393  *out = '\0';
394  return 1;
395  }
396 
397  return 0;
398 }
399 //-----------------------------------------------------------------------------
400 // fatfs_create_path_string: Append path & filename to create file path string.
401 // Returns: 1 if ok, 0 if not.
402 //-----------------------------------------------------------------------------
403 int fatfs_create_path_string(char* path, char *filename, char* out, int maxlen)
404 {
405  int len = 0;
406  char last = 0;
407  char seperator = '/';
408 
409  if (path && filename && out && maxlen > 0)
410  {
411  while (*path && len < (maxlen-2))
412  {
413  last = *path++;
414  if (last == '\\')
415  seperator = '\\';
416  *out++ = last;
417  len++;
418  }
419 
420  // Add a seperator if trailing one not found
421  if (last != '\\' && last != '/')
422  *out++ = seperator;
423 
424  while (*filename && len < (maxlen-1))
425  {
426  *out++ = *filename++;
427  len++;
428  }
429 
430  *out = '\0';
431 
432  return 1;
433  }
434 
435  return 0;
436 }
437 //-----------------------------------------------------------------------------
438 // Test Bench
439 //-----------------------------------------------------------------------------
440 #ifdef FAT_STRING_TESTBENCH
441 void main(void)
442 {
443  char output[255];
444  char output2[255];
445 
446  assert(fatfs_total_path_levels("C:\\folder\\file.zip") == 1);
447  assert(fatfs_total_path_levels("C:\\file.zip") == 0);
448  assert(fatfs_total_path_levels("C:\\folder\\folder2\\file.zip") == 2);
449  assert(fatfs_total_path_levels("C:\\") == -1);
450  assert(fatfs_total_path_levels("") == -1);
451  assert(fatfs_total_path_levels("/dev/etc/file.zip") == 2);
452  assert(fatfs_total_path_levels("/dev/file.zip") == 1);
453 
454  assert(fatfs_get_substring("C:\\folder\\file.zip", 0, output, sizeof(output)) == 0);
455  assert(strcmp(output, "folder") == 0);
456 
457  assert(fatfs_get_substring("C:\\folder\\file.zip", 1, output, sizeof(output)) == 0);
458  assert(strcmp(output, "file.zip") == 0);
459 
460  assert(fatfs_get_substring("/dev/etc/file.zip", 0, output, sizeof(output)) == 0);
461  assert(strcmp(output, "dev") == 0);
462 
463  assert(fatfs_get_substring("/dev/etc/file.zip", 1, output, sizeof(output)) == 0);
464  assert(strcmp(output, "etc") == 0);
465 
466  assert(fatfs_get_substring("/dev/etc/file.zip", 2, output, sizeof(output)) == 0);
467  assert(strcmp(output, "file.zip") == 0);
468 
469  assert(fatfs_split_path("C:\\folder\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
470  assert(strcmp(output, "C:\\folder") == 0);
471  assert(strcmp(output2, "file.zip") == 0);
472 
473  assert(fatfs_split_path("C:\\file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
474  assert(output[0] == 0);
475  assert(strcmp(output2, "file.zip") == 0);
476 
477  assert(fatfs_split_path("/dev/etc/file.zip", output, sizeof(output), output2, sizeof(output2)) == 0);
478  assert(strcmp(output, "/dev/etc") == 0);
479  assert(strcmp(output2, "file.zip") == 0);
480 
481  assert(FileString_GetExtension("C:\\file.zip") == strlen("C:\\file"));
482  assert(FileString_GetExtension("C:\\file.zip.ext") == strlen("C:\\file.zip"));
483  assert(FileString_GetExtension("C:\\file.zip.") == strlen("C:\\file.zip"));
484 
485  assert(FileString_TrimLength("C:\\file.zip", strlen("C:\\file.zip")) == strlen("C:\\file.zip"));
486  assert(FileString_TrimLength("C:\\file.zip ", strlen("C:\\file.zip ")) == strlen("C:\\file.zip"));
487  assert(FileString_TrimLength(" ", strlen(" ")) == 0);
488 
489  assert(fatfs_compare_names("C:\\file.ext", "C:\\file.ext") == 1);
490  assert(fatfs_compare_names("C:\\file2.ext", "C:\\file.ext") == 0);
491  assert(fatfs_compare_names("C:\\file .ext", "C:\\file.ext") == 1);
492  assert(fatfs_compare_names("C:\\file .ext", "C:\\file2.ext") == 0);
493 
494  assert(fatfs_string_ends_with_slash("C:\\folder") == 0);
495  assert(fatfs_string_ends_with_slash("C:\\folder\\") == 1);
496  assert(fatfs_string_ends_with_slash("/path") == 0);
497  assert(fatfs_string_ends_with_slash("/path/a") == 0);
498  assert(fatfs_string_ends_with_slash("/path/") == 1);
499 
500  assert(fatfs_get_extension("/mypath/file.wav", output, 4) == 1);
501  assert(strcmp(output, "wav") == 0);
502  assert(fatfs_get_extension("/mypath/file.WAV", output, 4) == 1);
503  assert(strcmp(output, "wav") == 0);
504  assert(fatfs_get_extension("/mypath/file.zip", output, 4) == 1);
505  assert(strcmp(output, "ext") != 0);
506 
507  assert(fatfs_create_path_string("/mydir1", "myfile.txt", output, sizeof(output)) == 1);
508  assert(strcmp(output, "/mydir1/myfile.txt") == 0);
509  assert(fatfs_create_path_string("/mydir2/", "myfile2.txt", output, sizeof(output)) == 1);
510  assert(strcmp(output, "/mydir2/myfile2.txt") == 0);
511  assert(fatfs_create_path_string("C:\\mydir3", "myfile3.txt", output, sizeof(output)) == 1);
512  assert(strcmp(output, "C:\\mydir3\\myfile3.txt") == 0);
513 }
514 #endif
fatfs_get_extension
int fatfs_get_extension(char *filename, char *out, int maxlen)
Definition: fat_string.c:370
fatfs_create_path_string
int fatfs_create_path_string(char *path, char *filename, char *out, int maxlen)
Definition: fat_string.c:403
string.h
fatfs_get_sfn_display_name
int fatfs_get_sfn_display_name(char *out, char *in)
Definition: fat_string.c:345
strcmp
int strcmp(const char *str1, const char *str2)
assert
#define assert(e)
Definition: assert.h:64
assert.h
strlen
int strlen(const char *str)
Definition: strlen.c:55
fatfs_get_substring
int fatfs_get_substring(char *path, int levelreq, char *output, int max_len)
Definition: fat_string.c:92
memcpy
void * memcpy(const void *dst, const void *src, size_t length)
fat_string.h
fatfs_string_ends_with_slash
int fatfs_string_ends_with_slash(char *path)
Definition: fat_string.c:323
fatfs_split_path
int fatfs_split_path(char *full_path, char *path, int max_path, char *filename, int max_filename)
Definition: fat_string.c:151
main
void main()
Definition: example.c:44
fatfs_compare_names
int fatfs_compare_names(char *strA, char *strB)
Definition: fat_string.c:260
fatfs_total_path_levels
int fatfs_total_path_levels(char *path)
Definition: fat_string.c:44
NULL
#define NULL
Definition: fat_string.h:17