Merge pull request #4791 from jmarshallnz/playlist_settings
[vuplus_xbmc] / lib / libhts / htsstr.c
1 /*
2  *  String helper functions
3  *  Copyright (C) 2008 Andreas Ă–man
4  *  Copyright (C) 2008 Mattias Wadman
5  *
6  *  This program is free software; you can redistribute it and/or
7  *  modify it under the terms of the GNU General Public License
8  *  as published by the Free Software Foundation; either version 2
9  *  of the License, or (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program; if not, write to the Free Software
18  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19  */
20
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #ifdef __APPLE__
25 #include "osx/OSXGNUReplacements.h"
26 #elif defined(_MSC_VER)
27 #include "msvc.h"
28 #endif
29 #include "htsstr.h"
30
31
32 static void htsstr_argsplit_add(char ***argv, int *argc, char *s);
33 static int htsstr_format0(const char *str, char *out, char **map);
34
35
36 char *
37 htsstr_unescape(char *str) {
38   char *s;
39
40   for(s = str; *s; s++) {
41     if(*s != '\\')
42       continue;
43
44     if(*(s + 1) == 'b')
45       *s = '\b';
46     else if(*(s + 1) == 'f')
47       *s = '\f';
48     else if(*(s + 1) == 'n')
49       *s = '\n';
50     else if(*(s + 1) == 'r')
51       *s = '\r';
52     else if(*(s + 1) == 't')
53       *s = '\t';
54     else
55       *s = *(s + 1);
56
57     if(*(s + 1)) {
58       /* shift string left, copies terminator too */
59       memmove(s + 1, s + 2, strlen(s + 2) + 1);
60     }
61   } 
62
63   return str;
64 }
65
66 static void
67 htsstr_argsplit_add(char ***argv, int *argc, char *s)
68 {
69   *argv = realloc(*argv, sizeof((*argv)[0]) * (*argc + 1));
70   (*argv)[(*argc)++] = s;
71 }
72
73 char **
74 htsstr_argsplit(const char *str) {
75   int quote = 0;
76   int inarg = 0;
77   const char *start = NULL;
78   const char *stop = NULL;
79   const char *s;
80   char **argv = NULL;
81   int argc = 0;
82
83   for(s = str; *s; s++) {
84     if(start && stop) {
85       htsstr_argsplit_add(&argv, &argc,
86                           htsstr_unescape(strndup(start, stop - start)));
87       start = stop = NULL;
88     }
89     
90     if(inarg) {
91       switch(*s) {
92         case '\\':
93           s++;
94           break;
95         case '"':
96           if(quote) {
97             inarg = 0;
98             quote = 0;
99             stop = s;
100           }
101           break;
102         case ' ':
103           if(quote)
104             break;
105           inarg = 0;
106           stop = s;
107           break;
108         default:
109           break;
110       }
111     } else {
112       switch(*s) {
113         case ' ':
114           break;
115         case '"':
116           quote = 1;
117           s++;
118           /* fallthru */
119         default:
120           inarg = 1;
121           start = s;
122           stop = NULL;
123           break;
124       }
125     }
126   }
127
128   if(start) {
129     if(!stop)
130       stop = str + strlen(str);
131     htsstr_argsplit_add(&argv, &argc,
132                         htsstr_unescape(strndup(start, stop - start)));
133   }
134
135   htsstr_argsplit_add(&argv, &argc, NULL);
136
137   return argv;
138 }
139
140 void 
141 htsstr_argsplit_free(char **argv) {
142   int i;
143
144   for(i = 0; argv[i]; i++)
145     free(argv[i]);
146   
147   free(argv);
148 }
149
150 static int
151 htsstr_format0(const char *str, char *out, char **map) {
152   const char *s = str;
153   char *f;
154   int n = 0;
155
156   while(*s) {
157     switch(*s) {
158       case '%':
159         f = map[(unsigned char)*(s + 1)];
160         if(*(s + 1) != '%' && f) {
161           s += 2; /* skip %f * */
162           if(out)
163             strcpy(&out[n], f);
164           n += strlen(f);
165           break;
166         }
167         /* fallthru */
168       default:
169         if(out)
170           out[n] = *s;
171         s++;
172         n++;
173         break;
174     }
175   }
176
177   if(out)
178     out[n] = '\0';
179
180   return n + 1; /* + \0 */
181 }
182
183 char *
184 htsstr_format(const char *str, char **map)
185 {
186   char *s;
187   
188   s = malloc(htsstr_format0(str, NULL, map));
189   htsstr_format0(str, s, map);
190
191   return s;
192 }
193