From 1e893ec6e3e6584ce6a7a2a9b209d4a075162ec8 Mon Sep 17 00:00:00 2001 From: Phil Sutter Date: Sat, 3 Oct 2009 20:01:33 +0200 Subject: [PATCH] iconv: outsource code into it's own file While testing, I found two already existing bugs: * the variable 'a' passed to iconv_convert() needs to be passed by reference in order to allow for the desired side effect. * Somehow the trailing junk after an iconv_conversion to a shorter string messes things up (and gets printed!). I couldn't exactly find out why this happens, but setting (*p) = 0; solves this problem. --- configure.ac.in | 1 + src/Makefile.am | 4 ++ src/conky.c | 13 ++-- src/core.c | 132 +++------------------------------------- src/core.h | 6 -- src/iconv_tools.c | 152 ++++++++++++++++++++++++++++++++++++++++++++++ src/iconv_tools.h | 41 +++++++++++++ 7 files changed, 214 insertions(+), 135 deletions(-) create mode 100644 src/iconv_tools.c create mode 100644 src/iconv_tools.h diff --git a/configure.ac.in b/configure.ac.in index 924727fe..bdfcbe39 100644 --- a/configure.ac.in +++ b/configure.ac.in @@ -568,6 +568,7 @@ if test "$am_cv_func_iconv" != yes; then else conky_LIBS="$conky_LIBS $LIBICONV" fi +AM_CONDITIONAL(BUILD_ICONV, test "$am_cv_func_iconv" = yes) dnl dnl Xext Double-buffering Extension diff --git a/src/Makefile.am b/src/Makefile.am index e2e30904..ac6f1b8a 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -80,6 +80,7 @@ lua = llua.c llua.h nvidia = nvidia.c nvidia.h imlib2 = imlib2.c imlib2.h apcupsd = apcupsd.c apcupsd.h +iconv = iconv_tools.c iconv_tools.h # make sure the files from above are always included in the distfile EXTRA_DIST = $(audacious) $(bmpx) $(ibm) $(mpd) $(moc) $(xmms2) $(linux) \ @@ -155,6 +156,9 @@ endif if BUILD_APCUPSD optional_sources += $(apcupsd) endif +if BUILD_ICONV +optional_sources += $(iconv) +endif # linux takes the standard to the max if BUILD_LINUX diff --git a/src/conky.c b/src/conky.c index 1a5aeafc..812d191a 100644 --- a/src/conky.c +++ b/src/conky.c @@ -80,6 +80,9 @@ #include "fonts.h" #endif #include "fs.h" +#ifdef HAVE_ICONV +#include "iconv_tools.h" +#endif #include "logging.h" #include "mixer.h" #include "mail.h" @@ -983,7 +986,6 @@ static void generate_text_internal(char *p, int p_max_size, #ifdef HAVE_ICONV char buff_in[p_max_size]; buff_in[0] = 0; - set_iconv_converting(0); #endif /* HAVE_ICONV */ p[0] = 0; @@ -2841,12 +2843,10 @@ static void generate_text_internal(char *p, int p_max_size, #ifdef HAVE_ICONV OBJ(iconv_start) { - set_iconv_converting(1); - set_iconv_selected(obj->a); + do_iconv_start(obj); } OBJ(iconv_stop) { - set_iconv_converting(0); - set_iconv_selected(0); + do_iconv_stop(); } #endif /* HAVE_ICONV */ @@ -3209,7 +3209,7 @@ static void generate_text_internal(char *p, int p_max_size, size_t a = strlen(p); #ifdef HAVE_ICONV - iconv_convert(a, buff_in, p, p_max_size); + iconv_convert(&a, buff_in, p, p_max_size); #endif /* HAVE_ICONV */ if (obj->type != OBJ_text && obj->type != OBJ_execp && obj->type != OBJ_execpi && obj->type != OBJ_lua && obj->type != OBJ_lua_parse) { @@ -3217,6 +3217,7 @@ static void generate_text_internal(char *p, int p_max_size, } p += a; p_max_size -= a; + (*p) = 0; } obj = obj->next; } diff --git a/src/core.c b/src/core.c index 208c6dee..14a0f6c5 100644 --- a/src/core.c +++ b/src/core.c @@ -39,6 +39,9 @@ #include "fonts.h" #endif #include "fs.h" +#ifdef HAVE_ICONV +#include "iconv_tools.h" +#endif #include "logging.h" #include "mixer.h" #include "mail.h" @@ -50,6 +53,10 @@ #include "timeinfo.h" #include "top.h" +#ifdef NCURSES +#include +#endif + /* check for OS and include appropriate headers */ #if defined(__linux__) #include "linux.h" @@ -65,107 +72,6 @@ void update_entropy(void); #include #include -#ifdef HAVE_ICONV -#include - -#ifdef NCURSES -#include -#endif - -#define ICONV_CODEPAGE_LENGTH 20 - -int register_iconv(iconv_t *new_iconv); - -long iconv_selected; -long iconv_count = 0; -char iconv_converting; -static iconv_t **iconv_cd = 0; - -char is_iconv_converting(void) -{ - return iconv_converting; -} - -void set_iconv_converting(char i) -{ - iconv_converting = i; -} - -long get_iconv_selected(void) -{ - return iconv_selected; -} - -void set_iconv_selected(long i) -{ - iconv_selected = i; -} - -int register_iconv(iconv_t *new_iconv) -{ - iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1)); - if (!iconv_cd) { - CRIT_ERR(NULL, NULL, "Out of memory"); - } - iconv_cd[iconv_count] = malloc(sizeof(iconv_t)); - if (!iconv_cd[iconv_count]) { - CRIT_ERR(NULL, NULL, "Out of memory"); - } - memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t)); - iconv_count++; - return iconv_count; -} - -void free_iconv(void) -{ - if (iconv_cd) { - long i; - - for (i = 0; i < iconv_count; i++) { - if (iconv_cd[i]) { - iconv_close(*iconv_cd[i]); - free(iconv_cd[i]); - } - } - free(iconv_cd); - } - iconv_cd = 0; -} - -void iconv_convert(size_t a, char *buff_in, char *p, size_t p_max_size) -{ - if (a > 0 && is_iconv_converting() && get_iconv_selected() > 0 - && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) { - int bytes; - size_t dummy1, dummy2; -#ifdef __FreeBSD__ - const char *ptr = buff_in; -#else - char *ptr = buff_in; -#endif - char *outptr = p; - - dummy1 = dummy2 = a; - - strncpy(buff_in, p, p_max_size); - - iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL); - while (dummy1 > 0) { - bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1, - &outptr, &dummy2); - if (bytes == -1) { - NORM_ERR("Iconv codeset conversion failed"); - break; - } - } - - /* It is nessecary when we are converting from multibyte to - * singlebyte codepage */ - a = outptr - p; - } -} -#endif /* HAVE_ICONV */ - /* strip a leading /dev/ if any, following symlinks first * * BEWARE: this function returns a pointer to static content @@ -1364,29 +1270,9 @@ struct text_object *construct_text_object(const char *s, const char *arg, long scan_tztime(obj, arg); #ifdef HAVE_ICONV END OBJ_ARG(iconv_start, 0, "Iconv requires arguments") - char iconv_from[ICONV_CODEPAGE_LENGTH]; - char iconv_to[ICONV_CODEPAGE_LENGTH]; - - if (is_iconv_converting()) { - CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before " - "starting another"); - } - if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) { - CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start"); - } else { - iconv_t new_iconv; - - new_iconv = iconv_open(iconv_to, iconv_from); - if (new_iconv == (iconv_t) (-1)) { - NORM_ERR("Can't convert from %s to %s.", iconv_from, iconv_to); - } else { - obj->a = register_iconv(&new_iconv); - set_iconv_converting(1); - } - } + init_iconv_start(obj, free_at_crash, arg); END OBJ(iconv_stop, 0) - set_iconv_converting(0); - + init_iconv_stop(); #endif END OBJ(totaldown, &update_net_stats) if (arg) { diff --git a/src/core.h b/src/core.h index c6078c96..1d1c140d 100644 --- a/src/core.h +++ b/src/core.h @@ -46,10 +46,4 @@ void free_text_objects(struct text_object *root, int internal); void scan_mixer_bar(const char *arg, int *a, int *w, int *h); #endif /* X11 */ -#ifdef HAVE_ICONV -void set_iconv_converting(char i); -void set_iconv_selected(long i); -void iconv_convert(size_t a, char *buff_in, char *p, size_t p_max_size); -#endif /* HAVE_ICONV */ - #endif /* _CONKY_CORE_H_ */ diff --git a/src/iconv_tools.c b/src/iconv_tools.c new file mode 100644 index 00000000..0c4912b7 --- /dev/null +++ b/src/iconv_tools.c @@ -0,0 +1,152 @@ +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * + * Conky, a system monitor, based on torsmo + * + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen + * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * 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 3 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, see . + * + */ + +#include "config.h" +#include "logging.h" +#include "text_object.h" +#include +#include +#include +#include + +#define ICONV_CODEPAGE_LENGTH 20 + +static long iconv_selected; +static long iconv_count = 0; +static char iconv_converting = 0; +static iconv_t **iconv_cd = 0; + +int register_iconv(iconv_t *new_iconv) +{ + iconv_cd = realloc(iconv_cd, sizeof(iconv_t *) * (iconv_count + 1)); + if (!iconv_cd) { + CRIT_ERR(NULL, NULL, "Out of memory"); + } + iconv_cd[iconv_count] = malloc(sizeof(iconv_t)); + if (!iconv_cd[iconv_count]) { + CRIT_ERR(NULL, NULL, "Out of memory"); + } + memcpy(iconv_cd[iconv_count], new_iconv, sizeof(iconv_t)); + iconv_count++; + return iconv_count; +} + +void free_iconv(void) +{ + long i; + + if (!iconv_cd) + return; + + for (i = 0; i < iconv_count; i++) { + if (iconv_cd[i]) { + iconv_close(*iconv_cd[i]); + free(iconv_cd[i]); + } + } + free(iconv_cd); + iconv_cd = 0; +} + +void iconv_convert(size_t *a, char *buff_in, char *p, size_t p_max_size) +{ + if (*a > 0 && iconv_converting && iconv_selected > 0 + && (iconv_cd[iconv_selected - 1] != (iconv_t) (-1))) { + int bytes; + size_t dummy1, dummy2; +#ifdef __FreeBSD__ + const char *ptr = buff_in; +#else + char *ptr = buff_in; +#endif + char *outptr = p; + + dummy1 = dummy2 = *a; + + strncpy(buff_in, p, p_max_size); + + iconv(*iconv_cd[iconv_selected - 1], NULL, NULL, NULL, NULL); + while (dummy1 > 0) { + bytes = iconv(*iconv_cd[iconv_selected - 1], &ptr, &dummy1, + &outptr, &dummy2); + if (bytes == -1) { + NORM_ERR("Iconv codeset conversion failed"); + break; + } + } + + /* It is nessecary when we are converting from multibyte to + * singlebyte codepage */ + //a = outptr - p; + //(*a) = *a - dummy2; + (*a) = outptr - p; + } +} + +void init_iconv_start(struct text_object *obj, void *free_at_crash, const char *arg) +{ + char iconv_from[ICONV_CODEPAGE_LENGTH]; + char iconv_to[ICONV_CODEPAGE_LENGTH]; + + if (iconv_converting) { + CRIT_ERR(obj, free_at_crash, "You must stop your last iconv conversion before " + "starting another"); + } + if (sscanf(arg, "%s %s", iconv_from, iconv_to) != 2) { + CRIT_ERR(obj, free_at_crash, "Invalid arguments for iconv_start"); + } else { + iconv_t new_iconv; + + new_iconv = iconv_open(iconv_to, iconv_from); + if (new_iconv == (iconv_t) (-1)) { + NORM_ERR("Can't convert from %s to %s.", iconv_from, iconv_to); + } else { + obj->a = register_iconv(&new_iconv); + iconv_converting = 1; + } + } +} + +void init_iconv_stop(void) +{ + iconv_converting = 0; +} + +void do_iconv_start(struct text_object *obj) +{ + iconv_converting = 1; + iconv_selected = obj->a; +} + +void do_iconv_stop(void) +{ + iconv_converting = 0; + iconv_selected = 0; +} diff --git a/src/iconv_tools.h b/src/iconv_tools.h new file mode 100644 index 00000000..73a1467d --- /dev/null +++ b/src/iconv_tools.h @@ -0,0 +1,41 @@ +/* -*- mode: c; c-basic-offset: 4; tab-width: 4; indent-tabs-mode: t -*- + * vim: ts=4 sw=4 noet ai cindent syntax=c + * + * Conky, a system monitor, based on torsmo + * + * Any original torsmo code is licensed under the BSD license + * + * All code written since the fork of torsmo is licensed under the GPL + * + * Please see COPYING for details + * + * Copyright (c) 2004, Hannu Saransaari and Lauri Hakkarainen + * Copyright (c) 2005-2009 Brenden Matthews, Philip Kovacs, et. al. + * (see AUTHORS) + * All rights reserved. + * + * 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 3 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, see . + * + */ + +#ifndef _ICONV_TOOLS_H +#define _ICONV_TOOLS_H + +void free_iconv(void); +void iconv_convert(size_t *, char *, char *, size_t); +void init_iconv_start(struct text_object *, void *, const char *); +void init_iconv_stop(void); +void do_iconv_start(struct text_object *); +void do_iconv_stop(void); + +#endif /* _ICONV_TOOLS_H */