Add 'smbiconv' program - a clone of the 'iconv' utility
authorJelmer Vernooij <jelmer@samba.org>
Sun, 27 Apr 2003 20:49:18 +0000 (20:49 +0000)
committerJelmer Vernooij <jelmer@samba.org>
Sun, 27 Apr 2003 20:49:18 +0000 (20:49 +0000)
that uses samba's internal iconv() functions. Useful for
testing purposes.

source/Makefile.in
source/torture/smbiconv.c [new file with mode: 0644]

index a73f8c96827216178852278ed642c7021ef2e2f0..9d0349255968b3ce172ce5ce39e412269d81b7e1 100644 (file)
@@ -525,6 +525,8 @@ NSSTEST_OBJ = torture/nsstest.o $(PARAM_OBJ) $(LIBSMB_OBJ) $(KRBCLIENT_OBJ) \
 
 VFSTEST_OBJ = torture/cmd_vfs.o torture/vfstest.o $(SMBD_OBJ_BASE) $(READLINE_OBJ)
 
+SMBICONV_OBJ = $(PARAM_OBJ) torture/smbiconv.o $(LIB_OBJ) $(UBIQX_OBJ) $(POPT_LIB_OBJ)
+
 LOCKTEST2_OBJ = torture/locktest2.o $(PARAM_OBJ) $(LOCKING_OBJ) $(LIBSMB_OBJ) \
                $(KRBCLIENT_OBJ) $(UBIQX_OBJ) $(LIB_OBJ)
 
@@ -861,6 +863,10 @@ bin/vfstest@EXEEXT@: $(VFSTEST_OBJ) @BUILD_POPT@ bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(VFSTEST_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(TERMLIBS) $(DYNEXP) $(PRINTLIBS) $(AUTHLIBS) $(ACLLIBS) $(LIBS) @POPTLIBS@ $(ADSLIBS)
 
+bin/smbiconv@EXEEXT@: $(SMBICONV_OBJ) @BUILD_POPT@ bin/.dummy
+       @echo Linking $@
+       @$(CC) $(FLAGS) -o $@ $(SMBICONV_OBJ) $(LDFLAGS) $(TERMLDFLAGS) $(TERMLIBS) $(DYNEXP) $(LIBS) @POPTLIBS@
+
 bin/locktest2@EXEEXT@: $(LOCKTEST2_OBJ) bin/.dummy
        @echo Linking $@
        @$(CC) $(FLAGS) -o $@ $(LOCKTEST2_OBJ) $(LDFLAGS) $(LIBS) $(KRB5LIBS)
diff --git a/source/torture/smbiconv.c b/source/torture/smbiconv.c
new file mode 100644 (file)
index 0000000..ce21a09
--- /dev/null
@@ -0,0 +1,243 @@
+/* 
+   Unix SMB/CIFS implementation.
+   Charset module tester
+
+   Copyright (C) Jelmer Vernooij 2003
+   Based on iconv/icon_prog.c from the GNU C Library, 
+      Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
+
+   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 2 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, write to the Free Software
+   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+*/
+
+#include "includes.h"
+
+static int
+process_block (smb_iconv_t cd, char *addr, size_t len, FILE *output)
+{
+#define OUTBUF_SIZE    32768
+  const char *start = addr;
+  char outbuf[OUTBUF_SIZE];
+  char *outptr;
+  size_t outlen;
+  size_t n;
+
+  while (len > 0)
+    {
+      outptr = outbuf;
+      outlen = OUTBUF_SIZE;
+      n = smb_iconv (cd, &addr, &len, &outptr, &outlen);
+
+      if (outptr != outbuf)
+       {
+         /* We have something to write out.  */
+         int errno_save = errno;
+
+         if (fwrite (outbuf, 1, outptr - outbuf, output)
+             < (size_t) (outptr - outbuf)
+             || ferror (output))
+           {
+             /* Error occurred while printing the result.  */
+             DEBUG (0, ("conversion stopped due to problem in writing the output"));
+             return -1;
+           }
+
+         errno = errno_save;
+       }
+
+      if (errno != E2BIG)
+       {
+         /* iconv() ran into a problem.  */
+         switch (errno)
+           {
+           case EILSEQ:
+             DEBUG(0,("illegal input sequence at position %ld", 
+                    (long) (addr - start)));
+             break;
+           case EINVAL:
+             DEBUG(0, ("\
+incomplete character or shift sequence at end of buffer"));
+             break;
+           case EBADF:
+             DEBUG(0, ("internal error (illegal descriptor)"));
+             break;
+           default:
+             DEBUG(0, ("unknown iconv() error %d", errno));
+             break;
+           }
+
+         return -1;
+       }
+    }
+
+  return 0;
+}
+
+
+static int
+process_fd (iconv_t cd, int fd, FILE *output)
+{
+  /* we have a problem with reading from a descriptor since we must not
+     provide the iconv() function an incomplete character or shift
+     sequence at the end of the buffer.  Since we have to deal with
+     arbitrary encodings we must read the whole text in a buffer and
+     process it in one step.  */
+  static char *inbuf = NULL;
+  static size_t maxlen = 0;
+  char *inptr = NULL;
+  size_t actlen = 0;
+
+  while (actlen < maxlen)
+    {
+      ssize_t n = read (fd, inptr, maxlen - actlen);
+
+      if (n == 0)
+       /* No more text to read.  */
+       break;
+
+      if (n == -1)
+       {
+         /* Error while reading.  */
+         DEBUG(0, ("error while reading the input"));
+         return -1;
+       }
+
+      inptr += n;
+      actlen += n;
+    }
+
+  if (actlen == maxlen)
+    while (1)
+      {
+       ssize_t n;
+       char *new_inbuf;
+
+       /* Increase the buffer.  */
+       new_inbuf = (char *) realloc (inbuf, maxlen + 32768);
+       if (new_inbuf == NULL)
+         {
+           DEBUG(0, ("unable to allocate buffer for input"));
+           return -1;
+         }
+       inbuf = new_inbuf;
+       maxlen += 32768;
+       inptr = inbuf + actlen;
+
+       do
+         {
+           n = read (fd, inptr, maxlen - actlen);
+
+           if (n == 0)
+             /* No more text to read.  */
+             break;
+
+           if (n == -1)
+             {
+               /* Error while reading.  */
+               DEBUG(0, ("error while reading the input"));
+               return -1;
+             }
+
+           inptr += n;
+           actlen += n;
+         }
+       while (actlen < maxlen);
+
+       if (n == 0)
+         /* Break again so we leave both loops.  */
+         break;
+      }
+
+  /* Now we have all the input in the buffer.  Process it in one run.  */
+  return process_block (cd, inbuf, actlen, output);
+}
+
+/* Main function */
+
+int main(int argc, char *argv[])
+{
+       const char *file = NULL;
+       char *from = "";
+       char *to = "";
+       char *output = NULL;
+       char *preload = NULL;
+       FILE *out = stdout;
+       int fd;
+       smb_iconv_t cd;
+
+       /* make sure the vars that get altered (4th field) are in
+          a fixed location or certain compilers complain */
+       poptContext pc;
+       struct poptOption long_options[] = {
+               POPT_AUTOHELP
+               { "from-code", 'f', POPT_ARG_STRING, &from, 0, "Encoding of original text" },
+               { "to-code", 't', POPT_ARG_STRING, &to, 0, "Encoding for output" },
+               { "output", 'o', POPT_ARG_STRING, &output, 0, "Write output to this file" },
+               { "preload-modules", 'p', POPT_ARG_STRING, &preload, 0, "Modules to load" },
+               POPT_COMMON_SAMBA
+               POPT_TABLEEND
+       };
+
+       setlinebuf(stdout);
+
+       pc = poptGetContext("smbiconv", argc, (const char **) argv,
+                           long_options, 0);
+
+       poptSetOtherOptionHelp(pc, "[FILE] ...");
+       
+       while(poptGetNextOpt(pc) != -1);
+
+       if(preload)smb_load_modules(str_list_make(preload, NULL));
+
+       if(output) {
+               output = fopen(output, "w");
+
+               if(!output) {
+                       DEBUG(0, ("Can't open output file '%s': %s, exiting...\n", output, strerror(errno)));
+                       return 1;
+               }
+       }
+
+       /* the following functions are part of the Samba debugging
+          facilities.  See lib/debug.c */
+       setup_logging("smbiconv", True);
+
+       cd = smb_iconv_open(to, from);
+       if((int)cd == -1) {
+               DEBUG(0,("unable to find from or to encoding, exiting...\n"));
+               return 1;
+       }
+
+       while((file = poptGetArg(pc))) {
+               if(strcmp(file, "-") == 0) fd = 0;
+               else {
+                       fd = open(file, O_RDONLY);
+                       
+                       if(!fd) {
+                               DEBUG(0, ("Can't open input file '%s': %s, ignoring...\n", file, strerror(errno)));
+                               continue;
+                       }
+               }
+
+               /* Loop thru all arguments */
+               process_fd(cd, fd, stdout);
+
+               close(fd);
+       }
+       poptFreeContext(pc);
+
+       fclose(out);
+
+       return 0;
+}