/*-------------------------------------------------------------+
 | addcr.c -- 5/16/1992 public domain                          |
 |            by Alex Matulich, Unicorn Research Corporation   |
 | Add a CR character before each LF character in a text file. |
 | Nothing is done where the CR+LF combination already exists. |
 +-------------------------------------------------------------*/

#include <stdio.h>
#include <string.h>
#include <stdlib.h>

#ifdef __ZTC__
#define stricmp(a,b) strcmpl(a,b)   /* Zortech's case-insensitive strcmp() */
#endif
#define LF '\x0A'
#define CR '\x0D'

long OUTBUFSIZ = 16384;

unsigned short replace, bufptr = 0;
signed char *buf = NULL;
FILE *infile, *outfile;
long inpos = 0L, outpos = 0L;       /* file position trackers */

int writebuf(void);


void main(int argc, char *argv[])
{
signed char ch[2];
short plast = 0, p, err;

if( argc != 3 && argc != 2) {
   puts("AddCR by Unicorn Research Corporation\nConvert LF end-of-line codes to CR+LF.\n\nUsage is:  AddCR infile [outfile]\n\nIf outfile is omitted, infile will be replaced.\nExisting CR+LF codes are not affected.\n");
   return;
   }
if((infile = fopen( argv[1], (replace = (argc == 2)) ? "rb+" : "rb" )) == NULL) {
   fputs("Could not open input file.\n", stdout);
   return;
   }
if (replace)
   outfile = infile;
else if ((outfile = fopen( argv[2], "wb" )) == NULL) {
   fputs("Could not open output file.\n", stdout);
   fclose(infile);
   return;
   }

begin:
err = 0;
OUTBUFSIZ <<= 1;
if ((buf = (signed char *)realloc(buf, OUTBUFSIZ)) == NULL) {
   fputs("Not enough memory!\n", stdout);
   goto cleanup;
   }

while( (ch[p=plast] = fgetc(infile)) != EOF ) {
   ++inpos;
   plast = !p;
   if( ch[p] == LF && ch[plast] != CR) {
      buf[bufptr++] = CR;
      if (bufptr == OUTBUFSIZ) err = writebuf();
      if (err > 0) break;
      }
   buf[bufptr++] = ch[p];
   if (err == -100) goto begin;
   if (bufptr == OUTBUFSIZ) if ((err = writebuf()) > 0) break;
   if (err == -100) goto begin;
   }

while (!err && bufptr) {
   inpos = outpos+bufptr;  /* reset to allow remaining writes */
   err = writebuf();
   }

if (err == 1)
   fputs("Error writing output file.\n", stdout);
else if (err == 2)
   fputs("Error reading input file.\n", stdout);
else if (replace) {
   fputs(argv[1], stdout);
   fputs(" now has CR+LF end-of-line codes.\n", stdout);
   }
else {
   fputs("File ", stdout);
   fputs(argv[2], stdout);
   fputs(" successfully created with CR+LF end-of-line codes.\n", stdout);
   }

cleanup:
free(buf);
fclose(infile);
if (!replace) fclose(outfile);
}


/* Write the buffer to the output file, when full or when done.
 * Stop writing when end of buffer is hit, or, if we are in replace mode,
 * when current input pointer is hit. */
int writebuf()
{
unsigned short i = 0, j = 0, buflimit;
if (replace) {
   if ((buflimit = inpos - outpos) <= 0) return -100;
   if (fseek(outfile, outpos, 0)) return 1;
   }
else
   buflimit = bufptr;
while (i < buflimit)
   if (fputc(buf[i++], outfile) == EOF) return 1;
outpos += buflimit;
if (replace) {
   if (fseek(infile, inpos, 0)) return 2;
   for (i = buflimit; i < bufptr;) buf[j++] = buf[i++];
   }
bufptr -= buflimit;
return 0;
}
