123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994 |
- #include <stdlib.h>
- #include <unistd.h>
- #include <stdio.h>
- #include "sed.h"
- struct label *labtab = ltab;
- char CGMES[] = "sed: Command garbled: %s\n";
- char TMMES[] = "sed: Too much text: %s\n";
- char LTL[] = "sed: Label too long: %s\n";
- char AD0MES[] = "sed: No addresses allowed: %s\n";
- char AD1MES[] = "sed: Only one address allowed: %s\n";
- uchar bittab[] = {
- 1,
- 2,
- 4,
- 8,
- 16,
- 32,
- 64,
- 128
- };
- main(int argc, char **argv)
- {
- eargc = argc;
- eargv = (uchar**)argv;
- badp = &bad;
- aptr = abuf;
- hspend = holdsp;
- lab = labtab + 1; /* 0 reserved for end-pointer */
- rep = ptrspace;
- rep->r1.ad1 = respace;
- lbend = &linebuf[LBSIZE];
- hend = &holdsp[LBSIZE];
- lcomend = &genbuf[64];
- ptrend = &ptrspace[PTRSIZE];
- reend = &respace[RESIZE];
- labend = &labtab[LABSIZE];
- lnum = 0;
- pending = 0;
- depth = 0;
- spend = linebuf;
- hspend = holdsp;
- fcode[0] = stdout;
- nfiles = 1;
- lastre = NULL;
- if(eargc == 1)
- exit(0);
- while (--eargc > 0 && (++eargv)[0][0] == '-')
- switch (eargv[0][1]) {
- case 'n':
- nflag++;
- continue;
- case 'f':
- if(eargc-- <= 0) exit(2);
- if((fin = fopen((char*)(*++eargv), "r")) == NULL) {
- fprintf(stderr, "sed: Cannot open pattern-file: %s\n", *eargv);
- exit(2);
- }
- fcomp();
- fclose(fin);
- continue;
- case 'e':
- eflag++;
- fcomp();
- eflag = 0;
- continue;
- case 'g':
- gflag++;
- continue;
- default:
- fprintf(stderr, "sed: Unknown flag: %c\n", eargv[0][1]);
- continue;
- }
- if(compfl == 0) {
- eargv--;
- eargc++;
- eflag++;
- fcomp();
- eargv++;
- eargc--;
- eflag = 0;
- }
- if(depth) {
- fprintf(stderr, "sed: Too many {'s\n");
- exit(2);
- }
- labtab->address = rep;
- dechain();
- /* abort(); /*DEBUG*/
- if(eargc <= 0)
- execute((uchar *)NULL);
- else while(--eargc >= 0) {
- execute(*eargv++);
- }
- fclose(stdout);
- exit(0);
- }
- void
- fcomp(void)
- {
- uchar *p, *op, *tp;
- uchar *address(uchar*);
- union reptr *pt, *pt1;
- int i;
- struct label *lpt;
- compfl = 1;
- op = lastre;
- if(rline(linebuf) < 0) {
- lastre = op;
- return;
- }
- if(*linebuf == '#') {
- if(linebuf[1] == 'n')
- nflag = 1;
- }
- else {
- cp = linebuf;
- goto comploop;
- }
- for(;;) {
- if(rline(linebuf) < 0) break;
- cp = linebuf;
- comploop:
- /* fprintf(stdout, "cp: %s\n", cp); /*DEBUG*/
- while(*cp == ' ' || *cp == '\t') cp++;
- if(*cp == '\0' || *cp == '#') continue;
- if(*cp == ';') {
- cp++;
- goto comploop;
- }
- p = address(rep->r1.ad1);
- if(p == badp) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(p == 0) {
- p = rep->r1.ad1;
- rep->r1.ad1 = 0;
- } else {
- if(p == rep->r1.ad1) {
- if(op)
- rep->r1.ad1 = op;
- else {
- fprintf(stderr, "sed: First RE may not be null\n");
- exit(2);
- }
- }
- if(*rep->r1.ad1 != CLNUM && *rep->r1.ad1 != CEND)
- op = rep->r1.ad1;
- if(*cp == ',' || *cp == ';') {
- cp++;
- if((rep->r1.ad2 = p) > reend) {
- fprintf(stderr, TMMES, linebuf);
- exit(2);
- }
- p = address(rep->r1.ad2);
- if(p == badp || p == 0) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(p == rep->r1.ad2)
- rep->r1.ad2 = op;
- else{
- if(*rep->r1.ad2 != CLNUM && *rep->r1.ad2 != CEND)
- op = rep->r1.ad2;
- }
- } else
- rep->r1.ad2 = 0;
- }
- if(p > reend) {
- fprintf(stderr, "sed: Too much text: %s\n", linebuf);
- exit(2);
- }
- while(*cp == ' ' || *cp == '\t') cp++;
- swit:
- switch(*cp++) {
- default:
- /*fprintf(stderr, "cp = %d; *cp = %o\n", cp - linebuf, *cp);*/
- fprintf(stderr, "sed: Unrecognized command: %s\n", linebuf);
- exit(2);
- case '!':
- rep->r1.negfl = 1;
- goto swit;
- case '{':
- rep->r1.command = BCOM;
- rep->r1.negfl = !(rep->r1.negfl);
- cmpend[depth++] = &rep->r2.lb1;
- if(++rep >= ptrend) {
- fprintf(stderr, "sed: Too many commands: %s\n", linebuf);
- exit(2);
- }
- rep->r1.ad1 = p;
- if(*cp == '\0') continue;
- goto comploop;
- case '}':
- if(rep->r1.ad1) {
- fprintf(stderr, AD0MES, linebuf);
- exit(2);
- }
- if(--depth < 0) {
- fprintf(stderr, "sed: Too many }'s\n");
- exit(2);
- }
- *cmpend[depth] = rep;
- rep->r1.ad1 = p;
- if(*cp == 0) continue;
- goto comploop;
- case '=':
- rep->r1.command = EQCOM;
- if(rep->r1.ad2) {
- fprintf(stderr, AD1MES, linebuf);
- exit(2);
- }
- break;
- case ':':
- if(rep->r1.ad1) {
- fprintf(stderr, AD0MES, linebuf);
- exit(2);
- }
- while(*cp++ == ' ');
- cp--;
- tp = lab->asc;
- while((*tp = *cp++) && *tp != ';')
- if(++tp >= &(lab->asc[8])) {
- fprintf(stderr, LTL, linebuf);
- exit(2);
- }
- *tp = '\0';
- if(*lab->asc == 0) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(lpt = search(lab)) {
- if(lpt->address) {
- fprintf(stderr, "sed: Duplicate labels: %s\n", linebuf);
- exit(2);
- }
- } else {
- lab->chain = 0;
- lpt = lab;
- if(++lab >= labend) {
- fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
- exit(2);
- }
- }
- lpt->address = rep;
- rep->r1.ad1 = p;
- continue;
- case 'a':
- rep->r1.command = ACOM;
- if(rep->r1.ad2) {
- fprintf(stderr, AD1MES, linebuf);
- exit(2);
- }
- if(*cp == '\\') cp++;
- if(*cp++ != '\n') {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- rep->r1.re1 = p;
- p = text(rep->r1.re1);
- break;
- case 'c':
- rep->r1.command = CCOM;
- if(*cp == '\\') cp++;
- if(*cp++ != ('\n')) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- rep->r1.re1 = p;
- p = text(rep->r1.re1);
- break;
- case 'i':
- rep->r1.command = ICOM;
- if(rep->r1.ad2) {
- fprintf(stderr, AD1MES, linebuf);
- exit(2);
- }
- if(*cp == '\\') cp++;
- if(*cp++ != ('\n')) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- rep->r1.re1 = p;
- p = text(rep->r1.re1);
- break;
- case 'g':
- rep->r1.command = GCOM;
- break;
- case 'G':
- rep->r1.command = CGCOM;
- break;
- case 'h':
- rep->r1.command = HCOM;
- break;
- case 'H':
- rep->r1.command = CHCOM;
- break;
- case 't':
- rep->r1.command = TCOM;
- goto jtcommon;
- case 'b':
- rep->r1.command = BCOM;
- jtcommon:
- while(*cp++ == ' ');
- cp--;
- if(*cp == '\0') {
- if(pt = labtab->chain) {
- while(pt1 = pt->r2.lb1)
- pt = pt1;
- pt->r2.lb1 = rep;
- } else
- labtab->chain = rep;
- break;
- }
- tp = lab->asc;
- while((*tp = *cp++) && *tp != ';')
- if(++tp >= &(lab->asc[8])) {
- fprintf(stderr, LTL, linebuf);
- exit(2);
- }
- cp--;
- *tp = '\0';
- if(*lab->asc == 0) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(lpt = search(lab)) {
- if(lpt->address) {
- rep->r2.lb1 = lpt->address;
- } else {
- pt = lpt->chain;
- while(pt1 = pt->r2.lb1)
- pt = pt1;
- pt->r2.lb1 = rep;
- }
- } else {
- lab->chain = rep;
- lab->address = 0;
- if(++lab >= labend) {
- fprintf(stderr, "sed: Too many labels: %s\n", linebuf);
- exit(2);
- }
- }
- break;
- case 'n':
- rep->r1.command = NCOM;
- break;
- case 'N':
- rep->r1.command = CNCOM;
- break;
- case 'p':
- rep->r1.command = PCOM;
- break;
- case 'P':
- rep->r1.command = CPCOM;
- break;
- case 'r':
- rep->r1.command = RCOM;
- if(rep->r1.ad2) {
- fprintf(stderr, AD1MES, linebuf);
- exit(2);
- }
- if(*cp++ != ' ') {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- rep->r1.re1 = p;
- p = text(rep->r1.re1);
- break;
- case 'd':
- rep->r1.command = DCOM;
- break;
- case 'D':
- rep->r1.command = CDCOM;
- rep->r2.lb1 = ptrspace;
- break;
- case 'q':
- rep->r1.command = QCOM;
- if(rep->r1.ad2) {
- fprintf(stderr, AD1MES, linebuf);
- exit(2);
- }
- break;
- case 'l':
- rep->r1.command = LCOM;
- break;
- case 's':
- rep->r1.command = SCOM;
- seof = *cp++;
- rep->r1.re1 = p;
- p = compile(rep->r1.re1);
- if(p == badp) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(p == rep->r1.re1) {
- if(op == NULL) {
- fprintf(stderr, "sed: First RE may not be null.\n");
- exit(2);
- }
- rep->r1.re1 = op;
- } else {
- op = rep->r1.re1;
- }
- if((rep->r1.rhs = p) > reend) {
- fprintf(stderr, TMMES, linebuf);
- exit(2);
- }
- if((p = compsub(rep->r1.rhs)) == badp) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(*cp == 'g') {
- cp++;
- rep->r1.gfl++;
- } else if(gflag)
- rep->r1.gfl++;
- if(*cp == 'p') {
- cp++;
- rep->r1.pfl = 1;
- }
- if(*cp == 'P') {
- cp++;
- rep->r1.pfl = 2;
- }
- if(*cp == 'w') {
- cp++;
- if(*cp++ != ' ') {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(nfiles >= MAXFILES) {
- fprintf(stderr, "sed: Too many files in w commands 1 \n");
- exit(2);
- }
- text((uchar*)fname[nfiles]);
- for(i = nfiles - 1; i >= 0; i--)
- if(cmp((uchar*)fname[nfiles],(uchar*)fname[i]) == 0) {
- rep->r1.fcode = fcode[i];
- goto done;
- }
- if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
- fprintf(stderr, "sed: Cannot open %s\n", fname[nfiles]);
- exit(2);
- }
- fcode[nfiles++] = rep->r1.fcode;
- }
- break;
- case 'w':
- rep->r1.command = WCOM;
- if(*cp++ != ' ') {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(nfiles >= MAXFILES){
- fprintf(stderr, "sed: Too many files in w commands 2 \n");
- fprintf(stderr, "nfiles = %d; MAXF = %d\n", nfiles, MAXFILES);
- exit(2);
- }
- text((uchar*)fname[nfiles]);
- for(i = nfiles - 1; i >= 0; i--)
- if(cmp((uchar*)fname[nfiles], (uchar*)fname[i]) == 0) {
- rep->r1.fcode = fcode[i];
- goto done;
- }
- if((rep->r1.fcode = fopen(fname[nfiles], "w")) == NULL) {
- fprintf(stderr, "sed: Cannot create %s\n", fname[nfiles]);
- exit(2);
- }
- fcode[nfiles++] = rep->r1.fcode;
- break;
- case 'x':
- rep->r1.command = XCOM;
- break;
- case 'y':
- rep->r1.command = YCOM;
- seof = *cp++;
- rep->r1.re1 = p;
- p = ycomp(rep->r1.re1);
- if(p == badp) {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if(p > reend) {
- fprintf(stderr, TMMES, linebuf);
- exit(2);
- }
- break;
- }
- done:
- if(++rep >= ptrend) {
- fprintf(stderr, "sed: Too many commands, last: %s\n", linebuf);
- exit(2);
- }
- rep->r1.ad1 = p;
- if(*cp++ != '\0') {
- if(cp[-1] == ';')
- goto comploop;
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- }
- }
- uchar *
- compsub(uchar *rhsbuf)
- {
- uchar *p, *q, *r;
- p = rhsbuf;
- q = cp;
- for(;;) {
- if((*p = *q++) == '\\') {
- *++p = *q++;
- if(*p >= '1' && *p <= '9' && *p > numbra + '0')
- return(badp);
- if(*p == 'n')
- *--p = '\n';
- } else if(*p == seof) {
- *p++ = '\0';
- cp = q;
- return(p);
- }
- if(*p++ == '\0') {
- return(badp);
- }
- }
- }
- uchar *
- compile(uchar *expbuf)
- {
- int c;
- uchar *ep, *sp;
- uchar neg;
- uchar *lastep, *cstart;
- int cclcnt;
- int closed;
- uchar bracket[NBRA], *bracketp;
- if(*cp == seof) {
- cp++;
- return(expbuf);
- }
- ep = expbuf;
- lastep = 0;
- bracketp = bracket;
- closed = numbra = 0;
- sp = cp;
- if (*sp == '^') {
- *ep++ = 1;
- sp++;
- } else {
- *ep++ = 0;
- }
- for (;;) {
- if (ep >= reend) {
- cp = sp;
- return(badp);
- }
- if((c = *sp++) == seof) {
- if(bracketp != bracket) {
- cp = sp;
- return(badp);
- }
- cp = sp;
- *ep++ = CEOF;
- return(ep);
- }
- if(c != '*')
- lastep = ep;
- switch (c) {
- case '\\':
- if((c = *sp++) == '(') {
- if(numbra >= NBRA) {
- cp = sp;
- return(badp);
- }
- *bracketp++ = numbra;
- *ep++ = CBRA;
- *ep++ = numbra++;
- continue;
- }
- if(c == ')') {
- if(bracketp <= bracket) {
- cp = sp;
- return(badp);
- }
- *ep++ = CKET;
- *ep++ = *--bracketp;
- closed++;
- continue;
- }
- if(c >= '1' && c <= '9') {
- if((c -= '1') >= closed)
- return(badp);
-
- *ep++ = CBACK;
- *ep++ = c;
- continue;
- }
- if(c == '\n') {
- cp = sp;
- return(badp);
- }
- if(c == 'n') {
- c = '\n';
- }
- goto defchar;
- case '\0':
- case '\n':
- cp = sp;
- return(badp);
- case '.':
- *ep++ = CDOT;
- continue;
- case '*':
- if (lastep == 0)
- goto defchar;
- if(*lastep == CKET) {
- cp = sp;
- return(badp);
- }
- *lastep |= STAR;
- continue;
- case '$':
- if (*sp != seof)
- goto defchar;
- *ep++ = CDOL;
- continue;
- case '[':
- if(&ep[33] >= reend) {
- fprintf(stderr, "sed: RE too long: %s\n", linebuf);
- exit(2);
- }
- *ep++ = CCL;
- neg = 0;
- if((c = *sp++) == '^') {
- neg = 1;
- c = *sp++;
- }
- cstart = sp;
- do {
- if(c == '\0') {
- fprintf(stderr, CGMES, linebuf);
- exit(2);
- }
- if (c=='-' && sp>cstart && *sp!=']') {
- for (c = sp[-2]; c<*sp; c++)
- ep[c>>3] |= bittab[c&07];
- }
- if(c == '\\') {
- switch(c = *sp++) {
- case 'n':
- c = '\n';
- break;
- }
- }
- ep[c >> 3] |= bittab[c & 07];
- } while((c = *sp++) != ']');
- if(neg)
- for(cclcnt = 0; cclcnt < 32; cclcnt++)
- ep[cclcnt] ^= -1;
- ep[0] &= 0376;
- ep += 32;
- continue;
- defchar:
- default:
- *ep++ = CCHR;
- *ep++ = c;
- }
- }
- }
- int
- rline(uchar *lbuf)
- {
- uchar *p, *q;
- int t;
- static uchar *saveq;
- p = lbuf - 1;
- if(eflag) {
- if(eflag > 0) {
- eflag = -1;
- if(eargc-- <= 0)
- exit(2);
- q = *++eargv;
- while(*++p = *q++) {
- if(*p == '\\') {
- if((*++p = *q++) == '\0') {
- saveq = 0;
- return(-1);
- } else
- continue;
- }
- if(*p == '\n') {
- *p = '\0';
- saveq = q;
- return(1);
- }
- }
- saveq = 0;
- return(1);
- }
- if((q = saveq) == 0) return(-1);
- while(*++p = *q++) {
- if(*p == '\\') {
- if((*++p = *q++) == '0') {
- saveq = 0;
- return(-1);
- } else
- continue;
- }
- if(*p == '\n') {
- *p = '\0';
- saveq = q;
- return(1);
- }
- }
- saveq = 0;
- return(1);
- }
- while((t = getc(fin)) != EOF) {
- *++p = t;
- if(*p == '\\') {
- t = getc(fin);
- *++p = t;
- }
- else if(*p == '\n') {
- *p = '\0';
- return(1);
- }
- }
- *++p = '\0';
- return(-1);
- }
- uchar *
- address(uchar *expbuf)
- {
- uchar *rcp;
- long lno;
- if(*cp == '$') {
- cp++;
- *expbuf++ = CEND;
- *expbuf++ = CEOF;
- return(expbuf);
- }
- if(*cp == '/') {
- seof = '/';
- cp++;
- return(compile(expbuf));
- }
- rcp = cp;
- lno = 0;
- while(*rcp >= '0' && *rcp <= '9')
- lno = lno*10 + *rcp++ - '0';
- if(rcp > cp) {
- if(!lno){
- fprintf(stderr, "sed: line number 0 is illegal\n");
- exit(2);
- }
- *expbuf++ = CLNUM;
- *expbuf++ = lno;
- *expbuf++ = lno >> 8;
- *expbuf++ = lno >> 16;
- *expbuf++ = lno >> 24;
- *expbuf++ = CEOF;
- cp = rcp;
- return(expbuf);
- }
- return(0);
- }
- int
- cmp(uchar *a, uchar *b)
- {
- uchar *ra, *rb;
- ra = a - 1;
- rb = b - 1;
- while(*++ra == *++rb)
- if(*ra == '\0') return(0);
- return(1);
- }
- uchar *
- text(uchar *textbuf)
- {
- uchar *p, *q;
- p = textbuf;
- q = cp;
- while(*q == '\t' || *q == ' ') q++;
- for(;;) {
- if((*p = *q++) == '\\')
- *p = *q++;
- if(*p == '\0') {
- cp = --q;
- return(++p);
- }
- if(*p == '\n') {
- while(*q == '\t' || *q == ' ') q++;
- }
- p++;
- }
- }
- struct label *
- search(struct label *ptr)
- {
- struct label *rp;
- rp = labtab;
- while(rp < ptr) {
- if(cmp(rp->asc, ptr->asc) == 0)
- return(rp);
- rp++;
- }
- return(0);
- }
- void
- dechain(void)
- {
- struct label *lptr;
- union reptr *rptr, *trptr;
- for(lptr = labtab; lptr < lab; lptr++) {
- if(lptr->address == 0) {
- fprintf(stderr, "sed: Undefined label: %s\n", lptr->asc);
- exit(2);
- }
- if(lptr->chain) {
- rptr = lptr->chain;
- while(trptr = rptr->r2.lb1) {
- rptr->r2.lb1 = lptr->address;
- rptr = trptr;
- }
- rptr->r2.lb1 = lptr->address;
- }
- }
- }
- uchar *
- ycomp(uchar *expbuf)
- {
- uchar *ep, *tsp;
- int c;
- uchar *sp;
- ep = expbuf;
- sp = cp;
- for(tsp = cp; *tsp != seof; tsp++) {
- if(*tsp == '\\')
- tsp++;
- if(*tsp == '\n' || *tsp == '\0')
- return(badp);
- }
- tsp++;
- while((c = *sp++) != seof) {
- if(c == '\\' && *sp == 'n') {
- sp++;
- c = '\n';
- }
- if((ep[c] = *tsp++) == '\\' && *tsp == 'n') {
- ep[c] = '\n';
- tsp++;
- }
- if(ep[c] == seof || ep[c] == '\0')
- return(badp);
- }
- if(*tsp != seof)
- return(badp);
- cp = ++tsp;
- for(c = 0; c<0400; c++)
- if(ep[c] == 0)
- ep[c] = c;
- return(ep + 0400);
- }
|