tizen 2.4 release
[external/xdelta3.git] / xdelta3-main.h
1 /* xdelta3 - delta compression tools and library
2  * Copyright (C) 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
3  * 2009, 2010, 2011, 2012, 2013 Joshua P. MacDonald
4  *
5  *  This program is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU General Public License as published by
7  *  the Free Software Foundation; either version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This program is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU General Public License for more details.
14  *
15  *  You should have received a copy of the GNU General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  */
19
20 /* This is all the extra stuff you need for convenience to users in a
21  * command line application.  It contains these major components:
22  *
23  * 1. VCDIFF tools 2. external compression support (this is
24  * POSIX-specific).  3. a general read/write loop that handles all of
25  * the Xdelta decode/encode/VCDIFF-print functions 4. command-line
26  * interpreter 5. an Xdelta application header which stores default
27  * filename, external compression settings 6. output/error printing
28  * 7. basic file support and OS interface
29  */
30
31 /* TODO list: 1. do exact gzip-like filename, stdout handling.  make a
32  * .vcdiff extension, refuse to encode to stdout without -cf, etc.
33  * 2. Allow the user to add a comment string to the app header without
34  * disturbing the default behavior.
35  */
36
37 /* On error handling and printing:
38  *
39  * The xdelta library sets stream->msg to indicate what condition
40  * caused an internal failure, but many failures originate here and
41  * are printed here.  The return convention is 0 for success, as
42  * throughout Xdelta code, but special attention is required here for
43  * the operating system calls with different error handling.  See the
44  * main_file_* routines.  All errors in this file have a message
45  * printed at the time of occurance.  Since some of these calls occur
46  * within calls to the library, the error may end up being printed
47  * again with a more general error message.
48  */
49
50 /*********************************************************************/
51
52 #ifndef XD3_POSIX
53 #define XD3_POSIX 0
54 #endif
55 #ifndef XD3_STDIO
56 #define XD3_STDIO 0
57 #endif
58 #ifndef XD3_WIN32
59 #define XD3_WIN32 0
60 #endif
61 #ifndef NOT_MAIN
62 #define NOT_MAIN 0
63 #endif
64
65 /* Combines xd3_strerror() and strerror() */
66 const char* xd3_mainerror(int err_num);
67
68 #include "xdelta3-internal.h"
69
70 int
71 xsnprintf_func (char *str, int n, const char *fmt, ...)
72 {
73   va_list a;
74   int ret;
75   va_start (a, fmt);
76   ret = vsnprintf_func (str, n, fmt, a);
77   va_end (a);
78   if (ret < 0)
79     {
80       ret = n;
81     }
82   return ret;
83 }
84
85 /* If none are set, default to posix. */
86 #if (XD3_POSIX + XD3_STDIO + XD3_WIN32) == 0
87 #undef XD3_POSIX
88 #define XD3_POSIX 1
89 #endif
90
91 /* Handle externally-compressed inputs. */
92 #ifndef EXTERNAL_COMPRESSION
93 #define EXTERNAL_COMPRESSION 1
94 #endif
95
96 #define PRINTHDR_SPECIAL -4378291
97
98 /* The number of soft-config variables.  */
99 #define XD3_SOFTCFG_VARCNT 7
100
101 /* this is used as in XPR(NT XD3_LIB_ERRMSG (stream, ret)) to print an
102  * error message from the library. */
103 #define XD3_LIB_ERRMSG(stream, ret) "%s: %s\n", \
104     xd3_errstring (stream), xd3_mainerror (ret)
105
106 #if XD3_POSIX
107 #include <unistd.h> /* close, read, write... */
108 #include <sys/types.h>
109 #include <fcntl.h>
110 #endif
111
112 #ifndef _WIN32
113 #include <unistd.h> /* lots */
114 #include <sys/time.h> /* gettimeofday() */
115 #include <sys/stat.h> /* stat() and fstat() */
116 #else
117 #if defined(_MSC_VER)
118 #define strtoll _strtoi64
119 #endif
120 #include <sys/types.h>
121 #include <sys/stat.h>
122 #ifndef WIFEXITED
123 #   define WIFEXITED(stat)  (((*((int *) &(stat))) & 0xff) == 0)
124 #endif
125 #ifndef WEXITSTATUS
126 #   define WEXITSTATUS(stat) (((*((int *) &(stat))) >> 8) & 0xff)
127 #endif
128 #ifndef S_ISREG
129 //#   ifdef S_IFREG
130 //#       define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
131 //#   else
132 #       define S_ISREG(m) 1
133 //#   endif
134 #endif /* !S_ISREG */
135
136 // For standard input/output handles
137 static STARTUPINFO winStartupInfo;
138 #endif
139
140 /**********************************************************************
141  ENUMS and TYPES
142  *********************************************************************/
143
144 /* These flags (mainly pertaining to main_read() operations) are set
145  * in the main_file->flags variable.  All are related to with external
146  * decompression support.
147  *
148  * RD_FIRST causes the external decompression check when the input is
149  * first read.
150  *
151  * RD_NONEXTERNAL disables external decompression for reading a
152  * compressed input, in the case of Xdelta inputs.  Note: Xdelta is
153  * supported as an external compression type, which makes is the
154  * reason for this flag.  An example to justify this is: to create a
155  * delta between two files that are VCDIFF-compressed.  Two external
156  * Xdelta decoders are run to supply decompressed source and target
157  * inputs to the Xdelta encoder. */
158 typedef enum
159 {
160   RD_FIRST       = (1 << 0),
161   RD_NONEXTERNAL = (1 << 1),
162   RD_DECOMPSET   = (1 << 2),
163   RD_MAININPUT   = (1 << 3),
164 } xd3_read_flags;
165
166 /* Main commands.  For example, CMD_PRINTHDR is the "xdelta printhdr"
167  * command. */
168 typedef enum
169 {
170   CMD_NONE = 0,
171   CMD_PRINTHDR,
172   CMD_PRINTHDRS,
173   CMD_PRINTDELTA,
174   CMD_RECODE,
175   CMD_MERGE_ARG,
176   CMD_MERGE,
177 #if XD3_ENCODER
178   CMD_ENCODE,
179 #endif
180   CMD_DECODE,
181   CMD_TEST,
182   CMD_CONFIG,
183 } xd3_cmd;
184
185 #if XD3_ENCODER
186 #define CMD_DEFAULT CMD_ENCODE
187 #define IS_ENCODE(cmd) (cmd == CMD_ENCODE)
188 #else
189 #define CMD_DEFAULT CMD_DECODE
190 #define IS_ENCODE(cmd) (0)
191 #endif
192
193 typedef struct _main_merge       main_merge;
194 typedef struct _main_merge_list  main_merge_list;
195
196 /* Various strings and magic values used to detect and call external
197  * compression.  See below for examples. */
198 struct _main_extcomp
199 {
200   const char    *recomp_cmdname;
201   const char    *recomp_options;
202
203   const char    *decomp_cmdname;
204   const char    *decomp_options;
205
206   const char    *ident;
207   const char    *magic;
208   usize_t        magic_size;
209   int            flags;
210 };
211
212 /* Merge state: */
213
214 struct _main_merge_list
215 {
216   main_merge_list  *next;
217   main_merge_list  *prev;
218 };
219
220 struct _main_merge
221 {
222   const char *filename;
223
224   main_merge_list  link;
225 };
226
227 XD3_MAKELIST(main_merge_list,main_merge,link);
228
229 /* TODO: really need to put options in a struct so that internal
230  * callers can easily reset state. */
231
232 #define DEFAULT_VERBOSE 0
233
234 /* Program options: various command line flags and options. */
235 static int         option_stdout             = 0;
236 static int         option_force              = 0;
237 static int         option_verbose            = DEFAULT_VERBOSE;
238 static int         option_quiet              = 0;
239 static int         option_use_appheader      = 1;
240 static uint8_t*    option_appheader          = NULL;
241 static int         option_use_secondary      = 0;
242 static const char* option_secondary          = NULL;
243 static int         option_use_checksum       = 1;
244 static const char* option_smatch_config      = NULL;
245 static int         option_no_compress        = 0;
246 static int         option_no_output          = 0; /* do not write output */
247 static const char *option_source_filename    = NULL;
248
249 static int         option_level              = XD3_DEFAULT_LEVEL;
250 static usize_t     option_iopt_size          = XD3_DEFAULT_IOPT_SIZE;
251 static usize_t     option_winsize            = XD3_DEFAULT_WINSIZE;
252 /* Note: option_srcwinsz is restricted from [16Kb, 4Gb], because
253  * addresses in the large hash checksum are 32 bits.  The flag is read
254  * as xoff_t, so that 4Gb != 0. */
255 static xoff_t      option_srcwinsz           = XD3_DEFAULT_SRCWINSZ;
256 static usize_t     option_sprevsz            = XD3_DEFAULT_SPREVSZ;
257
258 /* These variables are supressed to avoid their use w/o support.  main() warns
259  * appropriately when external compression is not enabled. */
260 #if EXTERNAL_COMPRESSION
261 static int         num_subprocs = 0;
262 static int         option_force2             = 0;
263 static int         option_decompress_inputs  = 1;
264 static int         option_recompress_outputs = 1;
265 #endif
266
267 /* This is for comparing "printdelta" output without attention to
268  * copy-instruction modes. */
269 #if VCDIFF_TOOLS
270 static int option_print_cpymode = 1; /* Note: see reset_defaults(). */
271 #endif
272
273 /* Static variables */
274 IF_DEBUG(static int main_mallocs = 0;)
275
276 static char*           program_name = NULL;
277 static uint8_t*        appheader_used = NULL;
278 static uint8_t*        main_bdata = NULL;
279 static usize_t         main_bsize = 0;
280
281 /* Hacks for VCDIFF tools, recode command. */
282 static int allow_fake_source = 0;
283
284 /* recode_stream is used by both recode/merge for reading vcdiff inputs */
285 static xd3_stream *recode_stream = NULL;
286
287 /* merge_stream is used by merge commands for storing the source encoding */
288 static xd3_stream *merge_stream = NULL;
289
290 /* This array of compressor types is compiled even if EXTERNAL_COMPRESSION is
291  * false just so the program knows the mapping of IDENT->NAME. */
292 static main_extcomp extcomp_types[] =
293 {
294   { "bzip2",    "-c",   "bzip2",      "-dc",   "B", "BZh",          3, 0 },
295   { "gzip",     "-c",   "gzip",       "-dc",   "G", "\037\213",     2, 0 },
296   { "compress", "-c",   "uncompress", "-c",    "Z", "\037\235",     2, 0 },
297
298   /* Xz is lzma with a magic number http://tukaani.org/xz/format.html */
299   { "xz", "-c", "xz", "-dc", "Y", "\xfd\x37\x7a\x58\x5a\x00", 2, 0 },
300 };
301
302 static int main_input (xd3_cmd cmd, main_file *ifile,
303                        main_file *ofile, main_file *sfile);
304 static void main_get_appheader (xd3_stream *stream, main_file *ifile,
305                                 main_file *output, main_file *sfile);
306
307 static int main_getblk_func (xd3_stream *stream,
308                              xd3_source *source,
309                              xoff_t      blkno);
310 static void main_free (void *ptr);
311 static void* main_malloc (size_t size);
312
313 static int main_file_stat (main_file *xfile, xoff_t *size);
314 static int main_file_seek (main_file *xfile, xoff_t pos);
315 static int main_read_primary_input (main_file   *file,
316                                     uint8_t     *buf,
317                                     size_t       size,
318                                     size_t      *nread);
319
320 static const char* main_format_bcnt (xoff_t r, shortbuf *buf);
321 static int main_help (void);
322
323 #if XD3_ENCODER
324 static int xd3_merge_input_output (xd3_stream *stream,
325                                    xd3_whole_state *source);
326 #endif
327
328 /* The code in xdelta3-blk.h is essentially part of this unit, see
329  * comments there. */
330 #include "xdelta3-blkcache.h"
331
332 void (*xprintf_message_func)(const char*msg) = NULL;
333
334 void
335 xprintf (const char *fmt, ...)
336 {
337   char buf[1000];
338   va_list a;
339   int size;
340   va_start (a, fmt);
341   size = vsnprintf_func (buf, 1000, fmt, a);
342   va_end (a);
343   if (size < 0)
344     {
345       size = sizeof(buf) - 1;
346       buf[size] = 0;
347     }
348   if (xprintf_message_func != NULL) {
349     xprintf_message_func(buf);
350   } else {
351     size_t ignore = fwrite(buf, 1, size, stderr);
352     (void) ignore;
353   }
354 }
355
356 static int
357 main_version (void)
358 {
359   /* $Format: "  XPR(NTR \"Xdelta version $Xdelta3Version$, Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013, Joshua MacDonald\\n\");" $ */
360   XPR(NTR "Xdelta version 3.0.8, Copyright (C) 2007, 2008, 2009, 2010, 2011, 2012, 2013 Joshua MacDonald\n");
361   XPR(NTR "Xdelta comes with ABSOLUTELY NO WARRANTY.\n");
362   XPR(NTR "This is free software, and you are welcome to redistribute it\n");
363   XPR(NTR "under certain conditions; see \"COPYING\" for details.\n");
364   return EXIT_SUCCESS;
365 }
366
367 static int
368 main_config (void)
369 {
370   main_version ();
371
372   XPR(NTR "EXTERNAL_COMPRESSION=%d\n", EXTERNAL_COMPRESSION);
373   XPR(NTR "REGRESSION_TEST=%d\n", REGRESSION_TEST);
374   XPR(NTR "SECONDARY_DJW=%d\n", SECONDARY_DJW);
375   XPR(NTR "SECONDARY_FGK=%d\n", SECONDARY_FGK);
376   XPR(NTR "SECONDARY_LZMA=%d\n", SECONDARY_LZMA);
377   XPR(NTR "UNALIGNED_OK=%d\n", UNALIGNED_OK);
378   XPR(NTR "VCDIFF_TOOLS=%d\n", VCDIFF_TOOLS);
379   XPR(NTR "XD3_ALLOCSIZE=%d\n", XD3_ALLOCSIZE);
380   XPR(NTR "XD3_DEBUG=%d\n", XD3_DEBUG);
381   XPR(NTR "XD3_ENCODER=%d\n", XD3_ENCODER);
382   XPR(NTR "XD3_POSIX=%d\n", XD3_POSIX);
383   XPR(NTR "XD3_STDIO=%d\n", XD3_STDIO);
384   XPR(NTR "XD3_WIN32=%d\n", XD3_WIN32);
385   XPR(NTR "XD3_USE_LARGEFILE64=%d\n", XD3_USE_LARGEFILE64);
386   XPR(NTR "XD3_DEFAULT_LEVEL=%d\n", XD3_DEFAULT_LEVEL);
387   XPR(NTR "XD3_DEFAULT_IOPT_SIZE=%d\n", XD3_DEFAULT_IOPT_SIZE);
388   XPR(NTR "XD3_DEFAULT_SPREVSZ=%d\n", XD3_DEFAULT_SPREVSZ);
389   XPR(NTR "XD3_DEFAULT_SRCWINSZ=%d\n", XD3_DEFAULT_SRCWINSZ);
390   XPR(NTR "XD3_DEFAULT_WINSIZE=%d\n", XD3_DEFAULT_WINSIZE);
391   XPR(NTR "XD3_HARDMAXWINSIZE=%d\n", XD3_HARDMAXWINSIZE);
392   XPR(NTR "sizeof(void*)=%d\n", (int)sizeof(void*));
393   XPR(NTR "sizeof(int)=%d\n", (int)sizeof(int));
394   XPR(NTR "sizeof(size_t)=%d\n", (int)sizeof(size_t));
395   XPR(NTR "sizeof(uint32_t)=%d\n", (int)sizeof(uint32_t));
396   XPR(NTR "sizeof(uint64_t)=%d\n", (int)sizeof(uint64_t));
397   XPR(NTR "sizeof(usize_t)=%d\n", (int)sizeof(usize_t));
398   XPR(NTR "sizeof(xoff_t)=%d\n", (int)sizeof(xoff_t));
399
400   return EXIT_SUCCESS;
401 }
402
403 static void
404 reset_defaults(void)
405 {
406   option_stdout = 0;
407   option_force = 0;
408   option_verbose = DEFAULT_VERBOSE;
409   option_quiet = 0;
410   option_appheader = NULL;
411   option_use_secondary = 0;
412   option_secondary = NULL;
413   option_smatch_config = NULL;
414   option_no_compress = 0;
415   option_no_output = 0;
416   option_source_filename = NULL;
417   program_name = NULL;
418   appheader_used = NULL;
419   main_bdata = NULL;
420   main_bsize = 0;
421   allow_fake_source = 0;
422   option_smatch_config = NULL;
423
424   main_lru_reset();
425
426   option_use_appheader = 1;
427   option_use_checksum = 1;
428 #if EXTERNAL_COMPRESSION
429   option_force2 = 0;
430   option_decompress_inputs  = 1;
431   option_recompress_outputs = 1;
432   num_subprocs = 0;
433 #endif
434 #if VCDIFF_TOOLS
435   option_print_cpymode = 1;
436 #endif
437   option_level = XD3_DEFAULT_LEVEL;
438   option_iopt_size = XD3_DEFAULT_IOPT_SIZE;
439   option_winsize = XD3_DEFAULT_WINSIZE;
440   option_srcwinsz = XD3_DEFAULT_SRCWINSZ;
441   option_sprevsz = XD3_DEFAULT_SPREVSZ;
442 }
443
444 static void*
445 main_malloc1 (size_t size)
446 {
447   void* r = malloc (size);
448   if (r == NULL) { XPR(NT "malloc: %s\n", xd3_mainerror (ENOMEM)); }
449   return r;
450 }
451
452 void* main_bufalloc (size_t size) {
453 #if XD3_WIN32
454   return VirtualAlloc(NULL, size, MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE);
455 #else
456   return main_malloc1(size);
457 #endif
458 }
459
460 static void*
461 main_malloc (size_t size)
462 {
463   void *r = main_malloc1 (size);
464   if (r) { IF_DEBUG (main_mallocs += 1); }
465   return r;
466 }
467
468 static void*
469 main_alloc (void   *opaque,
470             size_t  items,
471             usize_t  size)
472 {
473   return main_malloc1 (items * size);
474 }
475
476 static void
477 main_free1 (void *opaque, void *ptr)
478 {
479   free (ptr);
480 }
481
482 static void
483 main_free (void *ptr)
484 {
485   if (ptr)
486     {
487       IF_DEBUG (main_mallocs -= 1);
488       main_free1 (NULL, ptr);
489       IF_DEBUG (XD3_ASSERT(main_mallocs >= 0));
490     }
491 }
492
493 void main_buffree (void *ptr) {
494 #if XD3_WIN32
495   VirtualFree(ptr, 0, MEM_RELEASE);
496 #else
497   main_free1(NULL, ptr);
498 #endif
499 }
500
501 /* This ensures that (ret = errno) always indicates failure, in case errno was
502  * accidentally not set.  If this prints there's a bug somewhere. */
503 static int
504 get_errno (void)
505 {
506 #ifndef _WIN32
507   if (errno == 0)
508     {
509       XPR(NT "you found a bug: expected errno != 0\n");
510       errno = XD3_INTERNAL;
511     }
512   return errno;
513 #else
514   DWORD err_num = GetLastError();
515   if (err_num == NO_ERROR)
516     {
517       err_num = XD3_INTERNAL;
518     }
519   return err_num;
520 #endif
521 }
522
523 const char*
524 xd3_mainerror(int err_num) {
525 #ifndef _WIN32
526         const char* x = xd3_strerror (err_num);
527         if (x != NULL)
528           {
529             return x;
530           }
531         return strerror(err_num);
532 #else
533         static char err_buf[256];
534         const char* x = xd3_strerror (err_num);
535         if (x != NULL)
536           {
537             return x;
538           }
539         memset (err_buf, 0, 256);
540         FormatMessage (FORMAT_MESSAGE_FROM_SYSTEM |
541                        FORMAT_MESSAGE_IGNORE_INSERTS,
542                        NULL, err_num,
543                        MAKELANGID (LANG_NEUTRAL, SUBLANG_DEFAULT),
544                        err_buf, 256, NULL);
545         if (err_buf[0] != 0 && err_buf[strlen(err_buf) - 1] == '\n')
546           {
547             err_buf[strlen(err_buf) - 1] = 0;
548           }
549         return err_buf;
550 #endif
551 }
552
553 static long
554 get_millisecs_now (void)
555 {
556 #ifndef _WIN32
557   struct timeval tv;
558
559   gettimeofday (& tv, NULL);
560
561   return (tv.tv_sec) * 1000L + (tv.tv_usec) / 1000;
562 #else
563   SYSTEMTIME st;
564   FILETIME ft;
565   __int64 *pi = (__int64*)&ft;
566   GetLocalTime(&st);
567   SystemTimeToFileTime(&st, &ft);
568   return (long)((*pi) / 10000);
569 #endif
570 }
571
572 /* Always >= 1 millisec, right? */
573 static long
574 get_millisecs_since (void)
575 {
576   static long last = 0;
577   long now = get_millisecs_now();
578   long diff = now - last;
579   last = now;
580   return diff;
581 }
582
583 static const char*
584 main_format_bcnt (xoff_t r, shortbuf *buf)
585 {
586   static const char* fmts[] = { "B", "KiB", "MiB", "GiB", "TiB", "PiB", "EiB" };
587   usize_t i;
588
589   for (i = 0; i < SIZEOF_ARRAY(fmts) - 1; i += 1)
590     {
591       xoff_t new_r;
592
593       if (r == 0)
594         {
595           short_sprintf (*buf, "0 %s", fmts[i]);
596           return buf->buf;
597         }
598
599       if (r >= 1 && r < 10)
600         {
601           short_sprintf (*buf, "%.2f %s", (double) r, fmts[i]);
602           return buf->buf;
603         }
604
605       if (r >= 10 && r < 100)
606         {
607           short_sprintf (*buf, "%.1f %s", (double) r, fmts[i]);
608           return buf->buf;
609         }
610
611       if (r >= 100 && r < 1000)
612         {
613           short_sprintf (*buf, "%"Q"u %s", r, fmts[i]);
614           return buf->buf;
615         }
616
617       new_r = r / 1024;
618
619       if (new_r < 10)
620         {
621           short_sprintf (*buf, "%.2f %s", (double) r / 1024.0, fmts[i + 1]);
622           return buf->buf;
623         }
624
625       if (new_r < 100)
626         {
627           short_sprintf (*buf, "%.1f %s", (double) r / 1024.0, fmts[i + 1]);
628           return buf->buf;
629         }
630
631       r = new_r;
632     }
633   XD3_ASSERT (0);
634   return "";
635 }
636
637 static char*
638 main_format_rate (xoff_t bytes, long millis, shortbuf *buf)
639 {
640   xoff_t r = (xoff_t)(1.0 * bytes / (1.0 * millis / 1000.0));
641   static shortbuf lbuf;
642
643   main_format_bcnt (r, &lbuf);
644   short_sprintf (*buf, "%s/s", lbuf.buf);
645   return buf->buf;
646 }
647
648 static char*
649 main_format_millis (long millis, shortbuf *buf)
650 {
651   if (millis < 1000)
652     { 
653       short_sprintf (*buf, "%lu ms", millis); 
654     }
655   else if (millis < 10000) 
656     {
657       short_sprintf (*buf, "%.1f sec", millis / 1000.0);
658     }
659   else
660     {
661       short_sprintf (*buf, "%lu sec", millis / 1000L); 
662     }
663   return buf->buf;
664 }
665
666 /* A safe version of strtol for xoff_t. */
667 static int
668 main_strtoxoff (const char* s, xoff_t *xo, char which)
669 {
670   char *e;
671   xoff_t x;
672
673   XD3_ASSERT(s && *s != 0);
674
675   {
676     /* Should check LONG_MIN, LONG_MAX, LLONG_MIN, LLONG_MAX? */
677 #if SIZEOF_XOFF_T == 4
678     long xx = strtol (s, &e, 0);
679 #else
680     long long xx = strtoll (s, &e, 0);
681 #endif
682
683     if (xx < 0)
684       {
685         XPR(NT "-%c: negative integer: %s\n", which, s);
686         return EXIT_FAILURE;
687       }
688
689     x = xx;
690   }
691
692   if (*e != 0)
693     {
694       XPR(NT "-%c: invalid integer: %s\n", which, s);
695       return EXIT_FAILURE;
696     }
697
698   (*xo) = x;
699   return 0;
700 }
701
702 static int
703 main_atoux (const char* arg, xoff_t *xo, xoff_t low,
704             xoff_t high, char which)
705 {
706   xoff_t x;
707   int ret;
708
709   if ((ret = main_strtoxoff (arg, & x, which))) { return ret; }
710
711   if (x < low)
712     {
713       XPR(NT "-%c: minimum value: %"Q"u\n", which, low);
714       return EXIT_FAILURE;
715     }
716   if (high != 0 && x > high)
717     {
718       XPR(NT "-%c: maximum value: %"Q"u\n", which, high);
719       return EXIT_FAILURE;
720     }
721   (*xo) = x;
722   return 0;
723 }
724
725 static int
726 main_atou (const char* arg, usize_t *uo, usize_t low,
727            usize_t high, char which) 
728 {
729   int ret;
730   xoff_t xo;
731   if ((ret = main_atoux (arg, &xo, low, high, which)))
732     {
733       return ret;
734     }
735   *uo = (usize_t)xo;
736   return 0;
737 }
738
739 /******************************************************************
740  FILE BASICS
741  ******************************************************************/
742
743 /* With all the variation in file system-call semantics, arguments,
744  * return values and error-handling for the POSIX and STDIO file APIs,
745  * the insides of these functions make me sick, which is why these
746  * wrappers exist. */
747
748 #define XOPEN_OPNAME (xfile->mode == XO_READ ? "read" : "write")
749 #define XOPEN_STDIO  (xfile->mode == XO_READ ? "rb" : "wb")
750 #define XOPEN_POSIX  (xfile->mode == XO_READ ? \
751                       O_RDONLY : O_WRONLY | O_CREAT | O_TRUNC)
752 #define XOPEN_MODE   (xfile->mode == XO_READ ? 0 : 0666)
753
754 #define XF_ERROR(op, name, ret) \
755   do { if (!option_quiet) { XPR(NT "file %s failed: %s: %s: %s\n", (op), \
756        XOPEN_OPNAME, (name), xd3_mainerror (ret)); } } while (0)
757
758 #if XD3_STDIO
759 #define XFNO(f) fileno(f->file)
760 #define XSTDOUT_XF(f) { (f)->file = stdout; (f)->filename = "/dev/stdout"; }
761 #define XSTDIN_XF(f)  { (f)->file = stdin;  (f)->filename = "/dev/stdin"; }
762
763 #elif XD3_POSIX
764 #define XFNO(f) f->file
765 #define XSTDOUT_XF(f) \
766   { (f)->file = STDOUT_FILENO; (f)->filename = "/dev/stdout"; }
767 #define XSTDIN_XF(f) \
768   { (f)->file = STDIN_FILENO;  (f)->filename = "/dev/stdin"; }
769
770 #elif XD3_WIN32
771 #define XFNO(f) -1
772 #define XSTDOUT_XF(f) { \
773   (f)->file = GetStdHandle(STD_OUTPUT_HANDLE); \
774   (f)->filename = "(stdout)"; \
775   }
776 #define XSTDIN_XF(f) { \
777   (f)->file = GetStdHandle(STD_INPUT_HANDLE); \
778   (f)->filename = "(stdin)"; \
779   }
780 #endif
781
782 void
783 main_file_init (main_file *xfile)
784 {
785   memset (xfile, 0, sizeof (*xfile));
786
787 #if XD3_POSIX
788   xfile->file = -1;
789 #endif
790 #if XD3_WIN32
791   xfile->file = INVALID_HANDLE_VALUE;
792 #endif
793 }
794
795 int
796 main_file_isopen (main_file *xfile)
797 {
798 #if XD3_STDIO
799   return xfile->file != NULL;
800
801 #elif XD3_POSIX
802   return xfile->file != -1;
803
804 #elif XD3_WIN32
805   return xfile->file != INVALID_HANDLE_VALUE;
806 #endif
807 }
808
809 int
810 main_file_close (main_file *xfile)
811 {
812   int ret = 0;
813
814   if (! main_file_isopen (xfile))
815     {
816       return 0;
817     }
818
819 #if XD3_STDIO
820   ret = fclose (xfile->file);
821   xfile->file = NULL;
822
823 #elif XD3_POSIX
824   ret = close (xfile->file);
825   xfile->file = -1;
826
827 #elif XD3_WIN32
828   if (!CloseHandle(xfile->file)) {
829     ret = get_errno ();
830   }
831   xfile->file = INVALID_HANDLE_VALUE;
832 #endif
833
834   if (ret != 0) { XF_ERROR ("close", xfile->filename, ret = get_errno ()); }
835   return ret;
836 }
837
838 void
839 main_file_cleanup (main_file *xfile)
840 {
841   XD3_ASSERT (xfile != NULL);
842
843   if (main_file_isopen (xfile))
844     {
845       main_file_close (xfile);
846     }
847
848   if (xfile->snprintf_buf != NULL)
849     {
850       main_free(xfile->snprintf_buf);
851       xfile->snprintf_buf = NULL;
852     }
853
854   if (xfile->filename_copy != NULL)
855     {
856       main_free(xfile->filename_copy);
857       xfile->filename_copy = NULL;
858     }
859 }
860
861 int
862 main_file_open (main_file *xfile, const char* name, int mode)
863 {
864   int ret = 0;
865
866   xfile->mode = mode;
867
868   XD3_ASSERT (name != NULL);
869   XD3_ASSERT (! main_file_isopen (xfile));
870   if (name[0] == 0)
871     {
872       XPR(NT "invalid file name: empty string\n");
873       return XD3_INVALID;
874     }
875
876 #if XD3_STDIO
877   xfile->file = fopen (name, XOPEN_STDIO);
878
879   ret = (xfile->file == NULL) ? get_errno () : 0;
880
881 #elif XD3_POSIX
882   /* TODO: Should retry this call if interrupted, similar to read/write */
883   if ((ret = open (name, XOPEN_POSIX, XOPEN_MODE)) < 0)
884     {
885       ret = get_errno ();
886     }
887   else
888     {
889       xfile->file = ret;
890       ret = 0;
891     }
892
893 #elif XD3_WIN32
894   xfile->file = CreateFile(name,
895                            (mode == XO_READ) ? GENERIC_READ : GENERIC_WRITE,
896                            FILE_SHARE_READ,
897                            NULL,
898                            (mode == XO_READ) ?
899                            OPEN_EXISTING :
900                            (option_force ? CREATE_ALWAYS : CREATE_NEW),
901                            FILE_ATTRIBUTE_NORMAL,
902                            NULL);
903   if (xfile->file == INVALID_HANDLE_VALUE)
904     {
905       ret = get_errno ();
906     }
907 #endif
908   if (ret) { XF_ERROR ("open", name, ret); }
909   else     { xfile->realname = name; xfile->nread = 0; }
910   return ret;
911 }
912
913 int
914 main_file_stat (main_file *xfile, xoff_t *size)
915 {
916   int ret = 0;
917 #if XD3_WIN32
918   if (GetFileType(xfile->file) != FILE_TYPE_DISK)
919     {
920       return -1;
921     }
922 # if (_WIN32_WINNT >= 0x0500)
923   {
924     LARGE_INTEGER li;
925     if (GetFileSizeEx(xfile->file, &li) == 0)
926       {
927         return get_errno ();
928       }
929     *size = li.QuadPart;
930   }
931 # else
932   {
933     DWORD filesize = GetFileSize(xfile->file, NULL);
934     if (filesize == INVALID_FILE_SIZE)
935       {
936         return get_errno ()
937       }
938     *size = filesize;
939   }
940 # endif
941 #else
942   struct stat sbuf;
943   if (fstat (XFNO (xfile), & sbuf) < 0)
944     {
945       ret = get_errno ();
946       return ret;
947     }
948
949   if (! S_ISREG (sbuf.st_mode))
950     {
951       return ESPIPE;
952     }
953   (*size) = sbuf.st_size;
954 #endif
955   return ret;
956 }
957
958 int
959 main_file_exists (main_file *xfile)
960 {
961   struct stat sbuf;
962   return stat (xfile->filename, & sbuf) == 0 && S_ISREG (sbuf.st_mode);
963 }
964
965 #if (XD3_POSIX || EXTERNAL_COMPRESSION)
966 /* POSIX-generic code takes a function pointer to read() or write().
967  * This calls the function repeatedly until the buffer is full or EOF.
968  * The NREAD parameter is not set for write, NULL is passed.  Return
969  * is signed, < 0 indicate errors, otherwise byte count. */
970 typedef int (xd3_posix_func) (int fd, uint8_t *buf, usize_t size);
971
972 static int
973 xd3_posix_io (int fd, uint8_t *buf, size_t size,
974               xd3_posix_func *func, size_t *nread)
975 {
976   int ret;
977   size_t nproc = 0;
978
979   while (nproc < size)
980     {
981       size_t tryread = min(size - nproc, 1U << 30);
982       ssize_t result = (*func) (fd, buf + nproc, tryread);
983
984       if (result < 0)
985         {
986           ret = get_errno ();
987           if (ret != EAGAIN && ret != EINTR)
988             {
989               return ret;
990             }
991           continue;
992         }
993
994       if (nread != NULL && result == 0) { break; }
995
996       nproc += result;
997     }
998   if (nread != NULL) { (*nread) = nproc; }
999   return 0;
1000 }
1001 #endif
1002
1003 #if XD3_WIN32
1004 static int
1005 xd3_win32_io (HANDLE file, uint8_t *buf, size_t size,
1006               int is_read, size_t *nread)
1007 {
1008   int ret = 0;
1009   size_t nproc = 0;
1010
1011   while (nproc < size)
1012     {
1013       DWORD nproc2 = 0;  /* hmm */
1014           DWORD nremain = size - nproc;
1015       if ((is_read ?
1016            ReadFile (file, buf + nproc, nremain, &nproc2, NULL) :
1017            WriteFile (file, buf + nproc, nremain, &nproc2, NULL)) == 0)
1018         {
1019           ret = get_errno();
1020           if (ret != ERROR_HANDLE_EOF && ret != ERROR_BROKEN_PIPE)
1021             {
1022               return ret;
1023             }
1024           /* By falling through here, we'll break this loop in the
1025            * read case in case of eof or broken pipe. */
1026         }
1027
1028       nproc += nproc2;
1029
1030       if (nread != NULL && nproc2 == 0) { break; }
1031     }
1032   if (nread != NULL) { (*nread) = nproc; }
1033   return 0;
1034 }
1035 #endif
1036
1037 /* POSIX is unbuffered, while STDIO is buffered.  main_file_read()
1038  * should always be called on blocks. */
1039 int
1040 main_file_read (main_file  *ifile,
1041                 uint8_t    *buf,
1042                 size_t      size,
1043                 size_t     *nread,
1044                 const char *msg)
1045 {
1046   int ret = 0;
1047
1048 #if XD3_STDIO
1049   size_t result;
1050
1051   result = fread (buf, 1, size, ifile->file);
1052
1053   if (result < size && ferror (ifile->file))
1054     {
1055       ret = get_errno ();
1056     }
1057   else
1058     {
1059       *nread = result;
1060     }
1061
1062 #elif XD3_POSIX
1063   ret = xd3_posix_io (ifile->file, buf, size, (xd3_posix_func*) &read, nread);
1064 #elif XD3_WIN32
1065   ret = xd3_win32_io (ifile->file, buf, size, 1 /* is_read */, nread);
1066 #endif
1067
1068   if (ret)
1069     {
1070       XPR(NT "%s: %s: %s\n", msg, ifile->filename, xd3_mainerror (ret));
1071     }
1072   else
1073     {
1074       if (option_verbose > 4) { XPR(NT "read %s: %zu bytes\n",
1075                                     ifile->filename, (*nread)); }
1076       ifile->nread += (*nread);
1077     }
1078
1079   return ret;
1080 }
1081
1082 int
1083 main_file_write (main_file *ofile, uint8_t *buf, usize_t size, const char *msg)
1084 {
1085   int ret = 0;
1086
1087 #if XD3_STDIO
1088   usize_t result;
1089
1090   result = fwrite (buf, 1, size, ofile->file);
1091
1092   if (result != size) { ret = get_errno (); }
1093
1094 #elif XD3_POSIX
1095   ret = xd3_posix_io (ofile->file, buf, size, (xd3_posix_func*) &write, NULL);
1096
1097 #elif XD3_WIN32
1098   ret = xd3_win32_io (ofile->file, buf, size, 0, NULL);
1099
1100 #endif
1101
1102   if (ret)
1103     {
1104       XPR(NT "%s: %s: %s\n", msg, ofile->filename, xd3_mainerror (ret));
1105     }
1106   else
1107     {
1108       if (option_verbose > 5) { XPR(NT "write %s: %u bytes\n",
1109                                     ofile->filename, size); }
1110       ofile->nwrite += size;
1111     }
1112
1113   return ret;
1114 }
1115
1116 static int
1117 main_file_seek (main_file *xfile, xoff_t pos)
1118 {
1119   int ret = 0;
1120
1121 #if XD3_STDIO
1122   if (fseek (xfile->file, pos, SEEK_SET) != 0) { ret = get_errno (); }
1123
1124 #elif XD3_POSIX
1125   if ((xoff_t) lseek (xfile->file, pos, SEEK_SET) != pos)
1126     { ret = get_errno (); }
1127
1128 #elif XD3_WIN32
1129 # if (_WIN32_WINNT >= 0x0500)
1130   LARGE_INTEGER move, out;
1131   move.QuadPart = pos;
1132   if (SetFilePointerEx(xfile->file, move, &out, FILE_BEGIN) == 0)
1133     {
1134       ret = get_errno ();
1135     }
1136 # else
1137   if (SetFilePointer(xfile->file, (LONG)pos, NULL, FILE_BEGIN) ==
1138       INVALID_SET_FILE_POINTER)
1139     {
1140       ret = get_errno ();
1141     }
1142 # endif
1143 #endif
1144
1145   return ret;
1146 }
1147
1148 /* This function simply writes the stream output buffer, if there is
1149  * any, for encode, decode and recode commands.  (The VCDIFF tools use
1150  * main_print_func()). */
1151 static int
1152 main_write_output (xd3_stream* stream, main_file *ofile)
1153 {
1154   int ret;
1155
1156   if (option_no_output)
1157     {
1158       return 0;
1159     }
1160
1161   if (stream->avail_out > 0 &&
1162       (ret = main_file_write (ofile, stream->next_out,
1163                               stream->avail_out, "write failed")))
1164     {
1165       return ret;
1166     }
1167
1168   return 0;
1169 }
1170
1171 static int
1172 main_set_secondary_flags (xd3_config *config)
1173 {
1174   int ret;
1175   if (option_use_secondary)
1176     {
1177       /* The default secondary compressor is DJW, if it's compiled. */
1178       if (option_secondary == NULL)
1179         {
1180           if (SECONDARY_DJW)
1181             {
1182               config->flags |= XD3_SEC_DJW;
1183             }
1184         }
1185       else
1186         {
1187           if (strcmp (option_secondary, "fgk") == 0 && SECONDARY_FGK)
1188             {
1189               config->flags |= XD3_SEC_FGK;
1190             }
1191           else if (strcmp (option_secondary, "lzma") == 0 && SECONDARY_LZMA)
1192             {
1193               config->flags |= XD3_SEC_LZMA;
1194             }
1195           else if (strncmp (option_secondary, "djw", 3) == 0 && SECONDARY_DJW)
1196             {
1197               usize_t level = XD3_DEFAULT_SECONDARY_LEVEL;
1198
1199               config->flags |= XD3_SEC_DJW;
1200
1201               if (strlen (option_secondary) > 3 &&
1202                   (ret = main_atou (option_secondary + 3,
1203                                     &level,
1204                                     0, 9, 'S')) != 0 &&
1205                   !option_quiet)
1206                 {
1207                   return XD3_INVALID;
1208                 }
1209
1210               /* XD3_SEC_NOXXXX flags disable secondary compression on
1211                * a per-section basis.  For djw, ngroups=1 indicates
1212                * minimum work, ngroups=0 uses default settings, which
1213                * is > 1 groups by default. */
1214               if (level < 1) { config->flags |= XD3_SEC_NODATA; }
1215               if (level < 7) { config->sec_data.ngroups = 1; }
1216               else { config->sec_data.ngroups = 0; }
1217
1218               if (level < 3) { config->flags |= XD3_SEC_NOINST; }
1219               if (level < 8) { config->sec_inst.ngroups = 1; }
1220               else { config->sec_inst.ngroups = 0; }
1221
1222               if (level < 5) { config->flags |= XD3_SEC_NOADDR; }
1223               if (level < 9) { config->sec_addr.ngroups = 1; }
1224               else { config->sec_addr.ngroups = 0; }
1225             }
1226           else if (strcmp (option_secondary, "none") == 0 && SECONDARY_DJW)
1227             {
1228               /* No secondary */
1229             }
1230           else
1231             {
1232               if (!option_quiet)
1233                 {
1234                   XPR(NT "unrecognized secondary compressor type: %s\n",
1235                       option_secondary);
1236                   return XD3_INVALID;
1237                 }
1238             }
1239         }
1240     }
1241
1242   return 0;
1243 }
1244
1245 /******************************************************************
1246  VCDIFF TOOLS
1247  *****************************************************************/
1248
1249 #if VCDIFF_TOOLS
1250 #include "xdelta3-merge.h"
1251
1252 /* The following macros let VCDIFF print using main_file_write(),
1253  * for example:
1254  *
1255  *   VC(UT "trying to be portable: %d\n", x)VE;
1256  */
1257 #define SNPRINTF_BUFSIZE 1024
1258 #define VC do { if (((ret = xsnprintf_func
1259 #define UT (char*)xfile->snprintf_buf, SNPRINTF_BUFSIZE,
1260 #define VE ) >= SNPRINTF_BUFSIZE                               \
1261   && (ret = main_print_overflow(ret)) != 0)                    \
1262   || (ret = main_file_write(xfile, xfile->snprintf_buf,        \
1263                             (usize_t)ret, "print")) != 0)      \
1264   { return ret; } } while (0)
1265
1266 static int
1267 main_print_overflow (int x)
1268 {
1269   XPR(NT "internal print buffer overflow: %d bytes\n", x);
1270   return XD3_INTERNAL;
1271 }
1272
1273 /* This function prints a single VCDIFF window. */
1274 static int
1275 main_print_window (xd3_stream* stream, main_file *xfile)
1276 {
1277   int ret;
1278   usize_t size = 0;
1279
1280   VC(UT "  Offset Code Type1 Size1  @Addr1 + Type2 Size2 @Addr2\n")VE;
1281
1282   while (stream->inst_sect.buf < stream->inst_sect.buf_max)
1283     {
1284       usize_t code = stream->inst_sect.buf[0];
1285       const uint8_t *addr_before = stream->addr_sect.buf;
1286       const uint8_t *inst_before = stream->inst_sect.buf;
1287       usize_t addr_bytes;
1288       usize_t inst_bytes;
1289       usize_t size_before = size;
1290
1291       if ((ret = xd3_decode_instruction (stream)))
1292         {
1293           XPR(NT "instruction decode error at %"Q"u: %s\n",
1294               stream->dec_winstart + size, stream->msg);
1295           return ret;
1296         }
1297
1298       addr_bytes = (usize_t)(stream->addr_sect.buf - addr_before);
1299       inst_bytes = (usize_t)(stream->inst_sect.buf - inst_before);
1300
1301       VC(UT "  %06"Q"u %03u  %s %6u", stream->dec_winstart + size,
1302          option_print_cpymode ? code : 0,
1303          xd3_rtype_to_string ((xd3_rtype) stream->dec_current1.type,
1304                               option_print_cpymode),
1305          stream->dec_current1.size)VE;
1306
1307       if (stream->dec_current1.type != XD3_NOOP)
1308         {
1309           if (stream->dec_current1.type >= XD3_CPY)
1310             {
1311               if (stream->dec_current1.addr >= stream->dec_cpylen)
1312                 {
1313                   VC(UT " T@%-6u",
1314                      stream->dec_current1.addr - stream->dec_cpylen)VE;
1315                 }
1316               else
1317                 {
1318                   VC(UT " S@%-6"Q"u",
1319                      stream->dec_cpyoff + stream->dec_current1.addr)VE;
1320                 }
1321             }
1322           else
1323             {
1324               VC(UT "        ")VE;
1325             }
1326
1327           size += stream->dec_current1.size;
1328         }
1329
1330       if (stream->dec_current2.type != XD3_NOOP)
1331         {
1332           VC(UT "  %s %6u",
1333              xd3_rtype_to_string ((xd3_rtype) stream->dec_current2.type,
1334                                   option_print_cpymode),
1335              stream->dec_current2.size)VE;
1336
1337           if (stream->dec_current2.type >= XD3_CPY)
1338             {
1339               if (stream->dec_current2.addr >= stream->dec_cpylen)
1340                 {
1341                   VC(UT " T@%-6u",
1342                      stream->dec_current2.addr - stream->dec_cpylen)VE;
1343                 }
1344               else
1345                 {
1346                   VC(UT " S@%-6"Q"u",
1347                      stream->dec_cpyoff + stream->dec_current2.addr)VE;
1348                 }
1349             }
1350
1351           size += stream->dec_current2.size;
1352         }
1353
1354       VC(UT "\n")VE;
1355
1356       if (option_verbose &&
1357           addr_bytes + inst_bytes >= (size - size_before) &&
1358           (stream->dec_current1.type >= XD3_CPY ||
1359            stream->dec_current2.type >= XD3_CPY))
1360         {
1361           VC(UT "  %06"Q"u (inefficiency) %u encoded as %u bytes\n",
1362              stream->dec_winstart + size_before,
1363              size - size_before,
1364              addr_bytes + inst_bytes)VE;
1365         }
1366     }
1367
1368   if (stream->dec_tgtlen != size && (stream->flags & XD3_SKIP_WINDOW) == 0)
1369     {
1370       XPR(NT "target window size inconsistency");
1371       return XD3_INTERNAL;
1372     }
1373
1374   if (stream->dec_position != stream->dec_maxpos)
1375     {
1376       XPR(NT "target window position inconsistency");
1377       return XD3_INTERNAL;
1378     }
1379
1380   if (stream->addr_sect.buf != stream->addr_sect.buf_max)
1381     {
1382       XPR(NT "address section inconsistency");
1383       return XD3_INTERNAL;
1384     }
1385
1386   return 0;
1387 }
1388
1389 static int
1390 main_print_vcdiff_file (main_file *xfile, main_file *file, const char *type)
1391 {
1392   int ret;  /* Used by above macros */
1393   if (file->filename)
1394     {
1395       VC(UT "XDELTA filename (%s):     %s\n", type,
1396          file->filename)VE;
1397     }
1398   if (file->compressor)
1399     {
1400       VC(UT "XDELTA ext comp (%s):     %s\n", type,
1401          file->compressor->recomp_cmdname)VE;
1402     }
1403   return 0;
1404 }
1405
1406 /* This function prints a VCDIFF input, mainly for debugging purposes. */
1407 static int
1408 main_print_func (xd3_stream* stream, main_file *xfile)
1409 {
1410   int ret;
1411
1412   if (option_no_output)
1413     {
1414       return 0;
1415     }
1416
1417   if (xfile->snprintf_buf == NULL)
1418     {
1419       if ((xfile->snprintf_buf =
1420            (uint8_t*)main_malloc(SNPRINTF_BUFSIZE)) == NULL)
1421         {
1422           return ENOMEM;
1423         }
1424     }
1425
1426   if (stream->dec_winstart == 0)
1427     {
1428       VC(UT "VCDIFF version:               0\n")VE;
1429       VC(UT "VCDIFF header size:           %d\n",
1430          stream->dec_hdrsize)VE;
1431       VC(UT "VCDIFF header indicator:      ")VE;
1432       if ((stream->dec_hdr_ind & VCD_SECONDARY) != 0)
1433         VC(UT "VCD_SECONDARY ")VE;
1434       if ((stream->dec_hdr_ind & VCD_CODETABLE) != 0)
1435         VC(UT "VCD_CODETABLE ")VE;
1436       if ((stream->dec_hdr_ind & VCD_APPHEADER) != 0)
1437         VC(UT "VCD_APPHEADER ")VE;
1438       if (stream->dec_hdr_ind == 0)
1439         VC(UT "none")VE;
1440       VC(UT "\n")VE;
1441
1442       IF_SEC(VC(UT "VCDIFF secondary compressor:  %s\n",
1443                 stream->sec_type ? stream->sec_type->name : "none")VE);
1444       IF_NSEC(VC(UT "VCDIFF secondary compressor: unsupported\n")VE);
1445
1446       if (stream->dec_hdr_ind & VCD_APPHEADER)
1447         {
1448           uint8_t *apphead;
1449           usize_t appheadsz;
1450           ret = xd3_get_appheader (stream, & apphead, & appheadsz);
1451
1452           if (ret == 0 && appheadsz > 0)
1453             {
1454               int sq = option_quiet;
1455               main_file i, o, s;
1456               XD3_ASSERT (apphead != NULL);
1457               VC(UT "VCDIFF application header:    ")VE;
1458               if ((ret = main_file_write (xfile, apphead,
1459                                           appheadsz, "print")) != 0)
1460                 { return ret; }
1461               VC(UT "\n")VE;
1462
1463               main_file_init (& i);
1464               main_file_init (& o);
1465               main_file_init (& s);
1466               option_quiet = 1;
1467               main_get_appheader (stream, &i, & o, & s);
1468               option_quiet = sq;
1469               if ((ret = main_print_vcdiff_file (xfile, & o, "output")))
1470                 { return ret; }
1471               if ((ret = main_print_vcdiff_file (xfile, & s, "source")))
1472                 { return ret; }
1473               main_file_cleanup (& i);
1474               main_file_cleanup (& o);
1475               main_file_cleanup (& s);
1476             }
1477         }
1478     }
1479   else
1480     {
1481       VC(UT "\n")VE;
1482     }
1483
1484   VC(UT "VCDIFF window number:         %"Q"u\n", stream->current_window)VE;
1485   VC(UT "VCDIFF window indicator:      ")VE;
1486   if ((stream->dec_win_ind & VCD_SOURCE) != 0) VC(UT "VCD_SOURCE ")VE;
1487   if ((stream->dec_win_ind & VCD_TARGET) != 0) VC(UT "VCD_TARGET ")VE;
1488   if ((stream->dec_win_ind & VCD_ADLER32) != 0) VC(UT "VCD_ADLER32 ")VE;
1489   if (stream->dec_win_ind == 0) VC(UT "none")VE;
1490   VC(UT "\n")VE;
1491
1492   if ((stream->dec_win_ind & VCD_ADLER32) != 0)
1493     {
1494       VC(UT "VCDIFF adler32 checksum:      %08X\n",
1495          (usize_t)stream->dec_adler32)VE;
1496     }
1497
1498   if (stream->dec_del_ind != 0)
1499     {
1500       VC(UT "VCDIFF delta indicator:       ")VE;
1501       if ((stream->dec_del_ind & VCD_DATACOMP) != 0) VC(UT "VCD_DATACOMP ")VE;
1502       if ((stream->dec_del_ind & VCD_INSTCOMP) != 0) VC(UT "VCD_INSTCOMP ")VE;
1503       if ((stream->dec_del_ind & VCD_ADDRCOMP) != 0) VC(UT "VCD_ADDRCOMP ")VE;
1504       if (stream->dec_del_ind == 0) VC(UT "none")VE;
1505       VC(UT "\n")VE;
1506     }
1507
1508   if (stream->dec_winstart != 0)
1509     {
1510       VC(UT "VCDIFF window at offset:      %"Q"u\n", stream->dec_winstart)VE;
1511     }
1512
1513   if (SRCORTGT (stream->dec_win_ind))
1514     {
1515       VC(UT "VCDIFF copy window length:    %u\n",
1516          (usize_t)stream->dec_cpylen)VE;
1517       VC(UT "VCDIFF copy window offset:    %"Q"u\n",
1518          stream->dec_cpyoff)VE;
1519     }
1520
1521   VC(UT "VCDIFF delta encoding length: %u\n",
1522      (usize_t)stream->dec_enclen)VE;
1523   VC(UT "VCDIFF target window length:  %u\n",
1524      (usize_t)stream->dec_tgtlen)VE;
1525
1526   VC(UT "VCDIFF data section length:   %u\n",
1527      (usize_t)stream->data_sect.size)VE;
1528   VC(UT "VCDIFF inst section length:   %u\n",
1529      (usize_t)stream->inst_sect.size)VE;
1530   VC(UT "VCDIFF addr section length:   %u\n",
1531      (usize_t)stream->addr_sect.size)VE;
1532
1533   ret = 0;
1534   if ((stream->flags & XD3_JUST_HDR) != 0)
1535     {
1536       /* Print a header -- finished! */
1537       ret = PRINTHDR_SPECIAL;
1538     }
1539   else if ((stream->flags & XD3_SKIP_WINDOW) == 0)
1540     {
1541       ret = main_print_window (stream, xfile);
1542     }
1543
1544   return ret;
1545 }
1546
1547 static int
1548 main_recode_copy (xd3_stream* stream,
1549                   xd3_output* output,
1550                   xd3_desect* input)
1551 {
1552   int ret;
1553
1554   XD3_ASSERT(output != NULL);
1555   XD3_ASSERT(output->next_page == NULL);
1556
1557   if ((ret = xd3_decode_allocate (recode_stream,
1558                                   input->size,
1559                                   &output->base,
1560                                   &output->avail)))
1561     {
1562       XPR(NT XD3_LIB_ERRMSG (stream, ret));
1563       return ret;
1564     }
1565
1566   memcpy (output->base,
1567           /* Note: decoder advances buf, so get base of buffer with
1568            * buf_max - size */
1569           input->buf_max - input->size,
1570           input->size);
1571   output->next = input->size;
1572   return 0;
1573 }
1574
1575 // Re-encode one window
1576 static int
1577 main_recode_func (xd3_stream* stream, main_file *ofile)
1578 {
1579   int ret;
1580   xd3_source decode_source;
1581
1582   XD3_ASSERT(stream->dec_state == DEC_FINISH);
1583   XD3_ASSERT(recode_stream->enc_state == ENC_INIT ||
1584              recode_stream->enc_state == ENC_INPUT);
1585
1586   // Copy partial decoder output to partial encoder inputs
1587   if ((ret = main_recode_copy (recode_stream,
1588                                DATA_HEAD(recode_stream),
1589                                &stream->data_sect)) ||
1590       (ret = main_recode_copy (recode_stream,
1591                                INST_HEAD(recode_stream),
1592                                &stream->inst_sect)) ||
1593       (ret = main_recode_copy (recode_stream,
1594                                ADDR_HEAD(recode_stream),
1595                                &stream->addr_sect)))
1596     {
1597       return ret;
1598     }
1599
1600   // This jumps to xd3_emit_hdr()
1601   recode_stream->enc_state = ENC_FLUSH;
1602   recode_stream->avail_in = stream->dec_tgtlen;
1603
1604   if (SRCORTGT (stream->dec_win_ind))
1605     {
1606       recode_stream->src = & decode_source;
1607       decode_source.srclen = stream->dec_cpylen;
1608       decode_source.srcbase = stream->dec_cpyoff;
1609     }
1610
1611   if (option_use_checksum &&
1612       (stream->dec_win_ind & VCD_ADLER32) != 0)
1613     {
1614       recode_stream->flags |= XD3_ADLER32_RECODE;
1615       recode_stream->recode_adler32 = stream->dec_adler32;
1616     }
1617
1618   if (option_use_appheader != 0 &&
1619       option_appheader != NULL)
1620     {
1621       xd3_set_appheader (recode_stream, option_appheader,
1622                          (usize_t) strlen ((char*) option_appheader));
1623     }
1624   else if (option_use_appheader != 0 &&
1625            option_appheader == NULL)
1626     {
1627       if (stream->dec_appheader != NULL)
1628         {
1629           xd3_set_appheader (recode_stream,
1630                              stream->dec_appheader, stream->dec_appheadsz);
1631         }
1632     }
1633
1634   // Output loop
1635   for (;;)
1636     {
1637       switch((ret = xd3_encode_input (recode_stream)))
1638         {
1639         case XD3_INPUT: {
1640           /* finished recoding one window */
1641           stream->total_out = recode_stream->total_out;
1642           return 0;
1643         }
1644         case XD3_OUTPUT: {
1645           /* main_file_write below */
1646           break;
1647         }
1648         case XD3_GOTHEADER:
1649         case XD3_WINSTART:
1650         case XD3_WINFINISH: {
1651           /* ignore */
1652           continue;
1653         }
1654         case XD3_GETSRCBLK:
1655         case 0: {
1656             return XD3_INTERNAL;
1657           }
1658         default:
1659           return ret;
1660         }
1661
1662       if ((ret = main_write_output (recode_stream, ofile)))
1663         {
1664           return ret;
1665         }
1666
1667       xd3_consume_output (recode_stream);
1668     }
1669 }
1670 #endif /* VCDIFF_TOOLS */
1671
1672 /*******************************************************************
1673  VCDIFF merging
1674  ******************************************************************/
1675
1676 #if VCDIFF_TOOLS
1677 /* Modifies static state. */
1678 static int
1679 main_init_recode_stream (void)
1680 {
1681   int ret;
1682   int stream_flags = XD3_ADLER32_NOVER | XD3_SKIP_EMIT;
1683   int recode_flags;
1684   xd3_config recode_config;
1685
1686   XD3_ASSERT (recode_stream == NULL);
1687
1688   if ((recode_stream = (xd3_stream*) main_malloc(sizeof(xd3_stream))) == NULL)
1689     {
1690       return ENOMEM;
1691     }
1692
1693   recode_flags = (stream_flags & XD3_SEC_TYPE);
1694
1695   recode_config.alloc = main_alloc;
1696   recode_config.freef = main_free1;
1697
1698   xd3_init_config(&recode_config, recode_flags);
1699
1700   if ((ret = main_set_secondary_flags (&recode_config)) ||
1701       (ret = xd3_config_stream (recode_stream, &recode_config)) ||
1702       (ret = xd3_encode_init_partial (recode_stream)) ||
1703       (ret = xd3_whole_state_init (recode_stream)))
1704     {
1705       XPR(NT XD3_LIB_ERRMSG (recode_stream, ret));
1706       xd3_free_stream (recode_stream);
1707       recode_stream = NULL;
1708       return ret;
1709     }
1710
1711   return 0;
1712 }
1713
1714 /* This processes the sequence of -m arguments.  The final input
1715  * is processed as part of the ordinary main_input() loop. */
1716 static int
1717 main_merge_arguments (main_merge_list* merges)
1718 {
1719   int ret = 0;
1720   int count = 0;
1721   main_merge *merge = NULL;
1722   xd3_stream merge_input;
1723
1724   if (main_merge_list_empty (merges))
1725     {
1726       return 0;
1727     }
1728
1729   if ((ret = xd3_config_stream (& merge_input, NULL)) ||
1730       (ret = xd3_whole_state_init (& merge_input)))
1731     {
1732       XPR(NT XD3_LIB_ERRMSG (& merge_input, ret));
1733       return ret;
1734     }
1735
1736   merge = main_merge_list_front (merges);
1737   while (!main_merge_list_end (merges, merge))
1738     {
1739       main_file mfile;
1740       main_file_init (& mfile);
1741       mfile.filename = merge->filename;
1742       mfile.flags = RD_NONEXTERNAL;
1743
1744       if ((ret = main_file_open (& mfile, merge->filename, XO_READ)))
1745         {
1746           goto error;
1747         }
1748
1749       ret = main_input (CMD_MERGE_ARG, & mfile, NULL, NULL);
1750
1751       if (ret == 0)
1752         {
1753           if (count++ == 0)
1754             {
1755               /* The first merge source is the next merge input. */
1756               xd3_swap_whole_state (& recode_stream->whole_target,
1757                                     & merge_input.whole_target);
1758             }
1759           else
1760             {
1761               /* Merge the recode_stream with merge_input. */
1762               ret = xd3_merge_input_output (recode_stream,
1763                                             & merge_input.whole_target);
1764
1765               /* Save the next merge source in merge_input. */
1766               xd3_swap_whole_state (& recode_stream->whole_target,
1767                                     & merge_input.whole_target);
1768             }
1769         }
1770
1771       main_file_cleanup (& mfile);
1772
1773       if (recode_stream != NULL)
1774         {
1775           xd3_free_stream (recode_stream);
1776           main_free (recode_stream);
1777           recode_stream = NULL;
1778         }
1779
1780       if (main_bdata != NULL)
1781         {
1782           main_buffree (main_bdata);
1783           main_bdata = NULL;
1784           main_bsize = 0;
1785         }
1786
1787       if (ret != 0)
1788         {
1789           goto error;
1790         }
1791
1792       merge = main_merge_list_next (merge);
1793     }
1794
1795   XD3_ASSERT (merge_stream == NULL);
1796
1797   if ((merge_stream = (xd3_stream*) main_malloc (sizeof(xd3_stream))) == NULL)
1798     {
1799       ret = ENOMEM;
1800       goto error;
1801     }
1802
1803   if ((ret = xd3_config_stream (merge_stream, NULL)) ||
1804       (ret = xd3_whole_state_init (merge_stream)))
1805     {
1806       XPR(NT XD3_LIB_ERRMSG (& merge_input, ret));
1807       goto error;
1808     }
1809
1810   xd3_swap_whole_state (& merge_stream->whole_target,
1811                         & merge_input.whole_target);
1812   ret = 0;
1813  error:
1814   xd3_free_stream (& merge_input);
1815   return ret;
1816 }
1817
1818 /* This processes each window of the final merge input.  This routine
1819  * does not output, it buffers the entire delta into memory. */
1820 static int
1821 main_merge_func (xd3_stream* stream, main_file *no_write)
1822 {
1823   int ret;
1824
1825   if ((ret = xd3_whole_append_window (stream)))
1826     {
1827       return ret;
1828     }
1829
1830   return 0;
1831 }
1832
1833
1834 /* This is called after all windows have been read, as a final step in
1835  * main_input().  This is only called for the final merge step. */
1836 static int
1837 main_merge_output (xd3_stream *stream, main_file *ofile)
1838 {
1839   int ret;
1840   usize_t inst_pos = 0;
1841   xoff_t output_pos = 0;
1842   xd3_source recode_source;
1843   usize_t window_num = 0;
1844   int at_least_once = 0;
1845
1846   /* merge_stream is set if there were arguments.  this stream's input
1847    * needs to be applied to the merge_stream source. */
1848   if ((merge_stream != NULL) &&
1849       (ret = xd3_merge_input_output (stream,
1850                                      & merge_stream->whole_target)))
1851     {
1852       XPR(NT XD3_LIB_ERRMSG (stream, ret));
1853       return ret;
1854     }
1855
1856   if (option_use_appheader != 0 &&
1857       option_appheader != NULL)
1858     {
1859       xd3_set_appheader (recode_stream, option_appheader,
1860                          (usize_t) strlen ((char*) option_appheader));
1861     }
1862
1863   /* Enter the ENC_INPUT state and bypass the next_in == NULL test
1864    * and (leftover) input buffering logic. */
1865   XD3_ASSERT(recode_stream->enc_state == ENC_INIT);
1866   recode_stream->enc_state = ENC_INPUT;
1867   recode_stream->next_in = main_bdata;
1868   recode_stream->flags |= XD3_FLUSH;
1869
1870   /* This encodes the entire target. */
1871   while (inst_pos < stream->whole_target.instlen || !at_least_once)
1872     {
1873       xoff_t window_start = output_pos;
1874       int window_srcset = 0;
1875       xoff_t window_srcmin = 0;
1876       xoff_t window_srcmax = 0;
1877       usize_t window_pos = 0;
1878       usize_t window_size;
1879
1880       /* at_least_once ensures that we encode at least one window,
1881        * which handles the 0-byte case. */
1882       at_least_once = 1;
1883
1884       XD3_ASSERT (recode_stream->enc_state == ENC_INPUT);
1885
1886       if ((ret = xd3_encode_input (recode_stream)) != XD3_WINSTART)
1887         {
1888           XPR(NT "invalid merge state: %s\n", xd3_mainerror (ret));
1889           return XD3_INVALID;
1890         }
1891
1892       /* Window sizes must match from the input to the output, so that
1893        * target copies are in-range (and so that checksums carry
1894        * over). */
1895       XD3_ASSERT (window_num < stream->whole_target.wininfolen);
1896       window_size = stream->whole_target.wininfo[window_num].length;
1897
1898       /* Output position should also match. */
1899       if (output_pos != stream->whole_target.wininfo[window_num].offset)
1900         {
1901           XPR(NT "internal merge error: offset mismatch\n");
1902           return XD3_INVALID;
1903         }
1904
1905       if (option_use_checksum &&
1906           (stream->dec_win_ind & VCD_ADLER32) != 0)
1907         {
1908           recode_stream->flags |= XD3_ADLER32_RECODE;
1909           recode_stream->recode_adler32 =
1910             stream->whole_target.wininfo[window_num].adler32;
1911         }
1912
1913       window_num++;
1914
1915       if (main_bsize < window_size)
1916         {
1917           main_buffree (main_bdata);
1918           main_bdata = NULL;
1919           main_bsize = 0;
1920           if ((main_bdata = (uint8_t*)
1921                main_bufalloc (window_size)) == NULL)
1922             {
1923               return ENOMEM;
1924             }
1925           main_bsize = window_size;
1926         }
1927
1928       /* This encodes a single target window. */
1929       while (window_pos < window_size &&
1930              inst_pos < stream->whole_target.instlen)
1931         {
1932           xd3_winst *inst = &stream->whole_target.inst[inst_pos];
1933           usize_t take = min(inst->size, window_size - window_pos);
1934           xoff_t addr;
1935
1936           switch (inst->type)
1937             {
1938             case XD3_RUN:
1939               if ((ret = xd3_emit_run (recode_stream, window_pos, take,
1940                                        &stream->whole_target.adds[inst->addr])))
1941                 {
1942                   return ret;
1943                 }
1944               break;
1945
1946             case XD3_ADD:
1947               /* Adds are implicit, put them into the input buffer. */
1948               memcpy (main_bdata + window_pos,
1949                       stream->whole_target.adds + inst->addr, take);
1950               break;
1951
1952             default: /* XD3_COPY + copy mode */
1953               if (inst->mode != 0)
1954                 {
1955                   if (window_srcset) {
1956                     window_srcmin = min(window_srcmin, inst->addr);
1957                     window_srcmax = max(window_srcmax, inst->addr + take);
1958                   } else {
1959                     window_srcset = 1;
1960                     window_srcmin = inst->addr;
1961                     window_srcmax = inst->addr + take;
1962                   }
1963                   addr = inst->addr;
1964                 }
1965               else
1966                 {
1967                   XD3_ASSERT (inst->addr >= window_start);
1968                   addr = inst->addr - window_start;
1969                 }
1970               IF_DEBUG2 (XPR(NTR "[merge copy] winpos %u take %u addr %"Q"u mode %u\n",
1971                             window_pos, take, addr, inst->mode));
1972               if ((ret = xd3_found_match (recode_stream, window_pos, take,
1973                                           addr, inst->mode != 0)))
1974                 {
1975                   return ret;
1976                 }
1977               break;
1978             }
1979
1980           window_pos += take;
1981           output_pos += take;
1982
1983           if (take == inst->size)
1984             {
1985               inst_pos += 1;
1986             }
1987           else
1988             {
1989               /* Modify the instruction for the next pass. */
1990               if (inst->type != XD3_RUN)
1991                 {
1992                   inst->addr += take;
1993                 }
1994               inst->size -= take;
1995             }
1996         }
1997
1998       xd3_avail_input (recode_stream, main_bdata, window_pos);
1999
2000       recode_stream->enc_state = ENC_INSTR;
2001
2002       if (window_srcset) {
2003         recode_stream->srcwin_decided = 1;
2004         recode_stream->src = &recode_source;
2005         recode_source.srclen = (usize_t)(window_srcmax - window_srcmin);
2006         recode_source.srcbase = window_srcmin;
2007         recode_stream->taroff = recode_source.srclen;
2008
2009         XD3_ASSERT (recode_source.srclen != 0);
2010       } else {
2011         recode_stream->srcwin_decided = 0;
2012         recode_stream->src = NULL;
2013         recode_stream->taroff = 0;
2014       }
2015
2016       for (;;)
2017         {
2018           switch ((ret = xd3_encode_input (recode_stream)))
2019             {
2020             case XD3_INPUT: {
2021               goto done_window;
2022             }
2023             case XD3_OUTPUT: {
2024               /* main_file_write below */
2025               break;
2026             }
2027             case XD3_GOTHEADER:
2028             case XD3_WINSTART:
2029             case XD3_WINFINISH: {
2030               /* ignore */
2031               continue;
2032             }
2033             case XD3_GETSRCBLK:
2034             case 0: {
2035               return XD3_INTERNAL;
2036             }
2037             default:
2038               return ret;
2039             }
2040
2041           if ((ret = main_write_output(recode_stream, ofile)))
2042             {
2043               return ret;
2044             }
2045
2046           xd3_consume_output (recode_stream);
2047         }
2048     done_window:
2049       (void) 0;
2050     }
2051
2052   return 0;
2053 }
2054 #endif
2055
2056 /*******************************************************************
2057  Input decompression, output recompression
2058  ******************************************************************/
2059
2060 #if EXTERNAL_COMPRESSION
2061 /* This is tricky POSIX-specific code with lots of fork(), pipe(),
2062  * dup(), waitpid(), and exec() business.  Most of this code
2063  * originated in PRCS1, which did automatic package-file
2064  * decompression.  It works with both XD3_POSIX and XD3_STDIO file
2065  * disciplines.
2066  *
2067  * To automatically detect compressed inputs requires a child process
2068  * to reconstruct the input stream, which was advanced in order to
2069  * detect compression, because it may not be seekable.  In other
2070  * words, the main program reads part of the input stream, and if it
2071  * detects a compressed input it then forks a pipe copier process,
2072  * which copies the first-read block out of the main-program's memory,
2073  * then streams the remaining compressed input into the
2074  * input-decompression pipe.
2075  */
2076
2077 #include <signal.h>
2078 #include <unistd.h>
2079 #include <sys/stat.h>
2080 #include <sys/wait.h>
2081
2082 /* Remember which pipe FD is which. */
2083 #define PIPE_READ_FD  0
2084 #define PIPE_WRITE_FD 1
2085 #define MAX_SUBPROCS  4  /* max(source + copier + output,
2086                                 source + copier + input + copier). */
2087 static pid_t ext_subprocs[MAX_SUBPROCS];
2088
2089 /* Like write(), applies to a fd instead of a main_file, for the pipe
2090  * copier subprocess.  Does not print an error, to facilitate ignoring
2091  * trailing garbage, see main_pipe_copier(). */
2092 static int
2093 main_pipe_write (int outfd, uint8_t *exist_buf, usize_t remain)
2094 {
2095   int ret;
2096
2097   if ((ret = xd3_posix_io (outfd, exist_buf, remain,
2098                            (xd3_posix_func*) &write, NULL)))
2099     {
2100       return ret;
2101     }
2102
2103   return 0;
2104 }
2105
2106 /* A simple error-reporting waitpid interface. */
2107 static int
2108 main_waitpid_check(pid_t pid)
2109 {
2110   int status;
2111   int ret = 0;
2112
2113   if (waitpid (pid, & status, 0) < 0)
2114     {
2115       ret = get_errno ();
2116       XPR(NT "external compression [pid %d] wait: %s\n",
2117           pid, xd3_mainerror (ret));
2118     }
2119   else if (! WIFEXITED (status))
2120     {
2121       // SIGPIPE will be delivered to the child process whenever it
2122       // writes data after this process closes the pipe, 
2123       // happens if xdelta does not require access to the entire 
2124       // source file.  Considered normal.
2125       if (! WIFSIGNALED (status) || WTERMSIG (status) != SIGPIPE) 
2126         {
2127           ret = ECHILD;
2128           XPR(NT "external compression [pid %d] signal %d\n", pid, 
2129               WIFSIGNALED (status) ? WTERMSIG (status) : WSTOPSIG (status));
2130         }
2131       else if (option_verbose)
2132         {
2133           XPR(NT "external compression sigpipe\n");
2134         }
2135     }
2136   else if (WEXITSTATUS (status) != 0)
2137     {
2138       ret = ECHILD;
2139       if (option_verbose > 1)
2140         {
2141           /* Presumably, the error was printed by the subprocess. */
2142           XPR(NT "external compression [pid %d] exit %d\n",
2143               pid, WEXITSTATUS (status));
2144         }
2145     }
2146
2147   return ret;
2148 }
2149
2150 /* Wait for any existing child processes to check for abnormal exit. */
2151 static int
2152 main_external_compression_finish (void)
2153 {
2154   int i;
2155   int ret;
2156
2157   for (i = 0; i < num_subprocs; i += 1)
2158     {
2159       if (! ext_subprocs[i]) { continue; }
2160
2161       if ((ret = main_waitpid_check (ext_subprocs[i])))
2162         {
2163           return ret;
2164         }
2165
2166       ext_subprocs[i] = 0;
2167     }
2168
2169   return 0;
2170 }
2171
2172 /* Kills any outstanding compression process. */
2173 static void
2174 main_external_compression_cleanup (void)
2175 {
2176   int i;
2177
2178   for (i = 0; i < num_subprocs; i += 1)
2179     {
2180       if (! ext_subprocs[i]) { continue; }
2181
2182       kill (ext_subprocs[i], SIGTERM);
2183
2184       ext_subprocs[i] = 0;
2185     }
2186 }
2187
2188 /* This runs as a forked process of main_input_decompress_setup() to
2189  * copy input to the decompression process.  First, the available
2190  * input is copied out of the existing buffer, then the buffer is
2191  * reused to continue reading from the compressed input file. */
2192 static int
2193 main_pipe_copier (uint8_t     *pipe_buf,
2194                   usize_t      pipe_bufsize,
2195                   size_t       nread,
2196                   main_file   *ifile,
2197                   int          outfd)
2198 {
2199   int ret;
2200   xoff_t skipped = 0;
2201
2202   /* Prevent SIGPIPE signals, allow EPIPE return values instead.  This
2203    * is safe to comment-out, except that the -F flag will not work
2204    * properly (the parent would need to treat WTERMSIG(status) ==
2205    * SIGPIPE). */
2206   struct sigaction sa;
2207   sa.sa_handler = SIG_IGN;
2208   sigaction (SIGPIPE, &sa, NULL);
2209
2210   for (;;)
2211     {
2212       /* force_drain will be set when option_force and EPIPE cause us
2213        * to skip data.  This is reset each time through the loop, so
2214        * the break condition below works. */
2215       int force_drain = 0;
2216       if (nread > 0 && (ret = main_pipe_write (outfd, pipe_buf, nread)))
2217         {
2218           if (ret == EPIPE)
2219             {
2220               /* This causes the loop to continue reading until nread
2221                * == 0. */
2222               skipped += nread;
2223               force_drain = 1;
2224             }
2225           else
2226             {
2227               XPR(NT "pipe write failed: %s\n", xd3_mainerror (ret));
2228               return ret;
2229             }
2230         }
2231
2232       if (nread < pipe_bufsize && !force_drain)
2233         {
2234           break;
2235         }
2236
2237       if ((ret = main_file_read (ifile, pipe_buf, pipe_bufsize,
2238                                  & nread, "pipe read failed")) < 0)
2239         {
2240           return ret;
2241         }
2242     }
2243
2244   if (option_verbose && skipped != 0)
2245     {
2246       XPR(NT "skipping %"Q"u bytes in %s\n",
2247           skipped, ifile->filename);
2248     }
2249   return 0;
2250 }
2251
2252 /* This function is called after we have read some amount of data from
2253  * the input file and detected a compressed input.  Here we start a
2254  * decompression subprocess by forking twice.  The first process runs
2255  * the decompression command, the second process copies data to the
2256  * input of the first. */
2257 static int
2258 main_input_decompress_setup (const main_extcomp   *decomp,
2259                              main_file            *ifile,
2260                              uint8_t              *input_buf,
2261                              usize_t               input_bufsize,
2262                              uint8_t              *pipe_buf,
2263                              usize_t               pipe_bufsize,
2264                              usize_t               pipe_avail,
2265                              size_t               *nread)
2266 {
2267   /* The two pipes: input and output file descriptors. */
2268   int outpipefd[2], inpipefd[2];
2269   int input_fd = -1;  /* The resulting input_fd (output of decompression). */
2270   pid_t decomp_id, copier_id;  /* The two subprocs. */
2271   int ret;
2272
2273   outpipefd[0] = outpipefd[1] = -1;
2274   inpipefd[0]  = inpipefd[1]  = -1;
2275
2276   if (pipe (outpipefd) || pipe (inpipefd))
2277     {
2278       XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ()));
2279       goto pipe_cleanup;
2280     }
2281
2282   if ((decomp_id = fork ()) < 0)
2283     {
2284       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
2285       goto pipe_cleanup;
2286     }
2287
2288   /* The first child runs the decompression process: */
2289   if (decomp_id == 0)
2290     {
2291       if (option_verbose > 2)
2292         {
2293           XPR(NT "external decompression pid %d\n", getpid ());
2294         }
2295
2296       /* Setup pipes: write to the outpipe, read from the inpipe. */
2297       if (dup2 (outpipefd[PIPE_WRITE_FD], STDOUT_FILENO) < 0 ||
2298           dup2 (inpipefd[PIPE_READ_FD], STDIN_FILENO) < 0 ||
2299           close (outpipefd[PIPE_READ_FD]) ||
2300           close (outpipefd[PIPE_WRITE_FD]) ||
2301           close (inpipefd[PIPE_READ_FD]) ||
2302           close (inpipefd[PIPE_WRITE_FD]) ||
2303           execlp (decomp->decomp_cmdname, decomp->decomp_cmdname,
2304                   decomp->decomp_options,
2305                   option_force2 ? "-f" : NULL,
2306                   NULL))
2307         {
2308           XPR(NT "child process %s failed to execute: %s\n",
2309               decomp->decomp_cmdname, xd3_mainerror (get_errno ()));
2310         }
2311
2312       _exit (127);
2313     }
2314
2315   XD3_ASSERT(num_subprocs < MAX_SUBPROCS);
2316   ext_subprocs[num_subprocs++] = decomp_id;
2317
2318   if ((copier_id = fork ()) < 0)
2319     {
2320       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
2321       goto pipe_cleanup;
2322     }
2323
2324   /* The second child runs the copier process: */
2325   if (copier_id == 0)
2326     {
2327       int exitval = 0;
2328
2329       if (option_verbose > 2)
2330         {
2331           XPR(NT "child pipe-copier pid %d\n", getpid ());
2332         }
2333
2334       if (close (inpipefd[PIPE_READ_FD]) ||
2335           close (outpipefd[PIPE_READ_FD]) ||
2336           close (outpipefd[PIPE_WRITE_FD]) ||
2337           main_pipe_copier (pipe_buf, pipe_bufsize, pipe_avail,
2338                             ifile, inpipefd[PIPE_WRITE_FD]) ||
2339           close (inpipefd[PIPE_WRITE_FD]))
2340         {
2341           XPR(NT "child copier process failed: %s\n",
2342               xd3_mainerror (get_errno ()));
2343           exitval = 1;
2344         }
2345
2346       _exit (exitval);
2347     }
2348
2349   XD3_ASSERT(num_subprocs < MAX_SUBPROCS);
2350   ext_subprocs[num_subprocs++] = copier_id;
2351
2352   /* The parent closes both pipes after duplicating the output of
2353    * compression. */
2354   input_fd = dup (outpipefd[PIPE_READ_FD]);
2355
2356   if (input_fd < 0 ||
2357       main_file_close (ifile) ||
2358       close (outpipefd[PIPE_READ_FD]) ||
2359       close (outpipefd[PIPE_WRITE_FD]) ||
2360       close (inpipefd[PIPE_READ_FD]) ||
2361       close (inpipefd[PIPE_WRITE_FD]))
2362     {
2363       XPR(NT "dup/close failed: %s\n", xd3_mainerror (ret = get_errno ()));
2364       goto pipe_cleanup;
2365     }
2366
2367 #if XD3_STDIO
2368   /* Note: fdopen() acquires the fd, closes it when finished. */
2369   if ((ifile->file = fdopen (input_fd, "r")) == NULL)
2370     {
2371       XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ()));
2372       goto pipe_cleanup;
2373     }
2374
2375 #elif XD3_POSIX
2376   ifile->file = input_fd;
2377 #endif
2378
2379   ifile->compressor = decomp;
2380
2381   /* Now the input file is decompressed. */
2382   return main_file_read (ifile, input_buf, input_bufsize,
2383                          nread, "input decompression failed");
2384
2385  pipe_cleanup:
2386   close (input_fd);
2387   close (outpipefd[PIPE_READ_FD]);
2388   close (outpipefd[PIPE_WRITE_FD]);
2389   close (inpipefd[PIPE_READ_FD]);
2390   close (inpipefd[PIPE_WRITE_FD]);
2391   return ret;
2392 }
2393
2394
2395 /* This routine is called when the first buffer of input data is read
2396  * by the main program (unless input decompression is disabled by
2397  * command-line option).  If it recognizes the magic number of a known
2398  * input type it invokes decompression.
2399  *
2400  * Skips decompression if the decompression type or the file type is
2401  * RD_NONEXTERNAL.
2402  *
2403  * Behaves exactly like main_file_read, otherwise.
2404  *
2405  * This function uses a separate buffer to read the first small block
2406  * of input.  If a compressed input is detected, the separate buffer
2407  * is passed to the pipe copier.  This avoids using the same size
2408  * buffer in both cases. */
2409 static int
2410 main_secondary_decompress_check (main_file  *file,
2411                                  uint8_t    *input_buf,
2412                                  size_t      input_size,
2413                                  size_t     *nread)
2414 {
2415   int ret;
2416   usize_t i;
2417   usize_t try_read = min (input_size, XD3_ALLOCSIZE);
2418   size_t  check_nread = 0;
2419   uint8_t check_buf[XD3_ALLOCSIZE];  /* TODO: stack limit */
2420   const main_extcomp *decompressor = NULL;
2421
2422   if ((ret = main_file_read (file, check_buf,
2423                              try_read,
2424                              & check_nread, "input read failed")))
2425     {
2426       return ret;
2427     }
2428
2429   if (file->flags & RD_DECOMPSET)
2430     {
2431       /* This allows the application header to override the magic
2432        * number, for whatever reason. */
2433       decompressor = file->compressor;
2434     }
2435   else
2436     {
2437       for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
2438         {
2439           const main_extcomp *decomp = & extcomp_types[i];
2440
2441           if (check_nread > decomp->magic_size)
2442             {
2443               /* The following expr checks if we are trying to read a
2444                * VCDIFF input, in which case do not treat it as
2445                * "secondary" decompression. */
2446               int skip_this_type = (decomp->flags & RD_NONEXTERNAL) &&
2447                                    (file->flags & RD_NONEXTERNAL);
2448
2449               if (skip_this_type)
2450                 {
2451                   continue;
2452                 }
2453
2454               if (memcmp (check_buf, decomp->magic, decomp->magic_size) == 0)
2455                 {
2456                   decompressor = decomp;
2457                   break;
2458                 }
2459             }
2460         }
2461     }
2462
2463   if (decompressor != NULL)
2464     {
2465       if (! option_quiet)
2466         {
2467           XPR(NT "externally compressed input: %s %s%s < %s\n",
2468               decompressor->decomp_cmdname,
2469               decompressor->decomp_options,
2470               (option_force2 ? " -f" : ""),
2471               file->filename);
2472           if (file->flags & RD_MAININPUT)
2473             {
2474               XPR(NT
2475   "WARNING: the encoder is automatically decompressing the input file;\n");
2476               XPR(NT
2477   "WARNING: the decoder will automatically recompress the output file;\n");
2478               XPR(NT
2479   "WARNING: this may result in different compressed data and checksums\n");
2480               XPR(NT
2481   "WARNING: despite being identical data; if this is an issue, use -D\n");
2482               XPR(NT
2483   "WARNING: to avoid decompression and/or use -R to avoid recompression\n");
2484               XPR(NT
2485   "WARNING: and/or manually decompress the input file; if you know the\n");
2486               XPR(NT
2487   "WARNING: compression settings that will produce identical output\n");
2488               XPR(NT
2489   "WARNING: you may set those flags using the environment (e.g., GZIP=-9)\n");
2490             }
2491         }
2492
2493       file->size_known = 0;
2494       return main_input_decompress_setup (decompressor, file,
2495                                           input_buf, input_size,
2496                                           check_buf, XD3_ALLOCSIZE,
2497                                           check_nread, nread);
2498     }
2499
2500   /* Now read the rest of the input block. */
2501   (*nread) = 0;
2502
2503   if (check_nread == try_read)
2504     {
2505       ret = main_file_read (file,
2506                             input_buf + try_read,
2507                             input_size - try_read,
2508                             nread,
2509                             "input read failed");
2510     }
2511
2512   memcpy (input_buf, check_buf, check_nread);
2513
2514   (*nread) += check_nread;
2515
2516   return 0;
2517 }
2518
2519 /* Initiate re-compression of the output stream.  This is easier than
2520  * input decompression because we know beforehand that the stream will
2521  * be compressed, whereas the input has already been read when we
2522  * decide it should be decompressed.  Thus, it only requires one
2523  * subprocess and one pipe. */
2524 static int
2525 main_recompress_output (main_file *ofile)
2526 {
2527   pid_t recomp_id;  /* One subproc. */
2528   int   pipefd[2];  /* One pipe. */
2529   int   output_fd = -1;
2530   int   ret;
2531   const main_extcomp *recomp = ofile->compressor;
2532
2533   pipefd[0] = pipefd[1] = -1;
2534
2535   if (pipe (pipefd))
2536     {
2537       XPR(NT "pipe failed: %s\n", xd3_mainerror (ret = get_errno ()));
2538       goto pipe_cleanup;
2539     }
2540
2541   if ((recomp_id = fork ()) < 0)
2542     {
2543       XPR(NT "fork failed: %s\n", xd3_mainerror (ret = get_errno ()));
2544       goto pipe_cleanup;
2545     }
2546
2547   /* The child runs the recompression process: */
2548   if (recomp_id == 0)
2549     {
2550       if (option_verbose > 2)
2551         {
2552           XPR(NT "external recompression pid %d\n", getpid ());
2553         }
2554
2555       /* Setup pipes: write to the output file, read from the pipe. */
2556       if (dup2 (XFNO (ofile), STDOUT_FILENO) < 0 ||
2557           dup2 (pipefd[PIPE_READ_FD], STDIN_FILENO) < 0 ||
2558           close (pipefd[PIPE_READ_FD]) ||
2559           close (pipefd[PIPE_WRITE_FD]) ||
2560           execlp (recomp->recomp_cmdname, recomp->recomp_cmdname,
2561                   recomp->recomp_options,
2562                   option_force2 ? "-f" : NULL,
2563                   NULL))
2564         {
2565           XPR(NT "child process %s failed to execute: %s\n",
2566               recomp->recomp_cmdname, xd3_mainerror (get_errno ()));
2567         }
2568
2569       _exit (127);
2570     }
2571
2572   XD3_ASSERT(num_subprocs < MAX_SUBPROCS);
2573   ext_subprocs[num_subprocs++] = recomp_id;
2574
2575   /* The parent closes both pipes after duplicating the output-fd for
2576    * writing to the compression pipe. */
2577   output_fd = dup (pipefd[PIPE_WRITE_FD]);
2578
2579   if (output_fd < 0 ||
2580       main_file_close (ofile) ||
2581       close (pipefd[PIPE_READ_FD]) ||
2582       close (pipefd[PIPE_WRITE_FD]))
2583     {
2584       XPR(NT "close failed: %s\n", xd3_mainerror (ret = get_errno ()));
2585       goto pipe_cleanup;
2586     }
2587
2588 #if XD3_STDIO
2589   /* Note: fdopen() acquires the fd, closes it when finished. */
2590   if ((ofile->file = fdopen (output_fd, "w")) == NULL)
2591     {
2592       XPR(NT "fdopen failed: %s\n", xd3_mainerror (ret = get_errno ()));
2593       goto pipe_cleanup;
2594     }
2595
2596 #elif XD3_POSIX
2597   ofile->file = output_fd;
2598 #endif
2599
2600   /* Now the output file will be compressed. */
2601   return 0;
2602
2603  pipe_cleanup:
2604   close (output_fd);
2605   close (pipefd[PIPE_READ_FD]);
2606   close (pipefd[PIPE_WRITE_FD]);
2607   return ret;
2608 }
2609 #endif /* EXTERNAL_COMPRESSION */
2610
2611 /* Identify the compressor that was used based on its ident string,
2612  * which is passed in the application header. */
2613 static const main_extcomp*
2614 main_ident_compressor (const char *ident)
2615 {
2616   usize_t i;
2617
2618   for (i = 0; i < SIZEOF_ARRAY (extcomp_types); i += 1)
2619     {
2620       if (strcmp (extcomp_types[i].ident, ident) == 0)
2621         {
2622           return & extcomp_types[i];
2623         }
2624     }
2625
2626   return NULL;
2627 }
2628
2629 /* Return the main_extcomp record to use for this identifier, if possible. */
2630 static const main_extcomp*
2631 main_get_compressor (const char *ident)
2632 {
2633   const main_extcomp *ext = main_ident_compressor (ident);
2634
2635   if (ext == NULL)
2636     {
2637       if (! option_quiet)
2638         {
2639           XPR(NT "warning: cannot recompress output: "
2640                    "unrecognized external compression ID: %s\n", ident);
2641         }
2642       return NULL;
2643     }
2644   else if (! EXTERNAL_COMPRESSION)
2645     {
2646       if (! option_quiet)
2647         {
2648           XPR(NT "warning: external support not compiled: "
2649                    "original input was compressed: %s\n", ext->recomp_cmdname);
2650         }
2651       return NULL;
2652     }
2653   else
2654     {
2655       return ext;
2656     }
2657 }
2658
2659 /*********************************************************************
2660  APPLICATION HEADER
2661  *******************************************************************/
2662
2663 #if XD3_ENCODER
2664 static const char*
2665 main_apphead_string (const char* x)
2666 {
2667   const char *y;
2668
2669   if (x == NULL) { return ""; }
2670
2671   if (strcmp (x, "/dev/stdin") == 0 ||
2672       strcmp (x, "/dev/stdout") == 0 ||
2673       strcmp (x, "/dev/stderr") == 0) { return "-"; }
2674
2675   // TODO: this is not portable
2676   return (y = strrchr (x, '/')) == NULL ? x : y + 1;
2677 }
2678
2679 static int
2680 main_set_appheader (xd3_stream *stream, main_file *input, main_file *sfile)
2681 {
2682   /* The user may disable the application header.  Once the appheader
2683    * is set, this disables setting it again. */
2684   if (appheader_used || ! option_use_appheader) { return 0; }
2685
2686   /* The user may specify the application header, otherwise format the
2687      default header. */
2688   if (option_appheader)
2689     {
2690       appheader_used = option_appheader;
2691     }
2692   else
2693     {
2694       const char *iname;
2695       const char *icomp;
2696       const char *sname;
2697       const char *scomp;
2698       usize_t len;
2699
2700       iname = main_apphead_string (input->filename);
2701       icomp = (input->compressor == NULL) ? "" : input->compressor->ident;
2702       len = (usize_t) strlen (iname) + (usize_t) strlen (icomp) + 2;
2703
2704       if (sfile->filename != NULL)
2705         {
2706           sname = main_apphead_string (sfile->filename);
2707           scomp = (sfile->compressor == NULL) ? "" : sfile->compressor->ident;
2708           len += (usize_t) strlen (sname) + (usize_t) strlen (scomp) + 2;
2709         }
2710       else
2711         {
2712           sname = scomp = "";
2713         }
2714
2715       if ((appheader_used = (uint8_t*) main_malloc (len)) == NULL)
2716         {
2717           return ENOMEM;
2718         }
2719
2720       if (sfile->filename == NULL)
2721         {
2722           snprintf_func ((char*)appheader_used, len, "%s/%s", iname, icomp);
2723         }
2724       else
2725         {
2726           snprintf_func ((char*)appheader_used, len, "%s/%s/%s/%s",
2727                     iname, icomp, sname, scomp);
2728         }
2729     }
2730
2731   xd3_set_appheader (stream, appheader_used,
2732                      (usize_t) strlen ((char*)appheader_used));
2733
2734   return 0;
2735 }
2736 #endif
2737
2738 static void
2739 main_get_appheader_params (main_file *file, char **parsed,
2740                            int output, const char *type,
2741                            main_file *other)
2742 {
2743   /* Set the filename if it was not specified.  If output, option_stdout (-c)
2744    * overrides. */
2745   if (file->filename == NULL &&
2746       ! (output && option_stdout) &&
2747       strcmp (parsed[0], "-") != 0)
2748     {
2749       file->filename = parsed[0];
2750
2751       if (other->filename != NULL) {
2752         /* Take directory from the other file, if it has one. */
2753         /* TODO: This results in nonsense names like /dev/foo.tar.gz
2754          * and probably the filename-default logic interferes with
2755          * multi-file operation and the standard file extension?
2756          * Possibly the name header is bad, should be off by default.
2757          * Possibly we just want to remember external/compression
2758          * settings. */
2759         const char *last_slash = strrchr(other->filename, '/');
2760
2761         if (last_slash != NULL) {
2762           usize_t dlen = (usize_t) (last_slash - other->filename);
2763
2764           XD3_ASSERT(file->filename_copy == NULL);
2765           file->filename_copy =
2766             (char*) main_malloc(dlen + 2 + (usize_t) strlen(file->filename));
2767
2768           strncpy(file->filename_copy, other->filename, dlen);
2769           file->filename_copy[dlen] = '/';
2770           strcpy(file->filename_copy + dlen + 1, parsed[0]);
2771
2772           file->filename = file->filename_copy;
2773         }
2774       }
2775
2776       if (! option_quiet)
2777         {
2778           XPR(NT "using default %s filename: %s\n", type, file->filename);
2779         }
2780     }
2781
2782   /* Set the compressor, initiate de/recompression later. */
2783   if (file->compressor == NULL && *parsed[1] != 0)
2784     {
2785       file->flags |= RD_DECOMPSET;
2786       file->compressor = main_get_compressor (parsed[1]);
2787     }
2788 }
2789
2790 static void
2791 main_get_appheader (xd3_stream *stream, main_file *ifile,
2792                     main_file *output, main_file *sfile)
2793 {
2794   uint8_t *apphead;
2795   usize_t appheadsz;
2796   int ret;
2797
2798   /* The user may disable the application header.  Once the appheader
2799    * is set, this disables setting it again. */
2800   if (! option_use_appheader) { return; }
2801
2802   ret = xd3_get_appheader (stream, & apphead, & appheadsz);
2803
2804   /* Ignore failure, it only means we haven't received a header yet. */
2805   if (ret != 0) { return; }
2806
2807   if (appheadsz > 0)
2808     {
2809       const int kMaxArgs = 4;
2810       char *start = (char*)apphead;
2811       char *slash;
2812       int   place = 0;
2813       char *parsed[kMaxArgs];
2814
2815       memset (parsed, 0, sizeof (parsed));
2816
2817       while ((slash = strchr (start, '/')) != NULL && place < (kMaxArgs-1))
2818         {
2819           *slash = 0;
2820           parsed[place++] = start;
2821           start = slash + 1;
2822         }
2823
2824       parsed[place++] = start;
2825
2826       /* First take the output parameters. */
2827       if (place == 2 || place == 4)
2828         {
2829           main_get_appheader_params (output, parsed, 1, "output", ifile);
2830         }
2831
2832       /* Then take the source parameters. */
2833       if (place == 4)
2834         {
2835           main_get_appheader_params (sfile, parsed+2, 0, "source", ifile);
2836         }
2837     }
2838
2839   option_use_appheader = 0;
2840   return;
2841 }
2842
2843 /*********************************************************************
2844  Main I/O routines
2845  **********************************************************************/
2846
2847 /* This function acts like the above except it may also try to
2848  * recognize a compressed input (source or target) when the first
2849  * buffer of data is read.  The EXTERNAL_COMPRESSION code is called to
2850  * search for magic numbers. */
2851 static int
2852 main_read_primary_input (main_file   *file,
2853                          uint8_t     *buf,
2854                          size_t       size,
2855                          size_t      *nread)
2856 {
2857 #if EXTERNAL_COMPRESSION
2858   if (option_decompress_inputs && file->flags & RD_FIRST)
2859     {
2860       file->flags &= ~RD_FIRST;
2861       return main_secondary_decompress_check (file, buf, size, nread);
2862     }
2863 #endif
2864
2865   return main_file_read (file, buf, size, nread, "input read failed");
2866 }
2867
2868 /* Open the main output file, sets a default file name, initiate
2869  * recompression.  This function is expected to fprint any error
2870  * messages. */
2871 static int
2872 main_open_output (xd3_stream *stream, main_file *ofile)
2873 {
2874   int ret;
2875
2876   if (option_no_output)
2877     {
2878       return 0;
2879     }
2880
2881   if (ofile->filename == NULL)
2882     {
2883       XSTDOUT_XF (ofile);
2884
2885       if (option_verbose > 1)
2886         {
2887           XPR(NT "using standard output: %s\n", ofile->filename);
2888         }
2889     }
2890   else
2891     {
2892       /* Stat the file to check for overwrite. */
2893       if (option_force == 0 && main_file_exists (ofile))
2894         {
2895           if (!option_quiet)
2896             {
2897               XPR(NT "to overwrite output file specify -f: %s\n",
2898                   ofile->filename);
2899             }
2900           return EEXIST;
2901         }
2902
2903       if ((ret = main_file_open (ofile, ofile->filename, XO_WRITE)))
2904         {
2905           return ret;
2906         }
2907
2908       if (option_verbose > 1) { XPR(NT "output %s\n", ofile->filename); }
2909     }
2910
2911 #if EXTERNAL_COMPRESSION
2912   /* Do output recompression. */
2913   if (ofile->compressor != NULL && option_recompress_outputs == 1)
2914     {
2915       if (! option_quiet)
2916         {
2917           XPR(NT "externally compressed output: %s %s%s > %s\n",
2918               ofile->compressor->recomp_cmdname,
2919               ofile->compressor->recomp_options,
2920               (option_force2 ? " -f" : ""),
2921               ofile->filename);
2922         }
2923
2924       if ((ret = main_recompress_output (ofile)))
2925         {
2926           return ret;
2927         }
2928     }
2929 #endif
2930
2931   return 0;
2932 }
2933
2934 static usize_t
2935 main_get_winsize (main_file *ifile) {
2936   xoff_t file_size = 0;
2937   usize_t size = option_winsize;
2938   static shortbuf iszbuf;
2939
2940   if (main_file_stat (ifile, &file_size) == 0)
2941     {
2942       size = (usize_t) min(file_size, (xoff_t) size);
2943     }
2944
2945   size = max(size, XD3_ALLOCSIZE);
2946
2947   if (option_verbose > 1)
2948     {
2949       XPR(NT "input %s window size %s\n",
2950           ifile->filename,
2951           main_format_bcnt (size, &iszbuf));
2952     }
2953
2954   return size;
2955 }
2956
2957 /*********************************************************************
2958  Main routines
2959  ********************************************************************/
2960
2961 /* This is a generic input function.  It calls the xd3_encode_input or
2962  * xd3_decode_input functions and makes calls to the various input
2963  * handling routines above, which coordinate external decompression.
2964  */
2965 static int
2966 main_input (xd3_cmd     cmd,
2967             main_file   *ifile,
2968             main_file   *ofile,
2969             main_file   *sfile)
2970 {
2971   int        ret;
2972   xd3_stream stream;
2973   size_t     nread = 0;
2974   usize_t    winsize;
2975   int        stream_flags = 0;
2976   xd3_config config;
2977   xd3_source source;
2978   xoff_t     last_total_in = 0;
2979   xoff_t     last_total_out = 0;
2980   long       start_time;
2981   int        stdout_only = 0;
2982   int (*input_func) (xd3_stream*);
2983   int (*output_func) (xd3_stream*, main_file *);
2984
2985   memset (& stream, 0, sizeof (stream));
2986   memset (& source, 0, sizeof (source));
2987   memset (& config, 0, sizeof (config));
2988
2989   config.alloc = main_alloc;
2990   config.freef = main_free1;
2991
2992   config.iopt_size = option_iopt_size;
2993   config.sprevsz = option_sprevsz;
2994
2995   do_src_fifo = 0;
2996
2997   start_time = get_millisecs_now ();
2998
2999   if (option_use_checksum) { stream_flags |= XD3_ADLER32; }
3000
3001   /* main_input setup. */
3002   switch ((int) cmd)
3003     {
3004 #if VCDIFF_TOOLS
3005            if (1) { case CMD_PRINTHDR:   stream_flags |= XD3_JUST_HDR; }
3006       else if (1) { case CMD_PRINTHDRS:  stream_flags |= XD3_SKIP_WINDOW; }
3007       else        { case CMD_PRINTDELTA: stream_flags |= XD3_SKIP_EMIT; }
3008       ifile->flags |= RD_NONEXTERNAL;
3009       input_func    = xd3_decode_input;
3010       output_func   = main_print_func;
3011       stream_flags |= XD3_ADLER32_NOVER;
3012       stdout_only   = 1;
3013       break;
3014
3015     case CMD_RECODE:
3016     case CMD_MERGE:
3017     case CMD_MERGE_ARG:
3018       /* No source will be read */
3019       stream_flags |= XD3_ADLER32_NOVER | XD3_SKIP_EMIT;
3020       ifile->flags |= RD_NONEXTERNAL;
3021       input_func = xd3_decode_input;
3022
3023       if ((ret = main_init_recode_stream ()))
3024         {
3025           return EXIT_FAILURE;
3026         }
3027
3028       if (cmd == CMD_RECODE) { output_func = main_recode_func; }
3029       else                   { output_func = main_merge_func; }
3030       break;
3031 #endif /* VCDIFF_TOOLS */
3032
3033 #if XD3_ENCODER
3034     case CMD_ENCODE:
3035       do_src_fifo = 1;
3036       input_func  = xd3_encode_input;
3037       output_func = main_write_output;
3038
3039       if (option_no_compress)      { stream_flags |= XD3_NOCOMPRESS; }
3040       if (option_smatch_config)
3041         {
3042           const char *s = option_smatch_config;
3043           char *e;
3044           int values[XD3_SOFTCFG_VARCNT];
3045           int got;
3046
3047           config.smatch_cfg = XD3_SMATCH_SOFT;
3048
3049           for (got = 0; got < XD3_SOFTCFG_VARCNT; got += 1, s = e + 1)
3050             {
3051               values[got] = strtol (s, &e, 10);
3052
3053               if ((values[got] < 0) ||
3054                   (e == s) ||
3055                   (got < XD3_SOFTCFG_VARCNT-1 && *e == 0) ||
3056                   (got == XD3_SOFTCFG_VARCNT-1 && *e != 0))
3057                 {
3058                   XPR(NT "invalid string match specifier (-C) %d: %s\n",
3059                       got, s);
3060                   return EXIT_FAILURE;
3061                 }
3062             }
3063
3064           config.smatcher_soft.large_look    = values[0];
3065           config.smatcher_soft.large_step    = values[1];
3066           config.smatcher_soft.small_look    = values[2];
3067           config.smatcher_soft.small_chain   = values[3];
3068           config.smatcher_soft.small_lchain  = values[4];
3069           config.smatcher_soft.max_lazy      = values[5];
3070           config.smatcher_soft.long_enough   = values[6];
3071         }
3072       else
3073         {
3074           if (option_verbose > 2)
3075             {
3076               XPR(NT "compression level: %d\n", option_level);
3077             }
3078           if (option_level == 0)
3079             {
3080               stream_flags |= XD3_NOCOMPRESS;
3081               config.smatch_cfg = XD3_SMATCH_FASTEST;
3082             }
3083           else if (option_level == 1)
3084             { config.smatch_cfg = XD3_SMATCH_FASTEST; }
3085           else if (option_level == 2)
3086             { config.smatch_cfg = XD3_SMATCH_FASTER; }
3087           else if (option_level <= 5)
3088             { config.smatch_cfg = XD3_SMATCH_FAST; }
3089           else if (option_level == 6)
3090             { config.smatch_cfg = XD3_SMATCH_DEFAULT; }
3091           else
3092             { config.smatch_cfg = XD3_SMATCH_SLOW; }
3093         }
3094       break;
3095 #endif
3096     case CMD_DECODE:
3097       if (option_use_checksum == 0) { stream_flags |= XD3_ADLER32_NOVER; }
3098       ifile->flags |= RD_NONEXTERNAL;
3099       input_func    = xd3_decode_input;
3100       output_func   = main_write_output;
3101       break;
3102     default:
3103       XPR(NT "internal error\n");
3104       return EXIT_FAILURE;
3105     }
3106
3107   main_bsize = winsize = main_get_winsize (ifile);
3108
3109   if ((main_bdata = (uint8_t*) main_bufalloc (winsize)) == NULL)
3110     {
3111       return EXIT_FAILURE;
3112     }
3113
3114   config.winsize = winsize;
3115   config.getblk = main_getblk_func;
3116   config.flags = stream_flags;
3117
3118   if ((ret = main_set_secondary_flags (&config)) ||
3119       (ret = xd3_config_stream (& stream, & config)))
3120     {
3121       XPR(NT XD3_LIB_ERRMSG (& stream, ret));
3122       return EXIT_FAILURE;
3123     }
3124
3125 #if VCDIFF_TOOLS
3126   if ((cmd == CMD_MERGE || cmd == CMD_MERGE_ARG) &&
3127       (ret = xd3_whole_state_init (& stream)))
3128     {
3129       XPR(NT XD3_LIB_ERRMSG (& stream, ret));
3130       return EXIT_FAILURE;
3131     }
3132 #endif
3133
3134   if (cmd != CMD_DECODE)
3135     {
3136       /* When not decoding, set source now.  The decoder delays this
3137        * step until XD3_GOTHEADER. */
3138       if (sfile && sfile->filename != NULL)
3139         {
3140           if ((ret = main_set_source (& stream, cmd, sfile, & source)))
3141             {
3142               return EXIT_FAILURE;
3143             }
3144
3145           XD3_ASSERT(stream.src != NULL);
3146         }
3147     }
3148
3149   if (cmd == CMD_PRINTHDR ||
3150       cmd == CMD_PRINTHDRS ||
3151       cmd == CMD_PRINTDELTA ||
3152       cmd == CMD_RECODE)
3153     {
3154       if (sfile->filename == NULL)
3155         {
3156           allow_fake_source = 1;
3157           sfile->filename = "<placeholder>";
3158           main_set_source (& stream, cmd, sfile, & source);
3159         }
3160     }
3161
3162   /* This times each window. */
3163   get_millisecs_since ();
3164
3165   /* Main input loop. */
3166   do
3167     {
3168       xoff_t input_offset;
3169       xoff_t input_remain;
3170       usize_t try_read;
3171
3172       input_offset = ifile->nread;
3173
3174       input_remain = XOFF_T_MAX - input_offset;
3175
3176       try_read = (usize_t) min ((xoff_t) config.winsize, input_remain);
3177
3178       if ((ret = main_read_primary_input (ifile, main_bdata,
3179                                           try_read, & nread)))
3180         {
3181           return EXIT_FAILURE;
3182         }
3183
3184       /* If we've reached EOF tell the stream to flush. */
3185       if (nread < try_read)
3186         {
3187           stream.flags |= XD3_FLUSH;
3188         }
3189
3190 #if XD3_ENCODER
3191       /* After the first main_read_primary_input completes, we know
3192        * all the information needed to encode the application
3193        * header. */
3194       if (cmd == CMD_ENCODE &&
3195           (ret = main_set_appheader (& stream, ifile, sfile)))
3196         {
3197           return EXIT_FAILURE;
3198         }
3199 #endif
3200       xd3_avail_input (& stream, main_bdata, nread);
3201
3202       /* If we read zero bytes after encoding at least one window... */
3203       if (nread == 0 && stream.current_window > 0) {
3204         break;
3205       }
3206
3207     again:
3208       ret = input_func (& stream);
3209
3210       switch (ret)
3211         {
3212         case XD3_INPUT:
3213           continue;
3214
3215         case XD3_GOTHEADER:
3216           {
3217             XD3_ASSERT (stream.current_window == 0);
3218
3219             /* Need to process the appheader as soon as possible.  It may
3220              * contain a suggested default filename/decompression routine for
3221              * the ofile, and it may contain default/decompression routine for
3222              * the sources. */
3223             if (cmd == CMD_DECODE)
3224               {
3225                 /* May need to set the sfile->filename if none was given. */
3226                 main_get_appheader (& stream, ifile, ofile, sfile);
3227
3228                 /* Now open the source file. */
3229                   if ((sfile->filename != NULL) &&
3230                       (ret = main_set_source (& stream, cmd, sfile, & source)))
3231                   {
3232                     return EXIT_FAILURE;
3233                   }
3234               }
3235           }
3236         /* FALLTHROUGH */
3237         case XD3_WINSTART:
3238           {
3239             /* e.g., set or unset XD3_SKIP_WINDOW. */
3240             goto again;
3241           }
3242
3243         case XD3_OUTPUT:
3244           {
3245             /* Defer opening the output file until the stream produces its
3246              * first output for both encoder and decoder, this way we
3247              * delay long enough for the decoder to receive the
3248              * application header.  (Or longer if there are skipped
3249              * windows, but I can't think of any reason not to delay
3250              * open.) */
3251             if (ofile != NULL &&
3252                 ! main_file_isopen (ofile) &&
3253                 (ret = main_open_output (& stream, ofile)) != 0)
3254               {
3255                 return EXIT_FAILURE;
3256               }
3257
3258             if ((ret = output_func (& stream, ofile)) &&
3259                 (ret != PRINTHDR_SPECIAL))
3260               {
3261                 return EXIT_FAILURE;
3262               }
3263
3264             if (ret == PRINTHDR_SPECIAL)
3265               {
3266                 xd3_abort_stream (& stream);
3267                 ret = EXIT_SUCCESS;
3268                 goto done;
3269               }
3270
3271             ret = 0;
3272
3273             xd3_consume_output (& stream);
3274             goto again;
3275           }
3276
3277         case XD3_WINFINISH:
3278           {
3279             if (IS_ENCODE (cmd) || cmd == CMD_DECODE || cmd == CMD_RECODE)
3280               {
3281                 if (! option_quiet && IS_ENCODE (cmd) &&
3282                     main_file_isopen (sfile))
3283                   {
3284                     /* Warn when no source copies are found */
3285                     if (option_verbose && ! xd3_encoder_used_source (& stream))
3286                       {
3287                         XPR(NT "warning: input window %"Q"u..%"Q"u has "
3288                             "no source copies\n",
3289                             stream.current_window * winsize,
3290                             (stream.current_window+1) * winsize);
3291                         XD3_ASSERT (stream.src != NULL);
3292                       }
3293
3294                     /* Limited i-buffer size affects source copies
3295                      * when the sourcewin is decided early. */
3296                     if (option_verbose > 1 &&
3297                         stream.srcwin_decided_early &&
3298                         stream.i_slots_used > stream.iopt_size)
3299                       {
3300                         XPR(NT "warning: input position %"Q"u overflowed "
3301                             "instruction buffer, needed %u (vs. %u), "
3302                             "consider changing -I\n",
3303                             stream.current_window * winsize,
3304                             stream.i_slots_used, stream.iopt_size);
3305                       }
3306                   }
3307
3308                 if (option_verbose)
3309                   {
3310                     shortbuf rrateavg, wrateavg, tm;
3311                     shortbuf rdb, wdb;
3312                     shortbuf trdb, twdb;
3313                     shortbuf srcpos;
3314                     long millis = get_millisecs_since ();
3315                     usize_t this_read = (usize_t)(stream.total_in -
3316                                                   last_total_in);
3317                     usize_t this_write = (usize_t)(stream.total_out -
3318                                                    last_total_out);
3319                     last_total_in = stream.total_in;
3320                     last_total_out = stream.total_out;
3321
3322                     if (option_verbose > 1)
3323                       {
3324                         XPR(NT "%"Q"u: in %s (%s): out %s (%s): "
3325                             "total in %s: out %s: %s: srcpos %s\n",
3326                             stream.current_window,
3327                             main_format_bcnt (this_read, &rdb),
3328                             main_format_rate (this_read, millis, &rrateavg),
3329                             main_format_bcnt (this_write, &wdb),
3330                             main_format_rate (this_write, millis, &wrateavg),
3331                             main_format_bcnt (stream.total_in, &trdb),
3332                             main_format_bcnt (stream.total_out, &twdb),
3333                             main_format_millis (millis, &tm),
3334                             main_format_bcnt (sfile->source_position, &srcpos));
3335                       }
3336                     else
3337                       {
3338                         XPR(NT "%"Q"u: in %s: out %s: total in %s: "
3339                             "out %s: %s\n",
3340                             stream.current_window,
3341                             main_format_bcnt (this_read, &rdb),
3342                             main_format_bcnt (this_write, &wdb),
3343                             main_format_bcnt (stream.total_in, &trdb),
3344                             main_format_bcnt (stream.total_out, &twdb),
3345                             main_format_millis (millis, &tm));
3346                       }
3347                   }
3348               }
3349             goto again;
3350           }
3351
3352         default:
3353           /* input_func() error */
3354           XPR(NT XD3_LIB_ERRMSG (& stream, ret));
3355           if (! option_quiet && ret == XD3_INVALID_INPUT)
3356             {
3357               XPR(NT "normally this indicates that the source file is incorrect\n");
3358               XPR(NT "please verify the source file with sha1sum or equivalent\n");
3359             }
3360           return EXIT_FAILURE;
3361         }
3362     }
3363   while (nread == config.winsize);
3364 done:
3365   /* Close the inputs. (ifile must be open, sfile may be open) */
3366   main_file_close (ifile);
3367   if (sfile != NULL)
3368     {
3369       main_file_close (sfile);
3370     }
3371
3372 #if VCDIFF_TOOLS
3373   if (cmd == CMD_MERGE &&
3374       (ret = main_merge_output (& stream, ofile)))
3375     {
3376       return EXIT_FAILURE;
3377     }
3378
3379   if (cmd == CMD_MERGE_ARG)
3380     {
3381       xd3_swap_whole_state (& stream.whole_target,
3382                             & recode_stream->whole_target);
3383     }
3384 #endif /* VCDIFF_TOOLS */
3385
3386   /* If output file is not open yet because of delayed-open, it means
3387    * we never encountered a window in the delta, but it could have had
3388    * a VCDIFF header?  TODO: solve this elsewhere.  For now, it prints
3389    * "nothing to output" below, but the check doesn't happen in case
3390    * of option_no_output.  */
3391   if (! option_no_output && ofile != NULL)
3392     {
3393       if (!stdout_only && ! main_file_isopen (ofile))
3394         {
3395           XPR(NT "nothing to output: %s\n", ifile->filename);
3396           return EXIT_FAILURE;
3397         }
3398
3399       /* Have to close the output before calling
3400        * main_external_compression_finish, or else it hangs. */
3401       if (main_file_close (ofile) != 0)
3402         {
3403           return EXIT_FAILURE;
3404         }
3405     }
3406
3407 #if EXTERNAL_COMPRESSION
3408   if ((ret = main_external_compression_finish ()))
3409     {
3410       XPR(NT "external compression commands failed\n");
3411       return EXIT_FAILURE;
3412     }
3413 #endif
3414
3415   if ((ret = xd3_close_stream (& stream)))
3416     {
3417       XPR(NT XD3_LIB_ERRMSG (& stream, ret));
3418       return EXIT_FAILURE;
3419     }
3420
3421 #if XD3_ENCODER
3422   if (option_verbose > 1 && cmd == CMD_ENCODE)
3423     {
3424       XPR(NT "scanner configuration: %s\n", stream.smatcher.name);
3425       XPR(NT "target hash table size: %u\n", stream.small_hash.size);
3426       if (sfile != NULL && sfile->filename != NULL)
3427         {
3428           XPR(NT "source hash table size: %u\n", stream.large_hash.size);
3429         }
3430     }
3431
3432   if (option_verbose > 2 && cmd == CMD_ENCODE)
3433     {
3434       XPR(NT "source copies: %"Q"u (%"Q"u bytes)\n",
3435           stream.n_scpy, stream.l_scpy);
3436       XPR(NT "target copies: %"Q"u (%"Q"u bytes)\n",
3437           stream.n_tcpy, stream.l_tcpy);
3438       XPR(NT "adds: %"Q"u (%"Q"u bytes)\n", stream.n_add, stream.l_add);
3439       XPR(NT "runs: %"Q"u (%"Q"u bytes)\n", stream.n_run, stream.l_run);
3440     }
3441 #endif
3442
3443   xd3_free_stream (& stream);
3444
3445   if (option_verbose)
3446     {
3447       shortbuf tm;
3448       long end_time = get_millisecs_now ();
3449       xoff_t nwrite = ofile != NULL ? ofile->nwrite : 0;
3450
3451       XPR(NT "finished in %s; input %"Q"u output %"Q"u bytes (%0.2f%%)\n",
3452           main_format_millis (end_time - start_time, &tm),
3453           ifile->nread, nwrite, 100.0 * nwrite / ifile->nread);
3454     }
3455
3456   return EXIT_SUCCESS;
3457 }
3458
3459 /* free memory before exit, reset single-use variables. */
3460 static void
3461 main_cleanup (void)
3462 {
3463   if (appheader_used != NULL &&
3464       appheader_used != option_appheader)
3465     {
3466       main_free (appheader_used);
3467       appheader_used = NULL;
3468     }
3469
3470   main_buffree (main_bdata);
3471   main_bdata = NULL;
3472   main_bsize = 0;
3473
3474   main_lru_cleanup();
3475
3476   if (recode_stream != NULL)
3477     {
3478       xd3_free_stream (recode_stream);
3479       main_free (recode_stream);
3480       recode_stream = NULL;
3481     }
3482
3483   if (merge_stream != NULL)
3484     {
3485       xd3_free_stream (merge_stream);
3486       main_free (merge_stream);
3487       merge_stream = NULL;
3488     }
3489
3490   XD3_ASSERT (main_mallocs == 0);
3491 }
3492
3493 static void
3494 setup_environment (int argc,
3495                    char **argv,
3496                    int *argc_out,
3497                    char ***argv_out,
3498                    char ***argv_free,
3499                    char **env_free)
3500 {
3501   int n, i, i0;
3502   char *p, *v = getenv("XDELTA");
3503   if (v == NULL) {
3504     (*argc_out) = argc;
3505     (*argv_out) = argv;
3506     (*argv_free) = NULL;
3507     (*env_free) = NULL;
3508     return;
3509   }
3510
3511   (*env_free) = (char*) main_malloc((usize_t) strlen(v) + 1);
3512   strcpy(*env_free, v);
3513
3514   /* Space needed for extra args, at least # of spaces */
3515   n = argc + 1;
3516   for (p = *env_free; *p != 0; ) {
3517     if (*p++ == ' ') {
3518       n++;
3519     }
3520   }
3521
3522   (*argv_free) = (char**) main_malloc(sizeof(char*) * (n + 1));
3523   (*argv_out) = (*argv_free);
3524   (*argv_out)[0] = argv[0];
3525   (*argv_out)[n] = NULL;
3526
3527   i = 1;
3528   for (p = *env_free; *p != 0; ) {
3529     (*argv_out)[i++] = p;
3530     while (*p != ' ' && *p != 0) {
3531       p++;
3532     }
3533     while (*p == ' ') {
3534       *p++ = 0;
3535     }
3536   }
3537
3538   for (i0 = 1; i0 < argc; i0++) {
3539     (*argv_out)[i++] = argv[i0];
3540   }
3541
3542   /* Counting spaces is an upper bound, argv stays NULL terminated. */
3543   (*argc_out) = i;
3544   while (i <= n) {
3545     (*argv_out)[i++] = NULL;
3546   }
3547 }
3548
3549 #if PYTHON_MODULE || SWIG_MODULE || NOT_MAIN
3550 int xd3_main_cmdline (int argc, char **argv)
3551 #else
3552 int main (int argc, char **argv)
3553 #endif
3554 {
3555   static const char *flags =
3556     "0123456789cdefhnqvDFJNORVs:m:B:C:E:I:L:O:M:P:W:A::S::";
3557   xd3_cmd cmd;
3558   main_file ifile;
3559   main_file ofile;
3560   main_file sfile;
3561   main_merge_list merge_order;
3562   main_merge *merge;
3563   int my_optind;
3564   const char *my_optarg;
3565   const char *my_optstr;
3566   const char *sfilename;
3567   int env_argc;
3568   char **env_argv;
3569   char **free_argv;  /* malloc() in setup_environment() */
3570   char *free_value;  /* malloc() in setup_environment() */
3571   int ret;
3572
3573 #ifdef _WIN32
3574   GetStartupInfo(&winStartupInfo);
3575   setvbuf(stderr, NULL, _IONBF, 0);  /* Do not buffer stderr */
3576 #endif
3577
3578   main_file_init (& ifile);
3579   main_file_init (& ofile);
3580   main_file_init (& sfile);
3581   main_merge_list_init (& merge_order);
3582
3583   reset_defaults();
3584
3585   free_argv = NULL;
3586   free_value = NULL;
3587   setup_environment(argc, argv, &env_argc, &env_argv,
3588                     &free_argv, &free_value);
3589   cmd = CMD_NONE;
3590   sfilename = NULL;
3591   my_optind = 1;
3592   argv = env_argv;
3593   argc = env_argc;
3594   program_name = env_argv[0];
3595
3596  takearg:
3597   my_optarg = NULL;
3598   my_optstr = argv[my_optind];
3599
3600   /* This doesn't use getopt() because it makes trouble for -P & python which
3601    * reenter main() and thus care about freeing all memory.  I never had much
3602    * trust for getopt anyway, it's too opaque.  This implements a fairly
3603    * standard non-long-option getopt with support for named operations (e.g.,
3604    * "xdelta3 [encode|decode|printhdr...] < in > out"). */
3605   if (my_optstr)
3606     {
3607       if (*my_optstr == '-')    { my_optstr += 1; }
3608       else if (cmd == CMD_NONE) { goto nonflag; }
3609       else                      { my_optstr = NULL; }
3610     }
3611   while (my_optstr)
3612     {
3613       const char *s;
3614       my_optarg = NULL;
3615       if ((ret = *my_optstr++) == 0) { my_optind += 1; goto takearg; }
3616
3617       /* Option handling: first check for one ':' following the option in
3618        * flags, then check for two.  The syntax allows:
3619        *
3620        * 1. -Afoo                   defines optarg="foo"
3621        * 2. -A foo                  defines optarg="foo"
3622        * 3. -A ""                   defines optarg="" (allows empty-string)
3623        * 4. -A [EOA or -moreargs]   error (mandatory case)
3624        * 5. -A [EOA -moreargs]      defines optarg=NULL (optional case)
3625        * 6. -A=foo                  defines optarg="foo"
3626        * 7. -A=                     defines optarg="" (mandatory case)
3627        * 8. -A=                     defines optarg=NULL (optional case)
3628        *
3629        * See tests in test_command_line_arguments().
3630        */
3631       s = strchr (flags, ret);
3632       if (s && s[1] && s[1] == ':')
3633         {
3634           int option = s[2] && s[2] == ':';
3635
3636           /* Case 1, set optarg to the remaining characters. */
3637           my_optarg = my_optstr;
3638           my_optstr = "";
3639
3640           /* Case 2-5 */
3641           if (*my_optarg == 0)
3642             {
3643               /* Condition 4-5 */
3644               int have_arg = (my_optind < (argc - 1) &&
3645                               *argv[my_optind+1] != '-');
3646
3647               if (! have_arg)
3648                 {
3649                   if (! option)
3650                   {
3651                     /* Case 4 */
3652                     XPR(NT "-%c: requires an argument\n", ret);
3653                     ret = EXIT_FAILURE;
3654                     goto cleanup;
3655                   }
3656                   /* Case 5. */
3657                   my_optarg = NULL;
3658                 }
3659               else
3660                 {
3661                   /* Case 2-3. */
3662                   my_optarg = argv[++my_optind];
3663                 }
3664             }
3665           /* Case 6-8. */
3666           else if (*my_optarg == '=')
3667             {
3668               /* Remove the = in all cases. */
3669               my_optarg += 1;
3670
3671               if (option && *my_optarg == 0)
3672                 {
3673                   /* Case 8. */
3674                   my_optarg = NULL;
3675                 }
3676             }
3677         }
3678
3679       switch (ret)
3680         {
3681         /* case: if no '-' was found, maybe check for a command name. */
3682         nonflag:
3683                if (strcmp (my_optstr, "decode") == 0) { cmd = CMD_DECODE; }
3684           else if (strcmp (my_optstr, "encode") == 0)
3685             {
3686 #if XD3_ENCODER
3687               cmd = CMD_ENCODE;
3688 #else
3689               XPR(NT "encoder support not compiled\n");
3690               return EXIT_FAILURE;
3691 #endif
3692             }
3693           else if (strcmp (my_optstr, "config") == 0) { cmd = CMD_CONFIG; }
3694 #if REGRESSION_TEST
3695           else if (strcmp (my_optstr, "test") == 0) { cmd = CMD_TEST; }
3696 #endif
3697 #if VCDIFF_TOOLS
3698           else if (strcmp (my_optstr, "printhdr") == 0) { cmd = CMD_PRINTHDR; }
3699           else if (strcmp (my_optstr, "printhdrs") == 0)
3700             { cmd = CMD_PRINTHDRS; }
3701           else if (strcmp (my_optstr, "printdelta") == 0)
3702             { cmd = CMD_PRINTDELTA; }
3703           else if (strcmp (my_optstr, "recode") == 0) { cmd = CMD_RECODE; }
3704           else if (strcmp (my_optstr, "merge") == 0) { cmd = CMD_MERGE; }
3705 #endif
3706
3707           /* If no option was found and still no command, let the default
3708            * command be encode.  The remaining args are treated as
3709            * filenames. */
3710           if (cmd == CMD_NONE)
3711             {
3712               cmd = CMD_DEFAULT;
3713               my_optstr = NULL;
3714               break;
3715             }
3716           else
3717             {
3718               /* But if we find a command name, continue the getopt loop. */
3719               my_optind += 1;
3720               goto takearg;
3721             }
3722
3723           /* gzip-like options */
3724         case '0': case '1': case '2': case '3': case '4':
3725         case '5': case '6': case '7': case '8': case '9':
3726           option_level = ret - '0';
3727           break;
3728         case 'f': option_force = 1; break;
3729         case 'F':
3730 #if EXTERNAL_COMPRESSION
3731           option_force2 = 1;
3732 #else
3733           XPR(NT "warning: -F option ignored, "
3734               "external compression support was not compiled\n");
3735           break;
3736 #endif
3737         case 'v': option_verbose += 1; option_quiet = 0; break;
3738         case 'q': option_quiet = 1; option_verbose = 0; break;
3739         case 'c': option_stdout = 1; break;
3740         case 'd':
3741           if (cmd == CMD_NONE) { cmd = CMD_DECODE; }
3742           else { ret = main_help (); goto exit; }
3743           break;
3744         case 'e':
3745 #if XD3_ENCODER
3746           if (cmd == CMD_NONE) { cmd = CMD_ENCODE; }
3747           else { ret = main_help (); goto exit; }
3748           break;
3749 #else
3750           XPR(NT "encoder support not compiled\n");
3751           return EXIT_FAILURE;
3752 #endif
3753
3754         case 'n': option_use_checksum = 0; break;
3755         case 'N': option_no_compress = 1; break;
3756         case 'C': option_smatch_config = my_optarg; break;
3757         case 'J': option_no_output = 1; break;
3758         case 'S': if (my_optarg == NULL)
3759             {
3760               option_use_secondary = 1;
3761               option_secondary = "none";
3762             }
3763           else
3764             {
3765               option_use_secondary = 1;
3766               option_secondary = my_optarg;
3767             }
3768           break;
3769         case 'A': if (my_optarg == NULL) { option_use_appheader = 0; }
3770                   else { option_appheader = (uint8_t*) my_optarg; } break;
3771         case 'B': {
3772           xoff_t bsize;
3773           if ((ret = main_atoux (my_optarg, & bsize,
3774                                  XD3_MINSRCWINSZ, XD3_MAXSRCWINSZ, 'B')))
3775             {
3776               goto exit;
3777             }
3778           option_srcwinsz = bsize;
3779           break;
3780         }
3781         case 'I':
3782           if ((ret = main_atou (my_optarg, & option_iopt_size, 0,
3783                                 0, 'I')))
3784             {
3785               goto exit;
3786             }
3787           break;
3788         case 'P':
3789           if ((ret = main_atou (my_optarg, & option_sprevsz, 0,
3790                                 0, 'P')))
3791             {
3792               goto exit;
3793             }
3794           break;
3795         case 'W':
3796           if ((ret = main_atou (my_optarg, & option_winsize, XD3_ALLOCSIZE,
3797                                 XD3_HARDMAXWINSIZE, 'W')))
3798           {
3799             goto exit;
3800           }
3801           break;
3802         case 'D':
3803 #if EXTERNAL_COMPRESSION == 0
3804           if (option_verbose > 0)
3805             {
3806               XPR(NT "warning: -D option ignored, "
3807                   "external compression support was not compiled\n");
3808             }
3809 #else
3810           option_decompress_inputs  = 0;
3811 #endif
3812           break;
3813         case 'R':
3814 #if EXTERNAL_COMPRESSION == 0
3815           if (option_verbose > 0)
3816             {
3817               XPR(NT "warning: -R option ignored, "
3818                   "external compression support was not compiled\n");
3819             }
3820 #else
3821           option_recompress_outputs = 0;
3822 #endif
3823           break;
3824         case 's':
3825           if (sfilename != NULL)
3826             {
3827               XPR(NT "specify only one source file\n");
3828               goto cleanup;
3829             }
3830
3831           sfilename = my_optarg;
3832           break;
3833         case 'm':
3834           if ((merge = (main_merge*)
3835                main_malloc (sizeof (main_merge))) == NULL)
3836             {
3837               goto cleanup;
3838             }
3839           main_merge_list_push_back (& merge_order, merge);
3840           merge->filename = my_optarg;
3841           break;
3842         case 'V':
3843           ret = main_version (); goto exit;
3844         default:
3845           ret = main_help (); goto exit;
3846         }
3847     }
3848
3849   option_source_filename = sfilename;
3850
3851   /* In case there were no arguments, set the default command. */
3852   if (cmd == CMD_NONE) { cmd = CMD_DEFAULT; }
3853
3854   argc -= my_optind;
3855   argv += my_optind;
3856
3857   /* There may be up to two more arguments. */
3858   if (argc > 2)
3859     {
3860       XPR(NT "too many filenames: %s ...\n", argv[2]);
3861       goto cleanup;
3862     }
3863
3864   ifile.flags    = RD_FIRST | RD_MAININPUT;
3865   sfile.flags    = RD_FIRST;
3866   sfile.filename = option_source_filename;
3867
3868   /* The infile takes the next argument, if there is one.  But if not, infile
3869    * is set to stdin. */
3870   if (argc > 0)
3871     {
3872       ifile.filename = argv[0];
3873
3874       if ((ret = main_file_open (& ifile, ifile.filename, XO_READ)))
3875         {
3876           goto cleanup;
3877         }
3878     }
3879   else
3880     {
3881       XSTDIN_XF (& ifile);
3882     }
3883
3884   /* The ofile takes the following argument, if there is one.  But if not, it
3885    * is left NULL until the application header is processed.  It will be set
3886    * in main_open_output. */
3887   if (argc > 1)
3888     {
3889       /* Check for conflicting arguments. */
3890       if (option_stdout && ! option_quiet)
3891         {
3892           XPR(NT "warning: -c option overrides output filename: %s\n",
3893               argv[1]);
3894         }
3895
3896       if (! option_stdout) { ofile.filename = argv[1]; }
3897     }
3898
3899 #if VCDIFF_TOOLS
3900   if (cmd == CMD_MERGE &&
3901       (ret = main_merge_arguments (&merge_order)))
3902     {
3903       goto cleanup;
3904     }
3905 #endif /* VCDIFF_TOOLS */
3906
3907   switch (cmd)
3908     {
3909     case CMD_PRINTHDR:
3910     case CMD_PRINTHDRS:
3911     case CMD_PRINTDELTA:
3912 #if XD3_ENCODER
3913     case CMD_ENCODE:
3914     case CMD_RECODE:
3915     case CMD_MERGE:
3916 #endif
3917     case CMD_DECODE:
3918       ret = main_input (cmd, & ifile, & ofile, & sfile);
3919       break;
3920
3921 #if REGRESSION_TEST
3922     case CMD_TEST:
3923       main_config ();
3924       ret = xd3_selftest ();
3925       break;
3926 #endif
3927
3928     case CMD_CONFIG:
3929       ret = main_config ();
3930       break;
3931
3932     default:
3933       ret = main_help ();
3934       break;
3935     }
3936
3937   if (0)
3938     {
3939     cleanup:
3940       ret = EXIT_FAILURE;
3941     exit:
3942       (void)0;
3943     }
3944
3945 #if EXTERNAL_COMPRESSION
3946   main_external_compression_cleanup ();
3947 #endif
3948
3949   main_file_cleanup (& ifile);
3950   main_file_cleanup (& ofile);
3951   main_file_cleanup (& sfile);
3952
3953   while (! main_merge_list_empty (& merge_order))
3954     {
3955       merge = main_merge_list_pop_front (& merge_order);
3956       main_free (merge);
3957     }
3958
3959   main_free (free_argv);
3960   main_free (free_value);
3961
3962   main_cleanup ();
3963
3964   fflush (stdout);
3965   fflush (stderr);
3966   return ret;
3967 }
3968
3969 static int
3970 main_help (void)
3971 {
3972   main_version();
3973
3974   /* Note: update wiki when command-line features change */
3975   XPR(NTR "usage: xdelta3 [command/options] [input [output]]\n");
3976   XPR(NTR "make patch:\n");
3977   XPR(NTR "\n");
3978   XPR(NTR "  xdelta3.exe -e -s old_file new_file delta_file\n");
3979   XPR(NTR "\n");
3980   XPR(NTR "apply patch:\n");
3981   XPR(NTR "\n");
3982   XPR(NTR "  xdelta3.exe -d -s old_file delta_file decoded_new_file\n");
3983   XPR(NTR "\n");
3984   XPR(NTR "special command names:\n");
3985   XPR(NTR "    config      prints xdelta3 configuration\n");
3986   XPR(NTR "    decode      decompress the input\n");
3987   XPR(NTR "    encode      compress the input%s\n",
3988      XD3_ENCODER ? "" : " [Not compiled]");
3989 #if REGRESSION_TEST
3990   XPR(NTR "    test        run the builtin tests\n");
3991 #endif
3992 #if VCDIFF_TOOLS
3993   XPR(NTR "special commands for VCDIFF inputs:\n");
3994   XPR(NTR "    printdelta  print information about the entire delta\n");
3995   XPR(NTR "    printhdr    print information about the first window\n");
3996   XPR(NTR "    printhdrs   print information about all windows\n");
3997   XPR(NTR "    recode      encode with new application/secondary settings\n");
3998   XPR(NTR "    merge       merge VCDIFF inputs (see below)\n");
3999 #endif
4000   XPR(NTR "merge patches:\n");
4001   XPR(NTR "\n");
4002   XPR(NTR "  xdelta3 merge -m 1.vcdiff -m 2.vcdiff 3.vcdiff merged.vcdiff\n");
4003   XPR(NTR "\n");
4004   XPR(NTR "standard options:\n");
4005   XPR(NTR "   -0 .. -9     compression level\n");
4006   XPR(NTR "   -c           use stdout\n");
4007   XPR(NTR "   -d           decompress\n");
4008   XPR(NTR "   -e           compress%s\n",
4009      XD3_ENCODER ? "" : " [Not compiled]");
4010   XPR(NTR "   -f           force (overwrite, ignore trailing garbage)\n");
4011 #if EXTERNAL_COMPRESSION
4012   XPR(NTR "   -F           force the external-compression subprocess\n");
4013 #endif
4014   XPR(NTR "   -h           show help\n");
4015   XPR(NTR "   -q           be quiet\n");
4016   XPR(NTR "   -v           be verbose (max 2)\n");
4017   XPR(NTR "   -V           show version\n");
4018
4019   XPR(NTR "memory options:\n");
4020   XPR(NTR "   -B bytes     source window size\n");
4021   XPR(NTR "   -W bytes     input window size\n");
4022   XPR(NTR "   -P size      compression duplicates window\n");
4023   XPR(NTR "   -I size      instruction buffer size (0 = unlimited)\n");
4024
4025   XPR(NTR "compression options:\n");
4026   XPR(NTR "   -s source    source file to copy from (if any)\n");
4027   XPR(NTR "   -S [lzma|djw|fgk] enable/disable secondary compression\n");
4028   XPR(NTR "   -N           disable small string-matching compression\n");
4029   XPR(NTR "   -D           disable external decompression (encode/decode)\n");
4030   XPR(NTR "   -R           disable external recompression (decode)\n");
4031   XPR(NTR "   -n           disable checksum (encode/decode)\n");
4032   XPR(NTR "   -C           soft config (encode, undocumented)\n");
4033   XPR(NTR "   -A [apphead] disable/provide application header (encode)\n");
4034   XPR(NTR "   -J           disable output (check/compute only)\n");
4035   XPR(NTR "   -m           arguments for \"merge\"\n");
4036
4037   XPR(NTR "the XDELTA environment variable may contain extra args:\n");
4038   XPR(NTR "   XDELTA=\"-s source-x.y.tar.gz\" \\\n");
4039   XPR(NTR "   tar --use-compress-program=xdelta3 \\\n");
4040   XPR(NTR "       -cf target-x.z.tar.gz.vcdiff target-x.y\n");
4041   return EXIT_FAILURE;
4042 }