s3-popt: Only include popt-common.h when needed.
[nivanova/samba-autobuild/.git] / source3 / torture / smbiconv.c
1 /* 
2    Unix SMB/CIFS implementation.
3    Charset module tester
4
5    Copyright (C) Jelmer Vernooij 2003
6    Based on iconv/icon_prog.c from the GNU C Library, 
7       Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
8
9    This program is free software; you can redistribute it and/or modify
10    it under the terms of the GNU General Public License as published by
11    the Free Software Foundation; either version 3 of the License, or
12    (at your option) any later version.
13    
14    This program is distributed in the hope that it will be useful,
15    but WITHOUT ANY WARRANTY; without even the implied warranty of
16    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17    GNU General Public License for more details.
18    
19    You should have received a copy of the GNU General Public License
20    along with this program.  If not, see <http://www.gnu.org/licenses/>.
21 */
22
23 #include "includes.h"
24 #include "popt_common.h"
25 #undef realloc
26
27 static int
28 process_block (smb_iconv_t cd, const char *addr, size_t len, FILE *output)
29 {
30 #define OUTBUF_SIZE     32768
31   const char *start = addr;
32   char outbuf[OUTBUF_SIZE];
33   char *outptr;
34   size_t outlen;
35   size_t n;
36
37   while (len > 0)
38     {
39       outptr = outbuf;
40       outlen = OUTBUF_SIZE;
41       n = smb_iconv (cd,  &addr, &len, &outptr, &outlen);
42
43       if (outptr != outbuf)
44         {
45           /* We have something to write out.  */
46           int errno_save = errno;
47
48           if (fwrite (outbuf, 1, outptr - outbuf, output)
49               < (size_t) (outptr - outbuf)
50               || ferror (output))
51             {
52               /* Error occurred while printing the result.  */
53               DEBUG (0, ("conversion stopped due to problem in writing the output"));
54               return -1;
55             }
56
57           errno = errno_save;
58         }
59
60       if (errno != E2BIG)
61         {
62           /* iconv() ran into a problem.  */
63           switch (errno)
64             {
65             case EILSEQ:
66               DEBUG(0,("illegal input sequence at position %ld", 
67                      (long) (addr - start)));
68               break;
69             case EINVAL:
70               DEBUG(0, ("\
71 incomplete character or shift sequence at end of buffer"));
72               break;
73             case EBADF:
74               DEBUG(0, ("internal error (illegal descriptor)"));
75               break;
76             default:
77               DEBUG(0, ("unknown iconv() error %d", errno));
78               break;
79             }
80
81           return -1;
82         }
83     }
84
85   return 0;
86 }
87
88
89 static int
90 process_fd (smb_iconv_t cd, int fd, FILE *output)
91 {
92   /* we have a problem with reading from a descriptor since we must not
93      provide the iconv() function an incomplete character or shift
94      sequence at the end of the buffer.  Since we have to deal with
95      arbitrary encodings we must read the whole text in a buffer and
96      process it in one step.  */
97   static char *inbuf = NULL;
98   static size_t maxlen = 0;
99   char *inptr = NULL;
100   size_t actlen = 0;
101
102   while (actlen < maxlen)
103     {
104       ssize_t n = read (fd, inptr, maxlen - actlen);
105
106       if (n == 0)
107         /* No more text to read.  */
108         break;
109
110       if (n == -1)
111         {
112           /* Error while reading.  */
113           DEBUG(0, ("error while reading the input"));
114           return -1;
115         }
116
117       inptr += n;
118       actlen += n;
119     }
120
121   if (actlen == maxlen)
122     while (1)
123       {
124         ssize_t n;
125         char *new_inbuf;
126
127         /* Increase the buffer.  */
128         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
129         if (new_inbuf == NULL)
130           {
131             DEBUG(0, ("unable to allocate buffer for input"));
132             return -1;
133           }
134         inbuf = new_inbuf;
135         maxlen += 32768;
136         inptr = inbuf + actlen;
137
138         do
139           {
140             n = read (fd, inptr, maxlen - actlen);
141
142             if (n == 0)
143               /* No more text to read.  */
144               break;
145
146             if (n == -1)
147               {
148                 /* Error while reading.  */
149                 DEBUG(0, ("error while reading the input"));
150                 return -1;
151               }
152
153             inptr += n;
154             actlen += n;
155           }
156         while (actlen < maxlen);
157
158         if (n == 0)
159           /* Break again so we leave both loops.  */
160           break;
161       }
162
163   /* Now we have all the input in the buffer.  Process it in one run.  */
164   return process_block (cd, inbuf, actlen, output);
165 }
166
167 /* Main function */
168
169 int main(int argc, char *argv[])
170 {
171         const char *file = NULL;
172         const char *from = "";
173         const char *to = "";
174         char *output = NULL;
175         const char *preload_modules[] = {NULL, NULL};
176         FILE *out = stdout;
177         int fd;
178         smb_iconv_t cd;
179
180         /* make sure the vars that get altered (4th field) are in
181            a fixed location or certain compilers complain */
182         poptContext pc;
183         struct poptOption long_options[] = {
184                 POPT_AUTOHELP
185                 { "from-code", 'f', POPT_ARG_STRING, &from, 0, "Encoding of original text" },
186                 { "to-code", 't', POPT_ARG_STRING, &to, 0, "Encoding for output" },
187                 { "output", 'o', POPT_ARG_STRING, &output, 0, "Write output to this file" },
188                 { "preload-modules", 'p', POPT_ARG_STRING, &preload_modules[0], 0, "Modules to load" },
189                 POPT_COMMON_SAMBA
190                 POPT_TABLEEND
191         };
192
193         setlinebuf(stdout);
194
195         pc = poptGetContext("smbiconv", argc, (const char **) argv,
196                             long_options, 0);
197
198         poptSetOtherOptionHelp(pc, "[FILE] ...");
199         
200         while(poptGetNextOpt(pc) != -1);
201
202         /* the following functions are part of the Samba debugging
203            facilities.  See lib/debug.c */
204         setup_logging("smbiconv", True);
205
206         if (preload_modules[0]) smb_load_modules(preload_modules);
207
208         if(output) {
209                 out = fopen(output, "w");
210
211                 if(!out) {
212                         DEBUG(0, ("Can't open output file '%s': %s, exiting...\n", output, strerror(errno)));
213                         return 1;
214                 }
215         }
216
217         cd = smb_iconv_open(to, from);
218         if (cd == (smb_iconv_t)-1) {
219                 DEBUG(0,("unable to find from or to encoding, exiting...\n"));
220                 if (out != stdout) fclose(out);
221                 return 1;
222         }
223
224         while((file = poptGetArg(pc))) {
225                 if(strcmp(file, "-") == 0) fd = 0;
226                 else {
227                         fd = open(file, O_RDONLY);
228                         
229                         if(!fd) {
230                                 DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
231                                 continue;
232                         }
233                 }
234
235                 /* Loop thru all arguments */
236                 process_fd(cd, fd, out);
237
238                 close(fd);
239         }
240         poptFreeContext(pc);
241
242         fclose(out);
243
244         return 0;
245 }