// anynl.c  -- accept any unix, mac, or windows format text file and convert
//             line endings to any of the three conventions.  Defaults to
//             converting to the current platform's convention.
//
// When compiled on Windows this program must go out of its way to
// disable to normal ASCII translation of newlines done by the C
// runtime to map between C's '\n' and the Windows platform's CR/LF.
//

#include <stdio.h>
#include <fcntl.h>
#if defined(WIN32) || defined(__WIN32__) || defined(_Windows) || defined(_WIN32)
  #include <io.h>
#endif
#include <string.h>

#define LF ((char)10)
#define CR ((char)13)
#define CTRLZ ((char)26)

#if defined(_MSC_VER)
  #define strcasecmp(a,b) _stricmp(a,b)
#endif

void UnixNewline(void) {
  putchar(LF);
}

void MacNewline(void) {
  putchar(CR);
}

void DosNewline(void) {
  putchar(CR);
  putchar(LF);
}

int main(int argc, char **argv)
{
  char ch;
  int ich;
  void (*EmitNewline)(void);

  #if defined(WIN32) || defined(__WIN32__) || defined(_Windows) || defined(_WIN32)
    // switch stdin/stdout streams to binary mode
    _setmode(_fileno(stdin), _O_BINARY);
    _setmode(_fileno(stdout), _O_BINARY);

    EmitNewline = DosNewline;
  #else
    // default to targetting this platform.
    EmitNewline = UnixNewline;
  #endif

  while (++argv, --argc) {
    if (!strcasecmp(*argv, "-dos")) {
      EmitNewline = DosNewline;
    } else if (!strcasecmp(*argv, "-mac")) {
      EmitNewline = MacNewline;
    } else if (!strcasecmp(*argv, "-unix")) {
      EmitNewline = UnixNewline;
    }
  }

  while (EOF != (ich = getc(stdin))) {
    ch = ich;

    if (CR == ch) {
      (*EmitNewline)();

      // might be mac, with CR only, or dos, with CRLF
      if (EOF == (ich = getc(stdin))) {
        break;
      }
      ch = ich;
      if (LF != ch) {
        ungetc(ch, stdin);
      }
    } else if (LF == ch) {
      (*EmitNewline)();
    } else if (CTRLZ == ch) {  // DOS sometimes has ^Z to indicate EOF, stop there
      break;
    } else {
      putchar(ch);
    }
  }
}