OSDN Git Service

parted: honor --align option also in mkpartfs, resize and print cmds
[android-x86/external-parted.git] / parted / strlist.c
1 /*
2     parted - a frontend to libparted
3     Copyright (C) 1999-2001, 2007, 2009-2010 Free Software Foundation,
4     Inc.
5
6     This program 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     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, see <http://www.gnu.org/licenses/>.
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 = xrealloc (result, (wcslen (result) + 1) * sizeof (wchar_t));
128         return result;
129
130 error:
131         printf ("Error during translation: %s\n", strerror (errno));
132         exit (EXIT_FAILURE);
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 (EXIT_FAILURE);
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 = 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         void *p = (char *) (list->str); /* discard const */
231         free (p);
232         free (list);
233 }
234
235 StrList*
236 str_list_duplicate_node (const StrList* node)
237 {
238         StrList*        result = str_list_alloc ();
239         result->str = wchar_strdup (node->str);
240         return result;
241 }
242
243 StrList*
244 str_list_duplicate (const StrList* list)
245 {
246         if (list)
247                 return str_list_join (str_list_duplicate_node (list),
248                                       str_list_duplicate (list->next));
249         else
250                 return NULL;
251 }
252
253 StrList*
254 str_list_join (StrList* a, StrList* b)
255 {
256         StrList*        walk;
257
258         for (walk = a; walk && walk->next; walk = walk->next);
259
260         if (walk) {
261                 walk->next = b;
262                 return a;
263         } else {
264                 return b;
265         }
266 }
267
268 static StrList*
269 _str_list_append (StrList* list, const wchar_t* str)
270 {
271         StrList*        walk;
272
273         if (list) {
274                 for (walk = list; walk->next; walk = walk->next);
275                 walk->next = str_list_alloc ();
276                 walk = walk->next;
277         } else {
278                 walk = list = str_list_alloc ();
279         }
280         walk->str = str;
281
282         return list;
283 }
284
285 StrList*
286 str_list_append (StrList* list, const char* str)
287 {
288         return _str_list_append (list, gettext_to_wchar (str));
289 }
290
291 StrList*
292 str_list_append_unique (StrList* list, const char* str)
293 {
294         StrList*        walk;
295         wchar_t*        new_str = gettext_to_wchar (str);
296
297         for (walk=list; walk; walk=walk->next) {
298                 if (walk->str) {
299                         if (wchar_strcasecmp (new_str, walk->str) == 0) {
300                                 free (new_str);
301                                 return list;
302                         }
303                 }
304         }
305
306         return _str_list_append (list, new_str);
307 }
308
309 StrList*
310 str_list_insert (StrList* list, const char* str)
311 {
312         return str_list_join (str_list_create (str, NULL), list);
313 }
314
315 StrList*
316 str_list_create (const char* first, ...)
317 {
318         va_list         args;
319         char*           str;
320         StrList*        list;
321
322         list = str_list_append (NULL, first);
323
324         if (first) {
325                 va_start (args, first);
326                 while ( (str = va_arg (args, char*)) )
327                         str_list_append (list, str);
328                 va_end (args);
329         }
330
331         return list;
332 }
333
334 StrList*
335 str_list_create_unique (const char* first, ...)
336 {
337         va_list         args;
338         char*           str;
339         StrList*        list;
340
341         list = str_list_append (NULL, first);
342
343         if (first) {
344                 va_start (args, first);
345                 while ( (str = va_arg (args, char*)) )
346                         str_list_append_unique (list, str);
347                 va_end (args);
348         }
349
350         return list;
351 }
352
353 char*
354 str_list_convert_node (const StrList* list)
355 {
356         return wchar_to_str (list->str, 0);
357 }
358
359 char*
360 str_list_convert (const StrList* list)
361 {
362         const StrList*  walk;
363         int             pos = 0;
364         int             length = 1;
365         char*           str = xstrdup ("");
366
367         for (walk = list; walk; walk = walk->next) {
368                 if (walk->str) {
369                         char*   tmp = wchar_to_str (walk->str, 0);
370
371                         length += strlen (tmp);
372
373                         str = realloc (str, length);
374                         strcpy (str + pos, tmp);
375
376                         pos = length - 1;
377                         free (tmp);
378                 }
379         }
380
381         return str;
382 }
383
384 void
385 str_list_print (const StrList* list)
386 {
387         const StrList*  walk;
388
389         for (walk=list; walk; walk=walk->next) {
390                 if (walk->str)
391                         print_wchar (walk->str, 0);
392         }
393 }
394
395 static int
396 str_search (const wchar_t* str, int n, wchar_t c)
397 {
398         int     i;
399
400         for (i=0; i<n; i++)
401                 if (str [i] == c)
402                         return i;
403         return -1;
404 }
405
406
407 /* Japanese don't leave spaces between words, so ALL Japanese characters
408  * are treated as delimiters.  Note: since the translations should already
409  * be properly formatted (eg: spaces after commas), there should be no
410  * need to include them.  Best not to avoid side effects, like 3.
411 14159 :-)
412  * FIXME: how do we exclude "." and "(" ?
413  * FIXME: glibc doesn't like umlaute.  i.e. \"o (TeX notation), which should
414  * look like: รถ
415  */
416
417 static int
418 is_break_point (wchar_t c)
419 {
420 #ifdef ENABLE_NLS
421         return !iswalnum (c) && !iswpunct (c);
422 #else
423         return !isalnum (c) && !ispunct (c);
424 #endif
425 }
426
427 /* NOTE: this should not return '\n' as a space, because explicit '\n' may
428  * be placed inside strings.
429  */
430 static int
431 is_space (wchar_t c)
432 {
433 #ifdef ENABLE_NLS
434         return c == (wchar_t) btowc(' ');
435 #else
436         return c == ' ';
437 #endif
438 }
439
440 void
441 str_list_print_wrap (const StrList* list, int line_length, int offset,
442                      int indent)
443 {
444         const StrList*  walk;
445         const wchar_t*  str;
446         int             str_len;
447         int             cut_right;
448         int             cut_left;
449         int             line_left;
450         int             search_result;
451         int             line_break;
452
453         PED_ASSERT (line_length - indent > 10, return);
454
455         line_left = line_length - offset;
456
457         for (walk=list; walk; walk=walk->next) {
458                 if (!walk->str)
459                         continue;
460                 str = walk->str;
461                 str_len = wchar_strlen (str);
462
463                 while (line_left < str_len || wchar_strchr (str, '\n')) {
464                         line_break = 0;
465
466                         cut_left = MIN (line_left - 1, str_len - 1);
467
468                         /* we can have a space "over", but not a comma */
469                         if (cut_left < str_len
470                                         && is_space (str [cut_left + 1]))
471                                 cut_left++;
472
473                         while (cut_left && !is_break_point (str [cut_left]))
474                                 cut_left--;
475                         while (cut_left && is_space (str [cut_left]))
476                                 cut_left--;
477
478                 /* str [cut_left] is either the end of a word, or a
479                  * Japanese character, or the start of a blank line.
480                  */
481
482                         search_result = str_search (str, cut_left + 1, '\n');
483                         if (search_result != -1) {
484                                 cut_left = search_result - 1;
485                                 line_break = 1;
486                         }
487
488                         for (cut_right = cut_left + (line_break ? 2 : 1);
489                              cut_right < str_len && is_space (str [cut_right]);
490                              cut_right++);
491
492                         if (cut_left > 0)
493                                 print_wchar (str, cut_left + 1);
494
495                         str += cut_right;
496                         str_len -= cut_right;
497                         line_left = line_length - indent;
498
499                         if (walk->next || *str)
500                                 printf ("\n%*s", indent, "");
501                         else if (line_break)
502                                 putchar ('\n');
503                 }
504
505                 print_wchar (str, 0);
506                 line_left -= wchar_strlen (str);
507         }
508 }
509
510 static int
511 _str_list_match_node (const StrList* list, const wchar_t* str)
512 {
513         if (wchar_strcasecmp (list->str, str) == 0)
514                 return 2;
515         if (wchar_strncasecmp (list->str, str, wchar_strlen (str)) == 0)
516                 return 1;
517         return 0;
518 }
519
520 int
521 str_list_match_node (const StrList* list, const char* str)
522 {
523         wchar_t*        wc_str = gettext_to_wchar (str);        /* FIXME */
524         int             status;
525
526         status = _str_list_match_node (list, wc_str);
527         free (wc_str);
528
529         return status;
530 }
531
532 /* returns:  2 for full match
533              1 for partial match
534              0 for no match
535  */
536 int
537 str_list_match_any (const StrList* list, const char* str)
538 {
539         const StrList*  walk;
540         int             best_status = 0;
541         wchar_t*        wc_str = gettext_to_wchar (str);
542
543         for (walk = list; walk; walk = walk->next) {
544                 int     this_status = _str_list_match_node (walk, wc_str);
545                 if (this_status > best_status)
546                         best_status = this_status;
547         }
548
549         free (wc_str);
550         return best_status;
551 }
552
553 StrList*
554 str_list_match (const StrList* list, const char* str)
555 {
556         const StrList*  walk;
557         const StrList*  partial_match = NULL;
558         int             ambiguous = 0;
559         wchar_t*        wc_str = gettext_to_wchar (str);
560
561         for (walk = list; walk; walk = walk->next) {
562                 switch (_str_list_match_node (walk, wc_str)) {
563                         case 2:
564                                 free (wc_str);
565                                 return (StrList*) walk;
566
567                         case 1:
568                                 if (partial_match)
569                                         ambiguous = 1;
570                                 partial_match = walk;
571                 }
572         }
573
574         free (wc_str);
575         return ambiguous ? NULL : (StrList*) partial_match;
576 }
577
578 int
579 str_list_length (const StrList* list)
580 {
581         int             length = 0;
582         const StrList*  walk;
583
584         for (walk = list; walk; walk = walk->next)
585                 length++;
586
587         return length;
588 }