1 /*
2  * fromucs.c - convert Unicode to other character sets.
3  */
4 
5 #include "charset.h"
6 #include "internal.h"
7 
8 struct charset_emit_param {
9     char *output;
10     int outlen;
11     int writtenlen;
12     int stopped;
13 };
14 
charset_emit(void * ctx,long int output)15 static void charset_emit(void *ctx, long int output)
16 {
17     struct charset_emit_param *param = (struct charset_emit_param *)ctx;
18 
19     if (param->outlen != 0) {
20 	if (param->output)
21 	    *param->output++ = output;
22 	if (param->outlen > 0)
23 	    param->outlen--;
24 	param->writtenlen++;
25     } else {
26 	param->stopped = 1;
27     }
28 }
29 
charset_from_unicode(const wchar_t ** input,int * inlen,char * output,int outlen,int charset,charset_state * state,int * error)30 int charset_from_unicode(const wchar_t **input, int *inlen,
31 			 char *output, int outlen,
32 			 int charset, charset_state *state, int *error)
33 {
34     charset_spec const *spec = charset_find_spec(charset);
35     charset_state localstate = CHARSET_INIT_STATE;
36     struct charset_emit_param param;
37     int locallen;
38 
39     if (!input) {
40 	locallen = 1;
41 	inlen = &locallen;
42     }
43 
44     param.output = output;
45     param.outlen = outlen;
46     param.writtenlen = 0;
47     param.stopped = 0;
48 
49     if (state)
50 	localstate = *state;	       /* structure copy */
51     if (error)
52 	*error = FALSE;
53 
54     while (*inlen > 0) {
55 	int lenbefore = param.writtenlen;
56 	int ret;
57 
58 	if (input)
59 	    ret = spec->write(spec, **input, &localstate,
60 			      charset_emit, &param);
61 	else
62 	    ret = spec->write(spec, -1, &localstate, charset_emit, &param);
63 	if (error && !ret) {
64 	    /*
65 	     * We have hit a difficult character, which the user
66 	     * wants to know about. Leave now.
67 	     */
68 	    *error = TRUE;
69 	    return lenbefore;
70 	}
71 	if (param.stopped) {
72 	    /*
73 	     * The emit function has _tried_ to output some
74 	     * characters, but ran up against the end of the
75 	     * buffer. Leave immediately, and return what happened
76 	     * _before_ attempting to process this character.
77 	     */
78 	    return lenbefore;
79 	}
80 	if (state)
81 	    *state = localstate;       /* structure copy */
82 	if (input)
83 	    (*input)++;
84 	(*inlen)--;
85     }
86     return param.writtenlen;
87 }
88