Logo Search packages:      
Sourcecode: parted version File versions

strlist.c

/*
    parted - a frontend to libparted
    Copyright (C) 1999, 2000, 2001 Free Software Foundation, Inc.

    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#include "config.h"

#include <parted/debug.h>

#include <ctype.h>
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>

#ifdef ENABLE_NLS

#undef __USE_GNU
#define __USE_GNU

#include <wchar.h>
#include <wctype.h>

#else /* ENABLE_NLS */

#ifdef wchar_t
#undef wchar_t
#endif

#define wchar_t char

#endif /* !ENABLE_NLS */

#include "strlist.h"

#define MIN(a,b)  ( (a<b)?  a : b )

int
wchar_strlen (const wchar_t* str)
{
#ifdef ENABLE_NLS
      return wcslen (str);
#else
      return strlen (str);
#endif
}

wchar_t*
wchar_strchr (const wchar_t* str, char ch)
{
#ifdef ENABLE_NLS
      return wcschr (str, ch);
#else
      return strchr (str, ch);
#endif
}

int
wchar_strcasecmp (const wchar_t* a, const wchar_t* b)
{
#ifdef ENABLE_NLS
      return wcscasecmp (a, b);
#else
      return strcasecmp (a, b);
#endif
}

int
wchar_strncasecmp (const wchar_t* a, const wchar_t* b, size_t n)
{
#ifdef ENABLE_NLS
      return wcsncasecmp (a, b, n);
#else
      return strncasecmp (a, b, n);
#endif
}

wchar_t*
wchar_strdup (const wchar_t* str)
{
#ifdef ENABLE_NLS
      return wcsdup (str);
#else
      return strdup (str);
#endif
}

/* converts a string from the encoding in the gettext catalogues to wide
 * character strings (of type wchar_t*).
 */
#ifdef ENABLE_NLS
static wchar_t*
gettext_to_wchar (const char* str)
{
      int         count;
      wchar_t*    result;
      size_t            status;
      mbstate_t   ps;

      count = strlen (str) + 1;
      result = malloc (count * sizeof (wchar_t));
      if (!result)
            goto error;

      memset(&ps, 0, sizeof (ps));
      status = mbsrtowcs(result, &str, count, &ps);
      if (status == (size_t) -1)
            goto error;

      result = realloc (result, (wcslen (result) + 1) * sizeof (wchar_t));
      return result;

error:
      printf ("Error during translation: %s\n", strerror (errno));
      exit (1);
}

#else /* ENABLE_NLS */

static wchar_t*
gettext_to_wchar (const char* str)
{
      return strdup (str);
}

#endif /* !ENABLE_NLS */


#ifdef ENABLE_NLS
static char*
wchar_to_str (const wchar_t* str, size_t count)
{
      char*       result;
      char*       out_buf;
      size_t            status;
      mbstate_t   ps;
      size_t            i;

      if (count == 0 || wcslen(str) < count)
            count = wcslen (str);

      out_buf = result = malloc ((count + 1) *  MB_LEN_MAX);
      if (!result)
            goto error;

      memset(&ps, 0, sizeof(ps));

      for (i = 0; i < count; i++) {
            status = wcrtomb (out_buf, str[i], &ps);
            if (status == (size_t) -1)
                  goto error;
            out_buf += status;
      }

      status = wcrtomb (out_buf, 0, &ps);
      if (status == (size_t) -1)
            goto error;

      result = realloc (result, strlen (result) + 1);
      return result;

error:
      printf ("Error during translation: %s\n", strerror (errno));
      exit (1);
}

#else /* ENABLE_NLS */

static char*
wchar_to_str (const wchar_t* str, size_t count)
{
      char*       result;

      result = strdup (str);
      if (count && count < strlen (result))
            result [count] = 0;
      return result;
}

#endif /* !ENABLE_NLS */

static void
print_wchar (const wchar_t* str, size_t count)
{
      char* tmp = wchar_to_str (str, count);
      printf ("%s", tmp);
      free (tmp);
}

static StrList* 
str_list_alloc ()
{
      StrList*    list;

      list = (StrList*) malloc (sizeof (StrList));
      list->next = NULL;

      return list;
}

void
str_list_destroy (StrList* list)
{
      if (list) {
            str_list_destroy (list->next);
            str_list_destroy_node (list);
      }
}

void
str_list_destroy_node (StrList* list)
{
      free ((wchar_t*) list->str);
      free (list);
}

StrList*
str_list_duplicate_node (const StrList* node)
{
      StrList*    result = str_list_alloc ();
      result->str = wchar_strdup (node->str);
      return result;
}

StrList*
str_list_duplicate (const StrList* list)
{
      if (list)
            return str_list_join (str_list_duplicate_node (list),
                              str_list_duplicate (list->next));
      else
            return NULL;
}

StrList*
str_list_join (StrList* a, StrList* b)
{
      StrList*    walk;

      for (walk = a; walk && walk->next; walk = walk->next);

      if (walk) {
            walk->next = b;
            return a;
      } else {
            return b;
      }
}

static StrList*
_str_list_append (StrList* list, const wchar_t* str)
{
      StrList*    walk;

      if (list) {
            for (walk = list; walk->next; walk = walk->next);
            walk->next = str_list_alloc ();
            walk = walk->next;
      } else {
            walk = list = str_list_alloc ();
      }
      walk->str = str;

      return list;
}

StrList*
str_list_append (StrList* list, const char* str)
{
      return _str_list_append (list, gettext_to_wchar (str));
}

StrList*
str_list_append_unique (StrList* list, const char* str)
{
      StrList*    walk;
      wchar_t*    new_str = gettext_to_wchar (str);

      for (walk=list; walk; walk=walk->next) {
            if (walk->str) {
                  if (wchar_strcasecmp (new_str, walk->str) == 0) {
                        free (new_str);
                        return list;
                  }
            }
      }

      return _str_list_append (list, new_str);
}

StrList*
str_list_insert (StrList* list, const char* str)
{
      return str_list_join (str_list_create (str, NULL), list);
}

StrList*
str_list_create (const char* first, ...)
{
      va_list           args;
      char*       str;
      StrList*    list;

      list = str_list_append (NULL, first);

      if (first) {
            va_start (args, first);
            while ( (str = va_arg (args, char*)) )
                  str_list_append (list, str);
            va_end (args);
      }

      return list;
}

StrList*
str_list_create_unique (const char* first, ...)
{
      va_list           args;
      char*       str;
      StrList*    list;

      list = str_list_append (NULL, first);

      if (first) {
            va_start (args, first);
            while ( (str = va_arg (args, char*)) )
                  str_list_append_unique (list, str);
            va_end (args);
      }

      return list;
}

char*
str_list_convert_node (const StrList* list)
{
      return wchar_to_str (list->str, 0);
}

char*
str_list_convert (const StrList* list)
{
      const StrList*    walk;
      int         pos = 0;
      int         length = 1;
      char*       str = strdup ("");

      for (walk = list; walk; walk = walk->next) {
            if (walk->str) {
                  char* tmp = wchar_to_str (walk->str, 0);

                  length += strlen (tmp);

                  str = realloc (str, length);
                  strcpy (str + pos, tmp);

                  pos = length - 1;
                  free (tmp);
            }
      }

      return str;
}

void
str_list_print (const StrList* list)
{
      const StrList*    walk;

      for (walk=list; walk; walk=walk->next) {
            if (walk->str)
                  print_wchar (walk->str, 0);
      }
}

static char*
get_spaces (int space_count)
{
      char* str;
      int   i;

      str = malloc (space_count + 1);
      for (i = 0; i < space_count; i++)
            str [i] = ' ';
      str [i] = 0;

      return str;
}

static int
str_search (const wchar_t* str, int n, wchar_t c)
{
      int   i;

      for (i=0; i<n; i++)
            if (str [i] == c)
                  return i;
      return -1;
}


/* Japanese don't leave spaces between words, so ALL Japanese characters
 * are treated as delimiters.  Note: since the translations should already
 * be properly formatted (eg: spaces after commas), there should be no
 * need to include them.  Best not to avoid side effects, like 3.
14159 :-)
 * FIXME: how do we exclude "." and "(" ?
 * FIXME: glibc doesn't like umlaute.  i.e. \"o (TeX notation), which should
 * look like: 
 */

static int
is_break_point (wchar_t c)
{
#ifdef ENABLE_NLS
      return !iswalnum (c) && !iswpunct (c);
#else
      return !isalnum (c) && !ispunct (c);
#endif
}

/* NOTE: this should not return '\n' as a space, because explicit '\n' may
 * be placed inside strings.
 */
static int
is_space (wchar_t c)
{
#ifdef ENABLE_NLS
      return c == (wchar_t) btowc(' ');
#else
      return c == ' ';
#endif
}

void
str_list_print_wrap (const StrList* list, int line_length, int offset,
                 int indent)
{
      const StrList*    walk;
      const wchar_t*    str;
      int         str_len;
      int         cut_right;
      int         cut_left;
      int         line_left;
      char*       spaces;
      int         search_result;
      int         line_break;

      PED_ASSERT (line_length - indent > 10, return);

      spaces = get_spaces (indent);
      line_left = line_length - offset;

      for (walk=list; walk; walk=walk->next) {
            if (!walk->str)
                  continue;
            str = walk->str;
            str_len = wchar_strlen (str);

            while (line_left < str_len || wchar_strchr (str, '\n')) {
                  line_break = 0;

                  cut_left = MIN (line_left - 1, str_len - 1);

                  /* we can have a space "over", but not a comma */
                  if (cut_left < str_len
                              && is_space (str [cut_left + 1]))
                        cut_left++;

                  while (cut_left && !is_break_point (str [cut_left]))
                        cut_left--;
                  while (cut_left && is_space (str [cut_left]))
                        cut_left--;

            /* str [cut_left] is either the end of a word, or a
             * Japanese character, or the start of a blank line.
             */

                  search_result = str_search (str, cut_left + 1, '\n');
                  if (search_result != -1) {
                        cut_left = search_result - 1;
                        line_break = 1;
                  }

                  for (cut_right = cut_left + (line_break ? 2 : 1);
                       cut_right < str_len && is_space (str [cut_right]);
                       cut_right++);

                  if (cut_left > 0)
                        print_wchar (str, cut_left + 1);

                  str += cut_right;
                  str_len -= cut_right;
                  line_left = line_length - indent;

                  if (walk->next || *str)
                        printf ("\n%s", spaces);
                  else if (line_break)
                        printf ("\n");
            }

            print_wchar (str, 0);
            line_left -= wchar_strlen (str);
      }

      free (spaces);
}

static int
_str_list_match_node (const StrList* list, const wchar_t* str)
{
      if (wchar_strcasecmp (list->str, str) == 0)
            return 2;
      if (wchar_strncasecmp (list->str, str, wchar_strlen (str)) == 0)
            return 1;
      return 0;
}

int
str_list_match_node (const StrList* list, const char* str)
{
      wchar_t*    wc_str = gettext_to_wchar (str);    /* FIXME */
      int         status;

      status = _str_list_match_node (list, wc_str);
      free (wc_str);

      return status;
}

/* returns:  2 for full match
           1 for partial match
           0 for no match
 */
int
str_list_match_any (const StrList* list, const char* str)
{
      const StrList*    walk;
      int         best_status = 0;
      wchar_t*    wc_str = gettext_to_wchar (str);

      for (walk = list; walk; walk = walk->next) {
            int   this_status = _str_list_match_node (walk, wc_str);
            if (this_status > best_status)
                        best_status = this_status;
      }

      free (wc_str);
      return best_status;
}

StrList*
str_list_match (const StrList* list, const char* str)
{
      const StrList*    walk;
      const StrList*    partial_match = NULL;
      int         ambiguous = 0;
      wchar_t*    wc_str = gettext_to_wchar (str);

      for (walk = list; walk; walk = walk->next) {
            switch (_str_list_match_node (walk, wc_str)) {
                  case 2:
                        free (wc_str);
                        return (StrList*) walk;

                  case 1:
                        if (partial_match)
                              ambiguous = 1;
                        partial_match = walk;
            }
      }

      free (wc_str);
      return ambiguous ? NULL : (StrList*) partial_match;
}

int
str_list_length (const StrList* list)
{
      int         length = 0;
      const StrList*    walk;

      for (walk = list; walk; walk = walk->next)
            length++;

      return length;
}


Generated by  Doxygen 1.6.0   Back to index