#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "platform.h"
#define true 1
#define false 0
#define TABSIZE 4
#define DOS_CRLF 0
#define UNIX_LF 1
#define MAC_CR 2
typedef struct
{
Bool pushed;
int tabs;
int curcol;
int lastcol;
int maxcol;
int curline;
int pushed_char;
uint size;
uint length;
char *buf;
FILE *fp;
} Stream;
static int tabsize = TABSIZE;
static int endline = DOS_CRLF;
static Bool tabs = false;
void *MemAlloc(size_t size)
{
void *p;
p = malloc(size);
if (!p)
{
fprintf(stderr, "***** Out of memory! *****\n");
exit(1);
}
return p;
}
void *MemRealloc(void *old, size_t size)
{
void *p;
p = realloc(old, size);
if (!p)
{
fprintf(stderr, "***** Out of memory! *****\n");
return NULL;
}
return p;
}
void MemFree(void *p)
{
free(p);
p = NULL;
}
static Stream *NewStream(FILE *fp)
{
Stream *in;
in = (Stream *)MemAlloc(sizeof(Stream));
memset(in, 0, sizeof(Stream));
in->fp = fp;
return in;
}
static void FreeStream(Stream *in)
{
if (in->buf)
MemFree(in->buf);
MemFree(in);
}
static void AddByte(Stream *in, uint c)
{
if (in->size + 1 >= in->length)
{
while (in->size + 1 >= in->length)
{
if (in->length == 0)
in->length = 8192;
else
in->length = in->length * 2;
}
in->buf = (char *)MemRealloc(in->buf, in->length*sizeof(char));
}
in->buf[in->size++] = (char)c;
in->buf[in->size] = '\0';
}
static int ReadChar(Stream *in)
{
int c;
if (in->pushed)
{
in->pushed = false;
if (in->pushed_char == '\n')
in->curline--;
return in->pushed_char;
}
in->lastcol = in->curcol;
if (in->tabs > 0)
{
in->curcol++;
in->tabs--;
return ' ';
}
for (;;)
{
c = getc(in->fp);
if (c == EOF)
break;
if (c == '\r')
{
c = getc(in->fp);
if (c != '\n')
ungetc(c, in->fp);
c = '\n';
}
if (c == '\n')
{
if (in->maxcol < in->curcol)
in->maxcol = in->curcol;
in->curcol = 1;
in->curline++;
break;
}
if (c == '\t')
{
if (tabs)
in->curcol += tabsize - ((in->curcol - 1) % tabsize);
else
{
in->tabs = tabsize - ((in->curcol - 1) % tabsize) - 1;
in->curcol++;
c = ' ';
}
break;
}
if (c == '\033')
break;
if (0 < c && c < 32)
continue;
in->curcol++;
break;
}
return c;
}
static Stream *ReadFile(FILE *fin)
{
int c;
Stream *in = NewStream(fin);
while ((c = ReadChar(in)) >= 0)
AddByte(in, (uint)c);
return in;
}
static void WriteFile(Stream *in, FILE *fout)
{
int i, c;
char *p;
i = in->size;
p = in->buf;
while (i--)
{
c = *p++;
if (c == '\n')
{
if (endline == DOS_CRLF)
{
putc('\r', fout);
putc('\n', fout);
}
else if (endline == UNIX_LF)
putc('\n', fout);
else if (endline == MAC_CR)
putc('\r', fout);
continue;
}
putc(c, fout);
}
}
static void HelpText(FILE *errout, char *prog)
{
fprintf(errout, "%s: [options] [infile [outfile]] ...\n", prog);
fprintf(errout, "Utility to expand tabs and ensure consistent line endings\n");
fprintf(errout, "options for tab2space vers: 6th February 2003\n");
fprintf(errout, " -help or -h display this help message\n");
fprintf(errout, " -dos or -crlf set line ends to CRLF (PC-DOS/Windows - default)\n");
fprintf(errout, " -mac or -cr set line ends to CR (classic Mac OS)\n");
fprintf(errout, " -unix or -lf set line ends to LF (Unix)\n");
fprintf(errout, " -tabs preserve tabs, e.g. for Makefile\n");
fprintf(errout, " -t<n> set tabs to <n> (default is 4) spaces\n");
fprintf(errout, "\nNote this utility doesn't map spaces to tabs!\n");
}
int main(int argc, char **argv)
{
char const *infile, *outfile;
char *prog;
FILE *fin, *fout;
Stream *in = NULL;
prog = argv[0];
while (argc > 0)
{
if (argc > 1 && argv[1][0] == '-')
{
if (strcmp(argv[1], "-help") == 0 || argv[1][1] == 'h')
{
HelpText(stdout, prog);
return 1;
}
if (strcmp(argv[1], "-dos") == 0 ||
strcmp(argv[1], "-crlf") == 0)
endline = DOS_CRLF;
else if (strcmp(argv[1], "-mac") == 0 ||
strcmp(argv[1], "-cr") == 0)
endline = MAC_CR;
else if (strcmp(argv[1], "-unix") == 0 ||
strcmp(argv[1], "-lf") == 0)
endline = UNIX_LF;
else if (strcmp(argv[1], "-tabs") == 0)
tabs = true;
else if (strncmp(argv[1], "-t", 2) == 0)
sscanf(argv[1]+2, "%d", &tabsize);
--argc;
++argv;
continue;
}
if (argc > 1)
{
infile = argv[1];
fin = fopen(infile, "rb");
}
else
{
infile = "stdin";
fin = stdin;
}
if (argc > 2)
{
outfile = argv[2];
fout = NULL;
--argc;
++argv;
}
else
{
outfile = "stdout";
fout = stdout;
}
if (fin)
{
in = ReadFile(fin);
if (fin != stdin)
fclose(fin);
if (fout != stdout)
fout = fopen(outfile, "wb");
if (fout)
{
WriteFile(in, fout);
if (fout != stdout)
fclose(fout);
}
else
fprintf(stderr, "%s - can't open \"%s\" for writing\n", prog, outfile);
FreeStream(in);
}
else
fprintf(stderr, "%s - can't open \"%s\" for reading\n", prog, infile);
--argc;
++argv;
if (argc <= 1)
break;
}
return 0;
}