1 /*============================================================================ 2 epub2txt v2 3 string.c 4 Copyright (c)2020 Kevin Boone, GPL v3.0 5 ============================================================================*/ 6 7 #define _GNU_SOURCE 8 #include 9 #include 10 #include 11 12 #if !defined(__MACH__) 13 #include 14 #endif 15 16 #include 17 #include 18 #include 19 #include 20 #include 21 #include 22 #include 23 #include 24 #include 25 #include "custom_string.h" 26 #include "defs.h" 27 #include "log.h" 28 29 struct _String 30 { 31 char *str; 32 }; 33 34 35 /*========================================================================== 36 string_create_empty 37 *==========================================================================*/ 38 String *string_create_empty (void) 39 { 40 return string_create (""); 41 } 42 43 44 /*========================================================================== 45 string_create 46 *==========================================================================*/ 47 String *string_create (const char *s) 48 { 49 String *self = malloc (sizeof (String)); 50 self->str = strdup (s); 51 return self; 52 } 53 54 55 /*========================================================================== 56 string_destroy 57 *==========================================================================*/ 58 void string_destroy (String *self) 59 { 60 if (self) 61 { 62 if (self->str) free (self->str); 63 free (self); 64 } 65 } 66 67 68 /*========================================================================== 69 string_cstr 70 *==========================================================================*/ 71 const char *string_cstr (const String *self) 72 { 73 return self->str; 74 } 75 76 77 /*========================================================================== 78 string_cstr_safe 79 *==========================================================================*/ 80 const char *string_cstr_safe (const String *self) 81 { 82 if (self) 83 { 84 if (self->str) 85 return self->str; 86 else 87 return ""; 88 } 89 else 90 return ""; 91 } 92 93 94 /*========================================================================== 95 string_append 96 *==========================================================================*/ 97 void string_append (String *self, const char *s) 98 { 99 if (!s) return; 100 if (self->str == NULL) self->str = strdup (""); 101 int newlen = strlen (self->str) + strlen (s) + 2; 102 self->str = realloc (self->str, newlen); 103 strcat (self->str, s); 104 } 105 106 107 /*========================================================================== 108 string_prepend 109 *==========================================================================*/ 110 void string_prepend (String *self, const char *s) 111 { 112 if (!s) return; 113 if (self->str == NULL) self->str = strdup (""); 114 int newlen = strlen (self->str) + strlen (s) + 2; 115 char *temp = strdup (self->str); 116 free (self->str); 117 self->str = malloc (newlen); 118 strcpy (self->str, s); 119 strcat (self->str, temp); 120 free (temp); 121 } 122 123 124 /*========================================================================== 125 string_append_printf 126 *==========================================================================*/ 127 void string_append_printf (String *self, const char *fmt,...) 128 { 129 if (self->str == NULL) self->str = strdup (""); 130 va_list ap; 131 va_start (ap, fmt); 132 char *s; 133 vasprintf (&s, fmt, ap); 134 string_append (self, s); 135 free (s); 136 va_end (ap); 137 } 138 139 140 /*========================================================================== 141 string_length 142 *==========================================================================*/ 143 int string_length (const String *self) 144 { 145 if (self == NULL) return 0; 146 if (self->str == NULL) return 0; 147 return strlen (self->str); 148 } 149 150 151 /*========================================================================== 152 string_clone 153 *==========================================================================*/ 154 String *string_clone (const String *self) 155 { 156 if (!self) return NULL; 157 if (!self->str) return string_create_empty(); 158 return string_create (string_cstr (self)); 159 } 160 161 162 /*========================================================================== 163 string_find 164 *==========================================================================*/ 165 int string_find (const String *self, const char *search) 166 { 167 if (!self) return -1; 168 if (!self->str) return -1; 169 const char *p = strstr (self->str, search); 170 if (p) 171 return p - self->str; 172 else 173 return -1; 174 } 175 176 177 /*========================================================================== 178 string_delete 179 *==========================================================================*/ 180 void string_delete (String *self, const int pos, const int len) 181 { 182 char *str = self->str; 183 if (pos + len > strlen (str)) 184 string_delete (self, pos, strlen(str) - len); 185 else 186 { 187 char *buff = malloc (strlen (str) - len + 2); 188 strncpy (buff, str, pos); 189 strcpy (buff + pos, str + pos + len); 190 free (self->str); 191 self->str = buff; 192 } 193 } 194 195 196 /*========================================================================== 197 string_insert 198 *==========================================================================*/ 199 void string_insert (String *self, const int pos, 200 const char *replace) 201 { 202 char *buff = malloc (strlen (self->str) + strlen (replace) + 2); 203 char *str = self->str; 204 strncpy (buff, str, pos); 205 buff[pos] = 0; 206 strcat (buff, replace); 207 strcat (buff, str + pos); 208 free (self->str); 209 self->str = buff; 210 } 211 212 213 214 /*========================================================================== 215 string_substitute_all 216 *==========================================================================*/ 217 String *string_substitute_all (const String *self, 218 const char *search, const char *replace) 219 { 220 String *working = string_clone (self); 221 BOOL cont = TRUE; 222 while (cont) 223 { 224 int i = string_find (working, search); 225 if (i >= 0) 226 { 227 string_delete (working, i, strlen (search)); 228 string_insert (working, i, replace); 229 } 230 else 231 cont = FALSE; 232 } 233 return working; 234 } 235 236 237 /*========================================================================== 238 string_create_from_utf8_file 239 *==========================================================================*/ 240 BOOL string_create_from_utf8_file (const char *filename, 241 String **result, char **error) 242 { 243 String *self = NULL; 244 BOOL ok = FALSE; 245 int f = open (filename, O_RDONLY); 246 if (f > 0) 247 { 248 self = malloc (sizeof (String)); 249 struct stat sb; 250 fstat (f, &sb); 251 int64_t size = sb.st_size; 252 char *buff = malloc (size + 2); 253 self->str = buff; 254 255 // Read the first three characters, to check for a UTF-8 byte-order-mark 256 read (f, buff, 3); 257 if (buff[0] == (char)0xEF && buff[1] == (char)0xBB && buff[2] == (char)0xBF) 258 { 259 read (f, buff, size - 3); 260 self->str[size - 3] = 0; 261 } 262 else 263 { 264 read (f, buff + 3, size - 3); 265 self->str[size] = 0; 266 } 267 268 *result = self; 269 ok = TRUE; 270 } 271 else 272 { 273 asprintf (error, "Can't open file '%s' for reading: %s", 274 filename, strerror (errno)); 275 ok = FALSE; 276 } 277 278 return ok; 279 } 280 281 282 /*========================================================================== 283 string_encode_url 284 *==========================================================================*/ 285 static char to_hex(char code) 286 { 287 static char hex[] = "0123456789abcdef"; 288 return hex[code & 15]; 289 } 290 291 292 String *string_encode_url (const char *str) 293 { 294 if (!str) return string_create_empty();; 295 const char *pstr = str; 296 char *buf = malloc(strlen(str) * 3 + 1), *pbuf = buf; 297 while (*pstr) 298 { 299 if (isalnum(*pstr) || *pstr == '-' || *pstr == '_' 300 || *pstr == '.' || *pstr == '~') 301 *pbuf++ = *pstr; 302 else if (*pstr == ' ') 303 *pbuf++ = '+'; 304 else 305 *pbuf++ = '%', *pbuf++ = to_hex(*pstr >> 4), 306 *pbuf++ = to_hex(*pstr & 15); 307 pstr++; 308 } 309 *pbuf = '\0'; 310 String *result = string_create (buf); 311 free (buf); 312 return (result); 313 } 314 315 316 /*========================================================================== 317 string_append_byte 318 *==========================================================================*/ 319 void string_append_byte (String *self, const BYTE byte) 320 { 321 char buff[2]; 322 buff[0] = byte; 323 buff[1] = 0; 324 string_append (self, buff); 325 } 326 327 328 /*========================================================================== 329 string_append_c 330 *==========================================================================*/ 331 void string_append_c (String *self, const uint32_t ch) 332 { 333 if (ch < 0x80) 334 { 335 string_append_byte (self, (BYTE)ch); 336 } 337 else if (ch < 0x0800) 338 { 339 string_append_byte (self, (BYTE)((ch >> 6) | 0xC0)); 340 string_append_byte (self, (BYTE)((ch & 0x3F) | 0x80)); 341 } 342 else if (ch < 0x10000) 343 { 344 string_append_byte (self, (BYTE)((ch >> 12) | 0xE0)); 345 string_append_byte (self, (BYTE)((ch >> 6 & 0x3F) | 0x80)); 346 string_append_byte (self, (BYTE)((ch & 0x3F) | 0x80)); 347 } 348 else 349 { 350 string_append_byte (self, (BYTE)((ch >> 18) | 0xF0)); 351 string_append_byte (self, (BYTE)(((ch >> 12) & 0x3F) | 0x80)); 352 string_append_byte (self, (BYTE)(((ch >> 6) & 0x3F) | 0x80)); 353 string_append_byte (self, (BYTE)((ch & 0x3F) | 0x80)); 354 } 355 } 356 357 358 359