1N/A/*
1N/A parted - a frontend to libparted
1N/A Copyright (C) 1999-2001, 2007, 2009-2010 Free Software Foundation,
1N/A Inc.
1N/A
1N/A This program is free software; you can redistribute it and/or modify
1N/A it under the terms of the GNU General Public License as published by
1N/A the Free Software Foundation; either version 3 of the License, or
1N/A (at your option) any later version.
1N/A
1N/A This program is distributed in the hope that it will be useful,
1N/A but WITHOUT ANY WARRANTY; without even the implied warranty of
1N/A MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1N/A GNU General Public License for more details.
1N/A
1N/A You should have received a copy of the GNU General Public License
1N/A along with this program. If not, see <http://www.gnu.org/licenses/>.
1N/A*/
1N/A
1N/A#include <config.h>
1N/A
1N/A#include <parted/debug.h>
1N/A
1N/A#include <ctype.h>
1N/A#include <errno.h>
1N/A#include <stdarg.h>
1N/A#include <stdio.h>
1N/A#include <stdlib.h>
1N/A#include <string.h>
1N/A#include <limits.h>
1N/A#include "xalloc.h"
1N/A
1N/A#ifdef ENABLE_NLS
1N/A
1N/A#undef __USE_GNU
1N/A#define __USE_GNU
1N/A
1N/A#include <wchar.h>
1N/A#include <wctype.h>
1N/A
1N/A#endif /* !ENABLE_NLS */
1N/A
1N/A#include "strlist.h"
1N/A
1N/A#define MIN(a,b) ( (a<b)? a : b )
1N/A
1N/Aint
1N/Awchar_strlen (const wchar_t* str)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return wcslen (str);
1N/A#else
1N/A return strlen (str);
1N/A#endif
1N/A}
1N/A
1N/Awchar_t*
1N/Awchar_strchr (const wchar_t* str, char ch)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return wcschr (str, ch);
1N/A#else
1N/A return strchr (str, ch);
1N/A#endif
1N/A}
1N/A
1N/Aint
1N/Awchar_strcasecmp (const wchar_t* a, const wchar_t* b)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return wcscasecmp (a, b);
1N/A#else
1N/A return strcasecmp (a, b);
1N/A#endif
1N/A}
1N/A
1N/Aint
1N/Awchar_strncasecmp (const wchar_t* a, const wchar_t* b, size_t n)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return wcsncasecmp (a, b, n);
1N/A#else
1N/A return strncasecmp (a, b, n);
1N/A#endif
1N/A}
1N/A
1N/Awchar_t*
1N/Awchar_strdup (const wchar_t* str)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return wcsdup (str);
1N/A#else
1N/A return xstrdup (str);
1N/A#endif
1N/A}
1N/A
1N/A/* converts a string from the encoding in the gettext catalogues to wide
1N/A * character strings (of type wchar_t*).
1N/A */
1N/A#ifdef ENABLE_NLS
1N/Astatic wchar_t*
1N/Agettext_to_wchar (const char* str)
1N/A{
1N/A int count;
1N/A wchar_t* result;
1N/A size_t status;
1N/A mbstate_t ps;
1N/A
1N/A count = strlen (str) + 1;
1N/A result = malloc (count * sizeof (wchar_t));
1N/A if (!result)
1N/A goto error;
1N/A
1N/A memset(&ps, 0, sizeof (ps));
1N/A status = mbsrtowcs(result, &str, count, &ps);
1N/A if (status == (size_t) -1)
1N/A goto error;
1N/A
1N/A result = xrealloc (result, (wcslen (result) + 1) * sizeof (wchar_t));
1N/A return result;
1N/A
1N/Aerror:
1N/A printf ("Error during translation: %s\n", strerror (errno));
1N/A exit (EXIT_FAILURE);
1N/A}
1N/A
1N/A#else /* ENABLE_NLS */
1N/A
1N/Astatic wchar_t*
1N/Agettext_to_wchar (const char* str)
1N/A{
1N/A return xstrdup (str);
1N/A}
1N/A
1N/A#endif /* !ENABLE_NLS */
1N/A
1N/A
1N/A#ifdef ENABLE_NLS
1N/Astatic char*
1N/Awchar_to_str (const wchar_t* str, size_t count)
1N/A{
1N/A char* result;
1N/A char* out_buf;
1N/A size_t status;
1N/A mbstate_t ps;
1N/A size_t i;
1N/A
1N/A if (count == 0 || wcslen(str) < count)
1N/A count = wcslen (str);
1N/A
1N/A out_buf = result = malloc ((count + 1) * MB_LEN_MAX);
1N/A if (!result)
1N/A goto error;
1N/A
1N/A memset(&ps, 0, sizeof(ps));
1N/A
1N/A for (i = 0; i < count; i++) {
1N/A status = wcrtomb (out_buf, str[i], &ps);
1N/A if (status == (size_t) -1)
1N/A goto error;
1N/A out_buf += status;
1N/A }
1N/A
1N/A status = wcrtomb (out_buf, 0, &ps);
1N/A if (status == (size_t) -1)
1N/A goto error;
1N/A
1N/A result = realloc (result, strlen (result) + 1);
1N/A return result;
1N/A
1N/Aerror:
1N/A printf ("Error during translation: %s\n", strerror (errno));
1N/A exit (EXIT_FAILURE);
1N/A}
1N/A
1N/A#else /* ENABLE_NLS */
1N/A
1N/Astatic char*
1N/Awchar_to_str (const wchar_t* str, size_t count)
1N/A{
1N/A char* result;
1N/A
1N/A result = xstrdup (str);
1N/A if (count && count < strlen (result))
1N/A result [count] = 0;
1N/A return result;
1N/A}
1N/A
1N/A#endif /* !ENABLE_NLS */
1N/A
1N/Astatic void
1N/Aprint_wchar (const wchar_t* str, size_t count)
1N/A{
1N/A char* tmp = wchar_to_str (str, count);
1N/A printf ("%s", tmp);
1N/A free (tmp);
1N/A}
1N/A
1N/Astatic StrList*
1N/Astr_list_alloc ()
1N/A{
1N/A StrList* list;
1N/A
1N/A list = xmalloc (sizeof (StrList));
1N/A list->next = NULL;
1N/A
1N/A return list;
1N/A}
1N/A
1N/Avoid
1N/Astr_list_destroy (StrList* list)
1N/A{
1N/A if (list) {
1N/A str_list_destroy (list->next);
1N/A str_list_destroy_node (list);
1N/A }
1N/A}
1N/A
1N/Avoid
1N/Astr_list_destroy_node (StrList* list)
1N/A{
1N/A void *p = (char *) (list->str); /* discard const */
1N/A free (p);
1N/A free (list);
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_duplicate_node (const StrList* node)
1N/A{
1N/A StrList* result = str_list_alloc ();
1N/A result->str = wchar_strdup (node->str);
1N/A return result;
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_duplicate (const StrList* list)
1N/A{
1N/A if (list)
1N/A return str_list_join (str_list_duplicate_node (list),
1N/A str_list_duplicate (list->next));
1N/A else
1N/A return NULL;
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_join (StrList* a, StrList* b)
1N/A{
1N/A StrList* walk;
1N/A
1N/A for (walk = a; walk && walk->next; walk = walk->next);
1N/A
1N/A if (walk) {
1N/A walk->next = b;
1N/A return a;
1N/A } else {
1N/A return b;
1N/A }
1N/A}
1N/A
1N/Astatic StrList*
1N/A_str_list_append (StrList* list, const wchar_t* str)
1N/A{
1N/A StrList* walk;
1N/A
1N/A if (list) {
1N/A for (walk = list; walk->next; walk = walk->next);
1N/A walk->next = str_list_alloc ();
1N/A walk = walk->next;
1N/A } else {
1N/A walk = list = str_list_alloc ();
1N/A }
1N/A walk->str = str;
1N/A
1N/A return list;
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_append (StrList* list, const char* str)
1N/A{
1N/A return _str_list_append (list, gettext_to_wchar (str));
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_append_unique (StrList* list, const char* str)
1N/A{
1N/A StrList* walk;
1N/A wchar_t* new_str = gettext_to_wchar (str);
1N/A
1N/A for (walk=list; walk; walk=walk->next) {
1N/A if (walk->str) {
1N/A if (wchar_strcasecmp (new_str, walk->str) == 0) {
1N/A free (new_str);
1N/A return list;
1N/A }
1N/A }
1N/A }
1N/A
1N/A return _str_list_append (list, new_str);
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_insert (StrList* list, const char* str)
1N/A{
1N/A return str_list_join (str_list_create (str, NULL), list);
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_create (const char* first, ...)
1N/A{
1N/A va_list args;
1N/A char* str;
1N/A StrList* list;
1N/A
1N/A list = str_list_append (NULL, first);
1N/A
1N/A if (first) {
1N/A va_start (args, first);
1N/A while ( (str = va_arg (args, char*)) )
1N/A str_list_append (list, str);
1N/A va_end (args);
1N/A }
1N/A
1N/A return list;
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_create_unique (const char* first, ...)
1N/A{
1N/A va_list args;
1N/A char* str;
1N/A StrList* list;
1N/A
1N/A list = str_list_append (NULL, first);
1N/A
1N/A if (first) {
1N/A va_start (args, first);
1N/A while ( (str = va_arg (args, char*)) )
1N/A str_list_append_unique (list, str);
1N/A va_end (args);
1N/A }
1N/A
1N/A return list;
1N/A}
1N/A
1N/Achar*
1N/Astr_list_convert_node (const StrList* list)
1N/A{
1N/A return wchar_to_str (list->str, 0);
1N/A}
1N/A
1N/Achar*
1N/Astr_list_convert (const StrList* list)
1N/A{
1N/A const StrList* walk;
1N/A int pos = 0;
1N/A int length = 1;
1N/A char* str = xstrdup ("");
1N/A
1N/A for (walk = list; walk; walk = walk->next) {
1N/A if (walk->str) {
1N/A char* tmp = wchar_to_str (walk->str, 0);
1N/A
1N/A length += strlen (tmp);
1N/A
1N/A str = realloc (str, length);
1N/A strcpy (str + pos, tmp);
1N/A
1N/A pos = length - 1;
1N/A free (tmp);
1N/A }
1N/A }
1N/A
1N/A return str;
1N/A}
1N/A
1N/Avoid
1N/Astr_list_print (const StrList* list)
1N/A{
1N/A const StrList* walk;
1N/A
1N/A for (walk=list; walk; walk=walk->next) {
1N/A if (walk->str)
1N/A print_wchar (walk->str, 0);
1N/A }
1N/A}
1N/A
1N/Astatic int
1N/Astr_search (const wchar_t* str, int n, wchar_t c)
1N/A{
1N/A int i;
1N/A
1N/A for (i=0; i<n; i++)
1N/A if (str [i] == c)
1N/A return i;
1N/A return -1;
1N/A}
1N/A
1N/A
1N/A/* Japanese don't leave spaces between words, so ALL Japanese characters
1N/A * are treated as delimiters. Note: since the translations should already
1N/A * be properly formatted (eg: spaces after commas), there should be no
1N/A * need to include them. Best not to avoid side effects, like 3.
1N/A14159 :-)
1N/A * FIXME: how do we exclude "." and "(" ?
1N/A * FIXME: glibc doesn't like umlaute. i.e. \"o (TeX notation), which should
1N/A * look like: �
1N/A */
1N/A
1N/Astatic int
1N/Ais_break_point (wchar_t c)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return !iswalnum (c) && !iswpunct (c);
1N/A#else
1N/A return !isalnum (c) && !ispunct (c);
1N/A#endif
1N/A}
1N/A
1N/A/* NOTE: this should not return '\n' as a space, because explicit '\n' may
1N/A * be placed inside strings.
1N/A */
1N/Astatic int
1N/Ais_space (wchar_t c)
1N/A{
1N/A#ifdef ENABLE_NLS
1N/A return c == (wchar_t) btowc(' ');
1N/A#else
1N/A return c == ' ';
1N/A#endif
1N/A}
1N/A
1N/Avoid
1N/Astr_list_print_wrap (const StrList* list, int line_length, int offset,
1N/A int indent)
1N/A{
1N/A const StrList* walk;
1N/A const wchar_t* str;
1N/A int str_len;
1N/A int cut_right;
1N/A int cut_left;
1N/A int line_left;
1N/A int search_result;
1N/A int line_break;
1N/A
1N/A PED_ASSERT (line_length - indent > 10, return);
1N/A
1N/A line_left = line_length - offset;
1N/A
1N/A for (walk=list; walk; walk=walk->next) {
1N/A if (!walk->str)
1N/A continue;
1N/A str = walk->str;
1N/A str_len = wchar_strlen (str);
1N/A
1N/A while (line_left < str_len || wchar_strchr (str, '\n')) {
1N/A line_break = 0;
1N/A
1N/A cut_left = MIN (line_left - 1, str_len - 1);
1N/A
1N/A /* we can have a space "over", but not a comma */
1N/A if (cut_left < str_len
1N/A && is_space (str [cut_left + 1]))
1N/A cut_left++;
1N/A
1N/A while (cut_left && !is_break_point (str [cut_left]))
1N/A cut_left--;
1N/A while (cut_left && is_space (str [cut_left]))
1N/A cut_left--;
1N/A
1N/A /* str [cut_left] is either the end of a word, or a
1N/A * Japanese character, or the start of a blank line.
1N/A */
1N/A
1N/A search_result = str_search (str, cut_left + 1, '\n');
1N/A if (search_result != -1) {
1N/A cut_left = search_result - 1;
1N/A line_break = 1;
1N/A }
1N/A
1N/A for (cut_right = cut_left + (line_break ? 2 : 1);
1N/A cut_right < str_len && is_space (str [cut_right]);
1N/A cut_right++);
1N/A
1N/A if (cut_left > 0)
1N/A print_wchar (str, cut_left + 1);
1N/A
1N/A str += cut_right;
1N/A str_len -= cut_right;
1N/A line_left = line_length - indent;
1N/A
1N/A if (walk->next || *str)
1N/A printf ("\n%*s", indent, "");
1N/A else if (line_break)
1N/A putchar ('\n');
1N/A }
1N/A
1N/A print_wchar (str, 0);
1N/A line_left -= wchar_strlen (str);
1N/A }
1N/A}
1N/A
1N/Astatic int
1N/A_str_list_match_node (const StrList* list, const wchar_t* str)
1N/A{
1N/A if (wchar_strcasecmp (list->str, str) == 0)
1N/A return 2;
1N/A if (wchar_strncasecmp (list->str, str, wchar_strlen (str)) == 0)
1N/A return 1;
1N/A return 0;
1N/A}
1N/A
1N/Aint
1N/Astr_list_match_node (const StrList* list, const char* str)
1N/A{
1N/A wchar_t* wc_str = gettext_to_wchar (str); /* FIXME */
1N/A int status;
1N/A
1N/A status = _str_list_match_node (list, wc_str);
1N/A free (wc_str);
1N/A
1N/A return status;
1N/A}
1N/A
1N/A/* returns: 2 for full match
1N/A 1 for partial match
1N/A 0 for no match
1N/A */
1N/Aint
1N/Astr_list_match_any (const StrList* list, const char* str)
1N/A{
1N/A const StrList* walk;
1N/A int best_status = 0;
1N/A wchar_t* wc_str = gettext_to_wchar (str);
1N/A
1N/A for (walk = list; walk; walk = walk->next) {
1N/A int this_status = _str_list_match_node (walk, wc_str);
1N/A if (this_status > best_status)
1N/A best_status = this_status;
1N/A }
1N/A
1N/A free (wc_str);
1N/A return best_status;
1N/A}
1N/A
1N/AStrList*
1N/Astr_list_match (const StrList* list, const char* str)
1N/A{
1N/A const StrList* walk;
1N/A const StrList* partial_match = NULL;
1N/A int ambiguous = 0;
1N/A wchar_t* wc_str = gettext_to_wchar (str);
1N/A
1N/A for (walk = list; walk; walk = walk->next) {
1N/A switch (_str_list_match_node (walk, wc_str)) {
1N/A case 2:
1N/A free (wc_str);
1N/A return (StrList*) walk;
1N/A
1N/A case 1:
1N/A if (partial_match)
1N/A ambiguous = 1;
1N/A partial_match = walk;
1N/A }
1N/A }
1N/A
1N/A free (wc_str);
1N/A return ambiguous ? NULL : (StrList*) partial_match;
1N/A}
1N/A
1N/Aint
1N/Astr_list_length (const StrList* list)
1N/A{
1N/A int length = 0;
1N/A const StrList* walk;
1N/A
1N/A for (walk = list; walk; walk = walk->next)
1N/A length++;
1N/A
1N/A return length;
1N/A}