OSDN Git Service

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