#include <u.h>
#include <libc.h>
#include <bio.h>
#include <regexp.h>

char    digit[] = "0123456789";
char    *suffix = "";
char    *stem = "x";
char    suff[] = "aa";
char    name[200];
Biobuf  bout;
Biobuf  *output = &bout;

extern int nextfile(void);
extern int matchfile(Resub*);
extern void openf(void);
extern char *fold(char*,int);
extern void usage(void);
extern void badexp(void);

void
main(int argc, char *argv[])
{
       Reprog *exp;
       char *pattern = 0;
       int n = 1000;
       char *line;
       int xflag = 0;
       int iflag = 0;
       Biobuf bin;
       Biobuf *b = &bin;
       char buf[256];

       ARGBEGIN {
       case 'l':
       case 'n':
               n=atoi(EARGF(usage()));
               break;
       case 'e':
               pattern = strdup(EARGF(usage()));
               break;
       case 'f':
               stem = strdup(EARGF(usage()));
               break;
       case 's':
               suffix = strdup(EARGF(usage()));
               break;
       case 'x':
               xflag++;
               break;
       case 'i':
               iflag++;
               break;
       default:
               usage();
               break;

       } ARGEND;

       if(argc < 0 || argc > 1)
               usage();

       if(argc != 0) {
               b = Bopen(argv[0], OREAD);
               if(b == nil) {
                       fprint(2, "split: can't open %s: %r\n", argv[0]);
                       exits("open");
               }
       } else
               Binit(b, 0, OREAD);

       if(pattern) {
               Resub match[2];

               if(!(exp = regcomp(iflag? fold(pattern, strlen(pattern)):
                   pattern)))
                       badexp();
               memset(match, 0, sizeof match);
               matchfile(match);
               while((line=Brdline(b,'\n')) != 0) {
                       memset(match, 0, sizeof match);
                       line[Blinelen(b)-1] = 0;
                       if(regexec(exp, iflag? fold(line, Blinelen(b)-1): line,
                           match, 2)) {
                               if(matchfile(match) && xflag)
                                       continue;
                       } else if(output == 0)
                               nextfile();     /* at most once */
                       Bwrite(output, line, Blinelen(b)-1);
                       Bputc(output, '\n');
               }
       } else {
               int linecnt = n;

               while((line=Brdline(b,'\n')) != 0) {
                       if(++linecnt > n) {
                               nextfile();
                               linecnt = 1;
                       }
                       Bwrite(output, line, Blinelen(b));
               }

               /*
                * in case we didn't end with a newline, tack whatever's
                * left onto the last file
                */
               while((n = Bread(b, buf, sizeof(buf))) > 0)
                       Bwrite(output, buf, n);
       }
       if(b != nil)
               Bterm(b);
       exits(0);
}

int
nextfile(void)
{
       static int canopen = 1;

       if(suff[0] > 'z') {
               if(canopen)
                       fprint(2, "split: file %szz not split\n",stem);
               canopen = 0;
       } else {
               snprint(name, sizeof name, "%s%s", stem, suff);
               if(++suff[1] > 'z')
                       suff[1] = 'a', ++suff[0];
               openf();
       }
       return canopen;
}

int
matchfile(Resub *match)
{
       if(match[1].sp) {
               int len = match[1].ep - match[1].sp;

               strncpy(name, match[1].sp, len);
               strcpy(name+len, suffix);
               openf();
               return 1;
       }
       return nextfile();
}

void
openf(void)
{
       static int fd = 0;

       Bflush(output);
       Bterm(output);
       if(fd >= 0)
               close(fd);
       fd = create(name,OWRITE,0666);
       if(fd < 0) {
               fprint(2, "grep: can't create %s: %r\n", name);
               exits("create");
       }
       Binit(output, fd, OWRITE);
}

char *
fold(char *s, int n)
{
       static char *fline;
       static int linesize = 0;
       char *t;

       if(linesize < n+1){
               fline = realloc(fline,n+1);
               linesize = n+1;
       }
       for(t=fline; *t++ = tolower(*s++); )
               continue;
               /* we assume the 'A'-'Z' only appear as themselves
                * in a utf encoding.
                */
       return fline;
}

void
usage(void)
{
       fprint(2, "usage: split [-n num] [-e exp] [-f stem] [-s suff] [-x] [-i] [file]\n");
       exits("usage");
}

void
badexp(void)
{
       fprint(2, "split: bad regular expression\n");
       exits("bad regular expression");
}