Logo Search packages:      
Sourcecode: 9base version File versions  Download package

tr.c

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

typedef struct PCB      /* Control block controlling specification parse */
{
      char  *base;            /* start of specification */
      char  *current;   /* current parse point */
      long  last;       /* last Rune returned */
      long  final;            /* final Rune in a span */
} Pcb;

uchar bits[] = { 1, 2, 4, 8, 16, 32, 64, 128 };

#define     SETBIT(a, c)            ((a)[(c)/8] |= bits[(c)&07])
#define     CLEARBIT(a,c)           ((a)[(c)/8] &= ~bits[(c)&07])
#define     BITSET(a,c)       ((a)[(c)/8] & bits[(c)&07])

#define     MAXRUNE     0xFFFF

uchar f[(MAXRUNE+1)/8];
uchar t[(MAXRUNE+1)/8];
char  wbuf[4096];
char  *wptr;

Pcb pfrom, pto;

int cflag;
int dflag;
int sflag;

void  complement(void);
void  delete(void);
void  squeeze(void);
void  translit(void);
void  error(char*);
long  canon(Pcb*);
char  *getrune(char*, Rune*);
void  Pinit(Pcb*, char*);
void  Prewind(Pcb *p);
int   readrune(int, long*);
void  wflush(int);
void  writerune(int, Rune);

void
main(int argc, char **argv)
{
      ARGBEGIN{
      case 's':   sflag++; break;
      case 'd':   dflag++; break;
      case 'c':   cflag++; break;
      default:    error("bad option");
      }ARGEND
      if(argc>0)
            Pinit(&pfrom, argv[0]);
      if(argc>1)
            Pinit(&pto, argv[1]);
      if(argc>2)
            error("arg count");
      if(dflag) {
            if ((sflag && argc != 2) || (!sflag && argc != 1))
                  error("arg count");
            delete();
      } else {
            if (argc != 2)
                  error("arg count");
            if (cflag)
                  complement();
            else translit();
      }
      exits(0);
}

void
delete(void)
{
      long c, last;

      if (cflag) {
            memset((char *) f, 0xff, sizeof f);
            while ((c = canon(&pfrom)) >= 0)
                  CLEARBIT(f, c);
      } else {
            while ((c = canon(&pfrom)) >= 0)
                  SETBIT(f, c);
      }
      if (sflag) {
            while ((c = canon(&pto)) >= 0)
                  SETBIT(t, c);
      }

      last = 0x10000;
      while (readrune(0, &c) > 0) {
            if(!BITSET(f, c) && (c != last || !BITSET(t,c))) {
                  last = c;
                  writerune(1, (Rune) c);
            }
      }
      wflush(1);
}

void
complement(void)
{
      Rune *p;
      int i;
      long from, to, lastc, high;

      lastc = 0;
      high = 0;
      while ((from = canon(&pfrom)) >= 0) {
            if (from > high) high = from;
            SETBIT(f, from);
      }
      while ((to = canon(&pto)) > 0) {
            if (to > high) high = to;
            SETBIT(t,to);
      }
      Prewind(&pto);
      if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
            error("can't allocate memory");
      for (i = 0; i <= high; i++){
            if (!BITSET(f,i)) {
                  if ((to = canon(&pto)) < 0)
                        to = lastc;
                  else lastc = to;
                  p[i] = to;
            }
            else p[i] = i;
      }
      if (sflag){
            lastc = 0x10000;
            while (readrune(0, &from) > 0) {
                  if (from > high)
                        from = to;
                  else
                        from = p[from];
                  if (from != lastc || !BITSET(t,from)) {
                        lastc = from;
                        writerune(1, (Rune) from);
                  }
            }
                        
      } else {
            while (readrune(0, &from) > 0){
                  if (from > high)
                        from = to;
                  else
                        from = p[from];
                  writerune(1, (Rune) from);
            }
      }
      wflush(1);
}

void
translit(void)
{
      Rune *p;
      int i;
      long from, to, lastc, high;

      lastc = 0;
      high = 0;
      while ((from = canon(&pfrom)) >= 0)
            if (from > high) high = from;
      Prewind(&pfrom);
      if ((p = (Rune *) malloc((high+1)*sizeof(Rune))) == 0)
            error("can't allocate memory");
      for (i = 0; i <= high; i++)
            p[i] = i;
      while ((from = canon(&pfrom)) >= 0) {
            if ((to = canon(&pto)) < 0)
                  to = lastc;
            else lastc = to;
            if (BITSET(f,from) && p[from] != to)
                  error("ambiguous translation");
            SETBIT(f,from);
            p[from] = to;
            SETBIT(t,to);
      }
      while ((to = canon(&pto)) >= 0) {
            SETBIT(t,to);
      }
      if (sflag){
            lastc = 0x10000;
            while (readrune(0, &from) > 0) {
                  if (from <= high)
                        from = p[from];
                  if (from != lastc || !BITSET(t,from)) {
                        lastc = from;
                        writerune(1, (Rune) from);
                  }
            }
                        
      } else {
            while (readrune(0, &from) > 0) {
                  if (from <= high)
                        from = p[from];
                  writerune(1, (Rune) from);
            }
      }
      wflush(1);
}

int
readrune(int fd, long *rp)
{
      Rune r;
      int j;
      static int i, n;
      static char buf[4096];

      j = i;
      for (;;) {
            if (i >= n) {
                  wflush(1);
                  if (j != i)
                        memcpy(buf, buf+j, n-j);
                  i = n-j;
                  n = read(fd, &buf[i], sizeof(buf)-i);
                  if (n < 0)
                        error("read error");
                  if (n == 0)
                        return 0;
                  j = 0;
                  n += i;
            }
            i++;
            if (fullrune(&buf[j], i-j))
                  break;
      }
      chartorune(&r, &buf[j]);
      *rp = r;
      return 1;
}

void
writerune(int fd, Rune r)
{
      char buf[UTFmax];
      int n;

      if (!wptr)
            wptr = wbuf;
      n = runetochar(buf, (Rune*)&r);
      if (wptr+n >= wbuf+sizeof(wbuf))
            wflush(fd);
      memcpy(wptr, buf, n);
      wptr += n;
}

void
wflush(int fd)
{
      if (wptr && wptr > wbuf)
            if (write(fd, wbuf, wptr-wbuf) != wptr-wbuf)
                  error("write error");
      wptr = wbuf;
}

char *
getrune(char *s, Rune *rp)
{
      Rune r;
      char *save;
      int i, n;

      s += chartorune(rp, s);
      if((r = *rp) == '\\' && *s){
            n = 0;
            if (*s == 'x') {
                  s++;
                  for (i = 0; i < 4; i++) {
                        save = s;
                        s += chartorune(&r, s);
                        if ('0' <= r && r <= '9')
                              n = 16*n + r - '0';
                        else if ('a' <= r && r <= 'f')
                              n = 16*n + r - 'a' + 10;
                        else if ('A' <= r && r <= 'F')
                              n = 16*n + r - 'A' + 10;
                        else {
                              if (i == 0)
                                    *rp = 'x';
                              else *rp = n;
                              return save;
                        }
                  }
            } else {
                  for(i = 0; i < 3; i++) {
                        save = s;
                        s += chartorune(&r, s);
                        if('0' <= r && r <= '7')
                              n = 8*n + r - '0';
                        else {
                              if (i == 0)
                              {
                                    *rp = r;
                                    return s;
                              }
                              *rp = n;
                              return save;
                        }
                  }
                  if(n > 0377)
                        error("char>0377");
            }
            *rp = n;
      }
      return s;
}

long
canon(Pcb *p)
{
      Rune r;

      if (p->final >= 0) {
            if (p->last < p->final)
                  return ++p->last;
            p->final = -1;
      }
      if (*p->current == '\0')
            return -1;
      if(*p->current == '-' && p->last >= 0 && p->current[1]){
            p->current = getrune(p->current+1, &r);
            if (r < p->last)
                  error ("Invalid range specification");
            if (r > p->last) {
                  p->final = r;
                  return ++p->last;
            }
      }
      p->current = getrune(p->current, &r);
      p->last = r;
      return p->last;
}

void
Pinit(Pcb *p, char *cp)
{
      p->current = p->base = cp;
      p->last = p->final = -1;
}
void
Prewind(Pcb *p)
{
      p->current = p->base;
      p->last = p->final = -1;
}
void
error(char *s)
{
      fprint(2, "%s: %s\n", argv0, s);
      exits(s);
}

Generated by  Doxygen 1.6.0   Back to index