/* * String helper functions * Copyright (C) 2008 Andreas Ă–man * Copyright (C) 2008 Mattias Wadman * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License * as published by the Free Software Foundation; either version 2 * of the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ #include #include #include #ifdef __APPLE__ #include "osx/OSXGNUReplacements.h" #elif defined(_MSC_VER) #include "msvc.h" #endif #include "htsstr.h" static void htsstr_argsplit_add(char ***argv, int *argc, char *s); static int htsstr_format0(const char *str, char *out, char **map); char * htsstr_unescape(char *str) { char *s; for(s = str; *s; s++) { if(*s != '\\') continue; if(*(s + 1) == 'b') *s = '\b'; else if(*(s + 1) == 'f') *s = '\f'; else if(*(s + 1) == 'n') *s = '\n'; else if(*(s + 1) == 'r') *s = '\r'; else if(*(s + 1) == 't') *s = '\t'; else *s = *(s + 1); if(*(s + 1)) { /* shift string left, copies terminator too */ memmove(s + 1, s + 2, strlen(s + 2) + 1); } } return str; } static void htsstr_argsplit_add(char ***argv, int *argc, char *s) { *argv = realloc(*argv, sizeof((*argv)[0]) * (*argc + 1)); (*argv)[(*argc)++] = s; } char ** htsstr_argsplit(const char *str) { int quote = 0; int inarg = 0; const char *start = NULL; const char *stop = NULL; const char *s; char **argv = NULL; int argc = 0; for(s = str; *s; s++) { if(start && stop) { htsstr_argsplit_add(&argv, &argc, htsstr_unescape(strndup(start, stop - start))); start = stop = NULL; } if(inarg) { switch(*s) { case '\\': s++; break; case '"': if(quote) { inarg = 0; quote = 0; stop = s; } break; case ' ': if(quote) break; inarg = 0; stop = s; break; default: break; } } else { switch(*s) { case ' ': break; case '"': quote = 1; s++; /* fallthru */ default: inarg = 1; start = s; stop = NULL; break; } } } if(start) { if(!stop) stop = str + strlen(str); htsstr_argsplit_add(&argv, &argc, htsstr_unescape(strndup(start, stop - start))); } htsstr_argsplit_add(&argv, &argc, NULL); return argv; } void htsstr_argsplit_free(char **argv) { int i; for(i = 0; argv[i]; i++) free(argv[i]); free(argv); } static int htsstr_format0(const char *str, char *out, char **map) { const char *s = str; char *f; int n = 0; while(*s) { switch(*s) { case '%': f = map[(unsigned char)*(s + 1)]; if(*(s + 1) != '%' && f) { s += 2; /* skip %f * */ if(out) strcpy(&out[n], f); n += strlen(f); break; } /* fallthru */ default: if(out) out[n] = *s; s++; n++; break; } } if(out) out[n] = '\0'; return n + 1; /* + \0 */ } char * htsstr_format(const char *str, char **map) { char *s; s = malloc(htsstr_format0(str, NULL, map)); htsstr_format0(str, s, map); return s; }