X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/be15bd145f610c88dc2e17698b3863904872a3f0..refs/heads/mdw/cleanup:/lib.h diff --git a/lib.h b/lib.h index 5507f12..7c4a0cb 100644 --- a/lib.h +++ b/lib.h @@ -97,8 +97,16 @@ /* Function attributes. If you're not using GCC to build then you'll need to * say something different here. */ -#define PRINTF_LIKE(fmt, dots) __attribute__((format(printf, fmt, dots))) -#define NORETURN __attribute__((noreturn)) +#if (defined(__GNUC__) && (__GNUC__ > 2 || \ + (__GNUC__ == 2 && __GNUC_MINOR__ >= 5))) || \ + (defined(__clang__) && (__clang_major__ > 3 || \ + (__clang_major__ == 3 && __clang_minor__ >= 3))) +# define PRINTF_LIKE(fmt, dots) __attribute__((format(printf, fmt, dots))) +# define NORETURN __attribute__((noreturn)) +#else +# define PRINTF_LIKE(fmt, dots) +# define NORETURN +#endif /*----- Definitions for low-level DVD access ------------------------------*/ @@ -135,6 +143,75 @@ extern PRINTF_LIKE(2, 3) NORETURN * exit with status code 2. */ +/*----- Resizing buffers --------------------------------------------------*/ + +struct buf { + /* A buffer for a string which can grow automatically. */ + + char *p; /* pointer to the buffer */ + size_t n, sz; /* string length, buffer size */ +}; +#define BUF_INIT { 0, 0, 0 } + +static inline void buf_rewind(struct buf *b) { b->n = 0; } + /* Throw away the current contents of B so that new stuff gets added + * to the beginning. + */ + +static inline void buf_free(struct buf *b) + { free(b->p); b->p = 0; b->n = b->sz = 0; } + /* Release the memory allocated for B. The buffer can be reused + * immediately and/or freed again safely. + */ + +extern void buf__grow(struct buf *b); + /* Make B's buffer larger, so that (at least) one extra byte can be + * written to it. (Internal to `buf_putc'.) + */ + +static inline void buf_putc(struct buf *b, int ch) + { if (b->n >= b->sz) buf__grow(b); b->p[b->n++] = ch; } + /* Append the character CH to the buffer B. */ + +static inline void buf_putz(struct buf *b) + { if (b->n >= b->sz) buf__grow(b); b->p[b->n] = 0; } + /* Append a zero byte to B without increasing the string length, so + * that a future `buf_putc' will overwrite it. + */ + +/*----- Resizing vectors --------------------------------------------------*/ + +#define DEFVEC(vtype, etype) \ + typedef struct { etype *v; size_t n, sz; } vtype +#define VEC_INIT { 0, 0, 0 } + /* Define VTYPE as a (structured) type for vectors holding elements + * of ETYPE. + * + * A vector V has `V.n' elements, addressed as `V.v[0]' up to + * `V.v[V.n - 1]'. + */ + +#define VEC_FREE(vv) do { \ + free((vv)->v); (vv)->v 0; (vv)->n = (vv)->sz = 0; \ +} while (0) + /* Free the vector VV. It's safe to free a vector multiple times. */ + +extern void *vec__grow(void *p, size_t esz, size_t *sz_inout); + /* Extend the buffer P, which currently has space for *SZ_INOUT + * elements, each ESZ bytes in size, so that there's space for at + * least one one more; return the new buffer address, and update + * *SZ_INOUT with the new size. + */ + +#define VEC_PUSH(p, vv) do { \ + if ((vv)->n >= (vv)->sz) \ + (vv)->v = vec__grow((vv)->v, sizeof(*(vv)->v), &(vv)->sz); \ + (p) = &(vv)->v[(vv)->n++]; \ +} while (0) + /* Add an initialized element to the end of vector VV, storing its + * address in P. + */ + /*----- Parsing utilities -------------------------------------------------*/ #define PNF_JUNK 1u @@ -152,11 +229,24 @@ extern long parse_int(const char **p_inout, unsigned f, /*----- System utilities --------------------------------------------------*/ +extern double tvdiff(const struct timeval *tv_lo, + const struct timeval *tv_hi); + /* Return the (signed) difference from TV_LO to TV_HI, as a floating- + * point number of seconds. + */ + extern void sit(double t); /* Do nothing for T seconds. As implied by the type, T may be * fractional. */ +extern int read_line(FILE *fp, struct buf *b); + /* Read a line from FP, appending it to the buffer B, leaving the + * string in B null-terminated (as if by `buf_putz'). Return 0 on + * success, or -1 if nothing was read (not even an empty line) before + * we encountered end-of-file or a read error. + */ + extern void carefully_write(int fd, const void *buf, size_t sz); /* Write SZ bytes to file descriptor FD, starting at BUF. Report a * fatal error if this fails. Correctly handles short writes and @@ -190,7 +280,7 @@ extern off_t device_size(int fd, const char *file, int *blksz_out); * device only, store the block size in *BLKSZ_OUT. (Hence, * *BLKSZ_OUT will be left unchanged if FD is open on a regular * file.) If FD refers to any other kind of object then report a - * fatal error. + * fatal error quoting FILE as the name of the device. */ /*----- Progress utilities ------------------------------------------------*/ @@ -211,19 +301,19 @@ extern void hide_banner(void); /*----- DVD utilities -----------------------------------------------------*/ -extern void open_dvd(const char *device, int mode, - int *fd_out, dvd_reader_t **dvd_out); +extern int open_dvd(const char *device, int mode, + int *fd_out, dvd_reader_t **dvd_out); /* Open the DEVICE. If FD_OUT is not null, then open a file * descriptor onto the device, with the given open(2)-style MODE, * storing the descriptor in *FD_OUT; if DVD_OUT is not null, then * open a `libdvdread' handle onto the devie and store it in * *DVD_OUT. If both are null, then why are you calling this - * function? + * function? Returns 0 on success or -1 on failure. * * If DEVICE refers to an actual block device, and no medium is * currently inserted, then put up a banner prompting the user and - * wait for a medium to be inserted. Other problems are reported as - * fatal errors. + * wait for a medium to be inserted. Other problems are reported to + * stderr. */ enum { RAW, IFO, VOB, BUP };