aboutsummaryrefslogtreecommitdiffstats
path: root/plugin_iconv.c
blob: bd01f265f1d75b72e3f1af54d8bb2c9e793889d7 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* $Id$
 * $URL$
 *
 * iconv charset conversion plugin
 *
 * Copyright (C) 2006 Ernst Bachmann <e.bachmann@xebec.de>
 * Copyright (C) 2006 The LCD4Linux Team <lcd4linux-devel@users.sourceforge.net>
 *
 * This file is part of LCD4Linux.
 *
 * LCD4Linux 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, or (at your option)
 * any later version.
 *
 * LCD4Linux 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., 675 Mass Ave, Cambridge, MA 02139, USA.
 *
 */

/* 
 * exported functions:
 *
 * int plugin_init_iconv (void)
 * int plugin_exit_iconv (void)
 *
 */


#include "config.h"

#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include <iconv.h>
#include <errno.h>

/* these should always be included */
#include "debug.h"
#include "plugin.h"

#ifdef WITH_DMALLOC
#include <dmalloc.h>
#endif



/* iconv function, convert charsets */
/* valid "to" and "from" charsets can be listed by running "iconv --list" from a shell */
/* utf16 & utf32 encodings won't work, as they contain null bytes, confusing strlen */
static void my_iconv(RESULT * result, RESULT * charset_from, RESULT * charset_to, RESULT * arg)
{
    char *source;
    size_t source_left;
    char *dest;
    char *dest_pos;
    size_t dest_left;
    iconv_t cd;

    source = R2S(arg);
    source_left = strlen(source);

    /* use twice the memory needed in best case, but save lots of reallocs in worst case */
    /* increase to 4 if most conversions are to utf32 (quite unlikely) */
    /* also alloc a "safety byte" so we can always zero-terminate the string. */

    dest_left = 2 * source_left;
    dest = malloc(dest_left + 1);
    dest_pos = dest;

    cd = iconv_open(R2S(charset_to), R2S(charset_from));
    if (cd != (iconv_t) (-1)) {

	do {

	    /* quite spammy: debug("plugin_iconv: calling iconv with %ld,[%s]/%ld,%ld", cd, source, source_left, dest_left); */
	    if (iconv(cd, &source, &source_left, &dest_pos, &dest_left) == (size_t) (-1)) {
		switch (errno) {
		case EILSEQ:
		    /* illegal bytes in input sequence */
		    /* try to fix by skipping a byte */
		    info("plugin_iconv: illegal character in input string: %c", *source);
		    source_left--;
		    source++;
		    break;
		case EINVAL:
		    /* input string ends during a multibyte sequence */
		    /* try to fix by simply ignoring */
		    info("plugin_iconv: illegal character at end of input");
		    source_left = 0;
		    break;
		case E2BIG:
		    /* not enough bytes in outbuf. */
		    /* TODO: Realloc output buffer, probably doubling its size? */
		    /* for now, just bail out. For lcd4linux 99% of all conversions will go to ascii or latin1 anyways */
		    error
			("plugin_iconv: out of memory in destination buffer. Seems like Ernst was too lazy, complain to him!");
		    source_left = 0;
		    break;
		default:
		    error("plugin_iconv: strange errno state (%d) occured", errno);
		    source_left = 0;
		}
	    }
	} while (source_left > 0);	/* don't check for == 0, could be negative in EILSEQ case */

	/* terminate the string, we're sure to have that byte left, see above */
	*dest_pos = 0;
	dest_pos++;

	iconv_close(cd);
    } else {
	error("plugin_iconv: could not open conversion descriptor. Check if your charsets are supported!");
	/* guaranteed to fit. */
	strcpy(dest, source);
    }

    SetResult(&result, R_STRING, dest);

    free(dest);
}


/* plugin initialization */
int plugin_init_iconv(void)
{

    AddFunction("iconv", 3, my_iconv);

    return 0;
}

void plugin_exit_iconv(void)
{
    /* nothing to clean */
}
">{ { 0x01, "CW1602", 2, 16, 5, 0, 1 }, { 0x02, "CW12232", 4, 40, 6, 0, 2 }, { 0xff, "Unknown", -1, -1, -1, -1, -1 } }; // **************************************** // *** hardware dependant functions *** // **************************************** static void drv_CW_goto (int row, int col) { char cmd[6]="\376Gxy\375"; cmd[2]=(char)col; cmd[3]=(char)row; drv_generic_serial_write(cmd, 5); } static void drv_CW1602_defchar (int ascii, char *buffer) { int i; char cmd[12]="\376Nn12345678\375"; cmd[2]=(char)(ascii+1); for (i=0; i<8; i++) { cmd[3+i]=buffer[i]; } drv_generic_serial_write(cmd,12); usleep(20); // delay for cw1602 to settle the character defined! } static void drv_CW12232_defchar (int ascii, char *buffer) { int i, j; char cmd[10]="\376Nn123456\375"; cmd[2]=(char)(ascii+1); // The CW12232 uses a vertical bitmap layout, // so we have to 'rotate' the bitmap. for (i=0; i<6;i++) { cmd[3+i]=0; for (j=0; j<8;j++) { if (buffer[j] & (1<<(5-i))) { cmd[3+i]|=(1<<j); } } } drv_generic_serial_write (cmd, 10); } static int drv_CW_start (char *section) { int i; char *model; model=cfg_get(section, "Model", NULL); if (model!=NULL && *model!='\0') { for (i=0; Models[i].type!=0xff; i++) { if (strcasecmp(Models[i].name, model)==0) break; } if (Models[i].type==0xff) { error ("%s: %s.Model '%s' is unknown from %s", Name, section, model, cfg_source()); return -1; } Model=i; info ("%s: using model '%s'", Name, Models[Model].name); } else { error ("%s: no '%s.Model' entry from %s", Name, section, cfg_source()); return -1; } // open serial port if (drv_generic_serial_open(section, Name)<0) return -1; // this does not work as I'd expect it... #if 0 // read firmware version generic_serial_read(buffer,sizeof(buffer)); usleep(100000); generic_serial_write ("\3761", 2); usleep(100000); generic_serial_write ("\375", 1); usleep(100000); if (generic_serial_read(buffer,2)!=2) { info ("unable to read firmware version!"); } info ("Cwlinux Firmware %d.%d", (int)buffer[0], (int)buffer[1]); #endif // initialize global variables DROWS = Models[Model].rows; DCOLS = Models[Model].cols; XRES = Models[Model].xres; GPOS = Models[Model].gpos; Protocol = Models[Model].protocol; #if 0 drv_generic_serial_write("\376X\375",3); // Clear Display #else // for some mysterious reason, we have to sleep after // the command _and_ after the CMD_END... usleep(20); drv_generic_serial_write("\376X",2); // Clear Display usleep(20); drv_generic_serial_write("\375",1); // Command End usleep(20); #endif drv_generic_serial_write ("\376D\375", 3); // auto line wrap off drv_generic_serial_write ("\376R\375", 3); // auto scroll off drv_generic_serial_write ("\376K\375", 3); // underline cursor off drv_generic_serial_write ("\376B\375", 3); // backlight on return 0; } // **************************************** // *** plugins *** // **************************************** static void plugin_backlight (RESULT *result, RESULT *arg1) { char cmd[5]="\376A_\375"; double backlight; backlight=R2N(arg1); if (backlight<0) backlight=0; if (backlight>8) backlight=8; switch ((int)backlight) { case 0: drv_generic_serial_write ("\376F\375", 3); // backlight off break; case 8: drv_generic_serial_write ("\376B\375", 3); // backlight on break; default: cmd[2]=(char)backlight; drv_generic_serial_write (cmd, 4); // backlight level break; } SetResult(&result, R_NUMBER, &backlight); } // **************************************** // *** widget callbacks *** // **************************************** // using drv_generic_text_draw(W) // using drv_generic_text_icon_draw(W) // using drv_generic_text_bar_draw(W) // **************************************** // *** exported functions *** // **************************************** // list models int drv_CW_list (void) { int i; for (i=0; Models[i].type!=0xff; i++) { printf ("%s ", Models[i].name); } return 0; } // initialize driver & display int drv_CW_init (char *section) { WIDGET_CLASS wc; int ret; // display preferences XRES = 6; // pixel width of one char YRES = 8; // pixel height of one char CHARS = 8; // number of user-defineable characters CHAR0 = 128; // ASCII of first user-defineable char GOTO_COST = 3; // number of bytes a goto command requires // real worker functions drv_generic_text_real_write = drv_generic_serial_write; drv_generic_text_real_goto = drv_CW_goto; switch (Protocol) { case 1: drv_generic_text_real_defchar = drv_CW1602_defchar; break; case 2: drv_generic_text_real_defchar = drv_CW12232_defchar; break; } // start display if ((ret=drv_CW_start (section))!=0) return ret; // initialize generic text driver if ((ret=drv_generic_text_init(section, Name))!=0) return ret; // initialize generic icon driver if ((ret=drv_generic_text_icon_init())!=0) return ret; // initialize generic bar driver if ((ret=drv_generic_text_bar_init())!=0) return ret; // add fixed chars to the bar driver drv_generic_text_bar_add_segment (0, 0, 255, 32); // ASCII 32 = blank // register text widget wc=Widget_Text; wc.draw=drv_generic_text_draw; widget_register(&wc); // register icon widget wc=Widget_Icon; wc.draw=drv_generic_text_icon_draw; widget_register(&wc); // register bar widget wc=Widget_Bar; wc.draw=drv_generic_text_bar_draw; widget_register(&wc); // register plugins AddFunction ("backlight", 1, plugin_backlight); return 0; } // close driver & display int drv_CW_quit (void) { info("%s: shutting down.", Name); drv_generic_serial_close(); drv_generic_text_quit(); return (0); } DRIVER drv_Cwlinux = { name: Name, list: drv_CW_list, init: drv_CW_init, quit: drv_CW_quit, };