vczip.c revision 3f54fd611f536639ec30dd53c48e5ec1897cc7d9
0N/A/***********************************************************************
2362N/A* *
0N/A* This software is part of the ast package *
0N/A* Copyright (c) 2003-2011 AT&T Intellectual Property *
0N/A* and is licensed under the *
0N/A* Eclipse Public License, Version 1.0 *
2362N/A* by AT&T Intellectual Property *
0N/A* *
2362N/A* A copy of the License is available at *
0N/A* http://www.eclipse.org/org/documents/epl-v10.html *
0N/A* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
0N/A* *
0N/A* Information and Software Systems Research *
0N/A* AT&T Research *
0N/A* Florham Park NJ *
0N/A* *
0N/A* Phong Vo <kpv@research.att.com> *
0N/A* Glenn Fowler <gsf@research.att.com> *
0N/A* *
0N/A***********************************************************************/
2362N/A/* Command to encode and decode with Vcodex methods.
2362N/A**
2362N/A** Written by Kiem-Phong Vo (09/06/2003 - ILNGUYEN)
0N/A*/
0N/A
0N/A#if _PACKAGE_ast
0N/A
0N/A#define UNZIP ((char*)0)
0N/A#define DISABLED ((char*)disabled)
0N/A#define DFLTZIP "delta,huffgroup"
0N/A#define ALIASES "lib/vcodex/aliases"
0N/A#define VCZIPRC ".vcziprc"
0N/A#define VCZIP "vczip"
0N/A
0N/Astatic const char usage[] =
0N/A"[-?\n@(#)$Id: vczip (AT&T Research) 2009-10-01 $\n]"
0N/AUSAGE_LICENSE
0N/A"[+NAME?vczip - vcodex method encode/decode filter]"
0N/A"[+DESCRIPTION?\bvczip\b is a filter that decodes the standard input "
0N/A "and/or encodes the standard output. The \b--method\b option specifies "
0N/A "the encoding. The default encoding is \b--method=" DFLTZIP "\b. The "
0N/A "method is automatically determined when decoding.]"
0N/A"[+?For delta methods the \asource\a operand optionally specifies the "
0N/A "file to delta against. If \asource\a is omitted then the input file is "
0N/A "simply compressed. Delta-encoded data must be decoded with the same "
0N/A "\asource\a.]"
0N/A"[+?Method aliases may be defined in \b../" ALIASES "\b in one of the "
0N/A "directories on \b$PATH\b, or in \b$HOME/" VCZIPRC "\b, searched in "
0N/A "order. Each alias is a \aname=value\a pair where \avalue\a is a "
0N/A "\b--method\b option value, described below. Method names are searched "
0N/A "before alias names.]"
0N/A"[i:input?Input data is read from \afile\a instead of the standard "
0N/A "input.]:[file]"
0N/A"[m:method|encode?Set the transformation method from the \b,\b (or \b^\b) "
0N/A "separated list of \amethod\a[.\aarg\a]] elements, where \amethod\a is "
0N/A "a method alias or primitive method, \aarg\a is an optional method "
0N/A "specific argument, and \b-\b denotes the default argument. Parenthesized "
0N/A "values are implementation details. The \alibvcodex\a (\b-catalog\b) "
0N/A "denotes a method supplied by the default library. Otherwise the method "
0N/A "is a separate plugin; that plugin will be required to decode any "
0N/A "encoded data. The primitive methods and method aliases "
0N/A "are:]:[method[.arg]][,method[.arg]]...]]:=" DFLTZIP "]"
0N/A "{\fvcodex\f[vcdiff|ietf?Encode as defined in IETF RFC3284.]}"
0N/A"[o:output?Output data is written to \afile\a instead of the standard "
0N/A "output.]:[file]"
0N/A"[p:plain?Do not encode transformation information in the data. This means "
0N/A "the transform must be explicitly supplied to decode.]"
0N/A"[q:identify?Identify the standard input encoding and write the "
0N/A "\b--method\b transformation string on the standard output. "
0N/A "If the standard input is not vczip encoded then nothing is "
0N/A "printed.]"
0N/A"[t:transform?Apply the \bcodex\b(3) data transform around the "
0N/A "\bvcodex\b(3) transform. A codex transform is a catenation of the "
0N/A "following methods, each method prefixed by \b<\b to decode the input or "
0N/A "\b>\b to encode the output. Method arguments, if any, must be prefixed "
0N/A "by \b-\b. The method are:]:[[<>]]method[-arg...]]...]"
0N/A "{\fcodex\f}"
0N/A"[u:undo|decode?Decode data.]"
0N/A"[v:verbose?List the compresses size on the standard error.]"
0N/A"[w:window?Set the data partition window size to \awindow\a. "
0N/A "\amethod\a specifies an optional window matching "
0N/A "method. The window methods are:]:[window[,method]]]"
0N/A "{\fwindows\f}"
0N/A"[d:vcdiff|ietf?Encode as defined in IETF RFC3284. Obsolete -- use "
0N/A "--method=ietf.]"
0N/A"[D:debug?Set the debug trace level to \alevel\a. Higher levels produce "
0N/A "more output.]:[level]"
0N/A"[M:move?Use sfmove() for io.]"
0N/A"[P:pause?Debug: print the pid and sleep(10); then continue processing.]"
0N/A
0N/A"\n"
0N/A"\n[ source ] < input > output\n"
0N/A"\n"
0N/A
0N/A"[+FILES]"
0N/A "{"
0N/A "[+../" ALIASES "?\b--method\b \aname=value\a alias file, found "
0N/A "on \b$PATH\b.]"
0N/A "}"
0N/A"[+SEE ALSO?\bcodex\b(1), \bcodex\b(3), \bvcodex\b(3)]"
0N/A;
0N/A
0N/A#include <ast.h>
0N/A#include <error.h>
0N/A#include <ccode.h>
0N/A#include <ctype.h>
0N/A#include <vcodex.h>
0N/A#include <codex.h>
0N/A
0N/Astatic const char disabled[] = "disabled";
0N/A
0N/Astatic int
0N/Aoptmethod(Void_t* obj, char* name, char* desc, Void_t* handle)
0N/A{
0N/A Sfio_t* sp = (Sfio_t*)handle;
0N/A Vcmethod_t* mt = (Vcmethod_t*)obj;
0N/A int i;
0N/A
0N/A sfprintf(sp, "[+%s?", name);
0N/A optesc(sp, desc, 0);
0N/A if(mt->args)
0N/A { sfprintf(sp, " The arguments are:]{");
0N/A for(i = 0; mt->args[i].desc; i++)
0N/A { sfprintf(sp, "[+%s?", mt->args[i].name ? mt->args[i].name : "-");
0N/A if(mt->args[i].desc)
0N/A optesc(sp, mt->args[i].desc, 0);
0N/A sfputc(sp, ']');
0N/A if(!mt->args[i].name)
0N/A break;
0N/A }
0N/A }
0N/A else
0N/A sfputc(sp, ']');
0N/A if(mt->about)
0N/A { if(!mt->args)
0N/A sfputc(sp, '{');
0N/A sfprintf(sp, "%s}", mt->about);
0N/A }
0N/A else if(mt->args)
0N/A sfputc(sp, '}');
0N/A return 0;
0N/A}
0N/A
0N/Astatic int
0N/Aoptalias(Void_t* obj, char* name, char* desc, Void_t* handle)
0N/A{
0N/A Sfio_t* sp = (Sfio_t*)handle;
0N/A
0N/A sfprintf(sp, "[+%s?Equivalent to \b%s\b.]", name, desc);
0N/A return 0;
0N/A}
0N/A
0N/Astatic int
0N/Aoptwindow(Void_t* obj, char* name, char* desc, Void_t* handle)
0N/A{
0N/A Sfio_t* sp = (Sfio_t*)handle;
0N/A
0N/A sfprintf(sp, "[+%s?", name);
0N/A optesc(sp, desc, 0);
0N/A sfprintf(sp, "]");
0N/A return 0;
0N/A}
0N/A
0N/A/*
0N/A * optget() info discipline function
0N/A */
0N/A
0N/Astatic int
0N/Aoptinfo(Opt_t* op, Sfio_t* sp, const char* s, Optdisc_t* dp)
0N/A{
0N/A register Codexmeth_t* meth;
0N/A register const char* p;
0N/A register int c;
0N/A
0N/A switch (*s)
0N/A {
0N/A case 'c':
0N/A /* codex methods */
0N/A for (meth = codexlist(NiL); meth; meth = codexlist(meth))
0N/A {
0N/A sfprintf(sp, "[+%s\b", meth->name);
0N/A p = " (";
0N/A if (meth->identf)
0N/A {
0N/A sfprintf(sp, "%sident", p);
0N/A p = ",";
0N/A }
0N/A if (!(meth->flags & CODEX_ENCODE))
0N/A {
0N/A sfprintf(sp, "%sdecode", p);
0N/A p = ",";
0N/A }
0N/A if (*p == ',')
0N/A sfputc(sp, ')');
0N/A sfputc(sp, '?');
0N/A p = meth->description;
0N/A while (c = *p++)
0N/A {
0N/A if (c == ']')
0N/A sfputc(sp, c);
0N/A sfputc(sp, c);
0N/A }
0N/A sfputc(sp, ']');
0N/A if ((p = meth->options) || meth->optionsf)
0N/A {
0N/A sfprintf(sp, "{\n");
0N/A if (meth->optionsf)
0N/A (*meth->optionsf)(meth, sp);
0N/A if (p)
0N/A sfprintf(sp, "%s", p);
0N/A sfprintf(sp, "\n}");
0N/A }
0N/A }
0N/A break;
0N/A case 'v':
0N/A /* vcodex methods */
0N/A vcwalkmeth(optmethod, sp);
0N/A /* aliases */
0N/A vcwalkalias(optalias, sp);
0N/A break;
0N/A case 'w':
0N/A /* vcodex window methods */
0N/A vcwwalkmeth(optwindow, sp);
0N/A break;
0N/A }
0N/A return 0;
0N/A}
0N/A
0N/Astatic void
0N/Avcsferror(const char* mesg)
0N/A{
0N/A error(2, "%s", mesg);
0N/A}
0N/A
0N/A/*
0N/A * apply the codex and/or vcodex transforms to a single input/output pair
0N/A */
0N/A
0N/Astatic void
0N/Aapply(int action, const char* vt, Vcsfdata_t* vcodexdisc, const char* ct, Codexdisc_t* codexdisc, const char* input, const char* source, const char* output, void* buf, size_t bufsize, Sfoff_t donez, Sfoff_t lastz)
0N/A{
0N/A Sfio_t* ip;
0N/A Sfio_t* op;
0N/A ssize_t n;
0N/A
0N/A /*
0N/A * set up the sfio input stream
0N/A */
0N/A
0N/A if (!input || !*input || streq(input, "-") || streq(input, "/dev/stdin") || streq(input, "/dev/fd/0"))
0N/A {
0N/A input = "/dev/stdin";
0N/A ip = sfstdin;
0N/A sfset(ip, SF_SHARE, 0);
0N/A sfopen(ip, NiL, "rb");
0N/A }
0N/A else if (!(ip = sfopen(NiL, input, "rb")))
0N/A {
0N/A error(ERROR_SYSTEM|2, "%s: cannot read", input);
0N/A return;
0N/A }
0N/A
0N/A /*
0N/A * set up the sfio output stream
0N/A */
0N/A
0N/A if (!action)
0N/A {
0N/A sfprintf(sfstdout, "%s: ", input);
0N/A output = "/dev/null";
0N/A codexdisc->identify = sfstdout;
0N/A }
0N/A if (!output || !*output || streq(output, "-") || streq(output, "/dev/stdout") || streq(output, "/dev/fd/1"))
0N/A {
0N/A output = "/dev/stdout";
0N/A op = sfstdout;
0N/A sfset(op, SF_SHARE, 0);
0N/A sfopen(op, NiL, "wb");
0N/A }
0N/A else if (!(op = sfopen(NiL, output, "wb")))
0N/A {
0N/A error(ERROR_SYSTEM|2, "%s: cannot write", output);
0N/A if (ip != sfstdin)
0N/A sfclose(ip);
0N/A return;
0N/A }
0N/A
0N/A /*
0N/A * check codex sfio discipline
0N/A */
0N/A
0N/A error(-1, "AHA action=%s input=%s source=%s output=%s vt=%s ct=%s", action == VC_ENCODE ? "encode" : "decode", input, source, output, vt, ct);
0N/A if (ct != DISABLED)
0N/A {
0N/A if ((n = codex(ip, op, ct, action == VC_ENCODE ? CODEX_ENCODE : CODEX_DECODE, codexdisc, NiL)) < 0)
0N/A error(3, "%s: cannot push codex io stream discipline", input);
0N/A if (!action && n > 0)
0N/A sfprintf(sfstdout, ",");
2014N/A }
0N/A
0N/A /*
0N/A * check vcodex sfio discipline
0N/A */
0N/A
0N/A if (vt != DISABLED)
0N/A {
0N/A vcodexdisc->trans = (char*)vt;
0N/A vcodexdisc->source = (char*)source;
0N/A if (!vcsfio(action == VC_ENCODE ? op : ip, vcodexdisc, action))
0N/A error(3, "%s: cannot push vcodex io stream discipline", input);
0N/A else if (!action)
0N/A sfprintf(sfstdout, "%s", vcodexdisc->trans);
0N/A }
2014N/A
0N/A /*
0N/A * copy from ip to op
0N/A */
0N/A
0N/A if (action)
0N/A {
0N/A if (buf)
0N/A for (;;)
0N/A {
0N/A if ((n = sfread(ip, buf, bufsize)) <= 0)
0N/A {
0N/A if (n < 0)
0N/A error(ERROR_SYSTEM|2, "%s: read error", input);
0N/A break;
0N/A }
0N/A if (donez >= 0) /* verbose mode */
0N/A {
0N/A if (donez >= lastz + 64 * (bufsize > 1024*1024 ? bufsize : 1024*1024))
0N/A {
0N/A sfprintf(sfstderr, "done %10I*d %s\n", sizeof(donez), donez, output);
0N/A lastz = donez;
0N/A }
2014N/A donez += n;
0N/A }
0N/A if ((n = sfwrite(op, buf, n)) < 0)
0N/A {
0N/A error(ERROR_SYSTEM|2, "%s: write error", output);
0N/A break;
0N/A }
0N/A }
0N/A else
0N/A {
0N/A sfmove(ip, op, SF_UNBOUND, -1);
0N/A if (!sfeof(ip))
0N/A error(ERROR_SYSTEM|2, "%s: read error", input);
0N/A else if (sfsync(op) || sferror(op))
0N/A error(ERROR_SYSTEM|2, "%s: write error", output);
0N/A }
0N/A }
0N/A else
0N/A sfprintf(sfstdout, "\n");
0N/A if (ip != sfstdin)
0N/A sfclose(ip);
0N/A if (op != sfstdout)
0N/A sfclose(op);
0N/A}
0N/A
0N/Aint
0N/Amain(int argc, char** argv)
0N/A{
0N/A Vcchar_t *buf;
0N/A size_t bufsize;
0N/A int action; /* default is encoding */
0N/A int move = 0; /* sfmove() */
0N/A int vczip; /* are we vczip? */
0N/A int c;
0N/A char* vt; /* vcodex transform */
0N/A char* ct; /* codex transform */
0N/A Sfio_t* cs; /* codex transform buf */
0N/A Sfoff_t donez = -1, lastz = -1; /* amount processed */
0N/A Optdisc_t optdisc; /* optget() dscipline */
0N/A char name[256]; /* method name buffer */
0N/A
0N/A /* NOTE: disciplines may be accessed after main() returns */
0N/A
0N/A static Vcsfdata_t vcodexdisc; /* vcodex discipline */
0N/A static Codexdisc_t codexdisc; /* codex discipline */
0N/A
0N/A error_info.id = (ct = strrchr(argv[0], '/')) ? (ct + 1) : argv[0];
0N/A if (!(cs = sfstropen()))
0N/A error(ERROR_SYSTEM|3, "out of space");
0N/A action = VC_ENCODE;
0N/A ct = error_info.id;
0N/A vt = name;
0N/A while (vt < &name[sizeof(name)-1] && (c = tolower(*ct++)))
0N/A if (c == 'u' && tolower(*ct) == 'n')
0N/A { action = VC_DECODE;
0N/A ct++;
0N/A }
0N/A else
0N/A *vt++ = c;
0N/A *vt = 0;
4632N/A vczip = streq(name, VCZIP);
4632N/A if (!vczip && codexmeth(name))
0N/A {
0N/A vt = DISABLED;
0N/A sfprintf(cs, "%c%s", action == VC_DECODE ? '<' : '>', name);
0N/A }
0N/A else if (action == VC_DECODE)
0N/A vt = UNZIP;
0N/A else
0N/A vt = DFLTZIP;
0N/A memset(&vcodexdisc, 0, sizeof(vcodexdisc));
0N/A vcodexdisc.errorf = vcsferror;
0N/A codexinit(&codexdisc, errorf);
0N/A optinit(&optdisc, optinfo);
0N/A for (;;)
0N/A {
0N/A switch (optget(argv, usage))
0N/A {
0N/A case 'd':
0N/A vcodexdisc.type = VCSF_VCDIFF;
0N/A continue;
0N/A case 'i':
0N/A if (sfopen(sfstdin, opt_info.arg, "r") != sfstdin)
0N/A error(ERROR_SYSTEM|3, "%s: cannot read", opt_info.arg);
0N/A continue;
0N/A case 'm':
0N/A if (streq(opt_info.arg, "ietf") || streq(opt_info.arg, "vcdiff"))
0N/A vcodexdisc.type = VCSF_VCDIFF;
0N/A else if (streq(opt_info.arg, "-"))
0N/A vt = DISABLED;
0N/A else
0N/A vt = opt_info.arg;
0N/A continue;
0N/A case 'o':
0N/A if (sfopen(sfstdout, opt_info.arg, "w") != sfstdout)
0N/A error(ERROR_SYSTEM|3, "%s: cannot write", opt_info.arg);
0N/A continue;
0N/A case 'p':
0N/A vcodexdisc.type = VCSF_PLAIN;
0N/A continue;
0N/A case 'q':
0N/A action = 0;
0N/A continue;
0N/A case 't':
0N/A if (*opt_info.arg != '<' && *opt_info.arg != '>')
0N/A sfprintf(cs, "%c", action == VC_DECODE ? '<' : '>');
0N/A sfprintf(cs, "%s", opt_info.arg);
0N/A continue;
0N/A case 'u':
0N/A action = VC_DECODE;
0N/A if (vt)
0N/A vt = UNZIP;
0N/A continue;
0N/A case 'v':
0N/A donez = lastz = 0;
0N/A continue;
0N/A case 'w':
0N/A vcodexdisc.window = opt_info.arg;
0N/A continue;
0N/A case 'D':
0N/A error_info.trace = -(int)opt_info.num;
0N/A continue;
0N/A case 'M':
0N/A move = 1;
0N/A continue;
0N/A case 'P':
0N/A error(1, "pid %d", getpid());
0N/A sleep(10);
0N/A continue;
0N/A case ':':
0N/A error(2, "%s", opt_info.arg);
0N/A continue;
0N/A case '?':
0N/A error(ERROR_USAGE|4, "%s", opt_info.arg);
0N/A continue;
0N/A }
0N/A break;
0N/A }
0N/A argv += opt_info.index;
0N/A if (error_info.errors || argv[0] && argv[1])
0N/A error(ERROR_USAGE|4, "%s", optusage(NiL));
0N/A buf = 0;
0N/A if (!move)
0N/A for (bufsize = 1024*1024; bufsize > 0; bufsize /= 2)
0N/A if (buf = malloc(bufsize))
0N/A break;
0N/A if (!(ct = sfstruse(cs)))
0N/A error(ERROR_SYSTEM|3, "out of space");
0N/A if (streq(ct+1, "-"))
0N/A ct = DISABLED;
0N/A else if (!*(ct+1))
0N/A ct = UNZIP;
0N/A apply(action, vt, &vcodexdisc, ct, &codexdisc, NiL, *argv, NiL, buf, bufsize, donez, lastz);
0N/A return error_info.errors != 0;
0N/A}
0N/A
0N/A#else
0N/A
0N/A#include "vchdr.h"
0N/A
0N/A#define PR_METHOD ((Void_t*)1)
0N/A#define PR_ALIAS ((Void_t*)2)
0N/A
0N/A#define DFLTZIP "sieve.delta,bwt,mtf,rle.0,huffgroup"
0N/A
0N/Astatic char *Mesg[] =
0N/A{
0N/A "vczip [-Arguments] [SourceFile] < Input > Output\n",
0N/A
0N/A "\nBelow are the standard 'Arguments':\n",
0N/A "-?: This prints this message.\n",
0N/A "-i[InputFile]: This redefines the standard 'Input' to be 'InputFile'.\n",
0N/A "-o[OutputFile]: This redefines the standard 'Output' to be 'OutputFile'.\n",
0N/A "-w[size[.alg]]: This argument is ignored during decoding (i.e., -u).\n",
0N/A " On encoding, it defines the window processing for a large input file.\n",
0N/A " 'size' is the window size, i.e., the size to break the input file into\n",
0N/A " chunks for processing. Units 'k' and 'm' mean kilo and megabytes.\n",
0N/A " 'alg' selects a windowing matching algorithm for delta compression:\n",
0N/A " p: matching windows by a prefix matching method (default) or\n",
0N/A " m: matching windows by simply mirroring file positions.\n",
0N/A "-E[type]: This translates between EBCDIC and ASCII during encoding or\n",
0N/A " decoding via the given 'type'. See also the 'map' transform below.\n",
0N/A "-vcdiff: This encodes data as defined in IETF RFC3284.\n",
0N/A "-plain: This means that the transformed data will not have information\n",
0N/A " about the transformation used for encoding. So, that information\n",
0N/A " will have to be supplied explicitly on decoding.\n",
0N/A "-u[transformation]: This decodes some previously encoded data.\n",
0N/A " If 'transformation' is not empty, it is the transformation used\n",
0N/A " to encode data. The data to be decoded will be treated as if it\n",
0N/A " was encoded with '-plain'. That is, '-utransformation' is the same\n",
0N/A " as '-u -plain -mtransformation'.\n",
0N/A "-m[transformation]: A 'transformation' is defined as a comma-separated list:\n",
0N/A " transform1[.arg11.arg12...],transform2[.arg21.arg22],...'\n",
0N/A " For example, '-mbwt,mtf,rle.0,huffgroup' defines a transformation that\n"
0N/A " compresses data based on the Burrows-Wheeler transform. When the first\n",
0N/A " transform in a transformation is a delta compressor such as 'delta' or\n",
0N/A " 'sieve', a 'SourceFile' can help enhancing compression. In that case,\n"
0N/A " the same source file must be given on both encoding and decoding.\n",
0N/A 0
0N/A};
0N/A
0N/Astatic char *Program; /* name of executable */
0N/A
0N/Astatic void error(const char* mesg, ...)
0N/A{
0N/A va_list args;
0N/A va_start(args, mesg);
0N/A sfprintf(sfstderr,"%s: ",Program);
0N/A sfvprintf(sfstderr,mesg,args);
0N/A sfprintf(sfstderr,"\n");
0N/A va_end(args);
0N/A exit(1);
0N/A}
0N/A
0N/Astatic void vcsferror(const char* mesg)
0N/A{ sfprintf(sfstderr,"%s: %s\n", Program, mesg);
0N/A}
0N/A
0N/Astatic int printdesc(Void_t* obj, char* name, char* value, Void_t* type)
0N/A{
0N/A Vcmtarg_t *arg;
0N/A
0N/A if(type == PR_METHOD)
0N/A { if(!obj)
0N/A return -1;
0N/A sfprintf(sfstderr,"%s: %s.\n", name, value);
0N/A for(arg = ((Vcmethod_t*)obj)->args; arg && arg->name; ++arg)
0N/A sfprintf(sfstderr, " %12s: %s.\n", arg->name, arg->desc);
0N/A if(arg && !arg->name && arg->desc)
0N/A sfprintf(sfstderr, " %12s: %s.\n", "None", arg->desc);
0N/A }
0N/A else if(type == PR_ALIAS)
0N/A sfprintf(sfstderr, "-%s: %s.\n", name, value);
0N/A else return -1;
0N/A
0N/A return 0;
0N/A}
0N/A
0N/Astatic void printmesg()
0N/A{
0N/A int i;
0N/A
0N/A for(i = 0; Mesg[i]; ++i)
0N/A sfprintf(sfstderr,"%s", Mesg[i]);
0N/A
0N/A sfprintf(sfstderr, "\nThe default transformation is %s.\n", DFLTZIP);
0N/A sfprintf(sfstderr, "Below are short-hands for common transformations:\n");
0N/A vcwalkalias(printdesc, PR_ALIAS);
0N/A
0N/A /* print the set of primitive methods */
0N/A sfprintf(sfstderr, "\nBelow are the available transforms and their arguments:\n");
0N/A vcwalkmeth(printdesc, PR_METHOD);
0N/A}
0N/A
0N/Aint
0N/Amain(int argc, char** argv)
0N/A{
0N/A Vcchar_t *data, *dt;
0N/A ssize_t dtsz, n;
0N/A char buf[1024];
0N/A Vcsfdata_t sfdt; /* data passed to vcsf */
0N/A Vcsfio_t *sfio = NIL(Vcsfio_t*); /* IO handle */
0N/A Vcodex_t *eavc = NIL(Vcodex_t*); /* ebcdic <-> ascii */
0N/A int action = VC_ENCODE; /* default is encoding */
0N/A int type = 0; /* type of processing */
0N/A char *trans = DFLTZIP; /* transformation spec */
0N/A char *window = NIL(char*); /* window specification */
0N/A ssize_t donez = -1, lastz = -1; /* amount processed */
0N/A
0N/A /* get program name */
0N/A for(Program = argv[0]+strlen(argv[0]); Program > argv[0]; --Program)
0N/A if(Program[-1] == '/')
0N/A break;
0N/A
0N/A /* make list of default aliases */
0N/A vcaddalias(Dfltalias);
0N/A
0N/A for(; argc > 1 && argv[1][0] == '-'; argc--, argv++)
0N/A { switch(argv[1][1])
0N/A {
0N/A case '?':
0N/A printmesg();
0N/A return 0;
0N/A case 'o':
0N/A case 'i':
0N/A case 'S':
0N/A if(argv[1][1] == 'S')
0N/A ; /* state file has been made obsolete */
0N/A else if(argv[1][2] == 0)
0N/A error("No file was given for %s.", argv[1]);
0N/A else if(argv[1][1] == 'i')
0N/A { if(sfopen(sfstdin, argv[1]+2, "r") != sfstdin)
0N/A error("Can't open input file '%s'.", argv[1]+2);
0N/A }
0N/A else
0N/A { if(sfopen(sfstdout, argv[1]+2, "w") != sfstdout)
0N/A error("Can't open output file '%s'.", argv[1]+2);
0N/A }
0N/A break;
0N/A case 'w':
0N/A window = argv[1]+2;
0N/A break;
0N/A case 'E': /* ebcdic <-> ascii translation */
0N/A if(eavc)
0N/A vcclose(eavc);
0N/A if(!(eavc = vcopen(0, Vcmap, argv[1]+2, 0, VC_ENCODE)) )
0N/A error("'%s' specifies bad translation mode.", argv[1]);
0N/A break;
0N/A case 'v':
0N/A if(strcmp(argv[1]+1,"vcdiff") == 0)
0N/A type = VCSF_VCDIFF;
0N/A else goto dflt_arg;
0N/A break;
0N/A case 'p':
0N/A if(strcmp(argv[1]+1,"plain") == 0)
0N/A type = VCSF_PLAIN;
0N/A else goto dflt_arg;
0N/A break;
0N/A case 'u':
0N/A action = VC_DECODE;
0N/A if(argv[1][2])
0N/A { type = VCSF_PLAIN;
0N/A trans = argv[1]+2;
0N/A }
0N/A break;
0N/A case 'm':
0N/A trans = argv[1]+2;
0N/A break;
0N/A case 'V':
0N/A donez = lastz = 0;
0N/A break;
0N/A default:
0N/A dflt_arg:
0N/A trans = vcgetalias(argv[1]+1, buf, sizeof(buf));
0N/A if(!trans || trans == argv[1]+1)
0N/A error("'%s' is invalid. Use '-?' for help.", argv[1]);
0N/A }
0N/A }
0N/A
0N/A if(strcmp(Program, "vcunzip") == 0)
0N/A action = VC_DECODE;
0N/A else if(strncmp(Program, "vczip", 5) != 0 )
0N/A error("Program name should be vczip or vcunzip");
0N/A
0N/A if(sfsize(sfstdin) == 0) /* a potentially empty data stream */
0N/A { Void_t *data;
0N/A
0N/A /* see if this is just a pipe showing up initially empty */
0N/A if(!(data = sfreserve(sfstdin, -1, SF_LOCKR)) || sfvalue(sfstdin) == 0 )
0N/A return 0; /* empty data transforms to empty output */
0N/A else sfread(sfstdin, data, 0); /* reset stream for normal transformation */
0N/A }
0N/A
0N/A /* turn off share mode to avoid peeking on unseekable devices */
0N/A sfset(sfstdin, SF_SHARE, 0);
0N/A sfset(sfstdout, SF_SHARE, 0);
0N/A
0N/A#if _WIN32 /* on Windows systems, use binary mode for file I/O */
0N/A setmode(0, O_BINARY);
0N/A setmode(1, O_BINARY);
0N/A#endif
0N/A
0N/A /* open stream for data processing */
0N/A sfdt.type = type;
0N/A sfdt.trans = trans;
0N/A sfdt.source = argc == 2 ? argv[1] : NIL(char*);
0N/A sfdt.window = window;
0N/A sfdt.errorf = vcsferror;
0N/A if(!(sfio = vcsfio(action == VC_ENCODE ? sfstdout : sfstdin, &sfdt, action)) )
0N/A error("Can't set up stream to encode or decode data.");
0N/A
0N/A /* get buffer for IO */
0N/A data = NIL(Void_t*);
0N/A for(dtsz = 1024*1024; dtsz > 0; dtsz /= 2)
0N/A if((data = (Void_t*)malloc(dtsz)) )
0N/A break;
0N/A if(!data)
0N/A error("Can't allocate I/O buffer.");
0N/A
0N/A for(;;)
0N/A { if(action == VC_DECODE) /* get a chunk of data */
0N/A n = vcsfread(sfio, data, dtsz);
0N/A else n = sfread(sfstdin, data, dtsz);
0N/A if(n <= 0)
0N/A break;
0N/A
0N/A if(donez >= 0) /* verbose mode */
0N/A { if(donez >= lastz + 64*(dtsz > 1024*1024 ? dtsz : 1024*1024))
0N/A { sfprintf(sfstderr, "Done %d\n", donez);
0N/A lastz = donez;
0N/A }
0N/A donez += n;
0N/A }
0N/A
0N/A if(!eavc) /* do any ascii <-> ebcdic mapping required */
0N/A dt = data;
0N/A else if((n = vcapply(eavc, data, n, &dt)) <= 0)
0N/A error("Byte mapping failed.");
0N/A
0N/A if(action == VC_DECODE) /* write out the data */
0N/A n = sfwrite(sfstdout, dt, n);
0N/A else n = vcsfwrite(sfio, dt, n);
0N/A if(n <= 0)
0N/A error("Error writing out data.");
0N/A }
0N/A vcsfclose(sfio);
0N/A
0N/A return 0;
0N/A}
0N/A
0N/A#endif
0N/A