OSDN Git Service

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