Browse Source

add long long buffer routines

add tai64 and tai6464 typedefs
add error message buffer routines
add io timeout routines
master
Felix von Leitner 17 years ago
parent
commit
4c41a88194
25 changed files with 318 additions and 55 deletions
  1. +3
    -0
      CHANGES
  2. +1
    -1
      array.h
  3. +38
    -32
      buffer.h
  4. +11
    -0
      buffer/buffer_puterror.3
  5. +7
    -0
      buffer/buffer_puterror.c
  6. +13
    -0
      buffer/buffer_puterror2.3
  7. +6
    -0
      buffer/buffer_puterror2.c
  8. +1
    -1
      buffer/buffer_putlong.3
  9. +2
    -2
      buffer/buffer_putlong.c
  10. +13
    -0
      buffer/buffer_putlonglong.3
  11. +8
    -0
      buffer/buffer_putlonglong.c
  12. +13
    -0
      buffer/buffer_putulonglong.3
  13. +8
    -0
      buffer/buffer_putulonglong.c
  14. +2
    -2
      io.h
  15. +7
    -0
      io/io_timeout.c
  16. +19
    -0
      io/io_tryreadtimeout.c
  17. +19
    -0
      io/io_trywritetimeout.c
  18. +27
    -0
      io/io_waitread.c
  19. +27
    -0
      io/io_waitwrite.c
  20. +1
    -0
      io_internal.h
  21. +2
    -2
      tai.h
  22. +15
    -15
      taia.h
  23. +10
    -0
      taia/taia_addsec.c
  24. +39
    -0
      test/io3.c
  25. +26
    -0
      test/io4.c

+ 3
- 0
CHANGES View File

@@ -3,6 +3,9 @@
add API for integer multiply with overflow detection
change length counters from int to long for 64-bit platforms
add array API from http://cr.yp.to/lib/array.html
oops, had a declaration and man page for taia_addsec but not the
function itself
add buffer functions to write strerror(errno)

0.15:
man page update (document stralloc return values)


+ 1
- 1
array.h View File

@@ -32,6 +32,6 @@ void array_cat0(array* to);
void array_cate(array* to,const array* const from,int64 pos,int64 stop);

#define array_failed(x) (array_bytes(x)==-1)
#define array_allocated(x) (array_bytes(x)==0)
#define array_unallocated(x) (array_bytes(x)==0)

#endif

+ 38
- 32
buffer.h View File

@@ -15,18 +15,18 @@ typedef struct buffer {
#define BUFFER_INSIZE 8192
#define BUFFER_OUTSIZE 8192

extern void buffer_init(buffer* b,int (*op)(),int fd,char* y,unsigned int ylen);
void buffer_init(buffer* b,int (*op)(),int fd,char* y,unsigned int ylen);

extern int buffer_flush(buffer* b);
extern int buffer_put(buffer* b,const char* x,unsigned int len);
extern int buffer_putalign(buffer* b,const char* x,unsigned int len);
extern int buffer_putflush(buffer* b,const char* x,unsigned int len);
extern int buffer_puts(buffer* b,const char* x);
extern int buffer_putsalign(buffer* b,const char* x);
extern int buffer_putsflush(buffer* b,const char* x);
int buffer_flush(buffer* b);
int buffer_put(buffer* b,const char* x,unsigned int len);
int buffer_putalign(buffer* b,const char* x,unsigned int len);
int buffer_putflush(buffer* b,const char* x,unsigned int len);
int buffer_puts(buffer* b,const char* x);
int buffer_putsalign(buffer* b,const char* x);
int buffer_putsflush(buffer* b,const char* x);

extern int buffer_putspace(buffer* b);
extern int buffer_putnlflush(buffer* b); /* put \n and flush */
int buffer_putspace(buffer* b);
int buffer_putnlflush(buffer* b); /* put \n and flush */

#define buffer_PUTC(s,c) \
( ((s)->a != (s)->p) \
@@ -34,16 +34,16 @@ extern int buffer_putnlflush(buffer* b); /* put \n and flush */
: buffer_put((s),&(c),1) \
)

extern int buffer_get(buffer* b,char* x,unsigned int len);
extern int buffer_feed(buffer* b);
extern int buffer_getc(buffer* b,char* x);
extern int buffer_getn(buffer* b,char* x,unsigned int len);
int buffer_get(buffer* b,char* x,unsigned int len);
int buffer_feed(buffer* b);
int buffer_getc(buffer* b,char* x);
int buffer_getn(buffer* b,char* x,unsigned int len);

/* read bytes until the destination buffer is full (len bytes), end of
* file is reached or the read char is in charset (setlen bytes). An
* empty line when looking for \n will write '\n' to x and return 0. If
* EOF is reached, \0 is written to the buffer */
extern int buffer_get_token(buffer* b,char* x,unsigned int len,const char* charset,unsigned int setlen);
int buffer_get_token(buffer* b,char* x,unsigned int len,const char* charset,unsigned int setlen);
#define buffer_getline(b,x,len) buffer_get_token((b),(x),(len),"\n",1)

/* this predicate is given the string as currently read from the buffer
@@ -51,10 +51,10 @@ extern int buffer_get_token(buffer* b,char* x,unsigned int len,const char* chars
typedef int (*string_predicate)(const char* x,unsigned int len);

/* like buffer_get_token but the token ends when your predicate says so */
extern int buffer_get_token_pred(buffer* b,char* x,unsigned int len,string_predicate p);
int buffer_get_token_pred(buffer* b,char* x,unsigned int len,string_predicate p);

extern char *buffer_peek(buffer* b);
extern void buffer_seek(buffer* b,unsigned int len);
char *buffer_peek(buffer* b);
void buffer_seek(buffer* b,unsigned int len);

#define buffer_PEEK(s) ( (s)->x + (s)->p )
#define buffer_SEEK(s,len) ( (s)->p += (len) )
@@ -65,22 +65,28 @@ extern void buffer_seek(buffer* b,unsigned int len);
: buffer_get((s),(c),1) \
)

extern int buffer_copy(buffer* out,buffer* in);
int buffer_copy(buffer* out,buffer* in);

extern int buffer_putulong(buffer *b,unsigned long l);
extern int buffer_put8long(buffer *b,unsigned long l);
extern int buffer_putxlong(buffer *b,unsigned long l);
extern int buffer_putlong(buffer *b,unsigned long l);
int buffer_putulong(buffer *b,unsigned long l);
int buffer_put8long(buffer *b,unsigned long l);
int buffer_putxlong(buffer *b,unsigned long l);
int buffer_putlong(buffer *b,signed long l);

extern buffer *buffer_0;
extern buffer *buffer_0small;
extern buffer *buffer_1;
extern buffer *buffer_1small;
extern buffer *buffer_2;
int buffer_putlonglong(buffer* b,signed long long l);
int buffer_putulonglong(buffer* b,unsigned long long l);

int buffer_puterror(buffer* b);
int buffer_puterror2(buffer* b, int errnum);

buffer *buffer_0;
buffer *buffer_0small;
buffer *buffer_1;
buffer *buffer_1small;
buffer *buffer_2;

#ifdef STRALLOC_H
/* write stralloc to buffer */
extern int buffer_putsa(buffer* b,stralloc* sa);
int buffer_putsa(buffer* b,stralloc* sa);

/* these "read token" functions return 0 if the token was complete or
* EOF was hit or -1 on error. In contrast to the non-stralloc token
@@ -94,14 +100,14 @@ extern int buffer_putsa(buffer* b,stralloc* sa);
* data is available. */

/* read token from buffer to stralloc */
extern int buffer_get_token_sa(buffer* b,stralloc* sa,const char* charset,unsigned int setlen);
int buffer_get_token_sa(buffer* b,stralloc* sa,const char* charset,unsigned int setlen);
/* read line from buffer to stralloc */
extern int buffer_getline_sa(buffer* b,stralloc* sa);
int buffer_getline_sa(buffer* b,stralloc* sa);

typedef int (*sa_predicate)(stralloc* sa);

/* like buffer_get_token_sa but the token ends when your predicate says so */
extern int buffer_get_token_sa_pred(buffer* b,stralloc* sa,sa_predicate p);
int buffer_get_token_sa_pred(buffer* b,stralloc* sa,sa_predicate p);

/* make a buffer from a stralloc.
* Do not change the stralloc after this! */


+ 11
- 0
buffer/buffer_puterror.3 View File

@@ -0,0 +1,11 @@
.TH buffer_puterror 3
.SH NAME
buffer_puterror \- write error string to buffer and flush
.SH SYNTAX
.B #include <buffer.h>

int \fBbuffer_puterror\fP(buffer* \fIb\fR);
.SH DESCRIPTION
buffer_puterror is equivalent to calling buffer_puterror2 with errno.
.SH "SEE ALSO"
buffer_puterror2(3), buffer_puts(3), buffer_put(3), buffer_flush(3), buffer(3)

+ 7
- 0
buffer/buffer_puterror.c View File

@@ -0,0 +1,7 @@
#include "buffer.h"
#include <string.h>
#include <errno.h>

int buffer_puterror(buffer* b) {
return buffer_puts(b,strerror(errno));
}

+ 13
- 0
buffer/buffer_puterror2.3 View File

@@ -0,0 +1,13 @@
.TH buffer_puterror2 3
.SH NAME
buffer_puterror2 \- write error string to buffer and flush
.SH SYNTAX
.B #include <buffer.h>

int \fBbuffer_puterror2\fP(buffer* \fIb\fR,int \fIerrnum\fR);
.SH DESCRIPTION
buffer_puterror2 writes the error message corresponding to the error
number in \fIerrnum\fR to the buffer (e.g. "No such file or directory"
for ENOENT).
.SH "SEE ALSO"
buffer_puterror(3), buffer_puts(3), buffer_put(3), buffer_flush(3), buffer(3)

+ 6
- 0
buffer/buffer_puterror2.c View File

@@ -0,0 +1,6 @@
#include "buffer.h"
#include <string.h>

int buffer_puterror2(buffer* b,int errnum) {
return buffer_puts(b,strerror(errnum));
}

+ 1
- 1
buffer/buffer_putlong.3 View File

@@ -5,7 +5,7 @@ long integer to buffer
.SH SYNTAX
.B #include <buffer.h>

int \fBbuffer_putlong\fP(buffer* \fIb\fR,unsigned long \fIx\fR);
int \fBbuffer_putlong\fP(buffer* \fIb\fR,signed long \fIx\fR);
.SH DESCRIPTION
buffer_putlong is similar to passing the result of fmt_long to
buffer_put.


+ 2
- 2
buffer/buffer_putlong.c View File

@@ -1,8 +1,8 @@
#include "buffer.h"
#include "fmt.h"

int buffer_putlong(buffer *b,unsigned long l) {
char buf[FMT_ULONG];
int buffer_putlong(buffer *b,signed long l) {
char buf[FMT_LONG];
return buffer_put(b,buf,fmt_long(buf,l));
}


+ 13
- 0
buffer/buffer_putlonglong.3 View File

@@ -0,0 +1,13 @@
.TH buffer_putlonglong 3
.SH NAME
buffer_putlonglong \- write a decimal ASCII representation of a signed
long integer to buffer
.SH SYNTAX
.B #include <buffer.h>

int \fBbuffer_putlonglong\fP(buffer* \fIb\fR,signed long long \fIx\fR);
.SH DESCRIPTION
buffer_putlonglong is equivalent to passing the result of fmt_longlong to
buffer_put.
.SH "SEE ALSO"
fmt_longlong(3), buffer_put(3), buffer_flush(3), buffer(3)

+ 8
- 0
buffer/buffer_putlonglong.c View File

@@ -0,0 +1,8 @@
#include "buffer.h"
#include "fmt.h"

int buffer_putlonglong(buffer *b,signed long long l) {
char buf[FMT_LONG];
return buffer_put(b,buf,fmt_longlong(buf,l));
}


+ 13
- 0
buffer/buffer_putulonglong.3 View File

@@ -0,0 +1,13 @@
.TH buffer_putulonglong 3
.SH NAME
buffer_putulonglong \- write a decimal ASCII representation of a signed
long integer to buffer
.SH SYNTAX
.B #include <buffer.h>

int \fBbuffer_putulonglong\fP(buffer* \fIb\fR,unsigned long long \fIx\fR);
.SH DESCRIPTION
buffer_putulonglong is equivalent to passing the result of fmt_ulonglong to
buffer_put.
.SH "SEE ALSO"
fmt_ulonglong(3), buffer_put(3), buffer_flush(3), buffer(3)

+ 8
- 0
buffer/buffer_putulonglong.c View File

@@ -0,0 +1,8 @@
#include "buffer.h"
#include "fmt.h"

int buffer_putulonglong(buffer *b,unsigned long long l) {
char buf[FMT_ULONG];
return buffer_put(b,buf,fmt_ulonglong(buf,l));
}


+ 2
- 2
io.h View File

@@ -26,7 +26,7 @@ int64 io_trywrite(int64 d,const char* buf,int64 len);
int64 io_waitwrite(int64 d,const char* buf,int64 len);

/* modify timeout attribute of file descriptor */
void io_timeout(int64 d,struct taia t);
void io_timeout(int64 d,tai6464 t);

/* like io_tryread but will return -2,errno=ETIMEDOUT if d has a timeout
* associated and it is passed without input being there */
@@ -42,7 +42,7 @@ void io_dontwantread(int64 d);
void io_dontwantwrite(int64 d);

void io_wait();
void io_waituntil(struct taia t);
void io_waituntil(tai6464 t);
void io_check();

/* return next descriptor from io_wait that can be read from */


+ 7
- 0
io/io_timeout.c View File

@@ -0,0 +1,7 @@
#include "io_internal.h"

void io_timeout(int64 d,tai6464 t) {
io_entry* e=array_get(&io_fds,sizeof(io_entry),d);
if (e)
e->timeout=t;
}

+ 19
- 0
io/io_tryreadtimeout.c View File

@@ -0,0 +1,19 @@
#include <unistd.h>
#include <sys/time.h>
#include <poll.h>
#include <errno.h>
#include "io_internal.h"

int64 io_tryreadtimeout(int64 d,char* buf,int64 len) {
int64 r=io_tryread(d,buf,len);
if (r==-1) {
tai6464 x;
io_entry* e=array_get(&io_fds,sizeof(io_entry),d);
taia_now(&x);
if (taia_less(&x,&e->timeout)) {
errno=ETIMEDOUT;
r=-2;
}
}
return r;
}

+ 19
- 0
io/io_trywritetimeout.c View File

@@ -0,0 +1,19 @@
#include <unistd.h>
#include <sys/time.h>
#include <poll.h>
#include <errno.h>
#include "io_internal.h"

int64 io_trywritetimeout(int64 d,const char* buf,int64 len) {
int64 r=io_trywrite(d,buf,len);
if (r==-1) {
tai6464 x;
io_entry* e=array_get(&io_fds,sizeof(io_entry),d);
taia_now(&x);
if (taia_less(&x,&e->timeout)) {
errno=ETIMEDOUT;
r=-2;
}
}
return r;
}

+ 27
- 0
io/io_waitread.c View File

@@ -0,0 +1,27 @@
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include "io_internal.h"

int64 io_waitread(int64 d,char* buf,int64 len) {
long r;
struct pollfd p;
io_entry* e=array_get(&io_fds,sizeof(io_entry),d);
if (!e) { errno=EBADF; return -3; }
if (e->nonblock) {
again:
p.fd=d;
if (p.fd != d) { errno=EBADF; return -3; } /* catch overflow */
p.events=POLLIN;
switch (poll(&p,1,-1)) {
case -1: if (errno==EAGAIN) goto again; return -3;
}
}
r=read(d,buf,len);
if (r==-1) {
if (errno==EAGAIN)
goto again;
r=-3;
}
return r;
}

+ 27
- 0
io/io_waitwrite.c View File

@@ -0,0 +1,27 @@
#include <unistd.h>
#include <poll.h>
#include <errno.h>
#include "io_internal.h"

int64 io_waitwrite(int64 d,const char* buf,int64 len) {
long r;
struct pollfd p;
io_entry* e=array_get(&io_fds,sizeof(io_entry),d);
if (!e) { errno=EBADF; return -3; }
if (e->nonblock) {
again:
p.fd=d;
if (p.fd != d) { errno=EBADF; return -3; } /* catch overflow */
p.events=POLLOUT;
switch (poll(&p,1,-1)) {
case -1: if (errno==EAGAIN) goto again; return -3;
}
}
r=write(d,buf,len);
if (r==-1) {
if (errno==EAGAIN)
goto again;
r=-3;
}
return r;
}

+ 1
- 0
io_internal.h View File

@@ -8,6 +8,7 @@ typedef struct {
unsigned int canwrite:1;
unsigned int nonblock:1;
unsigned int inuse:1;
tai6464 timeout;
} io_entry;

array io_fds;


+ 2
- 2
tai.h View File

@@ -17,9 +17,9 @@
* difference between two TAI64 labels.
* See http://cr.yp.to/libtai/tai64.html */

struct tai {
typedef struct tai {
uint64 x;
} ;
} tai64;


#define tai_unix(t,u) ((void) ((t)->x = 4611686018427387914ULL + (uint64) (u)))


+ 15
- 15
taia.h View File

@@ -9,37 +9,37 @@
* exclusive. The number is a multiple of 10^-18. The format of struct
* taia is designed to speed up common operations; applications should
* not look inside struct taia. */
struct taia {
typedef struct taia {
struct tai sec;
unsigned long nano; /* 0...999999999 */
unsigned long atto; /* 0...999999999 */
};
} tai6464;

/* extract seconds */
extern void taia_tai(const struct taia *source,struct tai *dest);
void taia_tai(const tai6464 *source,tai64 *dest);

/* get current time */
extern void taia_now(struct taia *);
void taia_now(struct taia *);

/* return double-precision approximation; always nonnegative */
extern double taia_approx(const struct taia *);
double taia_approx(const tai6464 *);
/* return double-precision approximation of the fraction part;
* always nonnegative */
extern double taia_frac(const struct taia *);
double taia_frac(const tai6464 *);

/* add source1 to source2 modulo 2^64 and put the result in dest.
* The inputs and output may overlap */
extern void taia_add(struct taia *dest,const struct taia *source1,const struct taia *source2);
void taia_add(tai6464 *dest,const tai6464 *source1,const tai6464 *source2);
/* add secs seconds to source modulo 2^64 and put the result in dest. */
extern void taia_addsec(struct taia *dest,const struct taia *source,int secs);
void taia_addsec(tai6464 *dest,const tai6464 *source,long secs);
/* subtract source2 from source1 modulo 2^64 and put the result in dest.
* The inputs and output may overlap */
extern void taia_sub(struct taia *,const struct taia *,const struct taia *);
void taia_sub(tai6464 *,const tai6464 *,const tai6464 *);
/* divide source by 2, rouding down to a multiple of 10^-18, and put the
* result into dest. The input and output may overlap */
extern void taia_half(struct taia *dest,const struct taia *source);
void taia_half(tai6464 *dest,const tai6464 *source);
/* return 1 if a is less than b, 0 otherwise */
extern int taia_less(const struct taia *a,const struct taia *b);
int taia_less(const tai6464 *a,const tai6464 *b);

#define TAIA_PACK 16
/* char buf[TAIA_PACK] can be used to store a TAI64NA label in external
@@ -49,10 +49,10 @@ extern int taia_less(const struct taia *a,const struct taia *b);

/* convert a TAI64NA label from internal format in src to external
* TAI64NA format in buf. */
extern void taia_pack(char *buf,const struct taia *src);
void taia_pack(char *buf,const tai6464 *src);
/* convert a TAI64NA label from external TAI64NA format in buf to
* internal format in dest. */
extern void taia_unpack(const char *buf,struct taia *dest);
void taia_unpack(const char *buf,tai6464 *dest);

#define TAIA_FMTFRAC 19
/* print the 18-digit fraction part of t in decimal, without a decimal
@@ -60,9 +60,9 @@ extern void taia_unpack(const char *buf,struct taia *dest);
* terminating \0. It returns 18, the number of characters written. s
* may be zero; then taia_fmtfrac returns 18 without printing anything.
* */
extern unsigned int taia_fmtfrac(char *s,const struct taia *t);
unsigned int taia_fmtfrac(char *s,const tai6464 *t);

/* initialize t to secs seconds. */
extern void taia_uint(struct taia *t,unsigned int secs);
void taia_uint(tai6464 *t,unsigned int secs);

#endif

+ 10
- 0
taia/taia_addsec.c View File

@@ -0,0 +1,10 @@
#include "taia.h"

/* XXX: breaks tai encapsulation */

void taia_addsec(struct taia *t,const struct taia *u,long secs)
{
t->sec.x = u->sec.x + secs;
t->nano = u->nano;
t->atto = u->atto;
}

+ 39
- 0
test/io3.c View File

@@ -0,0 +1,39 @@
#include <unistd.h>
#include "buffer.h"
#include "io.h"

main() {
int64 pfd[2];
char buf[20480];
int i;
if (!io_pipe(pfd)) return 111;
io_nonblock(pfd[1]);
if (!io_fd(pfd[1])) return 111;
switch (fork()) {
case -1: return 111;
case 0: /* child */
io_close(pfd[1]);
sleep(1);
for (;;) {
switch (io_waitread(pfd[0],buf,sizeof buf)) {
case -1: buffer_putsflush(buffer_2,"io_waitread returned -1!\n"); return 111;
case -3: buffer_puts(buffer_2,"io_waitread: ");
buffer_puterror(buffer_2);
buffer_putnlflush(buffer_2);
return 111;
case 0: io_close(pfd[0]);
return 0;
}
}
}
io_close(pfd[0]);
for (i=0; i<sizeof(buf); ++i) buf[i]="abcdefghihjklmnopqrstuvwxyz"[i%26];
for (i=0; i<1000; ++i) {
int64 r;
if ((r=io_waitwrite(pfd[1],buf,sizeof buf))!=sizeof buf) {
buffer_puts(buffer_2,"io_waitwrite returned ");
buffer_putlonglong(buffer_2,r);
buffer_putnlflush(buffer_2);
}
}
}

+ 26
- 0
test/io4.c View File

@@ -0,0 +1,26 @@
#include "io.h"
#include "buffer.h"

main() {
char buf[2048];
int64 pfd[2];
tai6464 t;
int64 r;

if (!io_pipe(pfd)) {
buffer_puts(buffer_2,"io_pipe: ");
buffer_puterror(buffer_2);
buffer_putnlflush(buffer_2);
return 111;
}
taia_now(&t);
taia_addsec(&t,&t,1);
if (!io_fd(pfd[0])) return 111;
io_timeout(pfd[0],t);
if ((r=io_tryreadtimeout(pfd[0],buf,sizeof buf))!=-2) {
buffer_puts(buffer_2,"io_tryreadtimeout returned ");
buffer_putlonglong(buffer_2,r);
buffer_putnlflush(buffer_2);
return 111;
}
}

Loading…
Cancel
Save