s3-includes: only include system/filesys.h when needed.
[vlendec/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 "system/filesys.h"
25 #include "popt_common.h"
26 #undef realloc
27
28 static int
29 process_block (smb_iconv_t cd, const char *addr, size_t len, FILE *output)
30 {
31 #define OUTBUF_SIZE     32768
32   const char *start = addr;
33   char outbuf[OUTBUF_SIZE];
34   char *outptr;
35   size_t outlen;
36   size_t n;
37
38   while (len > 0)
39     {
40       outptr = outbuf;
41       outlen = OUTBUF_SIZE;
42       n = smb_iconv (cd,  &addr, &len, &outptr, &outlen);
43
44       if (outptr != outbuf)
45         {
46           /* We have something to write out.  */
47           int errno_save = errno;
48
49           if (fwrite (outbuf, 1, outptr - outbuf, output)
50               < (size_t) (outptr - outbuf)
51               || ferror (output))
52             {
53               /* Error occurred while printing the result.  */
54               DEBUG (0, ("conversion stopped due to problem in writing the output"));
55               return -1;
56             }
57
58           errno = errno_save;
59         }
60
61       if (errno != E2BIG)
62         {
63           /* iconv() ran into a problem.  */
64           switch (errno)
65             {
66             case EILSEQ:
67               DEBUG(0,("illegal input sequence at position %ld", 
68                      (long) (addr - start)));
69               break;
70             case EINVAL:
71               DEBUG(0, ("\
72 incomplete character or shift sequence at end of buffer"));
73               break;
74             case EBADF:
75               DEBUG(0, ("internal error (illegal descriptor)"));
76               break;
77             default:
78               DEBUG(0, ("unknown iconv() error %d", errno));
79               break;
80             }
81
82           return -1;
83         }
84     }
85
86   return 0;
87 }
88
89
90 static int
91 process_fd (smb_iconv_t cd, int fd, FILE *output)
92 {
93   /* we have a problem with reading from a descriptor since we must not
94      provide the iconv() function an incomplete character or shift
95      sequence at the end of the buffer.  Since we have to deal with
96      arbitrary encodings we must read the whole text in a buffer and
97      process it in one step.  */
98   static char *inbuf = NULL;
99   static size_t maxlen = 0;
100   char *inptr = NULL;
101   size_t actlen = 0;
102
103   while (actlen < maxlen)
104     {
105       ssize_t n = read (fd, inptr, maxlen - actlen);
106
107       if (n == 0)
108         /* No more text to read.  */
109         break;
110
111       if (n == -1)
112         {
113           /* Error while reading.  */
114           DEBUG(0, ("error while reading the input"));
115           return -1;
116         }
117
118       inptr += n;
119       actlen += n;
120     }
121
122   if (actlen == maxlen)
123     while (1)
124       {
125         ssize_t n;
126         char *new_inbuf;
127
128         /* Increase the buffer.  */
129         new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
130         if (new_inbuf == NULL)
131           {
132             DEBUG(0, ("unable to allocate buffer for input"));
133             return -1;
134           }
135         inbuf = new_inbuf;
136         maxlen += 32768;
137         inptr = inbuf + actlen;
138
139         do
140           {
141             n = read (fd, inptr, maxlen - actlen);
142
143             if (n == 0)
144               /* No more text to read.  */
145               break;
146
147             if (n == -1)
148               {
149                 /* Error while reading.  */
150                 DEBUG(0, ("error while reading the input"));
151                 return -1;
152               }
153
154             inptr += n;
155             actlen += n;
156           }
157         while (actlen < maxlen);
158
159         if (n == 0)
160           /* Break again so we leave both loops.  */
161           break;
162       }
163
164   /* Now we have all the input in the buffer.  Process it in one run.  */
165   return process_block (cd, inbuf, actlen, output);
166 }
167
168 /* Main function */
169
170 int main(int argc, char *argv[])
171 {
172         const char *file = NULL;
173         const char *from = "";
174         const char *to = "";
175         char *output = NULL;
176         const char *preload_modules[] = {NULL, NULL};
177         FILE *out = stdout;
178         int fd;
179         smb_iconv_t cd;
180
181         /* make sure the vars that get altered (4th field) are in
182            a fixed location or certain compilers complain */
183         poptContext pc;
184         struct poptOption long_options[] = {
185                 POPT_AUTOHELP
186                 { "from-code", 'f', POPT_ARG_STRING, &from, 0, "Encoding of original text" },
187                 { "to-code", 't', POPT_ARG_STRING, &to, 0, "Encoding for output" },
188                 { "output", 'o', POPT_ARG_STRING, &output, 0, "Write output to this file" },
189                 { "preload-modules", 'p', POPT_ARG_STRING, &preload_modules[0], 0, "Modules to load" },
190                 POPT_COMMON_SAMBA
191                 POPT_TABLEEND
192         };
193
194         setlinebuf(stdout);
195
196         pc = poptGetContext("smbiconv", argc, (const char **) argv,
197                             long_options, 0);
198
199         poptSetOtherOptionHelp(pc, "[FILE] ...");
200         
201         while(poptGetNextOpt(pc) != -1);
202
203         /* the following functions are part of the Samba debugging
204            facilities.  See lib/debug.c */
205         setup_logging("smbiconv", DEBUG_STDOUT);
206
207         if (preload_modules[0]) smb_load_modules(preload_modules);
208
209         if(output) {
210                 out = fopen(output, "w");
211
212                 if(!out) {
213                         DEBUG(0, ("Can't open output file '%s': %s, exiting...\n", output, strerror(errno)));
214                         return 1;
215                 }
216         }
217
218         cd = smb_iconv_open(to, from);
219         if (cd == (smb_iconv_t)-1) {
220                 DEBUG(0,("unable to find from or to encoding, exiting...\n"));
221                 if (out != stdout) fclose(out);
222                 return 1;
223         }
224
225         while((file = poptGetArg(pc))) {
226                 if(strcmp(file, "-") == 0) fd = 0;
227                 else {
228                         fd = open(file, O_RDONLY);
229                         
230                         if(!fd) {
231                                 DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
232                                 continue;
233                         }
234                 }
235
236                 /* Loop thru all arguments */
237                 process_fd(cd, fd, out);
238
239                 close(fd);
240         }
241         poptFreeContext(pc);
242
243         fclose(out);
244
245         return 0;
246 }