URI:
       tCcons.c - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
       tCcons.c (6722B)
       ---
            1 #include "stdinc.h"
            2 
            3 #include "9.h"
            4 
            5 enum {
            6         Nl        = 256,                        /* max. command line length */
            7         Nq        = 8*1024,                /* amount of I/O buffered */
            8 };
            9 
           10 typedef struct Q {
           11         QLock        lock;
           12         Rendez        full;
           13         Rendez        empty;
           14 
           15         char        q[Nq];
           16         int        n;
           17         int        r;
           18         int        w;
           19 } Q;
           20 
           21 typedef struct Cons {
           22         QLock        lock;
           23         int        ref;
           24         int        closed;
           25         int        fd;
           26         int        srvfd;
           27         int        ctlfd;
           28         Q*        iq;                /* points to console.iq */
           29         Q*        oq;                /* points to console.oq */
           30 } Cons;
           31 
           32 char *currfsysname;
           33 
           34 static struct {
           35         Q*        iq;                /* input */
           36         Q*        oq;                /* output */
           37         char        l[Nl];                /* command line assembly */
           38         int        nl;                /* current line length */
           39         int        nopens;
           40 
           41         char*        prompt;
           42         int        np;
           43 } console;
           44 
           45 static void
           46 consClose(Cons* cons)
           47 {
           48         qlock(&cons->lock);
           49         cons->closed = 1;
           50 
           51         cons->ref--;
           52         if(cons->ref > 0){
           53                 qlock(&cons->iq->lock);
           54                 rwakeup(&cons->iq->full);
           55                 qunlock(&cons->iq->lock);
           56                 qlock(&cons->oq->lock);
           57                 rwakeup(&cons->oq->empty);
           58                 qunlock(&cons->oq->lock);
           59                 qunlock(&cons->lock);
           60                 return;
           61         }
           62 
           63         if(cons->ctlfd != -1){
           64                 close(cons->ctlfd);
           65                 cons->srvfd = -1;
           66         }
           67         if(cons->srvfd != -1){
           68                 close(cons->srvfd);
           69                 cons->srvfd = -1;
           70         }
           71         if(cons->fd != -1){
           72                 close(cons->fd);
           73                 cons->fd = -1;
           74         }
           75         qunlock(&cons->lock);
           76         vtfree(cons);
           77         console.nopens--;
           78 }
           79 
           80 static void
           81 consIProc(void* v)
           82 {
           83         Q *q;
           84         Cons *cons;
           85         int n, w;
           86         char buf[Nq/4];
           87 
           88         threadsetname("consI");
           89 
           90         cons = v;
           91         q = cons->iq;
           92         for(;;){
           93                 /*
           94                  * Can't tell the difference between zero-length read
           95                  * and eof, so keep calling read until we get an error.
           96                  */
           97                 if(cons->closed || (n = read(cons->fd, buf, Nq/4)) < 0)
           98                         break;
           99                 qlock(&q->lock);
          100                 while(Nq - q->n < n && !cons->closed)
          101                         rsleep(&q->full);
          102                 w = Nq - q->w;
          103                 if(w < n){
          104                         memmove(&q->q[q->w], buf, w);
          105                         memmove(&q->q[0], buf + w, n - w);
          106                 }
          107                 else
          108                         memmove(&q->q[q->w], buf, n);
          109                 q->w = (q->w + n) % Nq;
          110                 q->n += n;
          111                 rwakeup(&q->empty);
          112                 qunlock(&q->lock);
          113         }
          114         consClose(cons);
          115 }
          116 
          117 static void
          118 consOProc(void* v)
          119 {
          120         Q *q;
          121         Cons *cons;
          122         char buf[Nq];
          123         int lastn, n, r;
          124 
          125         threadsetname("consO");
          126 
          127         cons = v;
          128         q = cons->oq;
          129         qlock(&q->lock);
          130         lastn = 0;
          131         for(;;){
          132                 while(lastn == q->n && !cons->closed)
          133                         rsleep(&q->empty);
          134                 if((n = q->n - lastn) > Nq)
          135                         n = Nq;
          136                 if(n > q->w){
          137                         r = n - q->w;
          138                         memmove(buf, &q->q[Nq - r], r);
          139                         memmove(buf+r, &q->q[0], n - r);
          140                 }
          141                 else
          142                         memmove(buf, &q->q[q->w - n], n);
          143                 lastn = q->n;
          144                 qunlock(&q->lock);
          145                 if(cons->closed || write(cons->fd, buf, n) < 0)
          146                         break;
          147                 qlock(&q->lock);
          148                 rwakeup(&q->empty);
          149         }
          150         consClose(cons);
          151 }
          152 
          153 int
          154 consOpen(int fd, int srvfd, int ctlfd)
          155 {
          156         Cons *cons;
          157 
          158         cons = vtmallocz(sizeof(Cons));
          159         cons->fd = fd;
          160         cons->srvfd = srvfd;
          161         cons->ctlfd = ctlfd;
          162         cons->iq = console.iq;
          163         cons->oq = console.oq;
          164         console.nopens++;
          165 
          166         qlock(&cons->lock);
          167         cons->ref = 2;
          168         cons->closed = 0;
          169         if(proccreate(consOProc, cons, STACK) < 0){
          170                 cons->ref--;
          171                 qunlock(&cons->lock);
          172                 consClose(cons);
          173                 return 0;
          174         }
          175         qunlock(&cons->lock);
          176 
          177         if(ctlfd >= 0)
          178                 consIProc(cons);
          179         else if(proccreate(consIProc, cons, STACK) < 0){
          180                 consClose(cons);
          181                 return 0;
          182         }
          183 
          184         return 1;
          185 }
          186 
          187 static int
          188 qWrite(Q* q, char* p, int n)
          189 {
          190         int w;
          191 
          192         qlock(&q->lock);
          193         if(n > Nq - q->w){
          194                 w = Nq - q->w;
          195                 memmove(&q->q[q->w], p, w);
          196                 memmove(&q->q[0], p + w, n - w);
          197                 q->w = n - w;
          198         }
          199         else{
          200                 memmove(&q->q[q->w], p, n);
          201                 q->w += n;
          202         }
          203         q->n += n;
          204         rwakeup(&q->empty);
          205         qunlock(&q->lock);
          206 
          207         return n;
          208 }
          209 
          210 static Q*
          211 qAlloc(void)
          212 {
          213         Q *q;
          214 
          215         q = vtmallocz(sizeof(Q));
          216         q->full.l = &q->lock;
          217         q->empty.l = &q->lock;
          218         q->n = q->r = q->w = 0;
          219 
          220         return q;
          221 }
          222 
          223 static void
          224 consProc(void* v)
          225 {
          226         USED(v);
          227         Q *q;
          228         int argc, i, n, r;
          229         char *argv[20], buf[Nq], *lp, *wbuf;
          230         char procname[64];
          231 
          232         snprint(procname, sizeof procname, "cons %s", currfsysname);
          233         threadsetname(procname);
          234 
          235         q = console.iq;
          236         qWrite(console.oq, console.prompt, console.np);
          237         qlock(&q->lock);
          238         for(;;){
          239                 while((n = q->n) == 0)
          240                         rsleep(&q->empty);
          241                 r = Nq - q->r;
          242                 if(r < n){
          243                         memmove(buf, &q->q[q->r], r);
          244                         memmove(buf + r, &q->q[0], n - r);
          245                 }
          246                 else
          247                         memmove(buf, &q->q[q->r], n);
          248                 q->r = (q->r + n) % Nq;
          249                 q->n -= n;
          250                 rwakeup(&q->full);
          251                 qunlock(&q->lock);
          252 
          253                 for(i = 0; i < n; i++){
          254                         switch(buf[i]){
          255                         case '\004':                                /* ^D */
          256                                 if(console.nl == 0){
          257                                         qWrite(console.oq, "\n", 1);
          258                                         break;
          259                                 }
          260                                 /*FALLTHROUGH*/
          261                         default:
          262                                 if(console.nl < Nl-1){
          263                                         qWrite(console.oq, &buf[i], 1);
          264                                         console.l[console.nl++] = buf[i];
          265                                 }
          266                                 continue;
          267                         case '\b':
          268                                 if(console.nl != 0){
          269                                         qWrite(console.oq, &buf[i], 1);
          270                                         console.nl--;
          271                                 }
          272                                 continue;
          273                         case '\n':
          274                                 qWrite(console.oq, &buf[i], 1);
          275                                 break;
          276                         case '\025':                                /* ^U */
          277                                 qWrite(console.oq, "^U\n", 3);
          278                                 console.nl = 0;
          279                                 break;
          280                         case '\027':                                /* ^W */
          281                                 console.l[console.nl] = '\0';
          282                                 wbuf = vtmalloc(console.nl+1);
          283                                 memmove(wbuf, console.l, console.nl+1);
          284                                 argc = tokenize(wbuf, argv, nelem(argv));
          285                                 if(argc > 0)
          286                                         argc--;
          287                                 console.nl = 0;
          288                                 lp = console.l;
          289                                 for(i = 0; i < argc; i++)
          290                                         lp += sprint(lp, "%q ", argv[i]);
          291                                 console.nl = lp - console.l;
          292                                 vtfree(wbuf);
          293                                 qWrite(console.oq, "^W\n", 3);
          294                                 if(console.nl == 0)
          295                                         break;
          296                                 qWrite(console.oq, console.l, console.nl);
          297                                 continue;
          298                         case '\177':
          299                                 qWrite(console.oq, "\n", 1);
          300                                 console.nl = 0;
          301                                 break;
          302                         }
          303 
          304                         console.l[console.nl] = '\0';
          305                         if(console.nl != 0)
          306                                 cliExec(console.l);
          307 
          308                         console.nl = 0;
          309                         qWrite(console.oq, console.prompt, console.np);
          310                 }
          311 
          312                 qlock(&q->lock);
          313         }
          314 }
          315 
          316 int
          317 consWrite(char* buf, int len)
          318 {
          319         if(console.oq == nil)
          320                 return write(2, buf, len);
          321         if(console.nopens == 0)
          322                 write(2, buf, len);
          323         return qWrite(console.oq, buf, len);
          324 }
          325 
          326 int
          327 consPrompt(char* prompt)
          328 {
          329         char buf[ERRMAX];
          330 
          331         if(prompt == nil)
          332                 prompt = "prompt";
          333 
          334         vtfree(console.prompt);
          335         console.np = snprint(buf, sizeof(buf), "%s: ", prompt);
          336         console.prompt = vtstrdup(buf);
          337 
          338         return console.np;
          339 }
          340 
          341 int
          342 consTTY(void)
          343 {
          344         int ctl, fd;
          345         char *name, *p;
          346 
          347         name = "/dev/cons";
          348         if((fd = open(name, ORDWR)) < 0){
          349 #ifdef PLAN9PORT
          350                 name = "/dev/tty";
          351 #else
          352                 name = "#c/cons";
          353 #endif
          354                 if((fd = open(name, ORDWR)) < 0){
          355                         werrstr("consTTY: open %s: %r", name);
          356                         return 0;
          357                 }
          358         }
          359 
          360 #ifdef PLAN9PORT
          361         USED(p);
          362         ctl = 0;
          363 #else
          364         p = smprint("%sctl", name);
          365         if((ctl = open(p, OWRITE)) < 0){
          366                 close(fd);
          367                 werrstr("consTTY: open %s: %r", p);
          368                 free(p);
          369                 return 0;
          370         }
          371         if(write(ctl, "rawon", 5) < 0){
          372                 close(ctl);
          373                 close(fd);
          374                 werrstr("consTTY: write %s: %r", p);
          375                 free(p);
          376                 return 0;
          377         }
          378         free(p);
          379 #endif
          380 
          381         if(consOpen(fd, fd, ctl) == 0){
          382                 close(ctl);
          383                 close(fd);
          384                 return 0;
          385         }
          386 
          387         return 1;
          388 }
          389 
          390 int
          391 consInit(void)
          392 {
          393         console.iq = qAlloc();
          394         console.oq = qAlloc();
          395         console.nl = 0;
          396 
          397         consPrompt(nil);
          398 
          399         if(proccreate(consProc, nil, STACK) < 0){
          400                 sysfatal("can't start console proc");
          401                 return 0;
          402         }
          403 
          404         return 1;
          405 }