Drizzled Public API Documentation

CSStrUtil.cc
00001 /* Copyright (C) 2008 PrimeBase Technologies GmbH, Germany
00002  *
00003  * PrimeBase Media Stream for MySQL
00004  *
00005  * This program is free software; you can redistribute it and/or modify
00006  * it under the terms of the GNU General Public License as published by
00007  * the Free Software Foundation; either version 2 of the License, or
00008  * (at your option) any later version.
00009  *
00010  * This program is distributed in the hope that it will be useful,
00011  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00012  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00013  * GNU General Public License for more details.
00014  *
00015  * You should have received a copy of the GNU General Public License
00016  * along with this program; if not, write to the Free Software
00017  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
00018  *
00019  * Original author: Paul McCullagh (H&G2JCtL)
00020  * Continued development: Barry Leslie
00021  *
00022  * 2007-05-21
00023  *
00024  * CORE SYSTEM:
00025  * Simple utility functions.
00026  *
00027  */
00028 
00029 #include "CSConfig.h"
00030 #include <inttypes.h>
00031 
00032 #include <stdlib.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 #include <ctype.h>
00036 
00037 #ifndef OS_WINDOWS
00038 #include <fnmatch.h>
00039 #endif
00040 
00041 #include "CSDefs.h"
00042 #include "CSStrUtil.h"
00043 #include "CSMemory.h"
00044 #include "CSGlobal.h"
00045 
00046 const char *cs_version()
00047 {
00048   static char version[124];
00049   
00050   if (!version[0]) {
00051     snprintf(version, 124, "%s(Built %s %s)", VERSION, __DATE__, __TIME__);
00052   }
00053   
00054   return version;
00055 }
00056 
00057 void cs_strcpy(size_t size, char *to, const char *from, size_t len)
00058 {
00059   if (size > 0) {
00060     size--;
00061     if (len > size)
00062       len = size;
00063     memcpy(to, from, len);
00064     to[len] = 0;
00065   }
00066 }
00067 
00068 void cs_strcpy(size_t size, char *to, const char *from)
00069 {
00070   if (size > 0) {
00071     size--;
00072     while (*from && size--)
00073       *to++ = *from++;
00074     *to = 0;
00075   }
00076 }
00077 
00078 /* This function adds '...' to the end of the string.
00079  * if it does not fit!
00080  */
00081 void cs_strcpy_dottt(size_t size, char *d, const char *s, size_t len)
00082 {
00083   if (len+1 <= size) {
00084     cs_strcpy(size, d, s, len);
00085     return;
00086   }
00087   if (size < 5) {
00088     /* Silly, but anyway... */
00089     cs_strcpy(size, d, "...");
00090     return;
00091   }
00092   memcpy(d, s, size-4);
00093   memcpy(d+size-4, "...", 3);
00094   d[size-1] = 0;
00095 }
00096 
00097 void cs_strcpy_left(size_t size, char *to, const char *from, char ch)
00098 {
00099   if (size > 0) {
00100     size--;
00101     while (*from && size-- && *from != ch)
00102       *to++ = *from++;
00103     *to = 0;
00104   }
00105 }
00106 
00107 void cs_strcpy_right(size_t size, char *to, const char *from, char ch)
00108 {
00109   if (size > 0) {
00110     size--;
00111     while (*from && *from != ch)
00112       from++;
00113     if (*from == ch)
00114       from++;
00115     while (*from && size-- && *from != ch)
00116       *to++ = *from++;
00117     *to = 0;
00118   }
00119 }
00120 
00121 void cs_strcat(size_t size, char *to, const char *from)
00122 {
00123   while (*to && size--) to++;
00124   cs_strcpy(size, to, from);
00125 }
00126 
00127 void cs_strcat(size_t size, char *to, char ch)
00128 {
00129   while (*to && size--) to++;
00130   if (size >= 1) {
00131     *to = ch;
00132     *(to+1) = 0;
00133   }
00134 }
00135 
00136 void cs_strcat(char **to, const char *to_cat)
00137 {
00138   size_t len = strlen(*to) + strlen(to_cat) + 1;
00139   
00140   cs_realloc((void **) to, len);
00141   strcat(*to, to_cat);
00142 }
00143 
00144 void cs_strcat(size_t size, char *to, int i)
00145 {
00146   char buffer[20];
00147   
00148   snprintf(buffer, 20, "%d", i);
00149   cs_strcat(size, to, buffer);
00150 }
00151 
00152 void cs_strcat(size_t size, char *to, uint32_t i)
00153 {
00154   char buffer[20];
00155   
00156   snprintf(buffer, 20, "%"PRIu32"", i);
00157   cs_strcat(size, to, buffer);
00158 }
00159 
00160 void cs_strcat(size_t size, char *to, uint64_t i)
00161 {
00162   char buffer[40];
00163   
00164   snprintf(buffer, 40, "%"PRIu64"", i);
00165   cs_strcat(size, to, buffer);
00166 }
00167 
00168 void cs_strcat_left(size_t size, char *to, const char *from, char ch)
00169 {
00170   while (*to && size--) to++;
00171   cs_strcpy_left(size, to, from, ch);
00172 }
00173 
00174 void cs_strcat_right(size_t size, char *to, const char *from, char ch)
00175 {
00176   while (*to && size--) to++;
00177   cs_strcpy_right(size, to, from, ch);
00178 }
00179 
00180 void cs_strcat_hex(size_t size, char *to, uint64_t i)
00181 {
00182   char buffer[80];
00183   
00184   snprintf(buffer, 80, "%"PRIx64"", i);
00185   cs_strcat(size, to, buffer);
00186 }
00187 
00188 void cs_format_context(size_t size, char *buffer, const char *func, const char *file, int line)
00189 {
00190   char *ptr;
00191 
00192   if (func) {
00193     cs_strcpy(size, buffer, func);
00194     // If the "pretty" function includes parameters, remove them:
00195     if ((ptr = strchr(buffer, '(')))
00196       *ptr = 0;
00197     cs_strcat(size, buffer, "(");
00198   }
00199   else
00200     *buffer = 0;
00201   if (file) {
00202     cs_strcat(size, buffer, cs_last_name_of_path(file));
00203     if (line) {
00204       cs_strcat(size, buffer, ":");
00205       cs_strcat(size, buffer, line);
00206     }
00207   }
00208   if (func)
00209     cs_strcat(size, buffer, ")");
00210 }
00211 
00212 int cs_path_depth(const char *path)
00213 {
00214   int count = 0;
00215   while (*path) {
00216     if (IS_DIR_CHAR(*path))
00217       count++;
00218 
00219     path++;
00220   }
00221   return count;
00222 }
00223 
00224 static const char *find_wildcard(const char *pattern)
00225 {
00226   bool escaped = false;
00227   while (*pattern) {
00228     if ((*pattern == '*' || *pattern == '?' ) && !escaped)
00229       return pattern;
00230       
00231     if (*pattern == '\\')
00232       escaped = !escaped;
00233     else
00234       escaped = false;
00235       
00236     pattern++;
00237   }
00238   
00239   return NULL;
00240 }
00241 
00242 // Check if the path contains any variable components.
00243 bool cs_fixed_pattern(const char *str)
00244 {
00245   return (find_wildcard(str) == NULL);
00246 }
00247 
00248 #ifdef OS_WINDOWS
00249 /* 
00250 bool cs_match_patern(const char *pattern, const char *str, bool ignore_case)
00251 {
00252   bool escaped = false;
00253   
00254   while (*pattern && *str) {
00255     if ((*pattern == '*' || *pattern == '?' ) && !escaped) {
00256       if (*pattern == '?') {
00257         pattern++;
00258         str++;  
00259         continue;     
00260       }
00261       
00262       while (*pattern == '*' || *pattern == '?' ) pattern++; // eat the pattern matching characters.
00263       
00264       if (!*pattern) // A * at the end of the pattern matches everything.
00265         return true;
00266         
00267       // This is where it gets complicted.
00268       
00269       coming soon!
00270       
00271     }
00272           
00273     if (*pattern == '\\')
00274       escaped = !escaped;
00275     else
00276       escaped = false;
00277       
00278     if (escaped)
00279       pattern++;
00280     else {
00281       if (ignore_case) {
00282         if (toupper(*pattern) != toupper(*str))
00283           return false;
00284       } else if (*pattern != *str)
00285         return false;
00286       pattern++;
00287       str++;        
00288     }
00289     
00290   }
00291   
00292   return ((!*pattern) && (!*str));
00293 }
00294 */
00295 #else
00296 bool cs_match_patern(const char *pattern, const char *str, bool ignore_case)
00297 {
00298   return (fnmatch(pattern, str, (ignore_case)?FNM_CASEFOLD:0) == 0);
00299 }
00300 #endif
00301 
00302 /* This function returns "" if the path ends with a dir char */
00303 char *cs_last_name_of_path(const char *path, int count)
00304 {
00305   size_t    length;
00306   const char  *ptr;
00307 
00308   length = strlen(path);
00309   if (!length)
00310     return((char *) path);
00311   ptr = path + length - 1;
00312   while (ptr != path) {
00313     if (IS_DIR_CHAR(*ptr)) {
00314       count--;
00315       if (!count)
00316         break;
00317     }
00318     ptr--;
00319   }
00320   if (IS_DIR_CHAR(*ptr)) ptr++;
00321   return((char *) ptr);
00322 }
00323 
00324 char *cs_last_name_of_path(const char *path)
00325 {
00326   return cs_last_name_of_path(path, 1);
00327 }
00328 
00329 /* This function returns the last name component, even if the path ends with a dir char */
00330 char *cs_last_directory_of_path(const char *path)
00331 {
00332   size_t  length;
00333   const char  *ptr;
00334 
00335   length = strlen(path);
00336   if (!length)
00337     return((char *)path);
00338   ptr = path + length - 1;
00339   if (IS_DIR_CHAR(*ptr))
00340     ptr--;
00341   while (ptr != path && !IS_DIR_CHAR(*ptr)) ptr--;
00342   if (IS_DIR_CHAR(*ptr)) ptr++;
00343   return((char *)ptr);
00344 }
00345 
00346 const char *cs_find_extension(const char *file_name)
00347 {
00348   const char  *ptr;
00349 
00350   for (ptr = file_name + strlen(file_name) - 1; ptr >= file_name; ptr--) {
00351     if (IS_DIR_CHAR(*ptr))
00352       break;
00353     if (*ptr == '.')
00354       return ptr + 1;
00355   }
00356   return NULL;
00357 }
00358 
00359 void cs_remove_extension(char *file_name)
00360 {
00361   char *ptr = (char *) cs_find_extension(file_name);
00362 
00363   if (ptr)
00364     *(ptr - 1) = 0;
00365 }
00366 
00367 bool cs_is_extension(const char *file_name, const char *ext)
00368 {
00369   const char *ptr;
00370 
00371   if ((ptr = cs_find_extension(file_name)))
00372     return strcmp(ptr, ext) == 0;
00373   return false;
00374 }
00375 
00376 /*
00377  * Optionally remove a trailing directory delimiter (If the directory name consists of one
00378  * character, the directory delimiter is not removed).
00379  */
00380 bool cs_remove_dir_char(char *dir_name)
00381 {
00382   size_t length;
00383   
00384   length = strlen(dir_name);
00385   if (length > 1) {
00386     if (IS_DIR_CHAR(dir_name[length - 1])) {
00387       dir_name[length - 1] = '\0';
00388       return true;
00389     }
00390   }
00391   return false;
00392 }
00393 
00394 void cs_remove_last_name_of_path(char *path)
00395 {
00396   char *ptr;
00397 
00398   if ((ptr = cs_last_name_of_path(path)))
00399     *ptr = 0;
00400 }
00401 
00402 static void cs_remove_last_directory_of_path(char *path)
00403 {
00404   char *ptr;
00405 
00406   if ((ptr = cs_last_directory_of_path(path)))
00407     *ptr = 0;
00408 }
00409 
00410 bool cs_add_dir_char(size_t max, char *path)
00411 {
00412   size_t slen = strlen(path);
00413 
00414   if (slen >= max)
00415     return false;
00416 
00417   if (slen == 0) {
00418     /* If no path is given we will be at the current working directory, under UNIX we must
00419      * NOT add a directory delimiter character:
00420      */
00421     return false;
00422   }
00423 
00424   if (!IS_DIR_CHAR(path[slen - 1])) {
00425     path[slen] = CS_DIR_CHAR;
00426     path[slen + 1] = '\0';
00427     return true;
00428   }
00429   return false;
00430 }
00431 
00432 bool cs_is_absolute(const char *path)
00433 {
00434   return IS_DIR_CHAR(*path);
00435 }
00436 
00437 void cs_add_name_to_path(size_t max, char *path, const char *name)
00438 {
00439   char *end_ptr = path + max - 1;
00440 
00441   cs_add_dir_char(max, path);
00442   path = path + strlen(path);
00443 
00444   if (IS_DIR_CHAR(*name))
00445     name++;
00446   while (*name && !IS_DIR_CHAR(*name) && path < end_ptr)
00447     *path++ = *name++;
00448   *path = 0;
00449 }
00450 
00451 const char *cs_next_name_of_path(const char *path)
00452 {
00453   if (IS_DIR_CHAR(*path))
00454     path++;
00455   while (*path && !IS_DIR_CHAR(*path))
00456     path++;
00457   if (IS_DIR_CHAR(*path))
00458     path++;
00459   return path;
00460 }
00461 
00462 static void cs_adjust_absolute_path(size_t max, char *path, const char *rel_path)
00463 {
00464   while (*rel_path) {
00465     if (*rel_path == '.') {
00466       if (*(rel_path + 1) == '.') {
00467         if (!*(rel_path + 2) || IS_DIR_CHAR(*(rel_path + 2))) {
00468           /* ..: move up one: */
00469           cs_remove_last_directory_of_path(path);
00470           goto loop;
00471         }
00472       }
00473       else {
00474         if (!*(rel_path + 1) || IS_DIR_CHAR(*(rel_path + 1)))
00475           /* .: stay here: */
00476           goto loop;
00477       }
00478     }
00479 
00480     /* Change to this directory: */
00481     cs_add_name_to_path(max, path, rel_path);
00482     loop:
00483     rel_path = cs_next_name_of_path(rel_path);
00484   }
00485 }
00486 
00487 void cs_make_absolute_path(size_t max, char *path, const char *rel_path, const char *cwd)
00488 {
00489   if (cs_is_absolute(rel_path))
00490     cs_strcpy(max, path, rel_path);
00491   else {
00492     /* Path is relative to the current directory */
00493     cs_strcpy(max, path, cwd);
00494     cs_adjust_absolute_path(max, path, rel_path);
00495   }
00496   cs_remove_dir_char(path);
00497 }
00498 
00499 char *cs_strdup(const char *in_str)
00500 {
00501   char *str;
00502   
00503   if (!in_str)
00504     return NULL;
00505 
00506   str = (char *) cs_malloc(strlen(in_str) + 1);
00507   strcpy(str, in_str);
00508   return str;
00509 }
00510 
00511 char *cs_strdup(int i)
00512 {
00513   char buffer[20];
00514   char *str;
00515 
00516   snprintf(buffer, 20, "%d", i);
00517   str = (char *) cs_malloc(strlen(buffer) + 1);
00518   strcpy(str, buffer);
00519   return str;
00520 }
00521 
00522 char *cs_strdup(const char *in_str, size_t len)
00523 {
00524   char *str;
00525   
00526   if (!in_str)
00527     return NULL;
00528 
00529   str = (char *) cs_malloc(len + 1);
00530 
00531   // Allow for allocation of an oversized buffer.
00532   size_t str_len = strlen(in_str);
00533   if (len > str_len)
00534     len = str_len;
00535     
00536   memcpy(str, in_str, len);
00537   str[len] = 0;
00538   return str;
00539 }
00540 
00541 bool cs_starts_with(const char *cstr, const char *w_cstr)
00542 {
00543   while (*cstr && *w_cstr) {
00544     if (*cstr != *w_cstr)
00545       return false;
00546     cstr++;
00547     w_cstr++;
00548   }
00549   return *cstr || !*w_cstr;
00550 }
00551 
00552 bool cs_ends_with(const char *cstr, const char *w_cstr)
00553 {
00554   size_t    len = strlen(cstr);
00555   size_t    w_len = strlen(w_cstr);
00556   const char  *ptr = cstr + len - 1;
00557   const char  *w_ptr = w_cstr + w_len - 1;
00558   
00559   if (w_len > len)
00560     return false;
00561 
00562   if (w_len == 0)
00563     return false;
00564 
00565   while (w_ptr >= w_cstr) {
00566     if (*w_ptr != *ptr)
00567       return false;
00568     w_ptr--;
00569     ptr--;
00570   }
00571 
00572   return true;
00573 }
00574 
00575 void cs_replace_string(size_t size, char *into, const char *find_str, const char *str)
00576 {
00577   char *ptr;
00578 
00579   if ((ptr = strstr(into, find_str))) {
00580     size_t len = strlen(into);
00581     size_t len2 = strlen(str);
00582     size_t len3 = strlen(find_str);
00583     
00584     if (len + len2 + len3 >= size)
00585       len2 = size - len;
00586     
00587     memmove(ptr+len2, ptr+len3, len - (ptr + len3 - into));
00588     memcpy(ptr, str, len2);
00589     into[len + len2 - len3] = 0;
00590   }
00591 }
00592 
00593 void cs_replace_string(size_t size, char *into, const char ch, const char *str)
00594 {
00595   char *ptr;
00596 
00597   if ((ptr = strchr(into, ch))) {
00598     size_t len = strlen(into);
00599     size_t len2 = strlen(str);
00600     
00601     if ((len + len2) > size)
00602       len2 = size - len;
00603     
00604     memmove(ptr+1, ptr+len2, len - (ptr - into + 1));
00605     memcpy(ptr, str, len2);
00606     into[len + len2 - 1] = 0;
00607   }
00608 }
00609 
00610 uint64_t cs_str_to_word8(const char *ptr, bool *overflow)
00611 {
00612   uint64_t value = 0;
00613 
00614   if (overflow)
00615     *overflow = false;
00616   while (*ptr == '0') ptr++;
00617   if (!*ptr)
00618     value = (uint64_t) 0;
00619   else {
00620     sscanf(ptr, "%"PRIu64"", &value);
00621     if (!value && overflow)
00622       *overflow = true;
00623   }
00624   return value;
00625 }
00626 
00627 int64_t cs_str_to_int8(const char *ptr, bool *overflow)
00628 {
00629   int64_t value = 0;
00630 
00631   if (overflow)
00632     *overflow = false;
00633   while (*ptr == '0') ptr++;
00634   if (!*ptr)
00635     value = (int64_t) 0;
00636   else {
00637     sscanf(ptr, "%"PRId64"", &value);
00638     if (!value && overflow)
00639       *overflow = true;
00640   }
00641   return value;
00642 }
00643 
00644 int64_t cs_byte_size_to_int8(const char *ptr, bool *invalid)
00645 {
00646   char  *end_ptr;
00647   int64_t size;
00648 
00649   if (invalid)
00650     *invalid = false;
00651 
00652   while (*ptr && isspace(*ptr))
00653     ptr++;
00654 
00655   if (!isdigit(*ptr) && *ptr != '.')
00656     goto failed;
00657 
00658   size = (int64_t) strtod(ptr, &end_ptr);
00659 
00660   ptr = end_ptr;
00661   while (*ptr && isspace(*ptr))
00662     ptr++;
00663   
00664   switch (toupper(*ptr)) {
00665     case 'P':
00666       size *= (int64_t) 1024;
00667     case 'T':
00668       size *= (int64_t) 1024;
00669     case 'G':
00670       size *= (int64_t) 1024;
00671     case 'M':
00672       size *= (int64_t) 1024;
00673     case 'K':
00674       size *= (int64_t) 1024;
00675       ptr++;
00676       break;
00677     case '\0':
00678       break;
00679     default:
00680       goto failed;
00681   }
00682   
00683   if (toupper(*ptr) == 'B')
00684     ptr++;
00685 
00686   while (*ptr && isspace(*ptr))
00687     ptr++;
00688 
00689   if (*ptr)
00690     goto failed;
00691 
00692   return (int64_t) size;
00693 
00694   failed:
00695   if (invalid)
00696     *invalid = true;
00697   return 0;
00698 }
00699 
00700 
00701 static uint32_t cs_hex_value(char ch)
00702 {
00703   u_char uch = (u_char) ch;
00704 
00705   if (uch >= '0' && uch <= '9')
00706     return uch - '0';
00707   if (uch >= 'A' && uch <= 'F')
00708     return uch - 'A' + 10; 
00709   if (uch >= 'a' && uch <= 'f')
00710     return uch - 'a' + 10;
00711   return 0;
00712 }
00713 
00714 size_t cs_hex_to_bin(size_t size, void *v_bin, size_t len, const char *hex)
00715 {
00716   size_t  tot_size = size;
00717   uint32_t  val = 0;
00718   size_t  shift = 0;
00719   u_char *bin = (u_char *) v_bin;
00720 
00721   if (len & 1)
00722     shift = 1;
00723   for (size_t i=shift; i<len+shift && size > 0; i++) {
00724     if (i & 1) {
00725       val = val | cs_hex_value(*hex);
00726       *bin = val;
00727       bin++;
00728       size--;
00729     }
00730     else
00731       val = cs_hex_value(*hex) << 4;
00732     hex++;
00733   }
00734   return tot_size - size;
00735 }
00736 
00737 size_t cs_hex_to_bin(size_t size, void *bin, const char *hex)
00738 {
00739   return cs_hex_to_bin(size, bin, strlen(hex), hex);
00740 }
00741 
00742 #define HEX_DIGIT(x)  ((x) <= 9 ? '0' + (x) : 'A' + ((x) - 10))
00743 
00744 // NOTE: cs_bin_to_hex() Always null terminates the result.
00745 void cs_bin_to_hex(size_t size, char *hex, size_t len, const void *v_bin)
00746 {
00747   const u_char *bin = (u_char *) v_bin;
00748   if (size == 0)
00749     return;
00750   size--;
00751   for (size_t i=0; i<len && size > 0; i++) {
00752     *hex = HEX_DIGIT(*bin >> 4);
00753     hex++;
00754     size--;
00755     if (size == 0)
00756       break;
00757     *hex = HEX_DIGIT(*bin & 0x0F);
00758     hex++;
00759     size--;
00760     bin++;
00761   }
00762   *hex = 0;
00763 } 
00764 
00765 void cs_strToUpper(char *ptr)
00766 {
00767   while (*ptr) {
00768     *ptr = toupper(*ptr);
00769     ptr++;
00770   }
00771 }
00772 
00773 void cs_strToLower(char *ptr)
00774 {
00775   while (*ptr) {
00776     *ptr = tolower(*ptr);
00777     ptr++;
00778   }
00779 }
00780 
00781 /*
00782  * Return failed if this is not a valid number.
00783  */
00784 bool cs_str_to_value(const char *ptr, uint32_t *value, uint8_t base)
00785 {
00786   char *endptr;
00787 
00788   *value = strtoul(ptr, &endptr, base);
00789   return *endptr ? false : true;
00790 }
00791 
00792