The Independent JPEG Group's JPEG software v4a
diff --git a/CHANGELOG b/CHANGELOG
index 02c63dc..ccbc6ea 100644
--- a/CHANGELOG
+++ b/CHANGELOG
@@ -1,5 +1,29 @@
 CHANGELOG for Independent JPEG Group's JPEG software
 
+
+Version 4A 18-Feb-93
+--------------------
+
+Substantial speedup for grayscale output from color JPEG file (suppress
+processing of chrominance components).  Lesser speedups in Huffman decoding
+and in compression quantization.
+
+Can switch stdin/stdout to binary mode with either fdopen() or setmode();
+this allows use of one-file command line style on a wider range of systems.
+Also added -outfile switch so that makefile test scripts don't have to depend
+on the command line style.
+
+New makefile.icc for Code Builder; makefile.sas is updated for SAS C 6.x.
+
+Hook added to allow surrounding application to read and write COM (comment)
+blocks.
+
+Bugfixes (DOS only): jmemdos.c code for accessing expanded memory only worked
+if struct fields are packed on byte boundaries.  This is not true by default
+for Microsoft C.  Furthermore, Microsoft C needs an _fheapmin() call to clean
+up the far heap correctly.
+
+
 Version 4  10-Dec-92
 --------------------
 
diff --git a/README b/README
index 9223de2..99c4d36 100644
--- a/README
+++ b/README
@@ -1,10 +1,10 @@
 The Independent JPEG Group's JPEG software
 ==========================================
 
-README for release 4 of 10-Dec-92
-=================================
+README for release 4A of 18-Feb-93
+==================================
 
-This distribution contains the fourth public release of the Independent JPEG
+This distribution contains a BETA TEST release of the Independent JPEG
 Group's free JPEG software.  You are welcome to redistribute this software and
 to use it for any purpose, subject to the conditions under LEGAL ISSUES, below.
 
@@ -24,8 +24,9 @@
 electronic mailing list.  Mailing list members are notified of updates and
 have a chance to participate in technical discussions, etc.
 
-This software is the work of Tom Lane, Philip Gladstone, Luis Ortiz,
-Lee Crocker, Ge' Weijers, and other members of the Independent JPEG Group.
+This software is the work of Tom Lane, Philip Gladstone, Luis Ortiz, Lee
+Crocker, George Phillips, Ge' Weijers, and other members of the Independent
+JPEG Group.
 
 
 DISCLAIMER
@@ -107,6 +108,9 @@
 ARCHIVE LOCATIONS
 =================
 
+[Version 4A is a beta-test release and will not be publicly archived.
+The following paragraphs refer to the most recent official release.]
+
 The "official" archive site for this software is ftp.uu.net (Internet
 address 137.39.1.9 or 192.48.96.9).  The most recent released version can
 always be found there in directory graphics/jpeg.  This particular version
diff --git a/SETUP b/SETUP
index dd633ae..85f0184 100644
--- a/SETUP
+++ b/SETUP
@@ -34,6 +34,7 @@
 	makefile.mc5:	for Microsoft C 5.x under MS-DOS.
 	makefile.mc6:	for Microsoft C 6.x and up under MS-DOS.
 	makefile.bcc:	for Borland C (Turbo C) under MS-DOS.
+	makefile.icc:	for Intel's Code Builder C under MS-DOS.
 	makefile.manx:	for Manx Aztec C on Amigas.
 	makefile.sas:	for SAS C on Amigas.
 	makcjpeg.st:	project file for Atari ST/STE/TT Pure C or Turbo C.
@@ -101,7 +102,10 @@
 can optionally come from standard input.  You MUST use two-file style on any
 system that doesn't cope well with binary data fed through stdin/stdout; this
 is true for most MS-DOS compilers, for example.  If you're not on a Unix
-system, it's probably safest to assume you need two-file style.
+system, it's probably safest to assume you need two-file style.  (But if your
+compiler provides either the Posix-standard fdopen() library routine or a
+Microsoft-compatible setmode() routine, you can use the Unix command line
+style, by defining USE_FDOPEN or USE_SETMODE respectively.)
 
 
 STEP 3: SELECT SYSTEM-DEPENDENT FILES
@@ -197,8 +201,13 @@
 programs.
 
 With most of the makefiles, "make test" will perform the necessary
-comparisons.  If you're using a makefile that doesn't provide this option, run
-djpeg and cjpeg to generate testout.ppm, testout.gif, and testout.jpg, then
+comparisons.  If you started with makefile.ansi or makefile.unix, and you
+defined TWO_FILE_COMMANDLINE, then change the makefile's test script to use
+two-file syntax (i.e., delete the ">" character from the invocations of cjpeg
+and djpeg).  The other makefiles will work with either command-line syntax.
+
+If you're using a makefile that doesn't provide the test option, run djpeg and
+cjpeg by hand to generate testout.ppm, testout.gif, and testout.jpg, then
 compare these to testimg.* with whatever binary file comparison tool you have.
 The files should be bit-for-bit identical.
 
@@ -206,6 +215,13 @@
 good bet that you needed to define RIGHT_SHIFT_IS_UNSIGNED.  Go back to step 2
 and run ckconfig.c.  (This is a good plan for any other test failure, too.)
 
+If you are using Unix (one-file) command line style on a non-Unix system,
+it's a good idea to check that binary I/O through stdin/stdout actually works.
+You should get the same results from "djpeg <testorig.jpg >out.ppm" as from
+"djpeg -outfile out.ppm  testorig.jpg".  Note that the non-Unix makefiles use
+the latter style and therefore do not exercise stdin/stdout.  If this test
+fails, try recompiling jcmain.c & jdmain.c with USE_SETMODE and/or USE_FDOPEN.
+
 If your choice of jmemsys.c was anything other than jmemnobs.c, you should
 test that temporary-file usage works.  Try "djpeg -gif -max 0 testorig.jpg"
 and make sure its output matches testimg.gif.  If you have any really large
@@ -227,7 +243,10 @@
 there's such a wide variety of installation procedures on different systems.)
 
 To learn to use the programs, read the file USAGE (or manual pages cjpeg(1)
-and djpeg(1) on Unix).
+and djpeg(1) on Unix).  Note that the man pages cjpeg.1/djpeg.1 only describe
+the Unix-style command line syntax; if you want to use these files with a
+version that uses two-file command line syntax, you'll have to modify the text
+accordingly.  The USAGE file describes both styles.
 
 
 OPTIMIZATION
@@ -373,7 +392,7 @@
 insert a line reading "#pragma novector" just before the loop	
     for (i = 1; i <= (int) htbl->bits[l]; i++)
       huffsize[p++] = (char) l;
-in fix_huff_tbl (in V3, line 42 of jchuff.c and line 38 of jdhuff.c).  The
+in fix_huff_tbl (in V4A, line 42 of jchuff.c and line 39 of jdhuff.c).  The
 usual symptom of not adding this line is a core-dump.  See Cray's SPR 48222.
 
 
@@ -461,9 +480,13 @@
 memory, otherwise use jmemansi.c or jmemname.c.
 
 Most MS-DOS compilers treat stdin/stdout as text files, so you must use
-two-file command line style.  But if your compiler has the setmode() library
-routine, you can define USE_SETMODE to get one-file style.  (Don't forget to
-change the "make test" script in the Makefile if you do so.)
+two-file command line style.  But if your compiler has either fdopen() or
+setmode(), you can use one-file style if you like.  To do this, define
+USE_FDOPEN or USE_SETMODE so that stdin/stdout will be set to binary mode.
+(USE_SETMODE seems to work with more DOS compilers than USE_FDOPEN.)  You
+should test that I/O through stdin/stdout produces the same results as I/O
+to explicitly named files... the "make test" procedures in the DOS-specific
+makefiles do NOT use stdin/stdout.
 
 If you add more switches to CFLAGS in the DOS-specific makefiles, you are
 likely to run up against DOS' 128-byte command line length limit.  In that
@@ -482,16 +505,18 @@
 creating jmemsys.c, even after you have done so.  If this happens to you,
 delete the four lines beginning with "jmemsys.c:" from the Makefile.
 
+If you want one-file command line style, define USE_SETMODE.  fdopen() does
+not work correctly.
+
 
 MS-DOS, DJGPP:
 
 Use makefile.ansi and jmemnobs.c, and put "-UMSDOS" in CFLAGS to undo the
 compiler's automatic definition of MSDOS.  Also put either "-DUSE_SETMODE" or
 "-DTWO_FILE_COMMANDLINE" in CFLAGS, depending on whether you prefer one-file
-or two-file command line style.  (If you choose two-file style, change the
-"make test" section of the Makefile accordingly.)  You'll also need to put the
-object-file lists into response files in order to circumvent DOS's 128-byte
-command line length limit at the final linking step.
+or two-file command line style.  You'll also need to put the object-file lists
+into response files in order to circumvent DOS's 128-byte command line length
+limit at the final linking step.
 
 
 MS-DOS, Microsoft C:
@@ -507,6 +532,9 @@
 in 6.00A and later versions.  6.00A still generates a bogus "conditional
 expression is constant" warning in jrdppm.c, but the emitted code seems OK.
 
+If you want one-file command line style, define USE_SETMODE.  fdopen() does
+not work correctly, at least not in 6.00A.
+
 
 SGI:
 
diff --git a/USAGE b/USAGE
index ebce6df..76044f8 100644
--- a/USAGE
+++ b/USAGE
@@ -52,6 +52,12 @@
 have pipes.  (You can get this style on Unix too, if you prefer, by defining
 TWO_FILE_COMMANDLINE when you compile the programs; see SETUP.)
 
+You can also say:
+	cjpeg [switches] -outfile jpegfile  imagefile
+or
+	djpeg [switches] -outfile imagefile  jpegfile
+This syntax works on all systems, so it is useful for scripts.
+
 The currently supported image file formats are: PPM (PBMPLUS color format),
 PGM (PBMPLUS gray-scale format), GIF, Targa, and RLE (Utah Raster Toolkit
 format).  (RLE is supported only if the URT library is available.)
@@ -212,8 +218,8 @@
 
 Switches for advanced users:
 
-	-blocksmooth	Perform cross-block smoothing.  This is quite
-			memory-intensive and only seems to improve the image
+	-blocksmooth	Perform cross-block smoothing.  This is slow, quite
+			memory-intensive, and only seems to improve the image
 			at very low quality settings (-quality 10 to 20 or so).
 			At normal quality settings it may make things worse.
 
diff --git a/djpeg.1 b/djpeg.1
index be5a815..7f45074 100644
--- a/djpeg.1
+++ b/djpeg.1
@@ -1,4 +1,4 @@
-.TH DJPEG 1 "2 August 1992"
+.TH DJPEG 1 "17 February 1993"
 .SH NAME
 djpeg \- decompress a JPEG file to an image file
 .SH SYNOPSIS
@@ -107,9 +107,9 @@
 Switches for advanced users:
 .TP
 .B \-blocksmooth
-Perform cross-block smoothing.  This is quite memory-intensive and only seems
-to improve the image at very low quality settings (\fB\-quality\fR 10 to 20 or
-so).  At normal quality settings it may make the image worse.
+Perform cross-block smoothing.  This is slow, quite memory-intensive, and only
+seems to improve the image at very low quality settings (\fB\-quality\fR 10 to
+20 or so).  At normal quality settings it may make the image worse.
 .TP
 .B \-grayscale
 Force gray-scale output even if JPEG file is color.
diff --git a/example.c b/example.c
index 3e7a5dd..666dd6f 100644
--- a/example.c
+++ b/example.c
@@ -340,7 +340,7 @@
  * Colormapped mode is also useful for reducing grayscale output to a small
  * number of gray levels: when using the 1-pass quantizer on grayscale data,
  * the colormap entries will be evenly spaced from 0 to MAX_JSAMPLE, so you
- * can regard the indexes are directly representing gray levels at reduced
+ * can regard the indexes as directly representing gray levels at reduced
  * precision.  In any other case, you should not depend on the colormap
  * entries having any particular order.
  * To get colormapped output, set cinfo->quantize_colors to TRUE and set
diff --git a/jcdeflts.c b/jcdeflts.c
index 48f4ed4..eddba20 100644
--- a/jcdeflts.c
+++ b/jcdeflts.c
@@ -1,7 +1,7 @@
 /*
  * jcdeflts.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -298,9 +298,11 @@
 
   cinfo->input_gamma = 1.0;	/* no gamma correction by default */
 
+  cinfo->write_JFIF_header = TRUE; /* write a JFIF marker */
+  cinfo->comment_text = NULL;	/* but no COM block */
+
   /* Prepare three color components; first is luminance which is also usable */
   /* for grayscale.  The others are assumed to be UV or similar chrominance. */
-  cinfo->write_JFIF_header = TRUE;
   cinfo->jpeg_color_space = CS_YCbCr;
   cinfo->num_components = 3;
   cinfo->comp_info = (jpeg_component_info *)
diff --git a/jchuff.c b/jchuff.c
index 3f657db..9eb558a 100644
--- a/jchuff.c
+++ b/jchuff.c
@@ -1,7 +1,7 @@
 /*
  * jchuff.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -66,15 +66,12 @@
   /* Set any codeless symbols to have code length 0;
    * this allows emit_bits to detect any attempt to emit such symbols.
    */
-  MEMZERO(htbl->ehufsi, SIZEOF(htbl->ehufsi));
+  MEMZERO(htbl->priv.enc.ehufsi, SIZEOF(htbl->priv.enc.ehufsi));
 
   for (p = 0; p < lastp; p++) {
-    htbl->ehufco[htbl->huffval[p]] = huffcode[p];
-    htbl->ehufsi[htbl->huffval[p]] = huffsize[p];
+    htbl->priv.enc.ehufco[htbl->huffval[p]] = huffcode[p];
+    htbl->priv.enc.ehufsi[htbl->huffval[p]] = huffsize[p];
   }
-  
-  /* We don't bother to fill in the decoding tables mincode[], maxcode[], */
-  /* and valptr[], since they are not used for encoding. */
 }
 
 
@@ -179,7 +176,7 @@
   }
   
   /* Emit the Huffman-coded symbol for the number of bits */
-  emit_bits(dctbl->ehufco[nbits], dctbl->ehufsi[nbits]);
+  emit_bits(dctbl->priv.enc.ehufco[nbits], dctbl->priv.enc.ehufsi[nbits]);
 
   /* Emit that number of bits of the value, if positive, */
   /* or the complement of its magnitude, if negative. */
@@ -196,7 +193,7 @@
     } else {
       /* if run length > 15, must emit special run-length-16 codes (0xF0) */
       while (r > 15) {
-	emit_bits(actbl->ehufco[0xF0], actbl->ehufsi[0xF0]);
+	emit_bits(actbl->priv.enc.ehufco[0xF0], actbl->priv.enc.ehufsi[0xF0]);
 	r -= 16;
       }
 
@@ -214,7 +211,7 @@
       
       /* Emit Huffman symbol for run length / number of bits */
       i = (r << 4) + nbits;
-      emit_bits(actbl->ehufco[i], actbl->ehufsi[i]);
+      emit_bits(actbl->priv.enc.ehufco[i], actbl->priv.enc.ehufsi[i]);
       
       /* Emit that number of bits of the value, if positive, */
       /* or the complement of its magnitude, if negative. */
@@ -226,7 +223,7 @@
 
   /* If the last coef(s) were zero, emit an end-of-block code */
   if (r > 0)
-    emit_bits(actbl->ehufco[0], actbl->ehufsi[0]);
+    emit_bits(actbl->priv.enc.ehufco[0], actbl->priv.enc.ehufsi[0]);
 }
 
 
diff --git a/jcmain.c b/jcmain.c
index fd6d831..03d24fc 100644
--- a/jcmain.c
+++ b/jcmain.c
@@ -1,7 +1,7 @@
 /*
  * jcmain.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -18,6 +18,9 @@
  * The second style is convenient on Unix but is unhelpful on systems that
  * don't support pipes.  Also, you MUST use the first style if your system
  * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided.  The syntax
+ *	cjpeg [options]  -outfile outputfile  inputfile
+ * works regardless of which command line style is used.
  */
 
 #include "jinclude.h"
@@ -218,6 +221,7 @@
 
 
 static char * progname;		/* program name for error messages */
+static char * outfilename;	/* for -outfile switch */
 
 
 LOCAL void
@@ -448,6 +452,7 @@
    */
   j_c_defaults(cinfo, 75, FALSE); /* default quality level = 75 */
   is_targa = FALSE;
+  outfilename = NULL;
 
   /* Scan command line options, adjust parameters */
 
@@ -455,8 +460,10 @@
     arg = argv[argn];
     if (*arg != '-') {
       /* Not a switch, must be a file name argument */
-      if (argn <= last_file_arg_seen)
-	continue;		/* ignore it if previously processed */
+      if (argn <= last_file_arg_seen) {
+	outfilename = NULL;	/* -outfile applies to just one input file */
+	continue;		/* ignore this name if previously processed */
+      }
       break;			/* else done parsing switches */
     }
     arg++;			/* advance past switch marker character */
@@ -516,6 +523,12 @@
       exit(EXIT_FAILURE);
 #endif
 
+    } else if (keymatch(arg, "outfile", 3)) {
+      /* Set output file name. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      outfilename = argv[argn];	/* save it away for later use */
+
     } else if (keymatch(arg, "quality", 1)) {
       /* Quality factor (quantization table scaling factor). */
       int val;
@@ -624,47 +637,75 @@
 #endif
 #endif
 
-  /* Scan command line: set up compression parameters, input & output files. */
+  /* Scan command line: set up compression parameters, find file names. */
 
   file_index = parse_switches(&cinfo, 0, argc, argv);
 
 #ifdef TWO_FILE_COMMANDLINE
-
-  if (file_index != argc-2) {
-    fprintf(stderr, "%s: must name one input and one output file\n", progname);
-    usage();
+  /* Must have either -outfile switch or explicit output file name */
+  if (outfilename == NULL) {
+    if (file_index != argc-2) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+    outfilename = argv[file_index+1];
+  } else {
+    if (file_index != argc-1) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
   }
-  if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
-    fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
-    exit(EXIT_FAILURE);
-  }
-  if ((cinfo.output_file = fopen(argv[file_index+1], WRITE_BINARY)) == NULL) {
-    fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index+1]);
-    exit(EXIT_FAILURE);
-  }
-
-#else /* not TWO_FILE_COMMANDLINE -- use Unix style */
-
-  cinfo.input_file = stdin;	/* default input file */
-  cinfo.output_file = stdout;	/* always the output file */
-
-#ifdef USE_SETMODE		/* need to hack file mode? */
-  setmode(fileno(stdin), O_BINARY);
-  setmode(fileno(stdout), O_BINARY);
-#endif
-
+#else
+  /* Unix style: expect zero or one file name */
   if (file_index < argc-1) {
     fprintf(stderr, "%s: only one input file\n", progname);
     usage();
   }
+#endif /* TWO_FILE_COMMANDLINE */
+
+  /* Open the input file. */
   if (file_index < argc) {
     if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
       exit(EXIT_FAILURE);
     }
+  } else {
+    /* default input file is stdin */
+#ifdef USE_SETMODE		/* need to hack file mode? */
+    setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+    if ((cinfo.input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open stdin\n", progname);
+      exit(EXIT_FAILURE);
+    }
+#else
+    cinfo.input_file = stdin;
+#endif
   }
 
-#endif /* TWO_FILE_COMMANDLINE */
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+#ifdef USE_SETMODE		/* need to hack file mode? */
+    setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+    if ((cinfo.output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open stdout\n", progname);
+      exit(EXIT_FAILURE);
+    }
+#else
+    cinfo.output_file = stdout;
+#endif
+  }
 
   /* Figure out the input file format, and set up to read it. */
   select_file_type(&cinfo);
diff --git a/jcmcu.c b/jcmcu.c
index e921b49..524a54f 100644
--- a/jcmcu.c
+++ b/jcmcu.c
@@ -32,7 +32,7 @@
 
 /* ZAG[i] is the natural-order position of the i'th element of zigzag order. */
 
-static const short ZAG[DCTSIZE2] = {
+static const int ZAG[DCTSIZE2] = {
   0,  1,  8, 16,  9,  2,  3, 10,
  17, 24, 32, 25, 18, 11,  4,  5,
  12, 19, 26, 33, 40, 48, 41, 34,
@@ -58,9 +58,6 @@
 
   { register JSAMPROW elemptr;
     register DCTELEM *localblkptr = block;
-#if DCTSIZE != 8
-    register int elemc;
-#endif
     register int elemr;
 
     for (elemr = DCTSIZE; elemr > 0; elemr--) {
@@ -75,8 +72,10 @@
       *localblkptr++ = (DCTELEM) (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
       *localblkptr++ = (DCTELEM) (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
 #else
-      for (elemc = DCTSIZE; elemc > 0; elemc--) {
-	*localblkptr++ = (DCTELEM) (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+      { register int elemc;
+	for (elemc = DCTSIZE; elemc > 0; elemc--) {
+	  *localblkptr++ = (DCTELEM) (GETJSAMPLE(*elemptr++) - CENTERJSAMPLE);
+	}
       }
 #endif
     }
@@ -89,22 +88,39 @@
   j_fwd_dct(block);
 
   { register JCOEF temp;
-    register short i;
+    register QUANT_VAL qval;
+    register int i;
 
     for (i = 0; i < DCTSIZE2; i++) {
+      qval = *quanttbl++;
       temp = (JCOEF) block[ZAG[i]];
-      /* divide by *quanttbl, ensuring proper rounding */
+      /* Divide the coefficient value by qval, ensuring proper rounding.
+       * Since C does not specify the direction of rounding for negative
+       * quotients, we have to force the dividend positive for portability.
+       *
+       * In most files, at least half of the output values will be zero
+       * (at default quantization settings, more like three-quarters...)
+       * so we should ensure that this case is fast.  On many machines,
+       * a comparison is enough cheaper than a divide to make a special test
+       * a win.  Since both inputs will be nonnegative, we need only test
+       * for a < b to discover whether a/b is 0.
+       * If your machine's division is fast enough, define FAST_DIVIDE.
+       */
+#ifdef FAST_DIVIDE
+#define DIVIDE_BY(a,b)	a /= b
+#else
+#define DIVIDE_BY(a,b)	(a >= b) ? (a /= b) : (a = 0)
+#endif
       if (temp < 0) {
 	temp = -temp;
-	temp += *quanttbl>>1;
-	temp /= *quanttbl;
+	temp += qval>>1;	/* for rounding */
+	DIVIDE_BY(temp, qval);
 	temp = -temp;
       } else {
-	temp += *quanttbl>>1;
-	temp /= *quanttbl;
+	temp += qval>>1;	/* for rounding */
+	DIVIDE_BY(temp, qval);
       }
       *output_data++ = temp;
-      quanttbl++;
     }
   }
 
@@ -112,7 +128,7 @@
   j_rev_dct(block);
 
   { register int diff;
-    register short i;
+    register int i;
 
     for (i = 0; i < DCTSIZE2; i++) {
       diff = block[i] - svblock[i];
diff --git a/jconfig.h b/jconfig.h
index aeb29fe..60ca005 100644
--- a/jconfig.h
+++ b/jconfig.h
@@ -1,7 +1,7 @@
 /*
  * jconfig.h
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -106,10 +106,12 @@
  */
 
 #ifdef MSDOS			/* two-file style is needed for PCs */
-#ifndef USE_SETMODE		/* unless you have setmode() */
+#ifndef USE_FDOPEN		/* unless you have fdopen() or setmode() */
+#ifndef USE_SETMODE
 #define TWO_FILE_COMMANDLINE
 #endif
 #endif
+#endif
 #ifdef THINK_C			/* it's needed for Macintosh too */
 #define TWO_FILE_COMMANDLINE
 #endif
diff --git a/jdcolor.c b/jdcolor.c
index fad9c73..f651c04 100644
--- a/jdcolor.c
+++ b/jdcolor.c
@@ -1,7 +1,7 @@
 /*
  * jdcolor.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -223,6 +223,8 @@
 GLOBAL void
 jseldcolor (decompress_info_ptr cinfo)
 {
+  int ci;
+
   /* Make sure num_components agrees with jpeg_color_space */
   switch (cinfo->jpeg_color_space) {
   case CS_GRAYSCALE:
@@ -247,7 +249,10 @@
     break;
   }
 
-  /* Set color_out_comps and conversion method based on requested space */
+  /* Set color_out_comps and conversion method based on requested space. */
+  /* Also clear the component_needed flags for any unused components, */
+  /* so that earlier pipeline stages can avoid useless computation. */
+
   switch (cinfo->out_color_space) {
   case CS_GRAYSCALE:
     cinfo->color_out_comps = 1;
@@ -257,6 +262,9 @@
       cinfo->methods->color_convert = grayscale_convert;
       cinfo->methods->colorout_init = null_init;
       cinfo->methods->colorout_term = null_term;
+      /* For color->grayscale conversion, only the Y (0) component is needed */
+      for (ci = 1; ci < cinfo->num_components; ci++)
+	cinfo->cur_comp_info[ci]->component_needed = FALSE;
     } else
       ERREXIT(cinfo->emethods, "Unsupported color conversion request");
     break;
diff --git a/jddeflts.c b/jddeflts.c
index fde74d1..b8f1229 100644
--- a/jddeflts.c
+++ b/jddeflts.c
@@ -1,7 +1,7 @@
 /*
  * jddeflts.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -42,6 +42,25 @@
 }
 
 
+/* Default comment-block processing routine.
+ * This can be overridden by an application that wishes to examine
+ * COM blocks found in the JPEG file.  The default routine does nothing.
+ * CAUTION: the comment processing routine MUST call JGETC() exactly
+ * comment_length times to read the comment data, whether it intends
+ * to do anything with the data or not!
+ * Keep in mind that (a) there may be more than one COM block in a file;
+ * (b) there's no guarantee that what's in the block is ASCII data.
+ */
+
+METHODDEF void
+process_comment (decompress_info_ptr cinfo, long comment_length)
+{
+  while (comment_length-- > 0) {
+    (void) JGETC(cinfo);
+  }
+}
+
+
 /*
  * Reload the input buffer after it's been emptied, and return the next byte.
  * See the JGETC macro for calling conditions.  Note in particular that
@@ -160,4 +179,7 @@
 
   /* Install default do-nothing progress monitoring method. */
   cinfo->methods->progress_monitor = progress_monitor;
+
+  /* Install default comment-block processing method. */
+  cinfo->methods->process_comment = process_comment;
 }
diff --git a/jdhuff.c b/jdhuff.c
index cdc9bd7..3ac46cf 100644
--- a/jdhuff.c
+++ b/jdhuff.c
@@ -1,7 +1,7 @@
 /*
  * jdhuff.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -26,6 +26,7 @@
 /* Compute derived values for a Huffman table */
 {
   int p, i, l, si;
+  int lookbits, ctr;
   char huffsize[257];
   UINT16 huffcode[257];
   UINT16 code;
@@ -55,23 +56,43 @@
     si++;
   }
 
-  /* We don't bother to fill in the encoding tables ehufco[] and ehufsi[], */
-  /* since they are not used for decoding. */
-
-  /* Figure F.15: generate decoding tables */
+  /* Figure F.15: generate decoding tables for bit-sequential decoding */
 
   p = 0;
   for (l = 1; l <= 16; l++) {
     if (htbl->bits[l]) {
-      htbl->valptr[l] = p;	/* huffval[] index of 1st sym of code len l */
-      htbl->mincode[l] = huffcode[p]; /* minimum code of length l */
+      htbl->priv.dec.valptr[l] = p; /* huffval[] index of 1st symbol of code length l */
+      htbl->priv.dec.mincode[l] = huffcode[p]; /* minimum code of length l */
       p += htbl->bits[l];
-      htbl->maxcode[l] = huffcode[p-1];	/* maximum code of length l */
+      htbl->priv.dec.maxcode[l] = huffcode[p-1]; /* maximum code of length l */
     } else {
-      htbl->maxcode[l] = -1;
+      htbl->priv.dec.maxcode[l] = -1; /* -1 if no codes of this length */
     }
   }
-  htbl->maxcode[17] = 0xFFFFFL;	/* ensures huff_DECODE terminates */
+  htbl->priv.dec.maxcode[17] = 0xFFFFFL; /* ensures huff_DECODE terminates */
+
+  /* Compute lookahead tables to speed up decoding.
+   * First we set all the table entries to 0, indicating "too long";
+   * then we iterate through the Huffman codes that are short enough and
+   * fill in all the entries that correspond to bit sequences starting
+   * with that code.
+   */
+
+  MEMZERO(htbl->priv.dec.look_nbits, SIZEOF(htbl->priv.dec.look_nbits));
+
+  p = 0;
+  for (l = 1; l <= HUFF_LOOKAHEAD; l++) {
+    for (i = 1; i <= (int) htbl->bits[l]; i++, p++) {
+      /* l = current code's length, p = its index in huffcode[] & huffval[]. */
+      /* Generate left-justified code followed by all possible bit sequences */
+      lookbits = huffcode[p] << (HUFF_LOOKAHEAD-l);
+      for (ctr = 1 << (HUFF_LOOKAHEAD-l); ctr > 0; ctr--) {
+	htbl->priv.dec.look_nbits[lookbits] = l;
+	htbl->priv.dec.look_sym[lookbits] = htbl->huffval[p];
+	lookbits++;
+      }
+    }
+  }
 }
 
 
@@ -82,11 +103,13 @@
  *
  * We read source bytes into get_buffer and dole out bits as needed.
  * If get_buffer already contains enough bits, they are fetched in-line
- * by the macros get_bits() and get_bit().  When there aren't enough bits,
- * fill_bit_buffer is called; it will attempt to fill get_buffer to the
- * "high water mark", then extract the desired number of bits.  The idea,
- * of course, is to minimize the function-call overhead cost of entering
- * fill_bit_buffer.
+ * by the macros check_bit_buffer and get_bits.  When there aren't enough
+ * bits, fill_bit_buffer is called; it will attempt to fill get_buffer to
+ * the "high water mark" (not just to the number of bits needed; this reduces
+ * the function-call overhead cost of entering fill_bit_buffer).
+ * On return, fill_bit_buffer guarantees that get_buffer contains at least
+ * the requested number of bits --- dummy zeroes are inserted if necessary.
+ *
  * On most machines MIN_GET_BITS should be 25 to allow the full 32-bit width
  * of get_buffer to be used.  (On machines with wider words, an even larger
  * buffer could be used.)  However, on some machines 32-bit shifts are
@@ -102,16 +125,13 @@
 #define MIN_GET_BITS  25	/* max value for 32-bit get_buffer */
 #endif
 
-static const int bmask[16] =	/* bmask[n] is mask for n rightmost bits */
-  { 0, 0x0001, 0x0003, 0x0007, 0x000F, 0x001F, 0x003F, 0x007F, 0x00FF,
-    0x01FF, 0x03FF, 0x07FF, 0x0FFF, 0x1FFF, 0x3FFF, 0x7FFF };
 
-
-LOCAL int
+LOCAL void
 fill_bit_buffer (int nbits)
-/* Load up the bit buffer and do get_bits(nbits) */
+/* Load up the bit buffer to a depth of at least nbits */
 {
   /* Attempt to load at least MIN_GET_BITS bits into get_buffer. */
+  /* (It is assumed that no request will be for more than that many bits.) */
   while (bits_left < MIN_GET_BITS) {
     register int c = JGETC(dcinfo);
     
@@ -128,10 +148,11 @@
 	if (bits_left >= nbits)
 	  break;
 	/* Uh-oh.  Report corrupted data to user and stuff zeroes into
-	 * the data stream, so we can produce some kind of image.
+	 * the data stream, so that we can produce some kind of image.
 	 * Note that this will be repeated for each byte demanded for the
 	 * rest of the segment; this is a bit slow but not unreasonably so.
-	 * The main thing is to avoid getting a zillion warnings, hence:
+	 * The main thing is to avoid getting a zillion warnings, hence
+	 * we use a flag to ensure that only one warning appears.
 	 */
 	if (! printed_eod) {
 	  WARNMS(dcinfo->emethods, "Corrupt JPEG data: premature end of data segment");
@@ -145,40 +166,81 @@
     get_buffer = (get_buffer << 8) | c;
     bits_left += 8;
   }
-
-  /* Having filled get_buffer, extract desired bits (this simplifies macros) */
-  bits_left -= nbits;
-  return ((int) (get_buffer >> bits_left)) & bmask[nbits];
 }
 
 
-/* Macros to make things go at some speed! */
-/* NB: parameter to get_bits should be simple variable, not expression */
+/*
+ * These macros provide the in-line portion of bit fetching.
+ * Correct usage is:
+ *	check_bit_buffer(n);		ensure there are N bits in get_buffer
+ *      val = get_bits(n);		fetch N bits
+ * The value n should be a simple variable, not an expression, because it
+ * is evaluated multiple times.
+ * peek_bits() fetches next N bits without removing them from the buffer.
+ */
+
+#define check_bit_buffer(nbits) \
+	{ if (bits_left < (nbits))  fill_bit_buffer(nbits); }
 
 #define get_bits(nbits) \
-	(bits_left >= (nbits) ? \
-	 ((int) (get_buffer >> (bits_left -= (nbits)))) & bmask[nbits] : \
-	 fill_bit_buffer(nbits))
+	(((int) (get_buffer >> (bits_left -= (nbits)))) & ((1<<(nbits))-1))
 
-#define get_bit() \
-	(bits_left ? \
-	 ((int) (get_buffer >> (--bits_left))) & 1 : \
-	 fill_bit_buffer(1))
+#define peek_bits(nbits) \
+	(((int) (get_buffer >> (bits_left -  (nbits)))) & ((1<<(nbits))-1))
 
 
-/* Figure F.16: extract next coded symbol from input stream */
+/*
+ * Routines to extract next Huffman-coded symbol from input bit stream.
+ * We use a lookahead table to process codes of up to HUFF_LOOKAHEAD bits
+ * without looping.  Usually, more than 95% of the Huffman codes will be 8
+ * or fewer bits long.  The few overlength codes are handled with a loop.
+ * The primary case is made a macro for speed reasons; the secondary
+ * routine slow_DECODE is rarely entered and need not be inline code.
+ *
+ * Notes about the huff_DECODE macro:
+ * 1. The first if-test is coded to call fill_bit_buffer only when necessary.
+ * 2. If the lookahead succeeds, we need only decrement bits_left to remove
+ *    the proper number of bits from get_buffer.
+ * 3. If the lookahead table contains no entry, the next code must be
+ *    more than HUFF_LOOKAHEAD bits long.
+ * 4. Near the end of the data segment, we may fail to get enough bits
+ *    for a lookahead.  In that case, we do it the hard way.
+ */
+
+#define huff_DECODE(htbl,result) \
+{ register int nb, look;					\
+  if (bits_left >= HUFF_LOOKAHEAD ||				\
+      (fill_bit_buffer(0), bits_left >= HUFF_LOOKAHEAD)) {	\
+    look = peek_bits(HUFF_LOOKAHEAD);				\
+    if ((nb = htbl->priv.dec.look_nbits[look]) != 0) {		\
+      bits_left -= nb;						\
+      result = htbl->priv.dec.look_sym[look];			\
+    } else							\
+      result = slow_DECODE(htbl, HUFF_LOOKAHEAD+1);		\
+  } else							\
+    result = slow_DECODE(htbl, 1);				\
+}
+
   
-INLINE
 LOCAL int
-huff_DECODE (HUFF_TBL * htbl)
+slow_DECODE (HUFF_TBL * htbl, int min_bits)
 {
-  register int l;
+  register int l = min_bits;
   register INT32 code;
-  
-  code = get_bit();
-  l = 1;
-  while (code > htbl->maxcode[l]) {
-    code = (code << 1) | get_bit();
+
+  /* huff_DECODE has determined that the code is at least min_bits */
+  /* bits long, so fetch that many bits in one swoop. */
+
+  check_bit_buffer(l);
+  code = get_bits(l);
+
+  /* Collect the rest of the Huffman code one bit at a time. */
+  /* This is per Figure F.16 in the JPEG spec. */
+
+  while (code > htbl->priv.dec.maxcode[l]) {
+    code <<= 1;
+    check_bit_buffer(1);
+    code |= get_bits(1);
     l++;
   }
 
@@ -189,11 +251,20 @@
     return 0;			/* fake a zero as the safest result */
   }
 
-  return htbl->huffval[ htbl->valptr[l] + ((int) (code - htbl->mincode[l])) ];
+  return htbl->huffval[ htbl->priv.dec.valptr[l] +
+		        ((int) (code - htbl->priv.dec.mincode[l])) ];
 }
 
 
-/* Figure F.12: extend sign bit */
+/* Figure F.12: extend sign bit.
+ * On some machines, a shift and add will be faster than a table lookup.
+ */
+
+#ifdef AVOID_TABLES
+
+#define huff_EXTEND(x,s)  ((x) < (1<<((s)-1)) ? (x) + (((-1)<<(s)) + 1) : (x))
+
+#else
 
 #define huff_EXTEND(x,s)  ((x) < extend_test[s] ? (x) + extend_offset[s] : (x))
 
@@ -207,6 +278,8 @@
     ((-1)<<9) + 1, ((-1)<<10) + 1, ((-1)<<11) + 1, ((-1)<<12) + 1,
     ((-1)<<13) + 1, ((-1)<<14) + 1, ((-1)<<15) + 1 };
 
+#endif /* AVOID_TABLES */
+
 
 /*
  * Initialize for a Huffman-compressed scan.
@@ -214,7 +287,7 @@
  */
 
 METHODDEF void
-huff_decoder_init (decompress_info_ptr cinfo)
+decoder_init (decompress_info_ptr cinfo)
 {
   short ci;
   jpeg_component_info * compptr;
@@ -294,7 +367,7 @@
 
 
 /* ZAG[i] is the natural-order position of the i'th element of zigzag order.
- * If the incoming data is corrupted, huff_decode_mcu could attempt to
+ * If the incoming data is corrupted, decode_mcu could attempt to
  * reference values beyond the end of the array.  To avoid a wild store,
  * we put some extra zeroes after the real entries.
  */
@@ -324,7 +397,7 @@
  */
 
 METHODDEF void
-huff_decode_mcu (decompress_info_ptr cinfo, JBLOCKROW *MCU_data)
+decode_mcu (decompress_info_ptr cinfo, JBLOCKROW *MCU_data)
 {
   register int s, k, r;
   short blkn, ci;
@@ -354,8 +427,9 @@
     /* Decode a single block's worth of coefficients */
 
     /* Section F.2.2.1: decode the DC coefficient difference */
-    s = huff_DECODE(dctbl);
+    huff_DECODE(dctbl, s);
     if (s) {
+      check_bit_buffer(s);
       r = get_bits(s);
       s = huff_EXTEND(r, s);
     }
@@ -369,13 +443,14 @@
     /* Section F.2.2.2: decode the AC coefficients */
     /* Since zero values are skipped, output area must be zeroed beforehand */
     for (k = 1; k < DCTSIZE2; k++) {
-      r = huff_DECODE(actbl);
+      huff_DECODE(actbl, s);
       
-      s = r & 15;
-      r = r >> 4;
+      r = s >> 4;
+      s &= 15;
       
       if (s) {
 	k += r;
+	check_bit_buffer(s);
 	r = get_bits(s);
 	s = huff_EXTEND(r, s);
 	/* Descale coefficient and output in natural (dezigzagged) order */
@@ -395,7 +470,7 @@
  */
 
 METHODDEF void
-huff_decoder_term (decompress_info_ptr cinfo)
+decoder_term (decompress_info_ptr cinfo)
 {
   /* No work needed */
 }
@@ -409,8 +484,8 @@
 jseldhuffman (decompress_info_ptr cinfo)
 {
   if (! cinfo->arith_code) {
-    cinfo->methods->entropy_decode_init = huff_decoder_init;
-    cinfo->methods->entropy_decode = huff_decode_mcu;
-    cinfo->methods->entropy_decode_term = huff_decoder_term;
+    cinfo->methods->entropy_decode_init = decoder_init;
+    cinfo->methods->entropy_decode = decode_mcu;
+    cinfo->methods->entropy_decode_term = decoder_term;
   }
 }
diff --git a/jdmain.c b/jdmain.c
index 4991653..efb93ea 100644
--- a/jdmain.c
+++ b/jdmain.c
@@ -1,7 +1,7 @@
 /*
  * jdmain.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -18,6 +18,9 @@
  * The second style is convenient on Unix but is unhelpful on systems that
  * don't support pipes.  Also, you MUST use the first style if your system
  * doesn't do binary I/O to stdin/stdout.
+ * To simplify script writing, the "-outfile" switch is provided.  The syntax
+ *	djpeg [options]  -outfile outputfile  inputfile
+ * works regardless of which command line style is used.
  */
 
 #include "jinclude.h"
@@ -186,6 +189,7 @@
 
 
 static char * progname;		/* program name for error messages */
+static char * outfilename;	/* for -outfile switch */
 
 
 LOCAL void
@@ -280,6 +284,7 @@
   /* Set up default JPEG parameters. */
   j_d_defaults(cinfo, TRUE);
   requested_fmt = DEFAULT_FMT;	/* set default output file format */
+  outfilename = NULL;
 
   /* Scan command line options, adjust parameters */
 
@@ -287,8 +292,10 @@
     arg = argv[argn];
     if (*arg != '-') {
       /* Not a switch, must be a file name argument */
-      if (argn <= last_file_arg_seen)
-	continue;		/* ignore it if previously processed */
+      if (argn <= last_file_arg_seen) {
+	outfilename = NULL;	/* -outfile applies to just one input file */
+	continue;		/* ignore this name if previously processed */
+      }
       break;			/* else done parsing switches */
     }
     arg++;			/* advance past switch marker character */
@@ -346,7 +353,13 @@
       /* Use fast one-pass quantization. */
       cinfo->two_pass_quantize = FALSE;
 
-    } else if (keymatch(arg, "pnm", 1)) {
+    } else if (keymatch(arg, "outfile", 3)) {
+      /* Set output file name. */
+      if (++argn >= argc)	/* advance to next argument */
+	usage();
+      outfilename = argv[argn];	/* save it away for later use */
+
+    } else if (keymatch(arg, "pnm", 1) || keymatch(arg, "ppm", 1)) {
       /* PPM/PGM output format. */
       requested_fmt = FMT_PPM;
 
@@ -399,47 +412,75 @@
 #endif
 #endif
 
-  /* Scan command line: set up compression parameters, input & output files. */
+  /* Scan command line: set up compression parameters, find file names. */
 
   file_index = parse_switches(&cinfo, 0, argc, argv);
 
 #ifdef TWO_FILE_COMMANDLINE
-
-  if (file_index != argc-2) {
-    fprintf(stderr, "%s: must name one input and one output file\n", progname);
-    usage();
+  /* Must have either -outfile switch or explicit output file name */
+  if (outfilename == NULL) {
+    if (file_index != argc-2) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
+    outfilename = argv[file_index+1];
+  } else {
+    if (file_index != argc-1) {
+      fprintf(stderr, "%s: must name one input and one output file\n",
+	      progname);
+      usage();
+    }
   }
-  if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
-    fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
-    exit(EXIT_FAILURE);
-  }
-  if ((cinfo.output_file = fopen(argv[file_index+1], WRITE_BINARY)) == NULL) {
-    fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index+1]);
-    exit(EXIT_FAILURE);
-  }
-
-#else /* not TWO_FILE_COMMANDLINE -- use Unix style */
-
-  cinfo.input_file = stdin;	/* default input file */
-  cinfo.output_file = stdout;	/* always the output file */
-
-#ifdef USE_SETMODE		/* need to hack file mode? */
-  setmode(fileno(stdin), O_BINARY);
-  setmode(fileno(stdout), O_BINARY);
-#endif
-
+#else
+  /* Unix style: expect zero or one file name */
   if (file_index < argc-1) {
     fprintf(stderr, "%s: only one input file\n", progname);
     usage();
   }
+#endif /* TWO_FILE_COMMANDLINE */
+
+  /* Open the input file. */
   if (file_index < argc) {
     if ((cinfo.input_file = fopen(argv[file_index], READ_BINARY)) == NULL) {
       fprintf(stderr, "%s: can't open %s\n", progname, argv[file_index]);
       exit(EXIT_FAILURE);
     }
+  } else {
+    /* default input file is stdin */
+#ifdef USE_SETMODE		/* need to hack file mode? */
+    setmode(fileno(stdin), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+    if ((cinfo.input_file = fdopen(fileno(stdin), READ_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open stdin\n", progname);
+      exit(EXIT_FAILURE);
+    }
+#else
+    cinfo.input_file = stdin;
+#endif
   }
 
-#endif /* TWO_FILE_COMMANDLINE */
+  /* Open the output file. */
+  if (outfilename != NULL) {
+    if ((cinfo.output_file = fopen(outfilename, WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open %s\n", progname, outfilename);
+      exit(EXIT_FAILURE);
+    }
+  } else {
+    /* default output file is stdout */
+#ifdef USE_SETMODE		/* need to hack file mode? */
+    setmode(fileno(stdout), O_BINARY);
+#endif
+#ifdef USE_FDOPEN		/* need to re-open in binary mode? */
+    if ((cinfo.output_file = fdopen(fileno(stdout), WRITE_BINARY)) == NULL) {
+      fprintf(stderr, "%s: can't open stdout\n", progname);
+      exit(EXIT_FAILURE);
+    }
+#else
+    cinfo.output_file = stdout;
+#endif
+  }
   
   /* Set up to read a JFIF or baseline-JPEG file. */
   /* A smarter UI would inspect the first few bytes of the input file */
diff --git a/jdmaster.c b/jdmaster.c
index 7a4a147..a490d4d 100644
--- a/jdmaster.c
+++ b/jdmaster.c
@@ -1,7 +1,7 @@
 /*
  * jdmaster.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -31,22 +31,8 @@
   /* JPEG file scanning method selection is already done. */
   /* So is output file format selection (both are done by user interface). */
 
-  /* Entropy decoding: either Huffman or arithmetic coding. */
-#ifdef D_ARITH_CODING_SUPPORTED
-  jseldarithmetic(cinfo);
-#else
-  if (cinfo->arith_code) {
-    ERREXIT(cinfo->emethods, "Arithmetic coding not supported");
-  }
-#endif
-  jseldhuffman(cinfo);
-  /* Cross-block smoothing */
-#ifdef BLOCK_SMOOTHING_SUPPORTED
-  jselbsmooth(cinfo);
-#else
-  cinfo->do_block_smoothing = FALSE;
-#endif
   /* Gamma and color space conversion */
+  /* NB: this may change the component_needed flags */
   jseldcolor(cinfo);
 
   /* Color quantization selection rules */
@@ -77,6 +63,23 @@
   jsel2quantize(cinfo);
 #endif
 
+  /* Cross-block smoothing */
+#ifdef BLOCK_SMOOTHING_SUPPORTED
+  jselbsmooth(cinfo);
+#else
+  cinfo->do_block_smoothing = FALSE;
+#endif
+
+  /* Entropy decoding: either Huffman or arithmetic coding. */
+#ifdef D_ARITH_CODING_SUPPORTED
+  jseldarithmetic(cinfo);
+#else
+  if (cinfo->arith_code) {
+    ERREXIT(cinfo->emethods, "Arithmetic coding not supported");
+  }
+#endif
+  jseldhuffman(cinfo);
+
   /* Pipeline control */
   jseldpipeline(cinfo);
   /* Overall control (that's me!) */
diff --git a/jdmcu.c b/jdmcu.c
index 3927055..951bb7e 100644
--- a/jdmcu.c
+++ b/jdmcu.c
@@ -1,7 +1,7 @@
 /*
  * jdmcu.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -102,14 +102,19 @@
   DCTBLOCK block;
   JBLOCKROW browptr;
   JSAMPARRAY srowptr;
+  jpeg_component_info * compptr;
   long blocksperrow, bi;
   short numrows, ri;
   short ci;
 
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
+    compptr = cinfo->cur_comp_info[ci];
+    /* don't bother to IDCT an uninteresting component */
+    if (! compptr->component_needed)
+      continue;
     /* calculate size of an MCU row in this component */
-    blocksperrow = cinfo->cur_comp_info[ci]->downsampled_width / DCTSIZE;
-    numrows = cinfo->cur_comp_info[ci]->MCU_height;
+    blocksperrow = compptr->downsampled_width / DCTSIZE;
+    numrows = compptr->MCU_height;
     /* iterate through all blocks in MCU row */
     for (ri = 0; ri < numrows; ri++) {
       browptr = coeff_data[ci][ri];
diff --git a/jdpipe.c b/jdpipe.c
index b87336f..26f1f69 100644
--- a/jdpipe.c
+++ b/jdpipe.c
@@ -1,7 +1,7 @@
 /*
  * jdpipe.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -362,6 +362,10 @@
 
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
     compptr = cinfo->cur_comp_info[ci];
+    /* don't bother to upsample an uninteresting component */
+    if (! compptr->component_needed)
+      continue;
+
     vs = compptr->v_samp_factor; /* row group height */
 
     if (above >= 0)
@@ -474,6 +478,10 @@
 
   for (ci = 0; ci < cinfo->comps_in_scan; ci++) {
     compptr = cinfo->cur_comp_info[ci];
+    /* don't bother to smooth an uninteresting component */
+    if (! compptr->component_needed)
+      continue;
+
     last = compptr->MCU_height - 1;
 
     if (above == NULL)
@@ -593,6 +601,7 @@
   cinfo->total_passes++;
 
   /* Allocate working memory: */
+  prepare_range_limit_table(cinfo);
   /* coeff_data holds a single MCU row of coefficient blocks */
   coeff_data = alloc_MCU_row(cinfo);
   /* if doing cross-block smoothing, need extra space for its input */
@@ -611,7 +620,6 @@
   /* output_workspace is the color-processed data */
   output_workspace = alloc_sampimage(cinfo, (int) cinfo->final_out_comps,
 				     (long) rows_in_mem, fullsize_width);
-  prepare_range_limit_table(cinfo);
 
   /* Tell the memory manager to instantiate big arrays.
    * We don't need any big arrays in this controller,
@@ -773,10 +781,10 @@
 			     (long) (cinfo->max_h_samp_factor * DCTSIZE));
 
   /* Allocate all working memory that doesn't depend on scan info */
+  prepare_range_limit_table(cinfo);
   /* output_workspace is the color-processed data */
   output_workspace = alloc_sampimage(cinfo, (int) cinfo->final_out_comps,
 				     (long) rows_in_mem, fullsize_width);
-  prepare_range_limit_table(cinfo);
 
   /* Get a big image: fullsize_image is sample data after upsampling. */
   fullsize_image = (big_sarray_ptr *) (*cinfo->emethods->alloc_small)
diff --git a/jinclude.h b/jinclude.h
index c8a529f..8e8d185 100644
--- a/jinclude.h
+++ b/jinclude.h
@@ -1,7 +1,7 @@
 /*
  * jinclude.h
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
diff --git a/jmemdos.c b/jmemdos.c
index 8190273..30f6a2e 100644
--- a/jmemdos.c
+++ b/jmemdos.c
@@ -13,6 +13,8 @@
  * if you compile in a small-data memory model; it should NOT be defined if
  * you use a large-data memory model.  This file is not recommended if you
  * are using a flat-memory-space 386 environment such as DJGCC or Watcom C.
+ * Also, this code will NOT work if struct fields are aligned on greater than
+ * 2-byte boundaries.
  *
  * Based on code contributed by Ge' Weijers.
  */
@@ -447,21 +449,35 @@
 
 #if EMS_SUPPORTED
 
-typedef union {			/* either offset/page or real-mode pointer */
-	struct { unsigned short offset, page; } ems;
-	void far * ptr;
-      } EMSPTR;
+/* The EMS move specification structure requires word and long fields aligned
+ * at odd byte boundaries.  Some compilers will align struct fields at even
+ * byte boundaries.  While it's usually possible to force byte alignment,
+ * that causes an overall performance penalty and may pose problems in merging
+ * JPEG into a larger application.  Instead we accept some rather dirty code
+ * here.  Note this code would fail if the hardware did not allow odd-byte
+ * word & long accesses, but all 80x86 CPUs do.
+ */
 
-typedef struct {		/* EMS move specification structure */
-	long length;
-	char src_type;		/* 1 = EMS, 0 = conventional memory */
-	EMSH src_handle;	/* use 0 if conventional memory */
-	EMSPTR src;
-	char dst_type;
-	EMSH dst_handle;
-	EMSPTR dst;
+typedef void far * EMSPTR;
+
+typedef union {			/* EMS move specification structure */
+	long length;		/* It's easy to access first 4 bytes */
+	char bytes[18];		/* Misaligned fields in here! */
       } EMSspec;
 
+/* Macros for accessing misaligned fields */
+#define FIELD_AT(spec,offset,type)  (*((type *) &(spec.bytes[offset])))
+#define SRC_TYPE(spec)		FIELD_AT(spec,4,char)
+#define SRC_HANDLE(spec)	FIELD_AT(spec,5,EMSH)
+#define SRC_OFFSET(spec)	FIELD_AT(spec,7,unsigned short)
+#define SRC_PAGE(spec)		FIELD_AT(spec,9,unsigned short)
+#define SRC_PTR(spec)		FIELD_AT(spec,7,EMSPTR)
+#define DST_TYPE(spec)		FIELD_AT(spec,11,char)
+#define DST_HANDLE(spec)	FIELD_AT(spec,12,EMSH)
+#define DST_OFFSET(spec)	FIELD_AT(spec,14,unsigned short)
+#define DST_PAGE(spec)		FIELD_AT(spec,16,unsigned short)
+#define DST_PTR(spec)		FIELD_AT(spec,14,EMSPTR)
+
 #define EMSPAGESIZE	16384L	/* gospel, see the EMS specs */
 
 #define HIBYTE(W)  (((W) >> 8) & 0xFF)
@@ -476,13 +492,13 @@
   EMSspec spec;
 
   spec.length = byte_count;
-  spec.src_type = 1;
-  spec.src_handle = info->handle.ems_handle;
-  spec.src.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
-  spec.src.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
-  spec.dst_type = 0;
-  spec.dst_handle = 0;
-  spec.dst.ptr = buffer_address;
+  SRC_TYPE(spec) = 1;
+  SRC_HANDLE(spec) = info->handle.ems_handle;
+  SRC_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
+  SRC_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
+  DST_TYPE(spec) = 0;
+  DST_HANDLE(spec) = 0;
+  DST_PTR(spec)    = buffer_address;
   
   ctx.ds_si = (void far *) & spec;
   ctx.ax = 0x5700;		/* move memory region */
@@ -500,13 +516,13 @@
   EMSspec spec;
 
   spec.length = byte_count;
-  spec.src_type = 0;
-  spec.src_handle = 0;
-  spec.src.ptr = buffer_address;
-  spec.dst_type = 1;
-  spec.dst_handle = info->handle.ems_handle;
-  spec.dst.ems.page = (unsigned short) (file_offset / EMSPAGESIZE);
-  spec.dst.ems.offset = (unsigned short) (file_offset % EMSPAGESIZE);
+  SRC_TYPE(spec) = 0;
+  SRC_HANDLE(spec) = 0;
+  SRC_PTR(spec)    = buffer_address;
+  DST_TYPE(spec) = 1;
+  DST_HANDLE(spec) = info->handle.ems_handle;
+  DST_PAGE(spec)   = (unsigned short) (file_offset / EMSPAGESIZE);
+  DST_OFFSET(spec) = (unsigned short) (file_offset % EMSPAGESIZE);
   
   ctx.ds_si = (void far *) & spec;
   ctx.ax = 0x5700;		/* move memory region */
@@ -609,5 +625,10 @@
 GLOBAL void
 jmem_term (void)
 {
-  /* no work */
+  /* Microsoft C, at least in v6.00A, will not successfully reclaim freed
+   * blocks of size > 32Kbytes unless we give it a kick in the rear, like so:
+   */
+#ifdef NEED_FHEAPMIN
+  _fheapmin();
+#endif
 }
diff --git a/jmemmgr.c b/jmemmgr.c
index 77b0253..f41e847 100644
--- a/jmemmgr.c
+++ b/jmemmgr.c
@@ -297,7 +297,7 @@
   hdr--;			/* point back to header */
 
   /* Remove item from list -- linear search is fast enough */
-  llink = &medium_list;
+  llink = (medium_ptr FAR *) &medium_list;
   while (*llink != hdr) {
     if (*llink == NULL)
       ERREXIT(methods, "Bogus free_medium request");
diff --git a/jpegdata.h b/jpegdata.h
index a8ce18d..8e0b886 100644
--- a/jpegdata.h
+++ b/jpegdata.h
@@ -1,7 +1,7 @@
 /*
  * jpegdata.h
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -165,6 +165,10 @@
 	/* the MCU dimensions; these are the working dimensions of the array */
 	/* as it is passed through the DCT or IDCT step.  NOTE: these values */
 	/* differ depending on whether the component is interleaved or not!! */
+  /* This flag is used only for decompression.  In cases where some of the */
+  /* components will be ignored (eg grayscale output from YCbCr image), */
+  /* we can skip IDCT etc. computations for the unused components. */
+	boolean component_needed; /* do we need the value of this component? */
 } jpeg_component_info;
 
 
@@ -184,7 +188,12 @@
 typedef QUANT_VAL * QUANT_TBL_PTR;	/* pointer to same */
 
 
-typedef struct {		/* A Huffman coding table */
+/* Huffman coding tables.
+ */
+
+#define HUFF_LOOKAHEAD	8	/* # of bits of lookahead */
+
+typedef struct {
   /* These two fields directly represent the contents of a JPEG DHT marker */
 	UINT8 bits[17];		/* bits[k] = # of symbols with codes of */
 				/* length k bits; bits[0] is unused */
@@ -195,16 +204,29 @@
 	boolean sent_table;	/* TRUE when table has been output */
   /* The remaining fields are computed from the above to allow more efficient
    * coding and decoding.  These fields should be considered private to the
-   * Huffman compression & decompression modules.
+   * Huffman compression & decompression modules.  We use a union since only
+   * one set of fields is needed at a time.
    */
-	/* encoding tables: */
-	UINT16 ehufco[256];	/* code for each symbol */
-	char ehufsi[256];	/* length of code for each symbol */
-	/* decoding tables: (element [0] of each array is unused) */
-	UINT16 mincode[17];	/* smallest code of length k */
-	INT32 maxcode[18];	/* largest code of length k (-1 if none) */
-	/* (maxcode[17] is a sentinel to ensure huff_DECODE terminates) */
-	short valptr[17];	/* huffval[] index of 1st symbol of length k */
+	union {
+	  struct {		/* encoding tables: */
+	    UINT16 ehufco[256];	/* code for each symbol */
+	    char ehufsi[256];	/* length of code for each symbol */
+	  } enc;
+	  struct {		/* decoding tables: */
+	    /* Basic tables: (element [0] of each array is unused) */
+	    INT32 mincode[17];	/* smallest code of length k */
+	    INT32 maxcode[18];	/* largest code of length k (-1 if none) */
+	    /* (maxcode[17] is a sentinel to ensure huff_DECODE terminates) */
+	    int valptr[17];	/* huffval[] index of 1st symbol of length k */
+	    /* Lookahead tables: indexed by the next HUFF_LOOKAHEAD bits of
+	     * the input data stream.  If the next Huffman code is no more
+	     * than HUFF_LOOKAHEAD bits long, we can obtain its length and
+	     * the corresponding symbol directly from these tables.
+	     */
+	    int look_nbits[1<<HUFF_LOOKAHEAD]; /* # bits, or 0 if too long */
+	    UINT8 look_sym[1<<HUFF_LOOKAHEAD]; /* symbol, or unused */
+	  } dec;
+	} priv;
 } HUFF_TBL;
 
 
@@ -254,6 +276,10 @@
 	UINT16 X_density;	/* Horizontal pixel density */
 	UINT16 Y_density;	/* Vertical pixel density */
 
+	char * comment_text;	/* Text for COM block, or NULL for no COM */
+	/* note: JPEG library will not free() the comment string, */
+	/* unless you allocate it via alloc_small(). */
+
 	short num_components;	/* # of color components in JPEG image */
 	jpeg_component_info * comp_info;
 	/* comp_info[i] describes component that appears i'th in SOF */
@@ -739,6 +765,9 @@
 struct Decompress_methods_struct {
 	/* Hook for user interface to get control after reading file header */
 	METHOD(void, d_ui_method_selection, (decompress_info_ptr cinfo));
+	/* Hook for user interface to process comment blocks */
+	METHOD(void, process_comment, (decompress_info_ptr cinfo,
+				       long comment_length));
 	/* Hook for user interface to do progress monitoring */
 	METHOD(void, progress_monitor, (decompress_info_ptr cinfo,
 					long loopcounter, long looplimit));
diff --git a/jquant1.c b/jquant1.c
index 83399e5..cfe03a1 100644
--- a/jquant1.c
+++ b/jquant1.c
@@ -1,7 +1,7 @@
 /*
  * jquant1.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -81,37 +81,39 @@
 
 /* Declarations for Floyd-Steinberg dithering.
  *
- * Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[].
- * These have resolutions of 1/16th of a pixel count.  The error at a given
- * pixel is propagated to its unprocessed neighbors using the standard F-S
- * fractions,
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count.  The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
  *		...	(here)	7/16
  *		3/16	5/16	1/16
  * We work left-to-right on even rows, right-to-left on odd rows.
  *
- * In each of the xxxrowerrs[] arrays, indexing is [component#][position].
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed.  We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column.  (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array is indexed [component#][position].
  * We provide (#columns + 2) entries per component; the extra entry at each
  * end saves us from special-casing the first and last pixels.
- * In evenrowerrs[], the entries for a component are stored left-to-right, but
- * in oddrowerrs[] they are stored right-to-left.  This means we always
- * process the current row's error entries in increasing order and the next
- * row's error entries in decreasing order, regardless of whether we are
- * working L-to-R or R-to-L in the pixel data!
  *
  * Note: on a wide image, we might not have enough room in a PC's near data
- * segment to hold the error arrays; so they are allocated with alloc_medium.
+ * segment to hold the error array; so it is allocated with alloc_medium.
  */
 
 #ifdef EIGHT_BIT_SAMPLES
 typedef INT16 FSERROR;		/* 16 bits should be enough */
+typedef int LOCFSERROR;		/* use 'int' for calculation temps */
 #else
-typedef INT32 FSERROR;		/* may need more than 16 bits? */
+typedef INT32 FSERROR;		/* may need more than 16 bits */
+typedef INT32 LOCFSERROR;	/* be sure calculation temps are big enough */
 #endif
 
 typedef FSERROR FAR *FSERRPTR;	/* pointer to error array (in FAR storage!) */
 
-static FSERRPTR evenrowerrs[MAX_COMPONENTS]; /* errors for even rows */
-static FSERRPTR oddrowerrs[MAX_COMPONENTS];  /* errors for odd rows */
+static FSERRPTR fserrors[MAX_COMPONENTS]; /* accumulated errors */
 static boolean on_odd_row;	/* flag to remember which row we are on */
 
 
@@ -349,10 +351,9 @@
     size_t arraysize = (size_t) ((cinfo->image_width + 2L) * SIZEOF(FSERROR));
 
     for (i = 0; i < cinfo->color_out_comps; i++) {
-      evenrowerrs[i] = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
-      oddrowerrs[i]  = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
-      /* we only need to zero the forward contribution for current row. */
-      jzero_far((void FAR *) evenrowerrs[i], arraysize);
+      fserrors[i] = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
+      /* Initialize the propagated errors to zero. */
+      jzero_far((void FAR *) fserrors[i], arraysize);
     }
     on_odd_row = FALSE;
   }
@@ -426,6 +427,9 @@
   register JSAMPROW ptr0, ptr1, ptr2, ptrout;
   register long col;
   int row;
+  JSAMPROW colorindex0 = colorindex[0];
+  JSAMPROW colorindex1 = colorindex[1];
+  JSAMPROW colorindex2 = colorindex[2];
   long width = cinfo->image_width;
 
   for (row = 0; row < num_rows; row++) {
@@ -435,9 +439,9 @@
     ptr2 = input_buffer[2];
     ptrout = output_data[row];
     for (col = width; col > 0; col--) {
-      pixcode  = GETJSAMPLE(colorindex[0][GETJSAMPLE(*ptr0++)]);
-      pixcode += GETJSAMPLE(colorindex[1][GETJSAMPLE(*ptr1++)]);
-      pixcode += GETJSAMPLE(colorindex[2][GETJSAMPLE(*ptr2++)]);
+      pixcode  = GETJSAMPLE(colorindex0[GETJSAMPLE(*ptr0++)]);
+      pixcode += GETJSAMPLE(colorindex1[GETJSAMPLE(*ptr1++)]);
+      pixcode += GETJSAMPLE(colorindex2[GETJSAMPLE(*ptr2++)]);
       *ptrout++ = (JSAMPLE) pixcode;
     }
   }
@@ -449,21 +453,24 @@
 		       JSAMPIMAGE input_data, JSAMPARRAY output_data)
 /* General case, with Floyd-Steinberg dithering */
 {
-  register FSERROR val;
-  FSERROR two_val;
-  register FSERRPTR thisrowerr, nextrowerr;
+  register LOCFSERROR cur;	/* current error or pixel value */
+  LOCFSERROR belowerr;		/* error for pixel below cur */
+  LOCFSERROR bpreverr;		/* error for below/prev col */
+  LOCFSERROR bnexterr;		/* error for below/next col */
+  LOCFSERROR delta;
+  register FSERRPTR errorptr;	/* => fserrors[] at column before current */
   register JSAMPROW input_ptr;
   register JSAMPROW output_ptr;
-  JSAMPLE *range_limit = cinfo->sample_range_limit;
   JSAMPROW colorindex_ci;
   JSAMPROW colormap_ci;
-  register int pixcode;
+  int pixcode;
   int dir;			/* 1 for left-to-right, -1 for right-to-left */
   int ci;
   int nc = cinfo->color_out_comps;
   int row;
   long col_counter;
   long width = cinfo->image_width;
+  JSAMPLE *range_limit = cinfo->sample_range_limit;
   SHIFT_TEMPS
 
   for (row = 0; row < num_rows; row++) {
@@ -472,56 +479,74 @@
     jzero_far((void FAR *) output_data[row],
 	      (size_t) (width * SIZEOF(JSAMPLE)));
     for (ci = 0; ci < nc; ci++) {
+      input_ptr = input_buffer[ci];
+      output_ptr = output_data[row];
       if (on_odd_row) {
 	/* work right to left in this row */
+	input_ptr += width - 1;	/* so point to rightmost pixel */
+	output_ptr += width - 1;
 	dir = -1;
-	input_ptr = input_buffer[ci] + (width-1);
-	output_ptr = output_data[row] + (width-1);
-	thisrowerr = oddrowerrs[ci] + 1;
-	nextrowerr = evenrowerrs[ci] + width;
+	errorptr = fserrors[ci] + (width+1); /* point to entry after last column */
       } else {
 	/* work left to right in this row */
 	dir = 1;
-	input_ptr = input_buffer[ci];
-	output_ptr = output_data[row];
-	thisrowerr = evenrowerrs[ci] + 1;
-	nextrowerr = oddrowerrs[ci] + width;
+	errorptr = fserrors[ci]; /* point to entry before first real column */
       }
       colorindex_ci = colorindex[ci];
       colormap_ci = colormap[ci];
-      *nextrowerr = 0;		/* need only initialize this one entry */
+      /* Preset error values: no error propagated to first pixel from left */
+      cur = 0;
+      /* and no error propagated to row below yet */
+      belowerr = bpreverr = 0;
+
       for (col_counter = width; col_counter > 0; col_counter--) {
-	/* Get accumulated error for this component, round to integer.
+	/* cur holds the error propagated from the previous pixel on the
+	 * current line.  Add the error propagated from the previous line
+	 * to form the complete error correction term for this pixel, and
+	 * round the error term (which is expressed * 16) to an integer.
 	 * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
 	 * for either sign of the error value.
+	 * Note: errorptr points to *previous* column's array entry.
 	 */
-	val = RIGHT_SHIFT(*thisrowerr + 8, 4);
-	/* Compute pixel value + error compensation, range-limit to
-	 * 0..MAXJSAMPLE.  Note max error value is +- MAXJSAMPLE.
+	cur = RIGHT_SHIFT(cur + errorptr[dir] + 8, 4);
+	/* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+	 * The maximum error is +- MAXJSAMPLE; this sets the required size
+	 * of the range_limit array.
 	 */
-	val = GETJSAMPLE(range_limit[GETJSAMPLE(*input_ptr) + val]);
+	cur += GETJSAMPLE(*input_ptr);
+	cur = GETJSAMPLE(range_limit[cur]);
 	/* Select output value, accumulate into output code for this pixel */
-	pixcode = GETJSAMPLE(*output_ptr) + GETJSAMPLE(colorindex_ci[val]);
-	*output_ptr = (JSAMPLE) pixcode;
+	pixcode = GETJSAMPLE(colorindex_ci[cur]);
+	*output_ptr += (JSAMPLE) pixcode;
 	/* Compute actual representation error at this pixel */
-	/* Note: we can do this even though we don't yet have the final */
-	/* value of pixcode, because the colormap is orthogonal. */
-	val -= GETJSAMPLE(colormap_ci[pixcode]);
-	/* Propagate error to (same component of) adjacent pixels */
-	/* Remember that nextrowerr entries are in reverse order! */
-	two_val = val * 2;
-	nextrowerr[-1]  = val; /* not +=, since not initialized yet */
-	val += two_val;		/* form error * 3 */
-	nextrowerr[ 1] += val;
-	val += two_val;		/* form error * 5 */
-	nextrowerr[ 0] += val;
-	val += two_val;		/* form error * 7 */
-	thisrowerr[ 1] += val;
+	/* Note: we can do this even though we don't have the final */
+	/* pixel code, because the colormap is orthogonal. */
+	cur -= GETJSAMPLE(colormap_ci[pixcode]);
+	/* Compute error fractions to be propagated to adjacent pixels.
+	 * Add these into the running sums, and simultaneously shift the
+	 * next-line error sums left by 1 column.
+	 */
+	bnexterr = cur;
+	delta = cur * 2;
+	cur += delta;		/* form error * 3 */
+	errorptr[0] = (FSERROR) (bpreverr + cur);
+	cur += delta;		/* form error * 5 */
+	bpreverr = belowerr + cur;
+	belowerr = bnexterr;
+	cur += delta;		/* form error * 7 */
+	/* At this point cur contains the 7/16 error value to be propagated
+	 * to the next pixel on the current line, and all the errors for the
+	 * next line have been shifted over. We are therefore ready to move on.
+	 */
 	input_ptr += dir;	/* advance input ptr to next column */
 	output_ptr += dir;	/* advance output ptr to next column */
-	thisrowerr++;		/* cur-row error ptr advances to right */
-	nextrowerr--;		/* next-row error ptr advances to left */
+	errorptr += dir;	/* advance errorptr to current column */
       }
+      /* Post-loop cleanup: we must unload the final error value into the
+       * final fserrors[] entry.  Note we need not unload belowerr because
+       * it is for the dummy column before or after the actual array.
+       */
+      errorptr[0] = (FSERROR) bpreverr; /* unload prev err into array */
     }
     on_odd_row = (on_odd_row ? FALSE : TRUE);
   }
diff --git a/jquant2.c b/jquant2.c
index c5c4110..4f3b191 100644
--- a/jquant2.c
+++ b/jquant2.c
@@ -1,7 +1,7 @@
 /*
  * jquant2.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -875,36 +875,39 @@
 
 /* Declarations for Floyd-Steinberg dithering.
  *
- * Errors are accumulated into the arrays evenrowerrs[] and oddrowerrs[].
- * These have resolutions of 1/16th of a pixel count.  The error at a given
- * pixel is propagated to its unprocessed neighbors using the standard F-S
- * fractions,
+ * Errors are accumulated into the array fserrors[], at a resolution of
+ * 1/16th of a pixel count.  The error at a given pixel is propagated
+ * to its not-yet-processed neighbors using the standard F-S fractions,
  *		...	(here)	7/16
  *		3/16	5/16	1/16
  * We work left-to-right on even rows, right-to-left on odd rows.
  *
- * Each of the arrays has (#columns + 2) entries; the extra entry
- * at each end saves us from special-casing the first and last pixels.
- * Each entry is three values long.
- * In evenrowerrs[], the entries for a component are stored left-to-right, but
- * in oddrowerrs[] they are stored right-to-left.  This means we always
- * process the current row's error entries in increasing order and the next
- * row's error entries in decreasing order, regardless of whether we are
- * working L-to-R or R-to-L in the pixel data!
+ * We can get away with a single array (holding one row's worth of errors)
+ * by using it to store the current row's errors at pixel columns not yet
+ * processed, but the next row's errors at columns already processed.  We
+ * need only a few extra variables to hold the errors immediately around the
+ * current column.  (If we are lucky, those variables are in registers, but
+ * even if not, they're probably cheaper to access than array elements are.)
+ *
+ * The fserrors[] array has (#columns + 2) entries; the extra entry at
+ * each end saves us from special-casing the first and last pixels.
+ * Each entry is three values long, one value for each color component.
  *
  * Note: on a wide image, we might not have enough room in a PC's near data
- * segment to hold the error arrays; so they are allocated with alloc_medium.
+ * segment to hold the error array; so it is allocated with alloc_medium.
  */
 
 #ifdef EIGHT_BIT_SAMPLES
 typedef INT16 FSERROR;		/* 16 bits should be enough */
+typedef int LOCFSERROR;		/* use 'int' for calculation temps */
 #else
-typedef INT32 FSERROR;		/* may need more than 16 bits? */
+typedef INT32 FSERROR;		/* may need more than 16 bits */
+typedef INT32 LOCFSERROR;	/* be sure calculation temps are big enough */
 #endif
 
 typedef FSERROR FAR *FSERRPTR;	/* pointer to error array (in FAR storage!) */
 
-static FSERRPTR evenrowerrs, oddrowerrs; /* current-row and next-row errors */
+static FSERRPTR fserrors;	/* accumulated errors */
 static boolean on_odd_row;	/* flag to remember which row we are on */
 
 
@@ -913,18 +916,15 @@
 	      JSAMPIMAGE image_data, JSAMPARRAY output_workspace)
 /* This version performs Floyd-Steinberg dithering */
 {
-#ifdef EIGHT_BIT_SAMPLES
-  register int c0, c1, c2;
-  int two_val;
-#else
-  register FSERROR c0, c1, c2;
-  FSERROR two_val;
-#endif
-  register FSERRPTR thisrowerr, nextrowerr;
-  JSAMPROW ptr0, ptr1, ptr2, outptr;
+  register LOCFSERROR cur0, cur1, cur2;	/* current error or pixel value */
+  LOCFSERROR belowerr0, belowerr1, belowerr2; /* error for pixel below cur */
+  LOCFSERROR bpreverr0, bpreverr1, bpreverr2; /* error for below/prev col */
+  register FSERRPTR errorptr;	/* => fserrors[] at column before current */
+  JSAMPROW ptr0, ptr1, ptr2;	/* => current input pixel */
+  JSAMPROW outptr;		/* => current output pixel */
   histptr cachep;
-  register int pixcode;
-  int dir;
+  int dir;			/* +1 or -1 depending on direction */
+  int dir3;			/* 3*dir, for advancing errorptr */
   int row;
   long col;
   long width = cinfo->image_width;
@@ -942,85 +942,111 @@
     outptr = output_workspace[row];
     if (on_odd_row) {
       /* work right to left in this row */
-      ptr0 += width - 1;
+      ptr0 += width - 1;	/* so point to rightmost pixel */
       ptr1 += width - 1;
       ptr2 += width - 1;
       outptr += width - 1;
       dir = -1;
-      thisrowerr = oddrowerrs + 3;
-      nextrowerr = evenrowerrs + width*3;
+      dir3 = -3;
+      errorptr = fserrors + (width+1)*3; /* point to entry after last column */
       on_odd_row = FALSE;	/* flip for next time */
     } else {
       /* work left to right in this row */
       dir = 1;
-      thisrowerr = evenrowerrs + 3;
-      nextrowerr = oddrowerrs + width*3;
+      dir3 = 3;
+      errorptr = fserrors;	/* point to entry before first real column */
       on_odd_row = TRUE;	/* flip for next time */
     }
-    /* need only initialize this one entry in nextrowerr */
-    nextrowerr[0] = nextrowerr[1] = nextrowerr[2] = 0;
+    /* Preset error values: no error propagated to first pixel from left */
+    cur0 = cur1 = cur2 = 0;
+    /* and no error propagated to row below yet */
+    belowerr0 = belowerr1 = belowerr2 = 0;
+    bpreverr0 = bpreverr1 = bpreverr2 = 0;
+
     for (col = width; col > 0; col--) {
-      /* For each component, get accumulated error and round to integer;
-       * form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+      /* curN holds the error propagated from the previous pixel on the
+       * current line.  Add the error propagated from the previous line
+       * to form the complete error correction term for this pixel, and
+       * round the error term (which is expressed * 16) to an integer.
        * RIGHT_SHIFT rounds towards minus infinity, so adding 8 is correct
-       * for either sign of the error value.  Max error is +- MAXJSAMPLE.
+       * for either sign of the error value.
+       * Note: errorptr points to *previous* column's array entry.
        */
-      c0 = RIGHT_SHIFT(thisrowerr[0] + 8, 4);
-      c1 = RIGHT_SHIFT(thisrowerr[1] + 8, 4);
-      c2 = RIGHT_SHIFT(thisrowerr[2] + 8, 4);
-      c0 += GETJSAMPLE(*ptr0);
-      c1 += GETJSAMPLE(*ptr1);
-      c2 += GETJSAMPLE(*ptr2);
-      c0 = GETJSAMPLE(range_limit[c0]);
-      c1 = GETJSAMPLE(range_limit[c1]);
-      c2 = GETJSAMPLE(range_limit[c2]);
+      cur0 = RIGHT_SHIFT(cur0 + errorptr[dir3+0] + 8, 4);
+      cur1 = RIGHT_SHIFT(cur1 + errorptr[dir3+1] + 8, 4);
+      cur2 = RIGHT_SHIFT(cur2 + errorptr[dir3+2] + 8, 4);
+      /* Form pixel value + error, and range-limit to 0..MAXJSAMPLE.
+       * The maximum error is +- MAXJSAMPLE; this sets the required size
+       * of the range_limit array.
+       */
+      cur0 += GETJSAMPLE(*ptr0);
+      cur1 += GETJSAMPLE(*ptr1);
+      cur2 += GETJSAMPLE(*ptr2);
+      cur0 = GETJSAMPLE(range_limit[cur0]);
+      cur1 = GETJSAMPLE(range_limit[cur1]);
+      cur2 = GETJSAMPLE(range_limit[cur2]);
       /* Index into the cache with adjusted pixel value */
-      cachep = & histogram[c0 >> Y_SHIFT][c1 >> C_SHIFT][c2 >> C_SHIFT];
+      cachep = & histogram[cur0 >> Y_SHIFT][cur1 >> C_SHIFT][cur2 >> C_SHIFT];
       /* If we have not seen this color before, find nearest colormap */
       /* entry and update the cache */
       if (*cachep == 0)
-	fill_inverse_cmap(cinfo, c0 >> Y_SHIFT, c1 >> C_SHIFT, c2 >> C_SHIFT);
+	fill_inverse_cmap(cinfo, cur0>>Y_SHIFT, cur1>>C_SHIFT, cur2>>C_SHIFT);
       /* Now emit the colormap index for this cell */
-      pixcode = *cachep - 1;
-      *outptr = (JSAMPLE) pixcode;
-      /* Compute representation error for this pixel */
-      c0 -= GETJSAMPLE(colormap0[pixcode]);
-      c1 -= GETJSAMPLE(colormap1[pixcode]);
-      c2 -= GETJSAMPLE(colormap2[pixcode]);
-      /* Propagate error to adjacent pixels */
-      /* Remember that nextrowerr entries are in reverse order! */
-      two_val = c0 * 2;
-      nextrowerr[0-3]  = c0;	/* not +=, since not initialized yet */
-      c0 += two_val;		/* form error * 3 */
-      nextrowerr[0+3] += c0;
-      c0 += two_val;		/* form error * 5 */
-      nextrowerr[0  ] += c0;
-      c0 += two_val;		/* form error * 7 */
-      thisrowerr[0+3] += c0;
-      two_val = c1 * 2;
-      nextrowerr[1-3]  = c1;	/* not +=, since not initialized yet */
-      c1 += two_val;		/* form error * 3 */
-      nextrowerr[1+3] += c1;
-      c1 += two_val;		/* form error * 5 */
-      nextrowerr[1  ] += c1;
-      c1 += two_val;		/* form error * 7 */
-      thisrowerr[1+3] += c1;
-      two_val = c2 * 2;
-      nextrowerr[2-3]  = c2;	/* not +=, since not initialized yet */
-      c2 += two_val;		/* form error * 3 */
-      nextrowerr[2+3] += c2;
-      c2 += two_val;		/* form error * 5 */
-      nextrowerr[2  ] += c2;
-      c2 += two_val;		/* form error * 7 */
-      thisrowerr[2+3] += c2;
-      /* Advance to next column */
-      ptr0 += dir;
+      { register int pixcode = *cachep - 1;
+	*outptr = (JSAMPLE) pixcode;
+	/* Compute representation error for this pixel */
+	cur0 -= GETJSAMPLE(colormap0[pixcode]);
+	cur1 -= GETJSAMPLE(colormap1[pixcode]);
+	cur2 -= GETJSAMPLE(colormap2[pixcode]);
+      }
+      /* Compute error fractions to be propagated to adjacent pixels.
+       * Add these into the running sums, and simultaneously shift the
+       * next-line error sums left by 1 column.
+       */
+      { register LOCFSERROR bnexterr, delta;
+
+	bnexterr = cur0;	/* Process component 0 */
+	delta = cur0 * 2;
+	cur0 += delta;		/* form error * 3 */
+	errorptr[0] = (FSERROR) (bpreverr0 + cur0);
+	cur0 += delta;		/* form error * 5 */
+	bpreverr0 = belowerr0 + cur0;
+	belowerr0 = bnexterr;
+	cur0 += delta;		/* form error * 7 */
+	bnexterr = cur1;	/* Process component 1 */
+	delta = cur1 * 2;
+	cur1 += delta;		/* form error * 3 */
+	errorptr[1] = (FSERROR) (bpreverr1 + cur1);
+	cur1 += delta;		/* form error * 5 */
+	bpreverr1 = belowerr1 + cur1;
+	belowerr1 = bnexterr;
+	cur1 += delta;		/* form error * 7 */
+	bnexterr = cur2;	/* Process component 2 */
+	delta = cur2 * 2;
+	cur2 += delta;		/* form error * 3 */
+	errorptr[2] = (FSERROR) (bpreverr2 + cur2);
+	cur2 += delta;		/* form error * 5 */
+	bpreverr2 = belowerr2 + cur2;
+	belowerr2 = bnexterr;
+	cur2 += delta;		/* form error * 7 */
+      }
+      /* At this point curN contains the 7/16 error value to be propagated
+       * to the next pixel on the current line, and all the errors for the
+       * next line have been shifted over.  We are therefore ready to move on.
+       */
+      ptr0 += dir;		/* Advance pixel pointers to next column */
       ptr1 += dir;
       ptr2 += dir;
       outptr += dir;
-      thisrowerr += 3;		/* cur-row error ptr advances to right */
-      nextrowerr -= 3;		/* next-row error ptr advances to left */
+      errorptr += dir3;		/* advance errorptr to current column */
     }
+    /* Post-loop cleanup: we must unload the final error values into the
+     * final fserrors[] entry.  Note we need not unload belowerrN because
+     * it is for the dummy column before or after the actual array.
+     */
+    errorptr[0] = (FSERROR) bpreverr0; /* unload prev errs into array */
+    errorptr[1] = (FSERROR) bpreverr1;
+    errorptr[2] = (FSERROR) bpreverr2;
   }
   /* Emit converted rows to the output file */
   (*cinfo->methods->put_pixel_rows) (cinfo, num_rows, &output_workspace);
@@ -1067,12 +1093,12 @@
   /* Allocate Floyd-Steinberg workspace if necessary */
   /* This isn't needed until pass 2, but again it is FAR storage. */
   if (cinfo->use_dithering) {
-    size_t arraysize = (size_t) ((cinfo->image_width + 2L) * 3L * SIZEOF(FSERROR));
+    size_t arraysize = (size_t) ((cinfo->image_width + 2L) *
+				 (3 * SIZEOF(FSERROR)));
 
-    evenrowerrs = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
-    oddrowerrs  = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
-    /* we only need to zero the forward contribution for current row. */
-    jzero_far((void FAR *) evenrowerrs, arraysize);
+    fserrors = (FSERRPTR) (*cinfo->emethods->alloc_medium) (arraysize);
+    /* Initialize the propagated errors to zero. */
+    jzero_far((void FAR *) fserrors, arraysize);
     on_odd_row = FALSE;
   }
 
@@ -1157,6 +1183,14 @@
     cinfo->methods->color_quant_doit = color_quant_doit;
     cinfo->methods->color_quant_term = color_quant_term;
     cinfo->methods->color_quantize = color_quantize;
+    /* Quantized grayscale output is normally done by jquant1.c (which will do
+     * a much better job of it).  But if the program is configured with only
+     * 2-pass quantization, then I have to do the job.  In this situation,
+     * jseldcolor's clearing of the Cb/Cr component_needed flags is incorrect,
+     * because I will look at those components before conversion.
+     */
+    cinfo->cur_comp_info[1]->component_needed = TRUE;
+    cinfo->cur_comp_info[2]->component_needed = TRUE;
   }
 }
 
diff --git a/jrdjfif.c b/jrdjfif.c
index 9d63d4d..b6bd57c 100644
--- a/jrdjfif.c
+++ b/jrdjfif.c
@@ -1,7 +1,7 @@
 /*
  * jrdjfif.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -178,6 +178,8 @@
       count += bits[i];
     }
 
+    length -= 1 + 16;
+
     TRACEMS8(cinfo->emethods, 2, "        %3d %3d %3d %3d %3d %3d %3d %3d",
 	     bits[1], bits[2], bits[3], bits[4],
 	     bits[5], bits[6], bits[7], bits[8]);
@@ -185,13 +187,13 @@
 	     bits[9], bits[10], bits[11], bits[12],
 	     bits[13], bits[14], bits[15], bits[16]);
 
-    if (count > 256)
+    if (count > 256 || ((INT32) count) > length)
       ERREXIT(cinfo->emethods, "Bogus DHT counts");
 
     for (i = 0; i < count; i++)
       huffval[i] = (UINT8) JGETC(cinfo);
 
-    length -= 1 + 16 + count;
+    length -= count;
 
     if (index & 0x10) {		/* AC table definition */
       index -= 0x10;
@@ -357,12 +359,27 @@
     TRACEMS1(cinfo->emethods, 1, "Short APP0 marker, length %u", (int) length);
   }
 
-  while (length-- > 0)		/* skip any remaining data */
+  while (--length >= 0)		/* skip any remaining data */
     (void) JGETC(cinfo);
 }
 
 
 LOCAL void
+get_com (decompress_info_ptr cinfo)
+/* Process a COM marker */
+/* Actually we just pass this off to an application-supplied routine */
+{
+  INT32 length;
+  
+  length = get_2bytes(cinfo) - 2;
+  
+  TRACEMS1(cinfo->emethods, 1, "Comment, length %u", (int) length);
+  
+  (*cinfo->methods->process_comment) (cinfo, (long) length);
+}
+
+
+LOCAL void
 get_sof (decompress_info_ptr cinfo, int code)
 /* Process a SOFn marker */
 {
@@ -417,7 +434,8 @@
     compptr->h_samp_factor = (c >> 4) & 15;
     compptr->v_samp_factor = (c     ) & 15;
     compptr->quant_tbl_no  = JGETC(cinfo);
-      
+    compptr->component_needed = TRUE; /* assume all components are wanted */
+
     TRACEMS4(cinfo->emethods, 1, "    Component %d: %dhx%dv q=%d",
 	     compptr->component_id, compptr->h_samp_factor,
 	     compptr->v_samp_factor, compptr->quant_tbl_no);
@@ -526,14 +544,14 @@
 }
 
 
-LOCAL JPEG_MARKER
+LOCAL int
 process_tables (decompress_info_ptr cinfo)
 /* Scan and process JPEG markers that can appear in any order */
 /* Return when an SOI, EOI, SOFn, or SOS is found */
 {
   int c;
 
-  while (TRUE) {
+  for (;;) {
     c = next_marker(cinfo);
       
     switch (c) {
@@ -554,7 +572,7 @@
     case M_SOI:
     case M_EOI:
     case M_SOS:
-      return ((JPEG_MARKER) c);
+      return c;
       
     case M_DHT:
       get_dht(cinfo);
@@ -575,6 +593,10 @@
     case M_APP0:
       get_app0(cinfo);
       break;
+      
+    case M_COM:
+      get_com(cinfo);
+      break;
 
     case M_RST0:		/* these are all parameterless */
     case M_RST1:
@@ -588,7 +610,7 @@
       TRACEMS1(cinfo->emethods, 1, "Unexpected marker 0x%02x", c);
       break;
 
-    default:	/* must be DNL, DHP, EXP, APPn, JPGn, COM, or RESn */
+    default:	/* must be DNL, DHP, EXP, APPn, JPGn, or RESn */
       skip_variable(cinfo, c);
       break;
     }
@@ -611,7 +633,7 @@
    * nonstandard headers in front of the SOI, it must skip over them itself
    * before calling jpeg_decompress().
    */
-  if (JGETC(cinfo) != 0xFF  ||  JGETC(cinfo) != M_SOI)
+  if (JGETC(cinfo) != 0xFF  ||  JGETC(cinfo) != (int) M_SOI)
     ERREXIT(cinfo->emethods, "Not a JPEG file");
 
   get_soi(cinfo);		/* OK, process SOI */
@@ -759,16 +781,16 @@
 	  marker, desired);
   /* Outer loop handles repeated decision after scanning forward. */
   for (;;) {
-    if (marker < M_SOF0)
+    if (marker < (int) M_SOF0)
       action = 2;		/* invalid marker */
-    else if (marker < M_RST0 || marker > M_RST7)
+    else if (marker < (int) M_RST0 || marker > (int) M_RST7)
       action = 3;		/* valid non-restart marker */
     else {
-      if (marker == (M_RST0 + ((desired+1) & 7)) ||
-	  marker == (M_RST0 + ((desired+2) & 7)))
+      if (marker == ((int) M_RST0 + ((desired+1) & 7)) ||
+	  marker == ((int) M_RST0 + ((desired+2) & 7)))
 	action = 3;		/* one of the next two expected restarts */
-      else if (marker == (M_RST0 + ((desired-1) & 7)) ||
-	       marker == (M_RST0 + ((desired-2) & 7)))
+      else if (marker == ((int) M_RST0 + ((desired-1) & 7)) ||
+	       marker == ((int) M_RST0 + ((desired-2) & 7)))
 	action = 2;		/* a prior restart, so advance */
       else
 	action = 1;		/* desired restart or too far away */
diff --git a/jrdppm.c b/jrdppm.c
index ad637af..b17dcf7 100644
--- a/jrdppm.c
+++ b/jrdppm.c
@@ -105,7 +105,7 @@
     ch = pbm_getc(cinfo->input_file);
     if (ch == EOF)
       ERREXIT(cinfo->emethods, "Premature EOF in PPM file");
-  } while (ch == ' ' || ch == '\t' || ch == '\n');
+  } while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r');
   
   if (ch < '0' || ch > '9')
     ERREXIT(cinfo->emethods, "Bogus data in PPM file");
diff --git a/jversion.h b/jversion.h
index 1f0171e..4946670 100644
--- a/jversion.h
+++ b/jversion.h
@@ -1,7 +1,7 @@
 /*
  * jversion.h
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -9,6 +9,6 @@
  */
 
 
-#define JVERSION	"4 10-Dec-92"
+#define JVERSION	"4A 18-Feb-93"
 
-#define JCOPYRIGHT	"Copyright (C) 1992, Thomas G. Lane"
+#define JCOPYRIGHT	"Copyright (C) 1993, Thomas G. Lane"
diff --git a/jwrgif.c b/jwrgif.c
index 612a22c..5519d94 100644
--- a/jwrgif.c
+++ b/jwrgif.c
@@ -1,7 +1,7 @@
 /*
  * jwrgif.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -100,7 +100,7 @@
     packetbuf[0] = (char) bytesinpkt++;
     if (JFWRITE(dcinfo->output_file, packetbuf, bytesinpkt)
 	!= (size_t) bytesinpkt)
-      ERREXIT(dcinfo->emethods, "Output file write error");
+      ERREXIT(dcinfo->emethods, "Output file write error --- out of disk space?");
     bytesinpkt = 0;
   }
 }
@@ -451,7 +451,7 @@
   /* Make sure we wrote the output file OK */
   fflush(cinfo->output_file);
   if (ferror(cinfo->output_file))
-    ERREXIT(cinfo->emethods, "Output file write error");
+    ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?");
   /* Free space */
   /* no work (we let free_all release the workspace) */
 }
diff --git a/jwrjfif.c b/jwrjfif.c
index 5bd7afb..f3daba0 100644
--- a/jwrjfif.c
+++ b/jwrjfif.c
@@ -1,7 +1,7 @@
 /*
  * jwrjfif.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -38,13 +38,13 @@
 #define WRITE_BYTES(cinfo,dataptr,datacount)  \
   { if (JFWRITE(cinfo->output_file, dataptr, datacount) \
 	!= (size_t) (datacount)) \
-      ERREXIT(cinfo->emethods, "Output file write error"); }
+      ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?"); }
 
 /* Clean up and verify successful output */
 #define CHECK_OUTPUT(cinfo)  \
   { fflush(cinfo->output_file); \
     if (ferror(cinfo->output_file)) \
-      ERREXIT(cinfo->emethods, "Output file write error"); }
+      ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?"); }
 
 
 /* End of stdio-specific code. */
@@ -328,6 +328,23 @@
 }
 
 
+LOCAL void
+emit_com (compress_info_ptr cinfo, char * dataptr, size_t datalen)
+/* Emit a COM marker */
+{
+  if ((unsigned) datalen <= (unsigned) 65533) {	/* safety check */
+    emit_marker(cinfo, M_COM);
+  
+    emit_2bytes(cinfo, (int) (datalen + 2)); /* length */
+
+    while (datalen--) {
+      emit_byte(cinfo, *dataptr);
+      dataptr++;
+    }
+  }
+}
+
+
 /*
  * Write the file header.
  */
@@ -345,6 +362,10 @@
   if (cinfo->write_JFIF_header)	/* next an optional JFIF APP0 */
     emit_jfif_app0(cinfo);
 
+  if (cinfo->comment_text != NULL) /* and an optional COM block */
+    emit_com(cinfo, cinfo->comment_text,
+	     (size_t) (strlen(cinfo->comment_text)));
+
   /* Emit DQT for each quantization table. */
   /* Note that doing it here means we can't adjust the QTs on-the-fly. */
   /* If we did want to do that, we'd have a problem with checking precision */
diff --git a/jwrppm.c b/jwrppm.c
index 5d9f60b..a6d10e3 100644
--- a/jwrppm.c
+++ b/jwrppm.c
@@ -1,7 +1,7 @@
 /*
  * jwrppm.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -313,7 +313,7 @@
   /* we let free_all release any workspace */
   fflush(cinfo->output_file);
   if (ferror(cinfo->output_file))
-    ERREXIT(cinfo->emethods, "Output file write error");
+    ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?");
 }
 
 
diff --git a/jwrrle.c b/jwrrle.c
index 4fec56e..0c8718e 100644
--- a/jwrrle.c
+++ b/jwrrle.c
@@ -1,7 +1,7 @@
 /*
  * jwrrle.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -208,7 +208,7 @@
   rle_puteof(&header);
   fflush(cinfo->output_file);
   if (ferror(cinfo->output_file))
-    ERREXIT(cinfo->emethods, "Output file write error");
+    ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?");
 
   /* Release memory */
   /* no work (we let free_all release the workspace) */
diff --git a/jwrtarga.c b/jwrtarga.c
index 009d0bb..4c952cb 100644
--- a/jwrtarga.c
+++ b/jwrtarga.c
@@ -1,7 +1,7 @@
 /*
  * jwrtarga.c
  *
- * Copyright (C) 1991, 1992, Thomas G. Lane.
+ * Copyright (C) 1991, 1992, 1993, Thomas G. Lane.
  * This file is part of the Independent JPEG Group's software.
  * For conditions of distribution and use, see the accompanying README file.
  *
@@ -319,7 +319,7 @@
   /* No work except to make sure we wrote the output file OK */
   fflush(cinfo->output_file);
   if (ferror(cinfo->output_file))
-    ERREXIT(cinfo->emethods, "Output file write error");
+    ERREXIT(cinfo->emethods, "Output file write error --- out of disk space?");
 }
 
 
diff --git a/makefile.ansi b/makefile.ansi
index 59bba3b..86e3118 100644
--- a/makefile.ansi
+++ b/makefile.ansi
@@ -54,7 +54,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
diff --git a/makefile.bcc b/makefile.bcc
index 8540afc..e404fb8 100644
--- a/makefile.bcc
+++ b/makefile.bcc
@@ -23,6 +23,9 @@
 # -DINCOMPLETE_TYPES_BROKEN suppresses bogus warning about undefined structures
 # -w-par suppresses warnings about unused function parameters
 # -O2 enables full code optimization (for pre-3.0 Borland C++, use -O -G -Z)
+# If you run up against DOS' 128-character limit on command line length,
+# you can get rid of some of the -D switches by adding equivalent #define
+# commands to the head of jinclude.h.
 
 # Link-time cc options:
 LDFLAGS= -ms
@@ -50,7 +53,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
@@ -119,12 +123,12 @@
 
 test:
 	del testout.*
-	djpeg testorig.jpg testout.ppm
-	djpeg -gif testorig.jpg testout.gif
-	cjpeg testimg.ppm testout.jpg
-	fc testimg.ppm testout.ppm
-	fc testimg.gif testout.gif
-	fc testimg.jpg testout.jpg
+	djpeg -outfile testout.ppm  testorig.jpg
+	djpeg -gif -outfile testout.gif  testorig.jpg
+	cjpeg -outfile testout.jpg  testimg.ppm
+	fc /b testimg.ppm testout.ppm
+	fc /b testimg.gif testout.gif
+	fc /b testimg.jpg testout.jpg
 
 
 jbsmooth.obj : jbsmooth.c jinclude.h jconfig.h jpegdata.h
diff --git a/makefile.icc b/makefile.icc
new file mode 100644
index 0000000..1f0d6fc
--- /dev/null
+++ b/makefile.icc
@@ -0,0 +1,141 @@
+# Makefile for Independent JPEG Group's software
+
+# This makefile is for Intel's Code Builder 32-bit DOS/Windows compiler.
+# Thanks to Bailey Brown.
+
+# Read SETUP instructions before saying "make" !!
+
+# The name of your C compiler:
+CC= icc
+
+# You may want to adjust these cc options:
+CFLAGS= /O3 /Ll /DTWO_FILE_COMMANDLINE
+
+# Link-time cc options:
+LDFLAGS= /F /xregion=4M
+# /F removes floating-point support, which we don't need.
+# /xregionsize sets virtual memory region size.
+
+# To link any special libraries, add the necessary -l commands here.
+LDLIBS= 
+
+# miscellaneous OS-dependent stuff
+# linker
+LN= $(CC)
+# library (.lib) file creation command
+AR= lib32
+
+
+# source files (independently compilable files)
+SOURCES= jbsmooth.c jcarith.c jccolor.c jcdeflts.c jcexpand.c jchuff.c \
+        jcmain.c jcmaster.c jcmcu.c jcpipe.c jcsample.c jdarith.c jdcolor.c \
+        jddeflts.c jdhuff.c jdmain.c jdmaster.c jdmcu.c jdpipe.c jdsample.c \
+        jerror.c jquant1.c jquant2.c jfwddct.c jrevdct.c jutils.c jmemmgr.c \
+        jrdjfif.c jrdgif.c jrdppm.c jrdrle.c jrdtarga.c jwrjfif.c jwrgif.c \
+        jwrppm.c jwrrle.c jwrtarga.c
+# virtual source files (not present in distribution file, see SETUP)
+VIRTSOURCES= jmemsys.c
+# system-dependent implementations of virtual source files
+SYSDEPFILES= jmemansi.c jmemname.c jmemnobs.c jmemdos.c jmemdos.h \
+        jmemdosa.asm
+# files included by source files
+INCLUDES= jinclude.h jconfig.h jpegdata.h jversion.h jmemsys.h
+# documentation, test, and support files
+DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
+MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
+        makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
+OTHERFILES= ansi2knr.c ckconfig.c example.c
+TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
+DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
+        $(OTHERFILES) $(TESTFILES)
+# objectfiles common to cjpeg and djpeg
+COMOBJECTS= jutils.obj jerror.obj jmemmgr.obj jmemsys.obj
+# compression objectfiles
+CLIBOBJECTS= jcmaster.obj jcdeflts.obj jcarith.obj jccolor.obj jcexpand.obj \
+        jchuff.obj jcmcu.obj jcpipe.obj jcsample.obj jfwddct.obj \
+        jwrjfif.obj jrdgif.obj jrdppm.obj jrdrle.obj jrdtarga.obj
+COBJECTS= jcmain.obj $(CLIBOBJECTS) $(COMOBJECTS)
+# decompression objectfiles
+DLIBOBJECTS= jdmaster.obj jddeflts.obj jbsmooth.obj jdarith.obj jdcolor.obj \
+        jdhuff.obj jdmcu.obj jdpipe.obj jdsample.obj jquant1.obj \
+        jquant2.obj jrevdct.obj jrdjfif.obj jwrgif.obj jwrppm.obj \
+        jwrrle.obj jwrtarga.obj
+DOBJECTS= jdmain.obj $(DLIBOBJECTS) $(COMOBJECTS)
+# These objectfiles are included in libjpeg.lib
+LIBOBJECTS= $(CLIBOBJECTS) $(DLIBOBJECTS) $(COMOBJECTS)
+
+
+all: cjpeg.exe djpeg.exe
+# By default, libjpeg.lib is not built unless you explicitly request it.
+# You can add libjpeg.lib to the line above if you want it built by default.
+
+
+cjpeg.exe: $(COBJECTS)
+	echo $(COBJECTS) >cjpeg.rsp
+	$(LN) $(LDFLAGS) /ecjpeg.exe @cjpeg.rsp $(LDLIBS)
+
+djpeg.exe: $(DOBJECTS)
+	echo $(DOBJECTS) >djpeg.rsp
+	$(LN) $(LDFLAGS) /edjpeg.exe @djpeg.rsp $(LDLIBS)
+
+# libjpeg.lib is useful if you are including the JPEG software in a larger
+# program; you'd include it in your link, rather than the individual modules.
+libjpeg.lib: $(LIBOBJECTS)
+	del libjpeg.lib
+	$(AR) libjpeg.lib  nobackup batch <makljpeg.icc
+
+jmemsys.c:
+	echo You must select a system-dependent jmemsys.c file.
+	echo Please read the SETUP directions.
+	exit 1
+
+test: cjpeg.exe djpeg.exe
+        del testout.*
+	djpeg -outfile testout.ppm  testorig.jpg
+	djpeg -gif -outfile testout.gif  testorig.jpg
+	cjpeg -outfile testout.jpg  testimg.ppm
+        fc /b testimg.ppm testout.ppm
+        fc /b testimg.gif testout.gif
+        fc /b testimg.jpg testout.jpg
+
+
+jbsmooth.obj : jbsmooth.c jinclude.h jconfig.h jpegdata.h
+jcarith.obj : jcarith.c jinclude.h jconfig.h jpegdata.h
+jccolor.obj : jccolor.c jinclude.h jconfig.h jpegdata.h
+jcdeflts.obj : jcdeflts.c jinclude.h jconfig.h jpegdata.h
+jcexpand.obj : jcexpand.c jinclude.h jconfig.h jpegdata.h
+jchuff.obj : jchuff.c jinclude.h jconfig.h jpegdata.h
+jcmain.obj : jcmain.c jinclude.h jconfig.h jpegdata.h jversion.h
+jcmaster.obj : jcmaster.c jinclude.h jconfig.h jpegdata.h
+jcmcu.obj : jcmcu.c jinclude.h jconfig.h jpegdata.h
+jcpipe.obj : jcpipe.c jinclude.h jconfig.h jpegdata.h
+jcsample.obj : jcsample.c jinclude.h jconfig.h jpegdata.h
+jdarith.obj : jdarith.c jinclude.h jconfig.h jpegdata.h
+jdcolor.obj : jdcolor.c jinclude.h jconfig.h jpegdata.h
+jddeflts.obj : jddeflts.c jinclude.h jconfig.h jpegdata.h
+jdhuff.obj : jdhuff.c jinclude.h jconfig.h jpegdata.h
+jdmain.obj : jdmain.c jinclude.h jconfig.h jpegdata.h jversion.h
+jdmaster.obj : jdmaster.c jinclude.h jconfig.h jpegdata.h
+jdmcu.obj : jdmcu.c jinclude.h jconfig.h jpegdata.h
+jdpipe.obj : jdpipe.c jinclude.h jconfig.h jpegdata.h
+jdsample.obj : jdsample.c jinclude.h jconfig.h jpegdata.h
+jerror.obj : jerror.c jinclude.h jconfig.h jpegdata.h
+jquant1.obj : jquant1.c jinclude.h jconfig.h jpegdata.h
+jquant2.obj : jquant2.c jinclude.h jconfig.h jpegdata.h
+jfwddct.obj : jfwddct.c jinclude.h jconfig.h jpegdata.h
+jrevdct.obj : jrevdct.c jinclude.h jconfig.h jpegdata.h
+jutils.obj : jutils.c jinclude.h jconfig.h jpegdata.h
+jmemmgr.obj : jmemmgr.c jinclude.h jconfig.h jpegdata.h jmemsys.h
+jrdjfif.obj : jrdjfif.c jinclude.h jconfig.h jpegdata.h
+jrdgif.obj : jrdgif.c jinclude.h jconfig.h jpegdata.h
+jrdppm.obj : jrdppm.c jinclude.h jconfig.h jpegdata.h
+jrdrle.obj : jrdrle.c jinclude.h jconfig.h jpegdata.h
+jrdtarga.obj : jrdtarga.c jinclude.h jconfig.h jpegdata.h
+jwrjfif.obj : jwrjfif.c jinclude.h jconfig.h jpegdata.h
+jwrgif.obj : jwrgif.c jinclude.h jconfig.h jpegdata.h
+jwrppm.obj : jwrppm.c jinclude.h jconfig.h jpegdata.h
+jwrrle.obj : jwrrle.c jinclude.h jconfig.h jpegdata.h
+jwrtarga.obj : jwrtarga.c jinclude.h jconfig.h jpegdata.h
+jmemsys.obj : jmemsys.c jinclude.h jconfig.h jpegdata.h jmemsys.h
diff --git a/makefile.manx b/makefile.manx
index 88e98a9..e13d70e 100644
--- a/makefile.manx
+++ b/makefile.manx
@@ -52,7 +52,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
@@ -105,9 +106,9 @@
 
 test: cjpeg djpeg
 	-$(RM) testout.ppm testout.gif testout.jpg
-	djpeg testorig.jpg testout.ppm
-	djpeg -gif testorig.jpg testout.gif
-	cjpeg testimg.ppm testout.jpg
+	djpeg -outfile testout.ppm  testorig.jpg
+	djpeg -gif -outfile testout.gif  testorig.jpg
+	cjpeg -outfile testout.jpg  testimg.ppm
 	cmp testimg.ppm testout.ppm
 	cmp testimg.gif testout.gif
 	cmp testimg.jpg testout.jpg
diff --git a/makefile.mc5 b/makefile.mc5
index db42f33..4335797 100644
--- a/makefile.mc5
+++ b/makefile.mc5
@@ -39,7 +39,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
diff --git a/makefile.mc6 b/makefile.mc6
index 64373ab..eca1c07 100644
--- a/makefile.mc6
+++ b/makefile.mc6
@@ -16,11 +16,15 @@
 #       -DINCLUDES_ARE_ANSI    and all the ANSI include files.
 #       -DMSDOS         we are on an MSDOS machine
 #       -DUSE_FMEM      we have _fmemcpy() and _fmemset()
+#       -DNEED_FHEAPMIN        our heap management routines are broken
 #       -DSHORTxLCONST_32      enables compiler-specific multiply optimization
 #       -DMEM_STATS     enable memory usage statistics (optional)
 # You might also want to add -G2 if you have an 80286, etc.
+# If you run up against DOS' 128-character limit on command line length,
+# you can get rid of some of the -D switches by adding equivalent #define
+# commands to the head of jinclude.h.
 
-CFLAGS = -AS -Ox -W3 -DHAVE_STDC -DINCLUDES_ARE_ANSI -DMSDOS -DUSE_FMEM -DSHORTxLCONST_32
+CFLAGS = -AS -Ox -W3 -DHAVE_STDC -DINCLUDES_ARE_ANSI -DMSDOS -DUSE_FMEM -DNEED_FHEAPMIN -DSHORTxLCONST_32
 
 # need linker response file because file list > 128 chars
 RFILE = libjpeg.ans
@@ -44,7 +48,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
@@ -112,12 +117,12 @@
 
 test:
         del testout.*
-        djpeg testorig.jpg testout.ppm
-        djpeg -gif testorig.jpg testout.gif
-        cjpeg testimg.ppm testout.jpg
-        fc testimg.ppm testout.ppm
-        fc testimg.gif testout.gif
-        fc testimg.jpg testout.jpg
+	djpeg -outfile testout.ppm  testorig.jpg
+	djpeg -gif -outfile testout.gif  testorig.jpg
+	cjpeg -outfile testout.jpg  testimg.ppm
+        fc /b testimg.ppm testout.ppm
+        fc /b testimg.gif testout.gif
+        fc /b testimg.jpg testout.jpg
 
 
 jbsmooth.obj : jbsmooth.c jinclude.h jconfig.h jpegdata.h
diff --git a/makefile.mms b/makefile.mms
index 690e96d..57818b6 100644
--- a/makefile.mms
+++ b/makefile.mms
@@ -28,7 +28,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
diff --git a/makefile.sas b/makefile.sas
index 458251a..7da8570 100644
--- a/makefile.sas
+++ b/makefile.sas
@@ -1,37 +1,41 @@
 # Makefile for Independent JPEG Group's software
 
-# This makefile is for Amiga systems using SAS C 5.10b.
-# Use jmemname.c as the system-dependent memory manager.
-# Contributed by Ed Hanway (sisd!jeh@uunet.uu.net).
+# This makefile is for Amiga systems using SAS C 6.0 and up.
+# Thanks to Ed Hanway, Mark Rinfret, and Jim Zepeda.
 
 # Read SETUP instructions before saying "make" !!
+# Use jmemname.c as the system-dependent memory manager.
 
 # The name of your C compiler:
-CC= lc
+CC= sc
 
 # Uncomment the following lines for generic 680x0 version
-ARCHFLAGS=
+ARCHFLAGS= cpu=any
 SUFFIX=
 
 # Uncomment the following lines for 68030-only version
-#ARCHFLAGS= -m3
+#ARCHFLAGS= cpu=68030
 #SUFFIX=.030
 
 # You may need to adjust these cc options:
-CFLAGS= -v -b -rr -O -j104 $(ARCHFLAGS) -DHAVE_STDC -DINCLUDES_ARE_ANSI \
-	-DAMIGA -DTWO_FILE_COMMANDLINE -DINCOMPLETE_TYPES_BROKEN \
-	-DNO_MKTEMP -DNEED_SIGNAL_CATCHER -DSHORTxSHORT_32
-# -j104 disables warnings for mismatched const qualifiers
+CFLAGS= nostackcheck data=near parms=register optimize $(ARCHFLAGS) \
+	ignore=104 ignore=304 ignore=306 \
+	define HAVE_STDC define INCLUDES_ARE_ANSI \
+	define AMIGA define TWO_FILE_COMMANDLINE \
+	define NO_MKTEMP define NEED_SIGNAL_CATCHER define SHORTxSHORT_32
+# ignore=104 disables warnings for mismatched const qualifiers
+# ignore=304 disables warnings for variables being optimized out
+# ignore=306 disables warnings for the inlining of functions
 
 # Link-time cc options:
 LDFLAGS= SC SD ND BATCH
 
 # To link any special libraries, add the necessary commands here.
-LDLIBS= LIB LIB:lcr.lib
+LDLIBS= LIB LIB:scm.lib LIB:sc.lib
 
 # miscellaneous OS-dependent stuff
 # linker
-LN= blink
+LN= slink
 # file deletion command
 RM= delete quiet
 # library (.lib) file creation command
@@ -56,7 +60,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
@@ -119,9 +124,9 @@
 
 test: cjpeg djpeg
 	-$(RM) testout.ppm testout.gif testout.jpg
-	djpeg testorig.jpg testout.ppm
-	djpeg -gif testorig.jpg testout.gif
-	cjpeg testimg.ppm testout.jpg
+	djpeg -outfile testout.ppm  testorig.jpg
+	djpeg -gif -outfile testout.gif  testorig.jpg
+	cjpeg -outfile testout.jpg  testimg.ppm
 	cmp testimg.ppm testout.ppm
 	cmp testimg.gif testout.gif
 	cmp testimg.jpg testout.jpg
diff --git a/makefile.unix b/makefile.unix
index 0681c92..6e6699b 100644
--- a/makefile.unix
+++ b/makefile.unix
@@ -56,7 +56,8 @@
 DOCS= README SETUP USAGE CHANGELOG cjpeg.1 djpeg.1 architecture codingrules
 MAKEFILES= makefile.ansi makefile.unix makefile.manx makefile.sas \
         makcjpeg.st makdjpeg.st makljpeg.st makefile.mc5 makefile.mc6 \
-        makefile.bcc makefile.mms makefile.vms makvms.opt
+        makefile.bcc makefile.icc makljpeg.icc makefile.mms makefile.vms \
+        makvms.opt
 OTHERFILES= ansi2knr.c ckconfig.c example.c
 TESTFILES= testorig.jpg testimg.ppm testimg.gif testimg.jpg
 DISTFILES= $(DOCS) $(MAKEFILES) $(SOURCES) $(SYSDEPFILES) $(INCLUDES) \
diff --git a/makljpeg.icc b/makljpeg.icc
new file mode 100644
index 0000000..1c34db8
--- /dev/null
+++ b/makljpeg.icc
@@ -0,0 +1,38 @@
+add jcmaster.obj
+add jcdeflts.obj
+add jcarith.obj
+add jccolor.obj
+add jcexpand.obj
+add jchuff.obj
+add jcmcu.obj
+add jcpipe.obj
+add jcsample.obj
+add jfwddct.obj
+add jwrjfif.obj
+add jrdgif.obj
+add jrdppm.obj
+add jrdrle.obj
+add jrdtarga.obj
+add jdmaster.obj
+add jddeflts.obj
+add jbsmooth.obj
+add jdarith.obj
+add jdcolor.obj
+add jdhuff.obj
+add jdmcu.obj
+add jdpipe.obj
+add jdsample.obj
+add jquant1.obj
+add jquant2.obj
+add jrevdct.obj
+add jrdjfif.obj
+add jwrgif.obj
+add jwrppm.obj
+add jwrrle.obj
+add jwrtarga.obj
+add jutils.obj
+add jerror.obj
+add jmemmgr.obj
+add jmemsys.obj
+update
+quit