dvd-info.c: Don't forget to dump the last titleset.
[dvdrip] / lib.c
diff --git a/lib.c b/lib.c
index 7fecbc4..4f2950c 100644 (file)
--- a/lib.c
+++ b/lib.c
@@ -6,36 +6,65 @@ 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, ...)
+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);
 }
 
 void sit(double t)
@@ -90,6 +119,25 @@ 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);
+}
+
 void store_filename(char *buf, ident id)
 {
   switch (id_kind(id)) {
@@ -114,6 +162,57 @@ void store_filename(char *buf, ident id)
   }
 }
 
+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, "<error reading volume info>");
+
+  *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, "<error reading disc-id>");
+
+  return (0);
+}
+
 struct progress_state progress = PROGRESS_STATE_INIT;
 static struct banner_progress_item banner_progress;