OSDN Git Service

remove more useless "if" tests before free
[android-x86/external-parted.git] / parted / strlist.c
1 /*
2     parted - a frontend to libparted
3     Copyright (C) 1999, 2000, 2001, 2007 Free Software Foundation, Inc.
4
5     This program is free software; you can redistribute it and/or modify
6     it under the terms of the GNU General Public License as published by
7     the Free Software Foundation; either version 3 of the License, or
8     (at your option) any later version.
9
10     This program is distributed in the hope that it will be useful,
11     but WITHOUT ANY WARRANTY; without even the implied warranty of
12     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13     GNU General Public License for more details.
14
15     You should have received a copy of the GNU General Public License
16     along with this program.  If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include <config.h>
20
21 #include <parted/debug.h>
22
23 #include <ctype.h>
24 #include <errno.h>
25 #include <stdarg.h>
26 #include <stdio.h>
27 #include <stdlib.h>
28 #include <string.h>
29 #include <limits.h>
30 #include "xalloc.h"
31
32 #ifdef ENABLE_NLS
33
34 #undef __USE_GNU
35 #define __USE_GNU
36
37 #include <wchar.h>
38 #include <wctype.h>
39
40 #else /* ENABLE_NLS */
41
42 #ifdef wchar_t
43 #undef wchar_t
44 #endif
45
46 #define wchar_t char
47
48 #endif /* !ENABLE_NLS */
49
50 #include "strlist.h"
51
52 #define MIN(a,b)        ( (a<b)?  a : b )
53
54 int
55 wchar_strlen (const wchar_t* str)
56 {
57 #ifdef ENABLE_NLS
58         return wcslen (str);
59 #else
60         return strlen (str);
61 #endif
62 }
63
64 wchar_t*
65 wchar_strchr (const wchar_t* str, char ch)
66 {
67 #ifdef ENABLE_NLS
68         return wcschr (str, ch);
69 #else
70         return strchr (str, ch);
71 #endif
72 }
73
74 int
75 wchar_strcasecmp (const wchar_t* a, const wchar_t* b)
76 {
77 #ifdef ENABLE_NLS
78         return wcscasecmp (a, b);
79 #else
80         return strcasecmp (a, b);
81 #endif
82 }
83
84 int
85 wchar_strncasecmp (const wchar_t* a, const wchar_t* b, size_t n)
86 {
87 #ifdef ENABLE_NLS
88         return wcsncasecmp (a, b, n);
89 #else
90         return strncasecmp (a, b, n);
91 #endif
92 }
93
94 wchar_t*
95 wchar_strdup (const wchar_t* str)
96 {
97 #ifdef ENABLE_NLS
98         return wcsdup (str);
99 #else
100         return xstrdup (str);
101 #endif
102 }
103
104 /* converts a string from the encoding in the gettext catalogues to wide
105  * character strings (of type wchar_t*).
106  */
107 #ifdef ENABLE_NLS
108 static wchar_t*
109 gettext_to_wchar (const char* str)
110 {
111         int             count;
112         wchar_t*        result;
113         size_t          status;
114         mbstate_t       ps;
115
116         count = strlen (str) + 1;
117         result = malloc (count * sizeof (wchar_t));
118         if (!result)
119                 goto error;
120
121         memset(&ps, 0, sizeof (ps));
122         status = mbsrtowcs(result, &str, count, &ps);
123         if (status == (size_t) -1)
124                 goto error;
125
126         result = realloc (result, (wcslen (result) + 1) * sizeof (wchar_t));
127         return result;
128
129 error:
130         printf ("Error during translation: %s\n", strerror (errno));
131         exit (1);
132 }
133
134 #else /* ENABLE_NLS */
135
136 static wchar_t*
137 gettext_to_wchar (const char* str)
138 {
139         return xstrdup (str);
140 }
141
142 #endif /* !ENABLE_NLS */
143
144
145 #ifdef ENABLE_NLS
146 static char*
147 wchar_to_str (const wchar_t* str, size_t count)
148 {
149         char*           result;
150         char*           out_buf;
151         size_t          status;
152         mbstate_t       ps;
153         size_t          i;
154
155         if (count == 0 || wcslen(str) < count)
156                 count = wcslen (str);
157
158         out_buf = result = malloc ((count + 1) *  MB_LEN_MAX);
159         if (!result)
160                 goto error;
161
162         memset(&ps, 0, sizeof(ps));
163
164         for (i = 0; i < count; i++) {
165                 status = wcrtomb (out_buf, str[i], &ps);
166                 if (status == (size_t) -1)
167                         goto error;
168                 out_buf += status;
169         }
170
171         status = wcrtomb (out_buf, 0, &ps);
172         if (status == (size_t) -1)
173                 goto error;
174
175         result = realloc (result, strlen (result) + 1);
176         return result;
177
178 error:
179         printf ("Error during translation: %s\n", strerror (errno));
180         exit (1);
181 }
182
183 #else /* ENABLE_NLS */
184
185 static char*
186 wchar_to_str (const wchar_t* str, size_t count)
187 {
188         char*           result;
189
190         result = xstrdup (str);
191         if (count && count < strlen (result))
192                 result [count] = 0;
193         return result;
194 }
195
196 #endif /* !ENABLE_NLS */
197
198 static void
199 print_wchar (const wchar_t* str, size_t count)
200 {
201         char*   tmp = wchar_to_str (str, count);
202         printf ("%s", tmp);
203         free (tmp);
204 }
205
206 static StrList* 
207 str_list_alloc ()
208 {
209         StrList*        list;
210
211         list = xmalloc (sizeof (StrList));
212         list->next = NULL;
213
214         return list;
215 }
216
217 void
218 str_list_destroy (StrList* list)
219 {
220         if (list) {
221                 str_list_destroy (list->next);
222                 str_list_destroy_node (list);
223         }
224 }
225
226 void
227 str_list_destroy_node (StrList* list)
228 {
229         free ((wchar_t*) list->str);
230         free (list);
231 }
232
233 StrList*
234 str_list_duplicate_node (const StrList* node)
235 {
236         StrList*        result = str_list_alloc ();
237         result->str = wchar_strdup (node->str);
238         return result;
239 }
240
241 StrList*
242 str_list_duplicate (const StrList* list)
243 {
244         if (list)
245                 return str_list_join (str_list_duplicate_node (list),
246                                       str_list_duplicate (list->next));
247         else
248                 return NULL;
249 }
250
251 StrList*
252 str_list_join (StrList* a, StrList* b)
253 {
254         StrList*        walk;
255
256         for (walk = a; walk && walk->next; walk = walk->next);
257
258         if (walk) {
259                 walk->next = b;
260                 return a;
261         } else {
262                 return b;
263         }
264 }
265
266 static StrList*
267 _str_list_append (StrList* list, const wchar_t* str)
268 {
269         StrList*        walk;
270
271         if (list) {
272                 for (walk = list; walk->next; walk = walk->next);
273                 walk->next = str_list_alloc ();
274                 walk = walk->next;
275         } else {
276                 walk = list = str_list_alloc ();
277         }
278         walk->str = str;
279
280         return list;
281 }
282
283 StrList*
284 str_list_append (StrList* list, const char* str)
285 {
286         return _str_list_append (list, gettext_to_wchar (str));
287 }
288
289 StrList*
290 str_list_append_unique (StrList* list, const char* str)
291 {
292         StrList*        walk;
293         wchar_t*        new_str = gettext_to_wchar (str);
294
295         for (walk=list; walk; walk=walk->next) {
296                 if (walk->str) {
297                         if (wchar_strcasecmp (new_str, walk->str) == 0) {
298                                 free (new_str);
299                                 return list;
300                         }
301                 }
302         }
303
304         return _str_list_append (list, new_str);
305 }
306
307 StrList*
308 str_list_insert (StrList* list, const char* str)
309 {
310         return str_list_join (str_list_create (str, NULL), list);
311 }
312
313 StrList*
314 str_list_create (const char* first, ...)
315 {
316         va_list         args;
317         char*           str;
318         StrList*        list;
319
320         list = str_list_append (NULL, first);
321
322         if (first) {
323                 va_start (args, first);
324                 while ( (str = va_arg (args, char*)) )
325                         str_list_append (list, str);
326                 va_end (args);
327         }
328
329         return list;
330 }
331
332 StrList*
333 str_list_create_unique (const char* first, ...)
334 {
335         va_list         args;
336         char*           str;
337         StrList*        list;
338
339         list = str_list_append (NULL, first);
340
341         if (first) {
342                 va_start (args, first);
343                 while ( (str = va_arg (args, char*)) )
344                         str_list_append_unique (list, str);
345                 va_end (args);
346         }
347
348         return list;
349 }
350
351 char*
352 str_list_convert_node (const StrList* list)
353 {
354         return wchar_to_str (list->str, 0);
355 }
356
357 char*
358 str_list_convert (const StrList* list)
359 {
360         const StrList*  walk;
361         int             pos = 0;
362         int             length = 1;
363         char*           str = xstrdup ("");
364
365         for (walk = list; walk; walk = walk->next) {
366                 if (walk->str) {
367                         char*   tmp = wchar_to_str (walk->str, 0);
368
369                         length += strlen (tmp);
370
371                         str = realloc (str, length);
372                         strcpy (str + pos, tmp);
373
374                         pos = length - 1;
375                         free (tmp);
376                 }
377         }
378
379         return str;
380 }
381
382 void
383 str_list_print (const StrList* list)
384 {
385         const StrList*  walk;
386
387         for (walk=list; walk; walk=walk->next) {
388                 if (walk->str)
389                         print_wchar (walk->str, 0);
390         }
391 }
392
393 static int
394 str_search (const wchar_t* str, int n, wchar_t c)
395 {
396         int     i;
397
398         for (i=0; i<n; i++)
399                 if (str [i] == c)
400                         return i;
401         return -1;
402 }
403
404
405 /* Japanese don't leave spaces between words, so ALL Japanese characters
406  * are treated as delimiters.  Note: since the translations should already
407  * be properly formatted (eg: spaces after commas), there should be no
408  * need to include them.  Best not to avoid side effects, like 3.
409 14159 :-)
410  * FIXME: how do we exclude "." and "(" ?
411  * FIXME: glibc doesn't like umlaute.  i.e. \"o (TeX notation), which should
412  * look like: รถ
413  */
414
415 static int
416 is_break_point (wchar_t c)
417 {
418 #ifdef ENABLE_NLS
419         return !iswalnum (c) && !iswpunct (c);
420 #else
421         return !isalnum (c) && !ispunct (c);
422 #endif
423 }
424
425 /* NOTE: this should not return '\n' as a space, because explicit '\n' may
426  * be placed inside strings.
427  */
428 static int
429 is_space (wchar_t c)
430 {
431 #ifdef ENABLE_NLS
432         return c == (wchar_t) btowc(' ');
433 #else
434         return c == ' ';
435 #endif
436 }
437
438 void
439 str_list_print_wrap (const StrList* list, int line_length, int offset,
440                      int indent)
441 {
442         const StrList*  walk;
443         const wchar_t*  str;
444         int             str_len;
445         int             cut_right;
446         int             cut_left;
447         int             line_left;
448         int             search_result;
449         int             line_break;
450
451         PED_ASSERT (line_length - indent > 10, return);
452
453         line_left = line_length - offset;
454
455         for (walk=list; walk; walk=walk->next) {
456                 if (!walk->str)
457                         continue;
458                 str = walk->str;
459                 str_len = wchar_strlen (str);
460
461                 while (line_left < str_len || wchar_strchr (str, '\n')) {
462                         line_break = 0;
463
464                         cut_left = MIN (line_left - 1, str_len - 1);
465
466                         /* we can have a space "over", but not a comma */
467                         if (cut_left < str_len
468                                         && is_space (str [cut_left + 1]))
469                                 cut_left++;
470
471                         while (cut_left && !is_break_point (str [cut_left]))
472                                 cut_left--;
473                         while (cut_left && is_space (str [cut_left]))
474                                 cut_left--;
475
476                 /* str [cut_left] is either the end of a word, or a
477                  * Japanese character, or the start of a blank line.
478                  */
479
480                         search_result = str_search (str, cut_left + 1, '\n');
481                         if (search_result != -1) {
482                                 cut_left = search_result - 1;
483                                 line_break = 1;
484                         }
485
486                         for (cut_right = cut_left + (line_break ? 2 : 1);
487                              cut_right < str_len && is_space (str [cut_right]);
488                              cut_right++);
489
490                         if (cut_left > 0)
491                                 print_wchar (str, cut_left + 1);
492
493                         str += cut_right;
494                         str_len -= cut_right;
495                         line_left = line_length - indent;
496
497                         if (walk->next || *str)
498                                 printf ("\n%*s", indent, "");
499                         else if (line_break)
500                                 putchar ('\n');
501                 }
502
503                 print_wchar (str, 0);
504                 line_left -= wchar_strlen (str);
505         }
506 }
507
508 static int
509 _str_list_match_node (const StrList* list, const wchar_t* str)
510 {
511         if (wchar_strcasecmp (list->str, str) == 0)
512                 return 2;
513         if (wchar_strncasecmp (list->str, str, wchar_strlen (str)) == 0)
514                 return 1;
515         return 0;
516 }
517
518 int
519 str_list_match_node (const StrList* list, const char* str)
520 {
521         wchar_t*        wc_str = gettext_to_wchar (str);        /* FIXME */
522         int             status;
523
524         status = _str_list_match_node (list, wc_str);
525         free (wc_str);
526
527         return status;
528 }
529
530 /* returns:  2 for full match
531              1 for partial match
532              0 for no match
533  */
534 int
535 str_list_match_any (const StrList* list, const char* str)
536 {
537         const StrList*  walk;
538         int             best_status = 0;
539         wchar_t*        wc_str = gettext_to_wchar (str);
540
541         for (walk = list; walk; walk = walk->next) {
542                 int     this_status = _str_list_match_node (walk, wc_str);
543                 if (this_status > best_status)
544                         best_status = this_status;
545         }
546
547         free (wc_str);
548         return best_status;
549 }
550
551 StrList*
552 str_list_match (const StrList* list, const char* str)
553 {
554         const StrList*  walk;
555         const StrList*  partial_match = NULL;
556         int             ambiguous = 0;
557         wchar_t*        wc_str = gettext_to_wchar (str);
558
559         for (walk = list; walk; walk = walk->next) {
560                 switch (_str_list_match_node (walk, wc_str)) {
561                         case 2:
562                                 free (wc_str);
563                                 return (StrList*) walk;
564
565                         case 1:
566                                 if (partial_match)
567                                         ambiguous = 1;
568                                 partial_match = walk;
569                 }
570         }
571
572         free (wc_str);
573         return ambiguous ? NULL : (StrList*) partial_match;
574 }
575
576 int
577 str_list_length (const StrList* list)
578 {
579         int             length = 0;
580         const StrList*  walk;
581
582         for (walk = list; walk; walk = walk->next)
583                 length++;
584
585         return length;
586 }