libmp3splt
src/string_utils.c
Go to the documentation of this file.
00001 /**********************************************************
00002  *
00003  * libmp3splt -- library based on mp3splt,
00004  *               for mp3/ogg splitting without decoding
00005  *
00006  * Copyright (c) 2002-2005 M. Trotta - <mtrotta@users.sourceforge.net>
00007  * Copyright (c) 2005-2011 Alexandru Munteanu - io_fx@yahoo.fr
00008  *
00009  * http://mp3splt.sourceforge.net
00010  *
00011  *********************************************************/
00012 
00013 /**********************************************************
00014  *
00015  * This program is free software; you can redistribute it and/or
00016  * modify it under the terms of the GNU General Public License
00017  * as published by the Free Software Foundation; either version 2
00018  * of the License, or (at your option) any later version.
00019  *
00020  * This program is distributed in the hope that it will be useful,
00021  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00022  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00023  * GNU General Public License for more details.
00024  *
00025  * You should have received a copy of the GNU General Public License
00026  * along with this program; if not, write to the Free Software
00027  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
00028  * 02111-1307,
00029  * USA.
00030  *
00031  *********************************************************/
00032 
00037 #include <stdio.h>
00038 #include <stdlib.h>
00039 #include <string.h>
00040 
00041 #include <assert.h>
00042 #include <stdarg.h>
00043 
00044 #include <ctype.h>
00045 
00046 #include "splt.h"
00047 
00048 void splt_su_replace_all_char(char *str, char to_replace, char replacement)
00049 {
00050   if (str == NULL)
00051   {
00052     return;
00053   }
00054 
00055   int i = 0;
00056   for (i = 0;i < strlen(str);i++)
00057   {
00058     if (str[i] == to_replace)
00059     {
00060       str[i] = replacement;
00061     }
00062   }
00063 }
00064 
00065 char *splt_su_replace_all(const char *str, char *to_replace,
00066     char *replacement, int *error)
00067 {
00068   if (str == NULL)
00069   {
00070     return NULL;
00071   }
00072 
00073   char *new_str = NULL;
00074   int err = SPLT_OK;
00075 
00076   if (to_replace == NULL || replacement == NULL)
00077   {
00078     int err = splt_su_copy(str, &new_str);
00079     if (err < 0) { *error = err; }
00080     return new_str;
00081   }
00082 
00083   const char *ptr = str;
00084   const char *prev_ptr = ptr;
00085   while ((ptr = strstr(ptr, to_replace)) != NULL)
00086   {
00087     err = splt_su_append(&new_str, prev_ptr, ptr - prev_ptr,
00088         replacement, strlen(replacement), NULL);
00089     if (err != SPLT_OK) { goto error; }
00090     ptr += strlen(to_replace);
00091     prev_ptr = ptr;
00092   }
00093 
00094   if (prev_ptr != NULL)
00095   {
00096     err = splt_su_append(&new_str, prev_ptr, (str + strlen(str)) - prev_ptr, NULL);
00097     if (err != SPLT_OK) { goto error; }
00098   }
00099  
00100   return new_str;
00101 
00102 error:
00103   if (new_str)
00104   {
00105     free(new_str);
00106   }
00107   *error = err;
00108 
00109   return NULL;
00110 }
00111 
00112 int splt_su_append_str(char **str, const char *to_append, ...)
00113 {
00114   int err = SPLT_OK;
00115   va_list ap;
00116 
00117   va_start(ap, to_append);
00118 
00119   while (to_append)
00120   {
00121     size_t to_append_size = strlen(to_append);
00122     err = splt_su_append(str, to_append, to_append_size, NULL);
00123     if (err < 0) { break; }
00124     to_append = va_arg(ap, const char *);
00125   }
00126 
00127   va_end(ap);
00128 
00129   return err;
00130 }
00131 
00132 static int splt_su_append_one(char **str, const char *to_append, size_t to_append_size)
00133 {
00134   if (str == NULL || to_append == NULL || to_append[0] == '\0' || to_append_size == 0)
00135   {
00136     return SPLT_OK;
00137   }
00138 
00139   size_t new_size = 0;
00140 
00141   if (*str == NULL)
00142   {
00143     new_size = to_append_size + 1;
00144     *str = malloc(new_size);
00145     if (*str == NULL)
00146     {
00147       return SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
00148     }
00149 
00150     *str[0] = '\0';
00151   }
00152   else
00153   {
00154     new_size = to_append_size + strlen(*str) + 1;
00155     *str = realloc(*str, new_size);
00156     if (*str == NULL)
00157     {
00158       return SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
00159     }
00160   }
00161 
00162   strncat(*str, to_append, to_append_size);
00163 
00164   return SPLT_OK;
00165 }
00166 
00167 int splt_su_append(char **str, const char *to_append, ...)
00168 {
00169   int err = SPLT_OK;
00170   va_list ap;
00171 
00172   va_start(ap, to_append);
00173 
00174   while (to_append)
00175   {
00176     size_t to_append_size = va_arg(ap, size_t);
00177     err = splt_su_append_one(str, to_append, to_append_size);
00178     if (err < 0) { break; }
00179     to_append = va_arg(ap, const char *);
00180   }
00181 
00182   va_end(ap);
00183 
00184   return err;
00185 }
00186 
00187 void splt_su_free_replace(char **str, char *replacement)
00188 {
00189   if (!str)
00190   {
00191     return;
00192   }
00193 
00194   if (*str)
00195   {
00196     free(*str);
00197   }
00198 
00199   *str = replacement;
00200 }
00201 
00202 int splt_su_copy(const char *src, char **dest)
00203 {
00204   if (!dest)
00205   {
00206     return SPLT_OK;
00207   }
00208 
00209   if (*dest)
00210   {
00211     free(*dest);
00212     *dest = NULL;
00213   }
00214 
00215   if (src == NULL)
00216   {
00217     *dest = NULL;
00218     return SPLT_OK;
00219   }
00220 
00221   int length = strlen(src) + 1;
00222   if ((*dest = malloc(sizeof(char) * length)) == NULL)
00223   {
00224     return SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
00225   }
00226 
00227   snprintf(*dest, length, "%s", src);
00228 
00229   return SPLT_OK;
00230 }
00231 
00232 static int splt_su_is_illegal_char(char c, int ignore_dirchar)
00233 {
00234   if ((ignore_dirchar) && (c == SPLT_DIRCHAR))
00235   {
00236     return SPLT_FALSE;
00237   }
00238 
00239   //for the sake of filename portability, we take the the windows illegal
00240   //characters (will be changed upon feature request)
00241   if ((c == '\\') || (c == '/') || (c == ':') || (c == '*') ||
00242       (c == '?') || (c == '"') || (c == '<') ||
00243       (c == '>') || (c == '|') || (c == '\r'))
00244   {
00245     return SPLT_TRUE;
00246   }
00247 
00248   return SPLT_FALSE;
00249 }
00250 
00251 static void splt_su_clean_string_(splt_state *state, char *s, int *error, int ignore_dirchar)
00252 {
00253   int i = 0, j=0;
00254   char *copy = NULL;
00255   if (s)
00256   {
00257     copy = strdup(s);
00258     if (copy)
00259     {
00260       for (i=0; i<=strlen(copy); i++)
00261       {
00262         if (! splt_su_is_illegal_char(copy[i], ignore_dirchar))
00263         {
00264           s[j++] = copy[i];
00265         }
00266         else
00267         {
00268           s[j++] = '_';
00269         }
00270       }
00271       free(copy);
00272       copy = NULL;
00273 
00274       // Trim string. I will never stop to be surprised about cddb strings dirtiness! ;-)
00275       for (i=strlen(s)-1; i >= 0; i--) 
00276       {
00277         if (s[i]==' ')
00278         {
00279           s[i] = '\0';
00280         }
00281         else 
00282         {
00283           break;
00284         }
00285       }
00286     }
00287     else
00288     {
00289       *error = SPLT_ERROR_CANNOT_ALLOCATE_MEMORY;
00290     }
00291   }
00292 }
00293 
00294 void splt_su_clean_string(splt_state *state, char *s, int *error)
00295 {
00296   splt_su_clean_string_(state, s, error, SPLT_FALSE);
00297 }
00298 
00299 char *splt_su_cut_spaces(char *c)
00300 {
00301   while (isspace(*c))
00302   {
00303     c++;
00304   }
00305 
00306   return c;
00307 }
00308 
00309 char *splt_su_skip_spaces(char *c)
00310 {
00311   while (*c == ' ' || *c == '\t')
00312   {
00313     c++;
00314   }
00315 
00316   return c;
00317 }
00318 
00319 void splt_su_cut_spaces_from_end(char *c)
00320 {
00321   if (c == NULL || *c == '\0')
00322   {
00323     return;
00324   }
00325 
00326   char *end = strchr(c, '\0');
00327   if (!end)
00328   {
00329     return;
00330   }
00331 
00332   end--;
00333 
00334   while (isspace(*end))
00335   {
00336     *end = '\0';
00337     end--;
00338   }
00339 }
00340 
00341 char *splt_su_trim_spaces(char *c)
00342 {
00343   splt_su_cut_spaces_from_end(c);
00344   return splt_su_cut_spaces(c);
00345 }
00346 
00347 int splt_su_is_empty_line(const char *line)
00348 {
00349   if (!line)
00350   {
00351     return SPLT_TRUE;
00352   }
00353 
00354   size_t size = strlen(line);
00355   int i = 0;
00356   for (i = 0;i < size;i++)
00357   {
00358     if (!isspace(line[i]))
00359     {
00360       return SPLT_FALSE;
00361     }
00362   }
00363 
00364   return SPLT_TRUE;
00365 }
00366 
00367 void splt_su_line_to_unix(char *line)
00368 {
00369   size_t line_size = strlen(line);
00370   if (line_size > 1)
00371   {
00372     if (line[line_size-2] == '\r')
00373     {
00374       line[line_size-2] = '\n';
00375       line[line_size-1] = '\0';
00376     }
00377   }
00378 }
00379 
00380 void splt_su_keep_path_and_remove_filename(char *path)
00381 {
00382   char *last_dirchar = strrchr(path, SPLT_DIRCHAR);
00383   if (last_dirchar == NULL)
00384   {
00385     return;
00386   }
00387 
00388   *(last_dirchar+1) = '\0';
00389 
00390 #ifdef __WIN32__
00391   if (!splt_w32_str_is_drive_root_directory(path))
00392   {
00393     *last_dirchar = '\0';
00394   }
00395 #else
00396   if (last_dirchar != path)
00397   {
00398     *last_dirchar = '\0';
00399   }
00400 #endif
00401 }
00402 
00403 const char *splt_su_get_fname_without_path(const char *filename)
00404 {
00405   char *c = NULL;
00406   while ((c = strchr(filename, SPLT_DIRCHAR)) != NULL)
00407   {
00408     filename = c + 1;
00409   }
00410 
00411   return filename;
00412 }
00413 
00414 char *splt_su_get_fname_without_path_and_extension(const char *filename, int *error)
00415 {
00416   const char *fname_without_path = splt_su_get_fname_without_path(filename);
00417 
00418   char *fname_without_path_and_extension = NULL;
00419   int err = splt_su_copy(fname_without_path, &fname_without_path_and_extension);
00420   if (err < 0) {
00421     *error = err;
00422     return NULL;
00423   }
00424 
00425   splt_su_cut_extension(fname_without_path_and_extension);
00426 
00427   return fname_without_path_and_extension;
00428 }
00429 
00430 char *splt_su_get_fname_with_path_and_extension(splt_state *state, int *error)
00431 {
00432   int err = SPLT_OK;
00433   char *output_fname_with_path = NULL;
00434 
00435   int current_split = splt_t_get_current_split(state);
00436   const char *output_fname = splt_sp_get_splitpoint_name(state, current_split, error);
00437 
00438   if (!output_fname)
00439   {
00440     char *stdout_str = NULL;
00441     err = splt_su_copy("-", &stdout_str);
00442     if (err < 0) { *error = err; }
00443     return stdout_str;
00444   }
00445 
00446   if (strcmp(output_fname, "-") == 0)
00447   {
00448     char *result = NULL;
00449     err = splt_su_copy(output_fname, &result);
00450     if (err < 0) { goto error; }
00451     return result;
00452   }
00453 
00454   const char *extension = splt_p_get_extension(state, &err);
00455   if (err < 0) { goto error; }
00456 
00457   const char *new_filename_path = splt_t_get_new_filename_path(state);
00458   if (new_filename_path[0] == '\0')
00459   {
00460     err = splt_su_append_str(&output_fname_with_path, output_fname,
00461         extension, NULL);
00462     if (err < 0) { goto error; }
00463   }
00464   else
00465   {
00466     if (new_filename_path[strlen(new_filename_path)-1] == SPLT_DIRCHAR)
00467     {
00468       err = splt_su_append_str(&output_fname_with_path, new_filename_path,
00469           output_fname, extension, NULL);
00470     }
00471     else
00472     {
00473       err = splt_su_append_str(&output_fname_with_path, new_filename_path,
00474           SPLT_DIRSTR, output_fname, extension, NULL);
00475     }
00476     if (err < 0) { goto error; }
00477   }
00478 
00479   const char *filename = splt_t_get_filename_to_split(state);
00480   if (splt_io_check_if_file(state, output_fname_with_path))
00481   {
00482     if (splt_check_is_the_same_file(state, filename, output_fname_with_path, &err))
00483     {
00484       splt_e_set_error_data(state,filename);
00485       err = SPLT_ERROR_INPUT_OUTPUT_SAME_FILE;
00486       goto error;
00487     }
00488   }
00489 
00490   //TODO: warning if a file already exists
00491 
00492   return output_fname_with_path;
00493 
00494 error:
00495   if (output_fname_with_path)
00496   {
00497     free(output_fname_with_path);
00498     output_fname_with_path = NULL;
00499   }
00500 
00501   *error = err;
00502 
00503   return NULL;
00504 }
00505 
00506 void splt_su_cut_extension(char *str)
00507 {
00508   char *point = strrchr(str , '.');
00509   if (point)
00510   {
00511     *point = '\0';
00512   }
00513 }
00514 
00515 void splt_su_str_cut_last_char(char *str)
00516 {
00517   if (!str)
00518   {
00519     return;
00520   }
00521 
00522   str[strlen(str)-1] = '\0';
00523 }
00524 
00525 double splt_su_str_line_to_double(const char *str)
00526 {
00527   if (!str)
00528   {
00529     return 0.0;
00530   }
00531 
00532   while ((*str != '\0') && (isdigit(*str) == 0))
00533   {
00534     str++;
00535   }
00536 
00537   return atof(str);
00538 }
00539 
00540 char *splt_su_get_file_with_output_path(splt_state *state, char *filename, int *error)
00541 {
00542   int err = SPLT_OK;
00543   char *new_fname = NULL;
00544 
00545   if (filename == NULL)
00546   {
00547     return NULL;
00548   }
00549 
00550   splt_su_clean_string(state, filename, error);
00551   if (error < 0) { return NULL; }
00552 
00553   const char *path_of_split = splt_t_get_path_of_split(state);
00554   if (path_of_split)
00555   {
00556     if (path_of_split[strlen(path_of_split)] == SPLT_DIRCHAR)
00557     {
00558       splt_su_append_str(&new_fname, path_of_split, filename, NULL);
00559       if (err < 0) { *error = err; }
00560       return new_fname;
00561     }
00562 
00563     splt_su_append_str(&new_fname, path_of_split, SPLT_DIRSTR, filename, NULL);
00564     if (err < 0) { *error = err; }
00565     return new_fname;
00566   }
00567 
00568   err = splt_su_copy(filename, &new_fname);
00569   if (err < 0) { *error = err; }
00570   return new_fname;
00571 }
00572 
00573 int splt_su_str_ends_with(const char *str1, const char *str2)
00574 {
00575   if (!str1 || !str2)
00576   {
00577     return SPLT_FALSE;
00578   }
00579 
00580   int str1_end_index = strlen(str1) - 1;
00581   int str2_end_index = strlen(str2) - 1;
00582 
00583   while (str1_end_index >= 0 && str2_end_index >= 0)
00584   {
00585     if (str1[str1_end_index] != str2[str2_end_index])
00586     {
00587       return SPLT_FALSE;
00588     }
00589 
00590     str1_end_index--;
00591     str2_end_index--;
00592   }
00593 
00594   return SPLT_TRUE;
00595 }
00596 
00597 char *splt_su_format_messagev(splt_state *state, const char *message, va_list ap)
00598 {
00599   int counter = 0;
00600 
00601   int written_chars = 0;
00602 
00603   int size = 255;
00604   char *mess = malloc(sizeof(char) * size);
00605   if (mess == NULL)
00606   {
00607     splt_d_send_memory_error_message(state);
00608     splt_e_error(SPLT_IERROR_CHAR, __func__, 0, _("not enough memory"));
00609     return NULL;
00610   }
00611 
00612   while (counter < LONG_MAX)
00613   {
00614     written_chars = vsnprintf(mess, size, message, ap);
00615 
00616     if ((written_chars > -1) &&
00617         (written_chars+1 < size))
00618     {
00619       break;
00620     }
00621     else {
00622       size += 255;
00623     }
00624 
00625     if ((mess = realloc(mess, size)) == NULL)
00626     {
00627       free(mess);
00628       splt_d_send_memory_error_message(state);
00629       splt_e_error(SPLT_IERROR_CHAR, __func__, 0, _("not enough memory"));
00630       return NULL;
00631     }
00632 
00633     counter++;
00634   }
00635 
00636   return mess;
00637 }
00638 
00639 char *splt_su_get_formatted_message(splt_state *state, char *message, ...)
00640 {
00641   char *mess = NULL;
00642 
00643   va_list ap;
00644   va_start(ap, message);
00645   mess = splt_su_format_messagev(state, message, ap);
00646   va_end(ap);
00647 
00648   return mess;
00649 }
00650 
00651 int splt_su_str_line_has_digit(const char *str)
00652 {
00653   while (*str != '\0')
00654   {
00655     if (isdigit(*str))
00656     {
00657       return SPLT_TRUE;
00658     }
00659 
00660     str++;
00661   }
00662 
00663   return SPLT_FALSE;
00664 }
00665 
00666 static char *splt_su_str_to_func(const char *str, int (*conversion_func)(int), int *error)
00667 {
00668   int err = SPLT_OK;
00669 
00670   if (!str)
00671   {
00672     return NULL;
00673   }
00674 
00675   char *result = NULL;
00676   err = splt_su_copy(str, &result);
00677   if (err < 0)
00678   {
00679     *error = err;
00680     return NULL;
00681   }
00682 
00683   int i = 0;
00684   for (i = 0;i < strlen(str);i++)
00685   {
00686     result[i] = conversion_func(str[i]);
00687   }
00688 
00689   return result;
00690 }
00691 
00692 
00693 char *splt_su_convert(const char *str, splt_str_format format, int *error)
00694 {
00695   if (str == NULL)
00696   {
00697     return NULL;
00698   }
00699 
00700   char *new_str = NULL;
00701 
00702   int lastspace = 1;
00703   int i = 0;
00704 
00705   if (format != SPLT_TO_LOWERCASE && format != SPLT_TO_UPPERCASE)
00706   {
00707     int err = splt_su_copy(str, &new_str);
00708     if (err < 0)
00709     {
00710       *error = err;
00711       return NULL;
00712     }
00713   }
00714 
00715   switch (format)
00716   {
00717     case SPLT_NO_CONVERSION:
00718       return new_str;
00719       break;
00720     case SPLT_TO_LOWERCASE:
00721       return splt_su_str_to_func(str, tolower, error);
00722       break;
00723     case SPLT_TO_UPPERCASE:
00724       return splt_su_str_to_func(str, toupper, error);
00725       break;
00726     case SPLT_TO_FIRST_UPPERCASE:
00727       new_str[0] = toupper(new_str[0]);
00728       return new_str;
00729       break;
00730     case SPLT_TO_WORD_FIRST_UPPERCASE:
00731       for (i = 0; i < strlen(new_str); i++)
00732       {
00733         if (lastspace && new_str[i] != ' ')
00734         {
00735           new_str[i] = toupper(new_str[i]);
00736         }
00737 
00738         if (new_str[i] == ' ')
00739         {
00740           lastspace = 1;
00741         }
00742         else
00743         {
00744           lastspace = 0;
00745         }
00746       }
00747       return new_str;
00748       break;
00749   }
00750 
00751   return NULL;
00752 }
00753