From be15bd145f610c88dc2e17698b3863904872a3f0 Mon Sep 17 00:00:00 2001 From: Mark Wooding Date: Fri, 25 Mar 2022 19:00:24 +0000 Subject: [PATCH] lib.[ch]: Add documentation and commentary. --- lib.c | 39 ++++++++++++++ lib.h | 192 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 225 insertions(+), 6 deletions(-) diff --git a/lib.c b/lib.c index 6772eec..55c4b48 100644 --- a/lib.c +++ b/lib.c @@ -1,5 +1,34 @@ +/* -*-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) @@ -33,6 +62,8 @@ void bail_syserr(int err, const char *fmt, ...) exit(2); } +/*----- Parsing utilities -------------------------------------------------*/ + double parse_float(const char **p_inout, unsigned f, double min, double max, const char *what) { @@ -67,6 +98,8 @@ long parse_int(const char **p_inout, unsigned f, return (x); } +/*----- System utilities --------------------------------------------------*/ + void sit(double t) { struct timeval tv; @@ -138,6 +171,8 @@ off_t device_size(int fd, const char *file, int *blksz_out) return ((off_t)volsz); } +/*----- Progress utilities ------------------------------------------------*/ + struct progress_state progress = PROGRESS_STATE_INIT; static struct banner_progress_item banner_progress; @@ -164,6 +199,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) @@ -289,3 +326,5 @@ int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file) return (0); } + +/*----- That's all, folks -------------------------------------------------*/ diff --git a/lib.h b/lib.h index b3ac99a..5507f12 100644 --- a/lib.h +++ b/lib.h @@ -1,9 +1,38 @@ +/* -*-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 . + */ + #ifndef LIB_H #define LIB_H +/*----- Preliminaries -----------------------------------------------------*/ + #define _GNU_SOURCE #define _FILE_OFFSET_BITS 64 +/*----- Header files ------------------------------------------------------*/ + #include #include #include @@ -37,85 +66,236 @@ #include "multiprogress.h" +/*----- Various macros with wide applicability ----------------------------*/ + +/* `ctype.h' functions are troublesome: in particular, they don't handle + * negative characters properly, if they're a thing that your platform + * believes in. So we have these macros which fix things up properly. + */ #define CTYPE_HACK(fn, ch) fn((unsigned char)(ch)) #define ISDIGIT(ch) CTYPE_HACK(isdigit, ch) #define ISSPACE(ch) CTYPE_HACK(isspace, ch) +/* It's easy to screw up the `foocmp' functions by leaving off the comparison + * with zero. These macros make it impossible to forget, and put the + * relation in the right place syntactically. + */ #define STRCMP(a, op, b) (strcmp((a), (b)) op 0) #define STRNCMP(a, op, b, n) (strncmp((a), (b), (n)) op 0) #define MEMCMP(a, op, b, n) (memcmp((a), (b), (n)) op 0) +/* Suppress some code unless we're debugging. */ #ifdef DEBUG # define D(x) x #else # define D(x) #endif +/* Count the number of elements in an array. */ #define N(v) (sizeof(v)/sizeof((v)[0])) +/* 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)) -#define SECTORSZ 2048 +/*----- Definitions for low-level DVD access ------------------------------*/ + +#define SECTORSZ 2048 /* the DVD sector size */ #define SECTORS(n) (((n) + (SECTORSZ - 1))/SECTORSZ) -typedef uint_least32_t secaddr; -#define PRIuSEC PRIuLEAST32 -#define SECLIMIT 0x00400000 + /* convert bytes to * sectors, rounding up */ +typedef uint_least32_t secaddr; /* a type for sector numbers */ +#define PRIuSEC PRIuLEAST32 /* how to print a sector number */ +#define SECLIMIT 0x00400000 /* upper bound on sector numbers */ + +/*----- Diagnostics -------------------------------------------------------*/ -extern const char *prog; +extern const char *prog; /* the program name; set with `set_prog' */ extern void set_prog(const char *p); + /* Set the program name to P, stripping any directory names. */ + extern void vmoan(const char *fmt, va_list ap); extern void vmoan_syserr(int err, const char *fmt, va_list ap); + /* Low-level warning reporting. See `moan' and `moan_syserr'. */ + extern PRINTF_LIKE(1, 2) void moan(const char *fmt, ...); extern PRINTF_LIKE(2, 3) void moan_syserr(int err, const char *fmt, ...); + /* Print a warning message, given as a `printf'-like format string + * FMT and arguments, to standard error. If ERR is nonzero, then + * append a colon and the human-readable description of the `errno' + * value ERR. + */ + extern PRINTF_LIKE(1, 2) NORETURN void bail(const char *fmt, ...); extern PRINTF_LIKE(2, 3) NORETURN void bail_syserr(int err, const char *fmt, ...); + /* Like the corresponding `moan' functions, except that they also + * exit with status code 2. + */ + +/*----- Parsing utilities -------------------------------------------------*/ #define PNF_JUNK 1u extern double parse_float(const char **p_inout, unsigned f, double min, double max, const char *what); extern long parse_int(const char **p_inout, unsigned f, long min, long max, const char *what); + /* Parse a number starting at *P_IN OUT, advancing that pointer past + * it, and return the resulting value. If no number can be read from + * the string, or the resulting number is not between MIN and MAX + * inclusive, or the `PNF_JUNK' bit is clear in F and the number is + * followed by anything other than whitespace, then report a fatal + * error, quoting WHAT as having been expected. + */ + +/*----- System utilities --------------------------------------------------*/ extern void sit(double t); + /* Do nothing for T seconds. As implied by the type, T may be + * fractional. + */ 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 + * `EINTR'. + */ + extern void open_file_on_demand(const char *file, FILE **fp_inout, const char *what); + /* If *FP_INOUT is not null, then do nothing. Otherwise, open FILE + * for writing, storing the resulting stream handle in *FP_INOUT; if + * this can't be done then report a fatal error, quoting WHAT as the + * kind of file. + */ + extern void check_write(FILE *fp, const char *what); + /* Flush any remaining output to FP and check that there were no + * errors. If there were problems, report a fatal error quoting WHAT + * as the kind of file. + */ + extern void carefully_fclose(FILE *fp, const char *what); + /* Flush output to FP and close it, reporting fatal errors as for + * `check_write'. If FP is null, then do nothing. + */ + extern off_t device_size(int fd, const char *file, int *blksz_out); + /* Determine the size of the device referred to by FD. Specifically, + * if FD is a regular file, then this is simply the size of the file; + * if FD is a block device, then this is the size of the block + * device. Return the resulting size, and, in the case of a block + * 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. + */ + +/*----- Progress utilities ------------------------------------------------*/ struct banner_progress_item { + /* A progress item which simply shows a banner message. */ struct progress_item _base; const char *msg; }; -extern struct progress_state progress; +extern struct progress_state progress; /* the shared progress reporter */ extern void show_banner(const char *msg); extern void hide_banner(void); + /* Show or hide a banner reporting a message. If a banner is already + * showing, then `show_banner' just changes the message. + */ + +/*----- DVD utilities -----------------------------------------------------*/ extern void 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? + * + * 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. + */ enum { RAW, IFO, VOB, BUP }; typedef uint_least32_t ident; + /* A convenient name for interesting files on a DVD. It consists of + * three components: + * + * * A `kind', which is `RAW', `IFO', `VOB', or `BUP'. `RAW' is a + * special token which refers to the whole disc; the other kinds + * refer to files in the DVD filesystem with the corresponding + * extensions. + * + * * A `title', which is a number between 0 and 99 inclusive. + * Title zero refers to the video management information and its + * corresponding menu; nonzero numbers refer to video titlesets. + * + * * A `part', which is only relevant for `VOB' files; part 0 + * refers to the menu data, while parts 1 to 9 inclusive refer to + * portions of the video titleset itself. + * + * Components which aren't applicable must be zero, so that idents + * can conveniently be compared as integers (so, specifically, the + * title, if kind is `RAW', and the part, if kind is not `VOB' or + * title is zero. + */ static inline ident mkident(unsigned kind, unsigned title, unsigned part) { return (((ident)kind << 0) | ((ident)title << 8) | ((ident)part << 16)); } static inline unsigned id_kind(ident id) { return ((id >> 0)&0x0ff); } static inline unsigned id_title(ident id) { return ((id >> 8)&0x0ff); } static inline unsigned id_part(ident id) { return ((id >> 16)&0x0ff); } + /* Functions for constructing and picking apart the fields of an + * ident. + */ #define MAXFNSZ (1 + 8 + 1 + 12 + 1) extern void store_filename(char *buf, ident id); + /* Store in BUF the filename corresponding to the ident ID. The + * filename will be at most `MAXFNSZ' bytes long, including the + * terminating zero. + */ #define DIF_MUSTVOLINF 1u #define DIF_MUSTIFOHASH 2u #define MAXIDSZ (32 + 1 + 32 + 1 + 32 + 1) extern int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file); + /* Determine a (hopefully) unique identifier for DVD. The identifier + * consists of two parts: + * + * * the volume name and serial number, from the volume + * information, and + * + * * a cryptographic hash of the `.IFO' files on the disc. + * + * The identifier is written, as plain text, at P, and consists of at + * most `MAXIDSZ' bytes, including the terminating zero. + * + * It's possible that determining either, or both, of these might + * fail: the behaviour is controlled by the `DIF_MUSTVOLINF' and + * `DIF_MUSTIFOHASH' flags in F: if the volume name/serial number, or + * `.IFO' hash, respectively, can't be determined, and the + * corresponding flag is clear, then a placeholder error message is + * written to the output buffer in place of the correct data; if the + * flag is set, then a warning message is printed to standard error + * and -1 is returned. In practice, the `.IFO' hash is more likely + * to be computed successfully, and probably more likely to actually + * be unique. + * + * Returns zero if the identifier was successfully determined, within + * the parameters set by the flags. + */ + +/*----- That's all, folks -------------------------------------------------*/ #endif -- 2.11.0