// *very* crude hack based in my earlier C to HTML that tries to remove
// comments from a C source file.  Should leave #-directives alone.
// Lots of redundant code left over here that wasn't worth removing.

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

int peekchar = -1;

int fpeek(FILE *f) {
  int ch;

  ch = fgetc(f);
  ungetc(ch, f);
  return ch;
}

void printchar(char inchar, FILE *fstream) { fputc(inchar, fstream); }

int uncomment(FILE *fstream, char *Title) {
  FILE *InFile;
  int inchar, i, newline = 1, WordIdx = 0;
  char word[280];

  for (i = 0; i < 280; ++i) word[i] = 0;

  /* Now we open the file for reading in text mode. */
  if (Title) {
    InFile = fopen(Title, "r");
    if (InFile == NULL) return -1;
  } else {
    InFile = stdin;
  }
  
  /* And start reading it in character by character. */
  inchar = fgetc(InFile);
  peekchar = fpeek(InFile);
  while (!feof(InFile)) {
    /* Everything else. */
    if (isalnum(inchar) || (inchar == '_')) {
      word[WordIdx++] = inchar;
      word[WordIdx] = '\0';
      inchar = fgetc(InFile);
      peekchar = fpeek(InFile);
      continue;
    }
    if (WordIdx > 0) {  // flush any newly-terminated word
      fprintf(fstream, "%s", word);
      WordIdx = 0;
    }

    if (inchar == '\n') {
      newline = 1;
    }
    if (!isspace(inchar)) {
      /* Handle all preproccessor directives. */
      if (inchar == '#') {
        if (newline == 1) {
          int in_comment = 0;
          for (;;) {
            if ((inchar != '\\') && (peekchar == '\n')) break;
            printchar(inchar, fstream);
            inchar = fgetc(InFile);
            peekchar = fpeek(InFile);
            if (inchar == '/' && peekchar == '/') {
              in_comment = 1;
            }
            // Not sure if /* at rhs of a #define is continued - should try & see.
            // However it's not something I would do - '//' support will be enough...
          }
          printchar(inchar, fstream);
          inchar = fgetc(InFile);
          peekchar = fpeek(InFile);
          newline = 1;
          continue;
        }
      }
      /* Handle single line comments. */
      else if ((inchar == '/') && (peekchar == '/')) {
        while ((inchar != '\n') && (inchar > 0)) {
          //printchar(inchar, fstream);
          inchar = fgetc(InFile);
          peekchar = fpeek(InFile);
        }
        newline = 1;
        continue;
      }
      /* Handle Multi-line comments. */
      else if ((inchar == '/') && (peekchar == '*')) {
        //fprintf(fstream, "/");
        for (;;) {
          inchar = fgetc(InFile);
          peekchar = fpeek(InFile);
          if ((inchar == '*') && (peekchar == '/')) break;
          //printchar(inchar, fstream);
        }
        inchar = fgetc(InFile);
        peekchar = fpeek(InFile);
        //fprintf(fstream, "*/");
        inchar = fgetc(InFile);
        peekchar = fpeek(InFile);
        continue; /* Now process next char */
      }
      /* Handle Double Quotes. */
      else if (inchar == '"') {
        fprintf(fstream, "\"");
        for (;;) {  // fix by simplifying
          inchar = fgetc(InFile);
          if (inchar == EOF) break;
          if (inchar == '"') break;
          if (inchar == '\\') {
            printchar(inchar, fstream);
            inchar = fgetc(InFile);
            if (inchar == EOF) break;
          }
          printchar(inchar, fstream);
        }
        inchar = fgetc(InFile);
        peekchar = fpeek(InFile);
        fprintf(fstream, "\"");
        newline = 0;
        continue;
      }
      /* Handle Single Quotes. */
      else if (inchar == '\'') {
        fprintf(fstream, "'");
        inchar = fgetc(InFile);
        if (inchar == EOF) continue;
        peekchar = fpeek(InFile);
        for (;;) {
          if ((inchar != '\\') && (peekchar == '\'')) break;
          if ((inchar == '\\') && (peekchar == '\\')) {
            printchar(inchar, fstream);
            inchar = fgetc(InFile);
            if (inchar == EOF) break;
            peekchar = fpeek(InFile);
            if (peekchar == '\'') break;
          }
          printchar(inchar, fstream);
          inchar = fgetc(InFile);
          if (inchar == EOF) break;
          peekchar = fpeek(InFile);
        }
        printchar(inchar, fstream);
        inchar = fgetc(InFile);
        peekchar = fpeek(InFile);
        printchar(inchar, fstream);
        inchar = fgetc(InFile);
        peekchar = fpeek(InFile);
        newline = 0;
        continue;
      }
      newline = 0;
    }

    printchar(inchar, fstream);
    inchar = fgetc(InFile);
    peekchar = fpeek(InFile);
  }
  fprintf(fstream, "\n");
  fclose(InFile);
  return 1;
}

int main(int argc, char *argv[]) {
  if (argc > 2) {
    printf("Usage: %s [Filename]\n\n", argv[0]);
    return -1;
  }
  FILE *pipe = popen("clang-format|grep -v ^$", "w");
  if (pipe == NULL) pipe = stdout;
  uncomment(pipe, argv[1]);
  pclose(pipe);
  return 0;
}
