@@@ dvdrip-upload: change settings while i'm stealing someone else's internet
[dvdrip] / lib.c
diff --git a/lib.c b/lib.c
index 80b1507..5bf0394 100644 (file)
--- 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 <https://www.gnu.org/licenses/>.
+ */
+
+/*----- Header files ------------------------------------------------------*/
+
 #include "lib.h"
 
+/*----- Diagnostics -------------------------------------------------------*/
+
 const char *prog = "<unset>";
 
 void set_prog(const char *p)
@@ -33,6 +62,64 @@ 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)
+{
+  const char *p;
+  char *q;
+  double x;
+  int err;
+
+  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;
@@ -44,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;
@@ -85,6 +191,120 @@ void carefully_fclose(FILE *fp, const char *what)
     bail_syserr(errno, "error writing %s file", what);
 }
 
+off_t device_size(int fd, const char *file, int *blksz_out)
+{
+  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;
+
+static void render_banner_progress(struct progress_item *item,
+                           struct progress_render_state *render)
+{
+  struct banner_progress_item *bi = (struct banner_progress_item *)item;
+
+  progress_putleft(render, " %s", bi->msg);
+  progress_shownotice(render, 4, 7);
+}
+
+void show_banner(const char *msg)
+{
+  banner_progress._base.render = render_banner_progress;
+  progress_additem(&progress, &banner_progress._base);
+  banner_progress.msg = msg;
+  progress_update(&progress);
+}
+
+void hide_banner(void)
+{
+  if (!progress_removeitem(&progress, &banner_progress._base))
+    progress_update(&progress);
+}
+
+/*----- DVD utilities -----------------------------------------------------*/
+
+#ifdef notdef
+static void logfn(void *p, dvd_logger_level_t lev,
+                 const char *fmt, va_list ap)
+{
+  switch (lev) {
+    case DVD_LOGGER_LEVEL_ERROR:
+      fprintf("%s (libdvdread error): ", prog);
+      break;
+    case DVD_LOGGER_LEVEL_WARN:
+      fprintf("%s (libdvdread warning): ", prog);
+      break;
+    default:
+      return;
+  }
+  vfprintf(stderr, fmt, ap);
+  fputc('\n', stderr);
+}
+static const dvd_logger_cb logger = { logfn };
+#endif
+
+int open_dvd(const char *device, int mode,
+            int *fd_out, dvd_reader_t **dvd_out)
+{
+  int fd = -1;
+  dvd_reader_t *dvd = 0;
+  int bannerp = 0, rc;
+
+  for (;;) {
+    fd = open(device, mode);
+    if (fd >= 0 || errno != ENOMEDIUM) break;
+    if (!bannerp) {
+      show_banner("Waiting for disc to be inserted...");
+      bannerp = 1;
+    }
+    sit(0.2);
+  }
+  if (bannerp) hide_banner();
+
+  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) {
+      moan("failed to open DVD on `%s'", device);
+      rc = -1; goto end;
+    }
+  }
+
+  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)) {
@@ -160,78 +380,4 @@ int dvd_id(char *p, dvd_reader_t *dvd, unsigned f, const char *file)
   return (0);
 }
 
-struct progress_state progress = PROGRESS_STATE_INIT;
-static struct banner_progress_item banner_progress;
-
-static void render_banner_progress(struct progress_item *item,
-                           struct progress_render_state *render)
-{
-  struct banner_progress_item *bi = (struct banner_progress_item *)item;
-
-  progress_putleft(render, " %s", bi->msg);
-  progress_shownotice(render, 4, 7);
-}
-
-void show_banner(const char *msg)
-{
-  banner_progress._base.render = render_banner_progress;
-  progress_additem(&progress, &banner_progress._base);
-  banner_progress.msg = msg;
-  progress_update(&progress);
-}
-
-void hide_banner(void)
-{
-  if (!progress_removeitem(&progress, &banner_progress._base))
-    progress_update(&progress);
-}
-
-#ifdef notdef
-static void logfn(void *p, dvd_logger_level_t lev,
-                 const char *fmt, va_list ap)
-{
-  switch (lev) {
-    case DVD_LOGGER_LEVEL_ERROR:
-      fprintf("%s (libdvdread error): ", prog);
-      break;
-    case DVD_LOGGER_LEVEL_WARN:
-      fprintf("%s (libdvdread warning): ", prog);
-      break;
-    default:
-      return;
-  }
-  vfprintf(stderr, fmt, ap);
-  fputc('\n', stderr);
-}
-static const dvd_logger_cb logger = { logfn };
-#endif
-
-void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out)
-{
-  int fd;
-  dvd_reader_t *dvd;
-  int bannerp = 0;
-
-  for (;;) {
-    fd = open(device, O_RDONLY);
-    if (fd >= 0 || errno != ENOMEDIUM) break;
-    if (!bannerp) {
-      show_banner("Waiting for disc to be inserted...");
-      bannerp = 1;
-    }
-    sit(0.2);
-  }
-  if (bannerp) hide_banner();
-  if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device);
-  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 (fd_out) *fd_out = fd;
-  else close(fd);
-}
+/*----- That's all, folks -------------------------------------------------*/