thio.c - plan9port - [fork] Plan 9 from user space
git clone git://src.adamsgaard.dk/plan9port
Log
Files
Refs
README
LICENSE
---
thio.c (7538B)
---
     1 #include 
     2 #include 
     3 #include 
     4 
     5 static        char        hstates[] = "nrewE";
     6 static        char        hxfers[] = " x";
     7 static int _hflush(Hio*, int, int);
     8 
     9 int
    10 hinit(Hio *h, int fd, int mode)
    11 {
    12         if(fd == -1 || mode != Hread && mode != Hwrite)
    13                 return -1;
    14         h->hh = nil;
    15         h->fd = fd;
    16         h->seek = 0;
    17         h->state = mode;
    18         h->start = h->buf + 16;                /* leave space for chunk length */
    19         h->stop = h->pos = h->start;
    20         if(mode == Hread){
    21                 h->bodylen = ~0UL;
    22                 *h->pos = '\0';
    23         }else
    24                 h->stop = h->start + Hsize;
    25         return 0;
    26 }
    27 
    28 int
    29 hiserror(Hio *h)
    30 {
    31         return h->state == Herr;
    32 }
    33 
    34 int
    35 hgetc(Hio *h)
    36 {
    37         uchar *p;
    38 
    39         p = h->pos;
    40         if(p < h->stop){
    41                 h->pos = p + 1;
    42                 return *p;
    43         }
    44         p -= UTFmax;
    45         if(p < h->start)
    46                 p = h->start;
    47         if(!hreadbuf(h, p) || h->pos == h->stop)
    48                 return -1;
    49         return *h->pos++;
    50 }
    51 
    52 int
    53 hungetc(Hio *h)
    54 {
    55         if(h->state == Hend)
    56                 h->state = Hread;
    57         else if(h->state == Hread)
    58                 h->pos--;
    59         if(h->pos < h->start || h->state != Hread){
    60                 h->state = Herr;
    61                 h->pos = h->stop;
    62                 return -1;
    63         }
    64         return 0;
    65 }
    66 
    67 /*
    68  * fill the buffer, saving contents from vsave onwards.
    69  * nothing is saved if vsave is nil.
    70  * returns the beginning of the buffer.
    71  *
    72  * understands message body sizes and chunked transfer encoding
    73  */
    74 void *
    75 hreadbuf(Hio *h, void *vsave)
    76 {
    77         Hio *hh;
    78         uchar *save;
    79         int c, in, cpy, dpos;
    80 
    81         save = vsave;
    82         if(save && (save < h->start || save > h->stop)
    83         || h->state != Hread && h->state != Hend){
    84                 h->state = Herr;
    85                 h->pos = h->stop;
    86                 return nil;
    87         }
    88 
    89         dpos = 0;
    90         if(save && h->pos > save)
    91                 dpos = h->pos - save;
    92         cpy = 0;
    93         if(save){
    94                 cpy = h->stop - save;
    95                 memmove(h->start, save, cpy);
    96         }
    97         h->seek += h->stop - h->start - cpy;
    98         h->pos = h->start + dpos;
    99 
   100         in = Hsize - cpy;
   101         if(h->state == Hend)
   102                 in = 0;
   103         else if(in > h->bodylen)
   104                 in = h->bodylen;
   105 
   106         /*
   107          * for chunked encoding, fill buffer,
   108          * then read in new chunk length and wipe out that line
   109          */
   110         hh = h->hh;
   111         if(hh != nil){
   112                 if(!in && h->xferenc && h->state != Hend){
   113                         if(h->xferenc == 2){
   114                                 c = hgetc(hh);
   115                                 if(c == '\r')
   116                                         c = hgetc(hh);
   117                                 if(c != '\n'){
   118                                         h->pos = h->stop;
   119                                         h->state = Herr;
   120                                         return nil;
   121                                 }
   122                         }
   123                         h->xferenc = 2;
   124                         in = 0;
   125                         while((c = hgetc(hh)) != '\n'){
   126                                 if(c >= '0' && c <= '9')
   127                                         c -= '0';
   128                                 else if(c >= 'a' && c <= 'f')
   129                                         c -= 'a' - 10;
   130                                 else if(c >= 'A' && c <= 'F')
   131                                         c -= 'A' - 10;
   132                                 else
   133                                         break;
   134                                 in = in * 16 + c;
   135                         }
   136                         while(c != '\n'){
   137                                 if(c < 0){
   138                                         h->pos = h->stop;
   139                                         h->state = Herr;
   140                                         return nil;
   141                                 }
   142                                 c = hgetc(hh);
   143                         }
   144                         h->bodylen = in;
   145 
   146                         in = Hsize - cpy;
   147                         if(in > h->bodylen)
   148                                 in = h->bodylen;
   149                 }
   150                 if(in){
   151                         while(hh->pos + in > hh->stop){
   152                                 if(hreadbuf(hh, hh->pos) == nil){
   153                                         h->pos = h->stop;
   154                                         h->state = Herr;
   155                                         return nil;
   156                                 }
   157                         }
   158                         memmove(h->start + cpy, hh->pos, in);
   159                         hh->pos += in;
   160                 }
   161         }else if(in){
   162                 if((in = read(h->fd, h->start + cpy, in)) < 0){
   163                         h->state = Herr;
   164                         h->pos = h->stop;
   165                         return nil;
   166                 }
   167         }
   168         if(in == 0)
   169                 h->state = Hend;
   170 
   171         h->bodylen -= in;
   172 
   173         h->stop = h->start + cpy + in;
   174         *h->stop = '\0';
   175         if(h->pos == h->stop)
   176                 return nil;
   177         return h->start;
   178 }
   179 
   180 int
   181 hbuflen(Hio *h, void *p)
   182 {
   183         return h->stop - (uchar*)p;
   184 }
   185 
   186 /*
   187  * prepare to receive a message body
   188  * len is the content length (~0 => unspecified)
   189  * te is the transfer encoding
   190  * returns < 0 if setup failed
   191  */
   192 Hio*
   193 hbodypush(Hio *hh, ulong len, HFields *te)
   194 {
   195         Hio *h;
   196         int xe;
   197 
   198         if(hh->state != Hread)
   199                 return nil;
   200         xe = 0;
   201         if(te != nil){
   202                 if(te->params != nil || te->next != nil)
   203                         return nil;
   204                 if(cistrcmp(te->s, "chunked") == 0){
   205                         xe = 1;
   206                         len = 0;
   207                 }else if(cistrcmp(te->s, "identity") == 0){
   208                         ;
   209                 }else
   210                         return nil;
   211         }
   212 
   213         h = malloc(sizeof *h);
   214         if(h == nil)
   215                 return nil;
   216 
   217         h->hh = hh;
   218         h->fd = -1;
   219         h->seek = 0;
   220         h->state = Hread;
   221         h->xferenc = xe;
   222         h->start = h->buf + 16;                /* leave space for chunk length */
   223         h->stop = h->pos = h->start;
   224         *h->pos = '\0';
   225         h->bodylen = len;
   226         return h;
   227 }
   228 
   229 /*
   230  * dump the state of the io buffer into a string
   231  */
   232 char *
   233 hunload(Hio *h)
   234 {
   235         uchar *p, *t, *stop, *buf;
   236         int ne, n, c;
   237 
   238         stop = h->stop;
   239         ne = 0;
   240         for(p = h->pos; p < stop; p++){
   241                 c = *p;
   242                 if(c == 0x80)
   243                         ne++;
   244         }
   245         p = h->pos;
   246 
   247         n = (stop - p) + ne + 3;
   248         buf = mallocz(n, 1);
   249         if(buf == nil)
   250                 return nil;
   251         buf[0] = hstates[h->state];
   252         buf[1] = hxfers[h->xferenc];
   253 
   254         t = &buf[2];
   255         for(; p < stop; p++){
   256                 c = *p;
   257                 if(c == 0 || c == 0x80){
   258                         *t++ = 0x80;
   259                         if(c == 0x80)
   260                                 *t++ = 0x80;
   261                 }else
   262                         *t++ = c;
   263         }
   264         *t++ = '\0';
   265         if(t != buf + n)
   266                 return nil;
   267         return (char*)buf;
   268 }
   269 
   270 /*
   271  * read the io buffer state from a string
   272  */
   273 int
   274 hload(Hio *h, char *buf)
   275 {
   276         uchar *p, *t, *stop;
   277         char *s;
   278         int c;
   279 
   280         s = strchr(hstates, buf[0]);
   281         if(s == nil)
   282                 return -1;
   283         h->state = s - hstates;
   284 
   285         s = strchr(hxfers, buf[1]);
   286         if(s == nil)
   287                 return -1;
   288         h->xferenc = s - hxfers;
   289 
   290         t = h->start;
   291         stop = t + Hsize;
   292         for(p = (uchar*)&buf[2]; c = *p; p++){
   293                 if(c == 0x80){
   294                         if(p[1] != 0x80)
   295                                 c = 0;
   296                         else
   297                                 p++;
   298                 }
   299                 *t++ = c;
   300                 if(t >= stop)
   301                         return -1;
   302         }
   303         *t = '\0';
   304         h->pos = h->start;
   305         h->stop = t;
   306         h->seek = 0;
   307         return 0;
   308 }
   309 
   310 void
   311 hclose(Hio *h)
   312 {
   313         if(h->fd >= 0){
   314                 if(h->state == Hwrite)
   315                         hxferenc(h, 0);
   316                 close(h->fd);
   317         }
   318         h->stop = h->pos = nil;
   319         h->fd = -1;
   320 }
   321 
   322 /*
   323  * flush the buffer and possibly change encoding modes
   324  */
   325 int
   326 hxferenc(Hio *h, int on)
   327 {
   328         if(h->xferenc && !on && h->pos != h->start)
   329                 hflush(h);
   330         if(_hflush(h, 1, 0) < 0)
   331                 return -1;
   332         h->xferenc = !!on;
   333         return 0;
   334 }
   335 
   336 int
   337 hputc(Hio *h, int c)
   338 {
   339         uchar *p;
   340 
   341         p = h->pos;
   342         if(p < h->stop){
   343                 h->pos = p + 1;
   344                 return *p = c;
   345         }
   346         if(hflush(h) < 0)
   347                 return -1;
   348         return *h->pos++ = c;
   349 }
   350 
   351 static int
   352 fmthflush(Fmt *f)
   353 {
   354         Hio *h;
   355 
   356         h = f->farg;
   357         h->pos = f->to;
   358         if(hflush(h) < 0)
   359                 return 0;
   360         f->stop = h->stop;
   361         f->to = h->pos;
   362         f->start = h->pos;
   363         return 1;
   364 }
   365 
   366 int
   367 hvprint(Hio *h, char *fmt, va_list args)
   368 {
   369         int n;
   370         Fmt f;
   371 
   372         f.runes = 0;
   373         f.stop = h->stop;
   374         f.to = h->pos;
   375         f.start = h->pos;
   376         f.flush = fmthflush;
   377         f.farg = h;
   378         f.nfmt = 0;
   379         fmtlocaleinit(&f, nil, nil, nil);
   380         n = fmtvprint(&f, fmt, args);
   381         h->pos = f.to;
   382         return n;
   383 }
   384 
   385 int
   386 hprint(Hio *h, char *fmt, ...)
   387 {
   388         int n;
   389         va_list arg;
   390 
   391         va_start(arg, fmt);
   392         n = hvprint(h, fmt, arg);
   393         va_end(arg);
   394         return n;
   395 }
   396 
   397 static int
   398 _hflush(Hio *h, int force, int dolength)
   399 {
   400         uchar *s;
   401         int w;
   402 
   403         if(h->state != Hwrite){
   404                 h->state = Herr;
   405                 h->stop = h->pos;
   406                 return -1;
   407         }
   408         s = h->start;
   409         w = h->pos - s;
   410         if(w == 0 && !force)
   411                 return 0;
   412         if(h->xferenc){
   413                 *--s = '\n';
   414                 *--s = '\r';
   415                 do{
   416                         *--s = "0123456789abcdef"[w & 0xf];
   417                         w >>= 4;
   418                 }while(w);
   419                 h->pos[0] = '\r';
   420                 h->pos[1] = '\n';
   421                 w = &h->pos[2] - s;
   422         }
   423         if(dolength)
   424                 fprint(h->fd, "Content-Length: %d\r\n\r\n", w);
   425         if(write(h->fd, s, w) != w){
   426                 h->state = Herr;
   427                 h->stop = h->pos;
   428                 return -1;
   429         }
   430         h->seek += w;
   431         h->pos = h->start;
   432         return 0;
   433 }
   434 
   435 int
   436 hflush(Hio *h)
   437 {
   438         return _hflush(h, 0, 0);
   439 }
   440 
   441 int
   442 hlflush(Hio* h)
   443 {
   444         return _hflush(h, 0, 1);
   445 }
   446 
   447 int
   448 hwrite(Hio *h, void *vbuf, int len)
   449 {
   450         uchar *buf;
   451         int n, m;
   452 
   453         buf = vbuf;
   454         n = len;
   455         if(n < 0 || h->state != Hwrite){
   456                 h->state = Herr;
   457                 h->stop = h->pos;
   458                 return -1;
   459         }
   460         if(h->pos + n >= h->stop){
   461                 if(h->start != h->pos)
   462                         if(hflush(h) < 0)
   463                                 return -1;
   464                 while(h->pos + n >= h->stop){
   465                         m = h->stop - h->pos;
   466                         if(h->xferenc){
   467                                 memmove(h->pos, buf, m);
   468                                 h->pos += m;
   469                                 if(hflush(h) < 0)
   470                                         return -1;
   471                         }else{
   472                                 if(write(h->fd, buf, m) != m){
   473                                         h->state = Herr;
   474                                         h->stop = h->pos;
   475                                         return -1;
   476                                 }
   477                                 h->seek += m;
   478                         }
   479                         n -= m;
   480                         buf += m;
   481                 }
   482         }
   483         memmove(h->pos, buf, n);
   484         h->pos += n;
   485         return len;
   486 }