new release
[gnupg.git] / util / iobuf.c
index d429d4c..772dfa1 100644 (file)
@@ -1,14 +1,14 @@
 /* iobuf.c  -  file handling
- *     Copyright (c) 1997 by Werner Koch (dd9jn)
+ *     Copyright (C) 1998 Free Software Foundation, Inc.
  *
- * This file is part of G10.
+ * This file is part of GNUPG.
  *
- * G10 is free software; you can redistribute it and/or modify
+ * GNUPG is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by
  * the Free Software Foundation; either version 2 of the License, or
  * (at your option) any later version.
  *
- * G10 is distributed in the hope that it will be useful,
+ * GNUPG is distributed in the hope that it will be useful,
  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  * GNU General Public License for more details.
@@ -24,6 +24,7 @@
 #include <string.h>
 #include <errno.h>
 #include <assert.h>
+#include <sys/types.h>
 #include <sys/stat.h>
 #include <unistd.h>
 
@@ -50,7 +51,7 @@ static int underflow(IOBUF a);
  * Read data from a file into buf which has an allocated length of *LEN.
  * return the number of read bytes in *LEN. OPAQUE is the FILE * of
  * the stream. A is not used.
- * control maybe:
+ * control may be:
  * IOBUFCTRL_INIT: called just before the function is linked into the
  *                list of function. This can be used to prepare internal
  *                data structures of the function.
@@ -313,7 +314,7 @@ iobuf_close( IOBUF a )
     size_t dummy_len;
     int rc=0;
 
-    for( ; a; a = a2 ) {
+    for( ; a && !rc ; a = a2 ) {
        a2 = a->chain;
        if( a->usage == 2 && (rc=iobuf_flush(a)) )
            log_error("iobuf_flush failed on close: %s\n", g10_errstr(rc));
@@ -371,7 +372,7 @@ iobuf_open( const char *fname )
     file_filter_ctx_t *fcx;
     size_t len;
 
-    if( !fname ) {
+    if( !fname || (*fname=='-' && !fname[1])  ) {
        fp = stdin; /* fixme: set binary mode for msdoze */
        fname = "[stdin]";
     }
@@ -392,7 +393,7 @@ iobuf_open( const char *fname )
 }
 
 /****************
- * create a iobuf for writing to a file; the file will be created.
+ * create an iobuf for writing to a file; the file will be created.
  */
 IOBUF
 iobuf_create( const char *fname )
@@ -423,8 +424,8 @@ iobuf_create( const char *fname )
 }
 
 /****************
- * append to a iobuf if the file does not exits; create it.
- * cannont be used for stdout.
+ * append to an iobuf; if the file does not exist, create it.
+ * cannot be used for stdout.
  */
 IOBUF
 iobuf_append( const char *fname )
@@ -579,7 +580,7 @@ iobuf_pop_filter( IOBUF a, int (*f)(void *opaque, int control,
        return rc;
     }
 
-    /* and look how to remove it */
+    /* and see how to remove it */
     if( a == b && !b->chain )
        log_bug("can't remove the last filter from the chain\n");
     else if( a == b ) { /* remove the first iobuf from the chain */
@@ -724,6 +725,67 @@ iobuf_readbyte(IOBUF a)
 
 
 int
+iobuf_read(IOBUF a, byte *buf, unsigned buflen )
+{
+    int c, n;
+
+    if( a->unget.buf || a->nlimit ) {
+       /* handle special cases */
+       for(n=0 ; n < buflen; n++, buf++ ) {
+           if( (c = iobuf_readbyte(a)) == -1 ) {
+               if( !n )
+                   return -1; /* eof */
+               break;
+           }
+           else
+               *buf = c;
+       }
+       return n;
+    }
+
+    n = 0;
+    do {
+       for( ; n < buflen && a->d.start < a->d.len; n++ )
+           *buf++ = a->d.buf[a->d.start++];
+       if( n < buflen ) {
+           if( (c=underflow(a)) == -1 ) {
+               a->nbytes += n;
+               return n? n : -1/*EOF*/;
+           }
+           *buf++ = c; n++;
+       }
+    } while( n < buflen );
+    a->nbytes += n;
+    return n;
+}
+
+
+/****************
+ * Have a look at the iobuf.
+ * NOTE: This only works in special cases.
+ */
+int
+iobuf_peek(IOBUF a, byte *buf, unsigned buflen )
+{
+    int n=0;
+
+    if( !(a->d.start < a->d.len) ) {
+       if( underflow(a) == -1 )
+           return -1;
+       /* and unget this character */
+       assert(a->d.start == 1);
+       a->d.start = 0;
+    }
+
+    for(n=0 ; n < buflen && (a->d.start+n) < a->d.len ; n++, buf++ )
+       *buf = a->d.buf[n];
+    return n;
+}
+
+
+
+
+int
 iobuf_writebyte(IOBUF a, unsigned c)
 {
     if( a->d.len == a->d.size )
@@ -739,12 +801,18 @@ iobuf_writebyte(IOBUF a, unsigned c)
 int
 iobuf_write(IOBUF a, byte *buf, unsigned buflen )
 {
-    for( ; buflen; buflen--, buf++ )
-       if( iobuf_writebyte(a, *buf) )
-           return -1;
+    do {
+       for( ; buflen && a->d.len < a->d.size; buflen--, buf++ )
+           a->d.buf[a->d.len++] = *buf;
+       if( buflen ) {
+           if( iobuf_flush(a) )
+               return -1;
+       }
+    } while( buflen );
     return 0;
 }
 
+
 int
 iobuf_writestr(IOBUF a, const char *buf )
 {
@@ -802,7 +870,7 @@ iobuf_unget_and_close_temp( IOBUF a, IOBUF temp )
 
 
 /****************
- * Set a limit, how much bytes may be read from the input stream A.
+ * Set a limit on how many bytes may be read from the input stream A.
  * Setting the limit to 0 disables this feature.
  */
 void
@@ -847,6 +915,11 @@ iobuf_tell( IOBUF a )
 }
 
 
+
+/****************
+ * This is a very limited implementation. It simply discards all internal
+ * buffering and removes all filters but the first one.
+ */
 int
 iobuf_seek( IOBUF a, ulong newpos )
 {
@@ -865,6 +938,10 @@ iobuf_seek( IOBUF a, ulong newpos )
        log_error("can't seek to %lu: %s\n", newpos, strerror(errno) );
        return -1;
     }
+    a->d.len = 0;   /* discard buffer */
+    a->d.start = 0;
+    a->nbytes = 0;
+    a->nlimit = 0;
     a->ntotal = newpos;
     /* remove filters, but the last */
     while( a->chain )
@@ -916,7 +993,7 @@ iobuf_set_block_mode( IOBUF a, size_t n )
 }
 
 /****************
- * enable patial block mode as descriped in the OpenPGP draft.
+ * enable partial block mode as described in the OpenPGP draft.
  * LEN is the first length
  */
 void
@@ -938,7 +1015,7 @@ iobuf_set_partial_block_mode( IOBUF a, size_t len )
 
 
 /****************
- * Checks wether the stream is in block mode
+ * Checks whether the stream is in block mode
  * Note: This does not work if other filters are pushed on the stream.
  */
 int