X-Git-Url: https://git.distorted.org.uk/~mdw/dvdrip/blobdiff_plain/00a5be1d63549628d56e33118d54f1a0f650b312..refs/heads/mdw/cleanup:/lib.c diff --git a/lib.c b/lib.c index 7fecbc4..5bf0394 100644 --- a/lib.c +++ b/lib.c @@ -1,43 +1,125 @@ +/* -*-c-*- + * + * Common functions for the DVDrip C utilities. + * + * (c) 2022 Mark Wooding + */ + +/*----- Licensing notice --------------------------------------------------* + * + * This file is part of the DVD ripping toolset. + * + * DVDrip 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 3 of the License, or (at your + * option) any later version. + * + * DVDrip 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. + * + * You should have received a copy of the GNU General Public License + * along with DVDrip. If not, see . + */ + +/*----- Header files ------------------------------------------------------*/ + #include "lib.h" +/*----- Diagnostics -------------------------------------------------------*/ + const char *prog = ""; void set_prog(const char *p) { const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; } void vmoan(const char *fmt, va_list ap) - { fprintf(stderr, "%s: ", prog); vfprintf(stderr, fmt, ap); } + { vmoan_syserr(0, fmt, ap); } -__attribute__((format(printf, 1, 2))) -void moan(const char *fmt, ...) +void vmoan_syserr(int err, const char *fmt, va_list ap) { - va_list ap; - - va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); + fprintf(stderr, "%s: ", prog); + vfprintf(stderr, fmt, ap); + if (err) fprintf(stderr, ": %s", strerror(errno)); fputc('\n', stderr); } -__attribute__((noreturn, format(printf, 1, 2))) +void moan(const char *fmt, ...) + { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); } + +void moan_syserr(int err, const char *fmt, ...) + { va_list ap; va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); } + void bail(const char *fmt, ...) + { va_list ap; va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); exit(2); } + +void bail_syserr(int err, const char *fmt, ...) { va_list ap; - va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); - fputc('\n', stderr); + va_start(ap, fmt); vmoan_syserr(err, fmt, ap); va_end(ap); exit(2); } -__attribute__((noreturn, format(printf, 2, 3))) -void bail_syserr(int err, const char *fmt, ...) +/*----- Parsing utilities -------------------------------------------------*/ + +double parse_float(const char **p_inout, unsigned f, + double min, double max, const char *what) { - va_list ap; + const char *p; + char *q; + double x; + int err; - va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); - if (err) fprintf(stderr, ": %s", strerror(errno)); - fputc('\n', stderr); - exit(2); + err = errno; errno = 0; + p = *p_inout; + x = strtod(p, &q); + if (errno || x < min || x > max || (!(f&PNF_JUNK) && *q)) + bail("bad %s `%s'", what, p); + *p_inout = q; errno = err; + return (x); } +long parse_int(const char **p_inout, unsigned f, + long min, long max, const char *what) +{ + const char *p; + char *q; + long x; + int err; + + err = errno; errno = 0; + p = *p_inout; + x = strtoul(p, &q, 0); + if (errno || x < min || x > max || (!(f&PNF_JUNK) && *q)) + bail("bad %s `%s'", what, p); + *p_inout = q; errno = err; + return (x); +} + +/*----- Resizing buffers and arrays ---------------------------------------*/ + +void buf__grow(struct buf *b) +{ + b->sz = b->sz ? 2*b->sz : 32; + b->p = realloc(b->p, b->sz); + if (!b->p) bail("out of memory allocating %zu bytes", b->sz); +} + +void *vec__grow(void *p, size_t esz, size_t *sz_inout) +{ + size_t sz = *sz_inout, want; + + sz = sz ? 2*sz : 32; + want = sz*esz; + p = realloc(p, want); + if (!p) bail("out of memory allocating %zu bytes", want); + *sz_inout = sz; return (p); +} + +/*----- System utilities --------------------------------------------------*/ + void sit(double t) { struct timeval tv; @@ -49,6 +131,25 @@ void sit(double t) } } +double tvdiff(const struct timeval *tv_lo, const struct timeval *tv_hi) +{ + return ((tv_hi->tv_sec - tv_lo->tv_sec) + + (tv_hi->tv_usec - tv_lo->tv_usec)/1.0e6); +} + +int read_line(FILE *fp, struct buf *b) +{ + int ch; + + ch = getc(fp); + if (ch == EOF) + return (-1); + else if (ch != '\n') + do { buf_putc(b, ch); ch = getc(fp); } while (ch != EOF && ch != '\n'); + buf_putz(b); + return (0); +} + void carefully_write(int fd, const void *buf, size_t sz) { const unsigned char *p = buf; @@ -90,30 +191,27 @@ void carefully_fclose(FILE *fp, const char *what) bail_syserr(errno, "error writing %s file", what); } -void store_filename(char *buf, ident id) +off_t device_size(int fd, const char *file, int *blksz_out) { - switch (id_kind(id)) { - case RAW: - sprintf(buf, "#"); - break; - case IFO: - if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO"); - else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id)); - break; - case BUP: - if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP"); - else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id)); - break; - case VOB: - if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB"); - else - sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id)); - break; - default: - abort(); - } + struct stat st; + uint64_t volsz; + + if (fstat(fd, &st)) + bail_syserr(errno, "failed to obtain status for `%s'", file); + if (S_ISREG(st.st_mode)) + volsz = st.st_size; + else if (S_ISBLK(st.st_mode)) { + if (ioctl(fd, BLKGETSIZE64, &volsz)) + bail_syserr(errno, "failed to get volume size for `%s'", file); + if (ioctl(fd, BLKSSZGET, blksz_out)) + bail_syserr(errno, "failed to get block size for `%s'", file); + } else + bail("can't read size for `%s': expected file or block device", file); + return ((off_t)volsz); } +/*----- Progress utilities ------------------------------------------------*/ + struct progress_state progress = PROGRESS_STATE_INIT; static struct banner_progress_item banner_progress; @@ -140,6 +238,8 @@ void hide_banner(void) progress_update(&progress); } +/*----- DVD utilities -----------------------------------------------------*/ + #ifdef notdef static void logfn(void *p, dvd_logger_level_t lev, const char *fmt, va_list ap) @@ -160,14 +260,15 @@ static void logfn(void *p, dvd_logger_level_t lev, static const dvd_logger_cb logger = { logfn }; #endif -void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out) +int open_dvd(const char *device, int mode, + int *fd_out, dvd_reader_t **dvd_out) { - int fd; - dvd_reader_t *dvd; - int bannerp = 0; + int fd = -1; + dvd_reader_t *dvd = 0; + int bannerp = 0, rc; for (;;) { - fd = open(device, O_RDONLY); + fd = open(device, mode); if (fd >= 0 || errno != ENOMEDIUM) break; if (!bannerp) { show_banner("Waiting for disc to be inserted..."); @@ -176,16 +277,107 @@ void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out) sit(0.2); } if (bannerp) hide_banner(); - if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device); + + if (fd < 0) { + moan_syserr(errno, "failed to open device `%s'", device); + rc = -1; goto end; + } + if (dvd_out) { #ifdef notdef dvd = DVDOpen2(0, &logger, device); #else dvd = DVDOpen(device); #endif - if (!dvd) bail("failed to open DVD on `%s'", device); - *dvd_out = dvd; + if (!dvd) { + moan("failed to open DVD on `%s'", device); + rc = -1; goto end; + } } - if (fd_out) *fd_out = fd; - else close(fd); + + if (fd_out) { *fd_out = fd; fd = -1; } + if (dvd_out) { *dvd_out = dvd; dvd = 0; } + rc = 0; + +end: + if (fd >= 0) close(fd); + DVDClose(dvd); + return (rc); } + +void store_filename(char *buf, ident id) +{ + switch (id_kind(id)) { + case RAW: + sprintf(buf, "#"); + break; + case IFO: + if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO"); + else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id)); + break; + case BUP: + if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP"); + else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id)); + break; + case VOB: + if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB"); + else + sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id)); + break; + default: + abort(); + } +} + +static char *copy_string(char *p, const char *q) +{ + while (*q) *p++ = *q++; + *p = 0; return (p); +} + +static char *copy_hex(char *p, const unsigned char *q, size_t sz) +{ + while (sz) { + sprintf(p, "%02x", *q); + p += 2; q++; sz--; + } + return (p); +} + +int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file) +{ + char volid[33]; + unsigned char volsetid[16], discid[16]; + int rc; + size_t n; + + rc = DVDUDFVolumeInfo(dvd, + volid, sizeof(volid), + volsetid, sizeof(volsetid)); + if (!rc) { + p = copy_string(p, volid); + *p++ = '-'; + for (n = sizeof(volsetid); n && !volsetid[n - 1]; n--); + p = copy_hex(p, volsetid, n); + } else if (f&DIF_MUSTVOLINF) { + if (file) moan("failed to read volume info for `%s'", file); + else moan("failed to read volume info"); + return (-1); + } else + p = copy_string(p, ""); + + *p++ = ':'; + rc = DVDDiscID(dvd, discid); + if (!rc) + p = copy_hex(p, discid, sizeof(discid)); + else if (f&DIF_MUSTIFOHASH) { + if (file) moan("failed to determine disc id of `%s'", file); + else moan("failed to determine disc id"); + return (-1); + } else + p = copy_string(p, ""); + + return (0); +} + +/*----- That's all, folks -------------------------------------------------*/