1 /*$
2 Copyright (C) 2016-2020 Azel.
3
4 This file is part of AzPainterB.
5
6 AzPainterB is free software: you can redistribute it and/or modify
7 it under the terms of the GNU General Public License as published by
8 the Free Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 AzPainterB 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, see <http://www.gnu.org/licenses/>.
18 $*/
19
20 /*****************************************
21 * mTextParam
22 *****************************************/
23
24 #include <string.h>
25 #include <stdlib.h>
26 #include <math.h>
27
28 #include "mDef.h"
29
30 #include "mTextParam.h"
31
32 #include "mStr.h"
33 #include "mList.h"
34 #include "mUtilStr.h"
35
36
37 //----------------------
38
39 struct _mTextParam
40 {
41 char *buf; //文字列バッファ
42 mList list; //キーと値のリスト
43 };
44
45 typedef struct
46 {
47 mListItem i;
48
49 char *key,*param; //バッファの位置
50 uint32_t hash; //キーのハッシュ値
51 }mTextParamItem;
52
53 //----------------------
54
55
56 /**
57 @defgroup textparam mTextParam
58 @brief 文字列から各パラメータを取得
59
60 \c "key1=param1;key2=param2;..." などのように指定文字で区切られた形式の文字列から、各値を取得する。\n
61 キー名は、大文字小文字を区別しない。
62
63 @ingroup group_etc
64 @{
65
66 @file mTextParam.h
67 */
68
69
70 //==============================
71 // sub
72 //==============================
73
74
75 /** ハッシュ値取得 */
76
_get_hash(const char * pc)77 static uint32_t _get_hash(const char *pc)
78 {
79 uint32_t h = 0;
80
81 for(; *pc; pc++)
82 h = h * 37 + (*pc);
83
84 return h;
85 }
86
87 /** 文字列からリスト作成 */
88
_create_list(mTextParam * p,char split,char splitparam)89 static void _create_list(mTextParam *p,char split,char splitparam)
90 {
91 char *pc,*end,*keyend;
92 mTextParamItem *pi;
93 mBool loop = TRUE;
94
95 for(pc = p->buf; loop && *pc; pc = end + 1)
96 {
97 //終端位置
98
99 end = strchr(pc, split);
100 if(!end)
101 {
102 end = strchr(pc, 0);
103 loop = FALSE;
104 }
105
106 *end = 0;
107
108 //空の場合は処理しない
109
110 if(!(*pc)) continue;
111
112 //キーと値の区切り文字位置
113
114 keyend = strchr(pc, splitparam);
115
116 if(keyend) *keyend = 0;
117
118 //キーを小文字に
119
120 mToLower(pc);
121
122 //項目追加
123
124 pi = (mTextParamItem *)mListAppendNew(&p->list, sizeof(mTextParamItem), NULL);
125 if(!pi) return;
126
127 pi->key = pc;
128 pi->param = (keyend)? keyend + 1: end;
129 pi->hash = _get_hash(pc);
130 }
131 }
132
133 /** キーから検索 */
134
_find(mTextParam * p,const char * key)135 static char *_find(mTextParam *p,const char *key)
136 {
137 mTextParamItem *pi;
138 uint32_t hash;
139 char *keycmp,*param = NULL;
140
141 //比較用に、キーを小文字に
142
143 keycmp = mStrdup(key);
144 if(!keycmp) return NULL;
145
146 mToLower(keycmp);
147
148 hash = _get_hash(keycmp);
149
150 //キー検索
151
152 for(pi = (mTextParamItem *)p->list.top; pi; pi = (mTextParamItem *)pi->i.next)
153 {
154 if(hash == pi->hash && strcmp(keycmp, pi->key) == 0)
155 {
156 param = pi->param;
157 break;
158 }
159 }
160
161 mFree(keycmp);
162
163 return param;
164 }
165
166
167 //==============================
168
169
170 /** 解放 */
171
mTextParamFree(mTextParam * p)172 void mTextParamFree(mTextParam *p)
173 {
174 if(p)
175 {
176 mFree(p->buf);
177 mListDeleteAll(&p->list);
178
179 mFree(p);
180 }
181 }
182
183 /** 文字列から作成
184 *
185 * @param split ';' など、各値を区切る文字
186 * @param splitparam '=' など、キーと値を区切る文字 (-1 で '=') */
187
mTextParamCreate(const char * text,int split,int splitparam)188 mTextParam *mTextParamCreate(const char *text,int split,int splitparam)
189 {
190 mTextParam *p;
191
192 if(splitparam < 0) splitparam = '=';
193
194 p = (mTextParam *)mMalloc(sizeof(mTextParam), TRUE);
195 if(!p) return NULL;
196
197 //文字列をコピー
198
199 p->buf = mStrdup(text);
200 if(!p->buf)
201 {
202 mFree(p);
203 return NULL;
204 }
205
206 //リストを作成
207
208 _create_list(p, split, splitparam);
209
210 return p;
211 }
212
213
214 /** int 値を取得
215 *
216 * 16進数 (0x...)、8進数 (0...) にも対応 */
217
mTextParamGetInt(mTextParam * p,const char * key,int * dst)218 mBool mTextParamGetInt(mTextParam *p,const char *key,int *dst)
219 {
220 char *pc = _find(p, key);
221
222 if(pc)
223 {
224 *dst = strtol(pc, NULL, 0);
225 return TRUE;
226 }
227 else
228 return FALSE;
229 }
230
231 /** int 値を取得 (範囲指定) */
232
mTextParamGetInt_range(mTextParam * p,const char * key,int * dst,int min,int max)233 mBool mTextParamGetInt_range(mTextParam *p,const char *key,int *dst,int min,int max)
234 {
235 int n;
236
237 if(!mTextParamGetInt(p, key, &n))
238 return FALSE;
239 else
240 {
241 if(n < min) n = min;
242 else if(n > max) n = max;
243
244 *dst = n;
245
246 return TRUE;
247 }
248 }
249
250 /** double 値を取得 */
251
mTextParamGetDouble(mTextParam * p,const char * key,double * dst)252 mBool mTextParamGetDouble(mTextParam *p,const char *key,double *dst)
253 {
254 char *pc = _find(p, key);
255
256 if(pc)
257 {
258 *dst = strtod(pc, NULL);
259 return TRUE;
260 }
261 else
262 return FALSE;
263 }
264
265 /** double 値を指定桁数の int にして取得 */
266
mTextParamGetDoubleInt(mTextParam * p,const char * key,int * dst,int dig)267 mBool mTextParamGetDoubleInt(mTextParam *p,const char *key,int *dst,int dig)
268 {
269 double d;
270 int n;
271
272 if(!mTextParamGetDouble(p, key, &d))
273 return FALSE;
274 else
275 {
276 for(n = 1; dig > 0; dig--, n *= 10);
277
278 *dst = (int)round(d * n);
279
280 return TRUE;
281 }
282 }
283
284 /** double 値を指定桁数の int にして取得 (範囲指定) */
285
mTextParamGetDoubleInt_range(mTextParam * p,const char * key,int * dst,int dig,int min,int max)286 mBool mTextParamGetDoubleInt_range(mTextParam *p,const char *key,int *dst,int dig,int min,int max)
287 {
288 int n;
289
290 if(!mTextParamGetDoubleInt(p, key, &n, dig))
291 return FALSE;
292 else
293 {
294 if(n < min) n = min;
295 else if(n > max) n = max;
296
297 *dst = n;
298
299 return TRUE;
300 }
301 }
302
303 /** 文字列をポインタで直接取得
304 *
305 * ポインタは解放したりしないこと。 */
306
mTextParamGetText_raw(mTextParam * p,const char * key,char ** dst)307 mBool mTextParamGetText_raw(mTextParam *p,const char *key,char **dst)
308 {
309 char *pc = _find(p, key);
310
311 if(pc)
312 {
313 *dst = pc;
314 return TRUE;
315 }
316 else
317 return FALSE;
318 }
319
320 /** 文字列を複製して取得 */
321
mTextParamGetText_dup(mTextParam * p,const char * key,char ** buf)322 mBool mTextParamGetText_dup(mTextParam *p,const char *key,char **buf)
323 {
324 char *pc = _find(p, key);
325
326 if(pc)
327 {
328 *buf = mStrdup(pc);
329 return TRUE;
330 }
331 else
332 return FALSE;
333 }
334
335 /** mStr に文字列を取得 */
336
mTextParamGetStr(mTextParam * p,const char * key,mStr * str)337 mBool mTextParamGetStr(mTextParam *p,const char *key,mStr *str)
338 {
339 char *pc = _find(p, key);
340
341 if(pc)
342 {
343 mStrSetText(str, pc);
344 return TRUE;
345 }
346 else
347 return FALSE;
348 }
349
350 /** key の値の文字列を単語リストから探し、そのインデックス番号を取得
351 *
352 * @param words '\0' で区切った単語リスト。最後は \0\0 で終わること。
353 * @return 見つからなかった場合、-1 */
354
mTextParamFindText(mTextParam * p,const char * key,const char * words,mBool bNoCase)355 int mTextParamFindText(mTextParam *p,const char *key,const char *words,mBool bNoCase)
356 {
357 char *param = _find(p, key);
358 const char *pc;
359 int ret,no;
360
361 if(param)
362 {
363 for(pc = words, no = 0; *pc; pc += strlen(pc) + 1, no++)
364 {
365 ret = (bNoCase)? strcasecmp(pc, param): strcmp(pc, param);
366
367 if(ret == 0) return no;
368 }
369 }
370
371 return -1;
372 }
373
374 /** @} */
375