/*
 * perl-like grep < lgrep.c >
 *
 * Perl 互換の正規表現による grep
 *
 * Copyright (c) 1998 Taiji Yamada, AIHARA Electrical Engineering Co., Ltd.
 */
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "escs.h"

#if !HAVE_RECOMP && !HAVE_REGEX && !HAVE_REGCMP && !HAVE_REGEXPR
#include "rege.h"
#endif
#if HAVE_RECOMP
#include <regex.h>
#endif
#if HAVE_REGEX
#include <regex.h>
#endif
#if HAVE_REGCMP
#include <libgen.h>
extern char *__loc1;
#endif
#if HAVE_REGEXPR
#include <regexpr.h>
extern char *loc1, *loc2;
#endif

int main(int argc, char *argv[])
{
  char buf[1024];
  char *p, *q, *from, *to;
  /*int escs_mode = !0;*/
  int escs_mode = 0;
#if !HAVE_RECOMP && !HAVE_REGEX && !HAVE_REGCMP && !HAVE_REGEXPR
  rege_t *rege_p;
#endif
#if HAVE_RECOMP
  regex_t *recomp_p;
  regmatch_t recomp_m;
#endif
#if HAVE_REGEX
  struct re_pattern_buffer re_buf;
  struct re_registers re_reg;
  regoff_t re_reg_start;
  regoff_t re_reg_end;
#endif
#if HAVE_REGCMP
  char *regcmp_p;
#endif
#if HAVE_REGEXPR
  char *regexpr_p;
#endif

  if (argc != 2) {
    fprintf(stderr, "usage: %s regular-expression\n", argv[0]);
    exit(1);
  }

#if !HAVE_RECOMP && !HAVE_REGEX && !HAVE_REGCMP && !HAVE_REGEXPR
  rege_p = rege_compile(argv[1], 0, NULL);
#endif

#if HAVE_RECOMP
  recomp_p = malloc(sizeof(regex_t));
  regcomp(recomp_p, argv[1], REG_EXTENDED|REG_NEWLINE);
#endif
#if HAVE_REGEX
  re_buf.allocated = 0;
  re_buf.buffer = NULL;
  re_buf.fastmap = NULL;
  re_buf.translate = NULL;
  re_compile_pattern(argv[1], strlen(argv[1]), &re_buf);
  re_reg.num_regs = 1;
  re_reg.start = &re_reg_start;
  re_reg.end = &re_reg_end;
#endif
#if HAVE_REGCMP
  regcmp_p = regcmp(argv[1], 0);
#endif
#if HAVE_REGEXPR
  regexpr_p = compile(argv[1], NULL, NULL);
#endif

  while (fgets(buf, sizeof(buf)-1, stdin) != NULL) {
    buf[sizeof(buf)] = '\0';
    /*if ((p=strchr(buf,'\n')) != NULL) *p = '\0';*/
    p = buf;
#define PRINT1 \
      if (!escs_mode) {\
        for (q=p; q<from; q++) printf(" ");\
        for (; q<to; q++) printf("-");\
        if (p==from && p==to)\
          if (*(to+1) == '\0') { printf("\n"); }\
          else printf(" ");\
      } else {\
        for (q=p; q<from; q++) printf("%c",*q);\
        if (!(p==from && p==to)) att(ESCS_REVERSE);\
        for (; q<to; q++) printf("%c",*q);\
        if (p==from && p==to)\
          if (*(to+1) == '\0') { printf("\n"); }\
          else printf("%c",*p);\
        if (!(p==from && p==to)) att(ESCS_DEFAULT);\
      }
#define PRINT2 \
        if (!escs_mode) {\
          for (q=p; *q!='\n' && *q!='\0'; q++) printf(" ");\
          printf("\n");\
        } else\
          for (q=p; *q!='\0'; q++) printf("%c",*q);
#if !HAVE_RECOMP && !HAVE_REGEX && !HAVE_REGCMP && !HAVE_REGEXPR
    rege_match(rege_p, p, strlen(p), &from, &to);
    if (!escs_mode) if (from != NULL) printf("%s", p);
    while (from != NULL) {
      PRINT1;
      if (p==from && p==to) if (*(to+1) == '\0') break; else to++;
      p = to;
      rege_next_match(rege_p, p, strlen(p), &from, &to);
      if (from == NULL) {
        PRINT2;
      }
    }
#endif
#if HAVE_RECOMP
    if (!regexec(recomp_p, p, 1, &recomp_m, 0)) {
      from = p + recomp_m.rm_so;
      to = p + recomp_m.rm_eo;
      if (!escs_mode) printf("%s", p);
    } else from = NULL;
    while (from != NULL) {
      PRINT1;
      if (p==from && p==to) if (*(to+1) == '\0') break; else to++;
      p = to;
      if (!regexec(recomp_p, p, 1, &recomp_m, REG_NOTBOL|REG_NOTEOL)) {
        from = p + recomp_m.rm_so;
        to = p + recomp_m.rm_eo;
      } else {
        PRINT2;
        from = NULL;
      }
    }
    /* The regular expression ends with '$' doesn't need '\n' before this. */
#endif
#if HAVE_REGEX
    re_buf.not_bol = 0;
    re_buf.not_eol = 0;
    if (re_search(&re_buf, p, strlen(p), 0, strlen(p), &re_reg)>=0) {
      from = p + re_reg.start[0];
      to = p + re_reg.end[0];
      if (!escs_mode) printf("%s", p);
    } else from = NULL;
    while (from != NULL) {
      PRINT1;
      if (p==from && p==to) if (*(to+1) == '\0') break; else to++;
      p = to;
      re_buf.not_bol = !0;
      re_buf.not_eol = !0;
      if (re_search(&re_buf, p, strlen(p), 0, strlen(p), &re_reg)>=0) {
        from = p + re_reg.start[0];
        to = p + re_reg.end[0];
      } else {
        PRINT2;
        from = NULL;
      }
    }
    /* The regular expression ends with '$' doesn't need '\n' before this. */
#endif
#if HAVE_REGCMP
    to = regex(regcmp_p, p);
    if (to != NULL) { from = __loc1; if (!escs_mode) printf("%s", p); }
    else from = NULL;
    while (from != NULL) {
      PRINT1;
      if (p==from && p==to) if (*(to+1) == '\0') break; else to++;
      p = to;
      to = regex(regcmp_p, p);
      if (to != NULL)
        from = __loc1;
      else {
        PRINT2;
        from = NULL;
      }
    }
    /* There is a problem at the regular expression starts with '^'. */
    /* There is a problem at the regular expression ends with '$'. */
#endif
#if HAVE_REGEXPR
    if (step(p, regexpr_p)) {
      from = loc1;
      to = loc2;
      if (!escs_mode) printf("%s", p);
    } else from = NULL;
    while (from != NULL) {
      PRINT1;
      if (p==from && p==to) if (*(to+1) == '\0') break; else to++;
      p = to;
      if (step(p, regexpr_p)) {
        from = loc1;
        to = loc2;
      } else {
        PRINT2;
        from = NULL;
      }
    }
    /* There is a problem at the regular expression starts with '^'. */
    /* The regular expression ends with '$' needs '\n' before this. */
#endif
  }
#if !HAVE_RECOMP && !HAVE_REGEX && !HAVE_REGCMP && !HAVE_REGEXPR
  rege_free(rege_p);
#endif
  return 0;
}
