tvheadend/src/htsstr.c

195 lines
3.8 KiB
C

/*
* 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 3 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, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "htsstr.h"
static void htsstr_argsplit_add(char ***argv, int *argc, char *s);
static int htsstr_format0(const char *str, char *out, const char **map);
char *
hts_strndup(const char *src, size_t len)
{
char *r = malloc(len + 1);
r[len] = 0;
return memcpy(r, src, len);
}
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(hts_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(hts_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, const char **map) {
const char *s = str;
const 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, const char **map)
{
char *s;
s = malloc(htsstr_format0(str, NULL, map));
htsstr_format0(str, s, map);
return s;
}