Luckily, I was able to track down this bug.
Code: Select all
/*
* Convert Life pattern from .RLE format to text format
* Implemented in Borland C 3.1 for MS-DOS
* (This should be easily convertible to other platforms)
*
* By Mark D. Niemiec 1997
* E-mail: mniemiec@interserv.com
* WWW: http://home.sprynet.com/interserv/mniemiec/lifepage.htm
*/
/*
Minor logic bug repaired by PM 2Ring, March 2009.
XXXX Needs work: lines should be padded to pattern width
*/
#include <stdio.h> // ferror fopen fprintf getc putc sprintf ungetc
#include <stdlib.h> // exit
#include <string.h> // strcat strlen strncpy strnicmp
/*
* Global variables
*/
char outputChars[7] = ".OXYZa"; /* dead state, 5 living states */
/*
* .RLE files are ASCII text files with a one-line header,
* and followed by a variable-length run-length encoded image.
*
* The header may be preceded by any number of blank lines and/or
* comment lines beginning with a pound sign '#'.
*
* The header consists of several fields separated by commas,
* and ending in a newline.
* The first two fields are "x = nnn" and "y = nnn", (where nnn
* is an integer) respectively specifying the pattern width and height.
* These fields are required.
*
* An optional rule field, of the form "rule = Bnnn/Snnn" may follow,
* encoding totalistic rules. By convention, this field is required
* a rule different from Life (B3/S23) is used.
*
* The data portion consists of one or more runs, terminated by
* an exclamation mark '!'.
* The runs are defined by a single character, preceded by an optional
* integer repeat factor (which defaults to 1 if omitted).
* The character may be one of the following:
* $ Newline
* b Dead cell
* o Living cell, or first living state in multi-state Life
* x* Second living state in multi-state Life
* y* Third living state in multi-state Life
* z* Fourth living state in multi-state Life
* other Unrecognized codes should be interpreted as living cells
* (NOTE: characters marked * above are extensions used by this program,
* but not part of the generally accepted de-facto RLE standard;
* however, x, y, and z behave correctly when treated as 'other')
* Embedded white space is ignored.
*
* The de-facto RLE standard adds the following additional stipulations:
* Lines should not exceed 70 characters to avoid confusing brain-damaged
* e-mail programs, so newlines should be added as required.
* Newlines and other white-space may not be inserted in the middle of a
* repeat factor, nor between a character and its repeat factor.
* This program can, however, read files which violate these stipulations.
*
* This program can also read .RLE files without headers,
* since it does not use the header information for anything.
*/
/*
* Read .RLE-format file
*/
void
ReadRle (FILE *srcFile, FILE *dstFile)
{
int repl; /* replication count */
int ifrepl; /* is replication count given? */
int c; /* character read from file */
int curx; /* x coordinate being written */
int cury; /* y coordinate being written */
for (;;) { /* strip leading comment lines: */
switch ((c = getc (srcFile))) {
case EOF: /* end of file: no comment */
break;
case '\n': /* blank line: ignored */
continue;
case '#': /* #: comment line */
while ((c = getc (srcFile)) != '\n') {
if (c == EOF) /* EOF in comment!?! */
break;
}
continue;
default: /* other: legitimate text */
ungetc (c, srcFile);
break;
}
break;
}
while ((c = getc(srcFile)) == ' ' || c == '\t' || c == '\n');
if (c == 'x') { /* header line is supplied (and ignored) */
while ((c = getc(srcFile)) != EOF && c != '\n');
} else { /* no header: translator doesn't care */
ungetc (c, srcFile);
}
for (repl = 1, ifrepl = 0, curx = cury = 0; ; ) {
while ((c = getc (srcFile)) == ' ' || c == '\t' || c == '\n')
;
//fputc (c, stderr);
switch (c) {
default:
if (c >= '0' && c <= '9') {
repl = (ifrepl ? 10*repl : 0) + (c-'0');
ifrepl = 1;
continue;
} else {
outputChars[5] = c;
c = 5;
break;
}
case EOF:
fprintf (stderr, "Missing end-of-file '!' mark\n");
break;
case '!':
if (curx != 0) /* ALWAYS flush last line */
fputc ('\n', dstFile);
return;
case 'b':
c = 0;
break;
case 'o':
c = 1;
break;
case 'x':
c = 2;
break;
case 'y':
c = 3;
break;
case 'z':
c = 4;
break;
case '$':
for (; repl > 0; ++cury, --repl, curx = 0)
fputc ('\n', dstFile);
repl = 1;
ifrepl = 0;
continue;
}
fprintf(stderr, "%d:%d %c\n", repl, c, outputChars[c]);
for (c = outputChars[c]; repl > 0; ++curx, --repl)
fputc (c, dstFile);
repl = 1;
ifrepl = 0;
}
}
/*
* Main
*/
int
main (int argc, char **argv)
{
char *arg; /* argument being examined */
FILE *srcFile; /* source file */
FILE *dstFile; /* destination file */
if (argc > 1 && strncmp (argv[1], "-c", 2) == 0) {
strncpy (outputChars, argv[1]+2, 5);
--argc;
++argv;
}
if (argc != 3) {
fprintf (stderr,
"Usage: rle2txt [-c[.[o[x[y[z]]]]]] infile.rle outfile.txt\n");
exit (1);
}
if (outputChars[0] == '\0')
strcat (outputChars, ".");
if (outputChars[1] == '\0')
strcat (outputChars, "*");
while (strlen (outputChars) < 5) {
sprintf (outputChars + strlen (outputChars),
"%c", outputChars[1]);
}
if ((srcFile = fopen (argv[1], "r")) == NULL) {
fprintf (stderr, "Cannot open %s\n", argv[1]);
exit (1);
}
if ((dstFile = fopen (argv[2], "w")) == NULL) {
fprintf (stderr, "Cannot create %s\n", argv[2]);
exit (1);
}
ReadRle (srcFile, dstFile);
if (ferror (dstFile)) {
fprintf (stderr, "Disk full writing to %s\n", argv[2]);
exit (1);
}
return 0;
}
Code: Select all
NAME
RLE2TXT - Life RLE file conversion utility, by Mark D. Niemiec
SYNOPSIS
RLE2TXT [-C[.[o[x[y[z]]]]]] infile.rle outfile.txt
DESCRIPTION
RLE2TXT converts a Life file in RLE format into a plain text file.
By default, dead cells are displayed as periods, while living cells
are displayed as Os. If multiple living states exist in the RLE
file, the first four such states are displayed as O, X, Y, and Z.
Other codes in the RLE file are displayed as-is without translation.
The output characters can be overridden by the -C command:
-C displays dead cells as ., and all living cells to *,*,*,*
(which is commonly used by many other Life programs)
-Cd displays dead cells as d, and all living cells as *,*,*,*
-Cdo displays dead cells as d, and all living cells as o,o,o,o
-Cdox displays dead cells as d, and all living cells as o,x,o,o
-Cdoxy displays dead cells as d, and all living cells as o,x,y,o
-Cdoxyz displays dead cells as d, and all living cells as o,x,y,z
-C.OXYZ is the default, if no -C command is given.
If the .RLE file contains a header, it is read but ignored.
PORTABILITY
Requires DOS 2.0 or higher.
Source code should be Unix compatible with only trivial changes.
BUGS
There is no way to output spaces for dead cells.
Does not support files with runs larger than 32767 (but then,
most other programs don't handle 32768-character lines well either.)