3 * Common functions for the DVDrip C utilities.
5 * (c) 2022 Mark Wooding
8 /*----- Licensing notice --------------------------------------------------*
10 * This file is part of the DVD ripping toolset.
12 * DVDrip is free software: you can redistribute it and/or modify it
13 * under the terms of the GNU General Public License as published by the
14 * Free Software Foundation; either version 3 of the License, or (at your
15 * option) any later version.
17 * DVDrip is distributed in the hope that it will be useful, but WITHOUT
18 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
19 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
22 * You should have received a copy of the GNU General Public License
23 * along with DVDrip. If not, see <https://www.gnu.org/licenses/>.
26 /*----- Header files ------------------------------------------------------*/
30 /*----- Diagnostics -------------------------------------------------------*/
32 const char *prog
= "<unset>";
34 void set_prog(const char *p
)
35 { const char *q
= strrchr(p
, '/'); prog
= q ? q
+ 1 : p
; }
37 void vmoan(const char *fmt
, va_list ap
)
38 { vmoan_syserr(0, fmt
, ap
); }
40 void vmoan_syserr(int err
, const char *fmt
, va_list ap
)
42 fprintf(stderr
, "%s: ", prog
);
43 vfprintf(stderr
, fmt
, ap
);
44 if (err
) fprintf(stderr
, ": %s", strerror(errno
));
48 void moan(const char *fmt
, ...)
49 { va_list ap
; va_start(ap
, fmt
); vmoan(fmt
, ap
); va_end(ap
); }
51 void moan_syserr(int err
, const char *fmt
, ...)
52 { va_list ap
; va_start(ap
, fmt
); vmoan_syserr(err
, fmt
, ap
); va_end(ap
); }
54 void bail(const char *fmt
, ...)
55 { va_list ap
; va_start(ap
, fmt
); vmoan(fmt
, ap
); va_end(ap
); exit(2); }
57 void bail_syserr(int err
, const char *fmt
, ...)
61 va_start(ap
, fmt
); vmoan_syserr(err
, fmt
, ap
); va_end(ap
);
65 /*----- Parsing utilities -------------------------------------------------*/
67 double parse_float(const char **p_inout
, unsigned f
,
68 double min
, double max
, const char *what
)
75 err
= errno
; errno
= 0;
78 if (errno
|| x
< min
|| x
> max
|| (!(f
&PNF_JUNK
) && *q
))
79 bail("bad %s `%s'", what
, p
);
80 *p_inout
= q
; errno
= err
;
84 long parse_int(const char **p_inout
, unsigned f
,
85 long min
, long max
, const char *what
)
92 err
= errno
; errno
= 0;
94 x
= strtoul(p
, &q
, 0);
95 if (errno
|| x
< min
|| x
> max
|| (!(f
&PNF_JUNK
) && *q
))
96 bail("bad %s `%s'", what
, p
);
97 *p_inout
= q
; errno
= err
;
101 /*----- Resizing buffers and arrays ---------------------------------------*/
103 void buf__grow(struct buf
*b
)
105 b
->sz
= b
->sz ?
2*b
->sz
: 32;
106 b
->p
= realloc(b
->p
, b
->sz
);
107 if (!b
->p
) bail("out of memory allocating %zu bytes", b
->sz
);
110 void *vec__grow(void *p
, size_t esz
, size_t *sz_inout
)
112 size_t sz
= *sz_inout
, want
;
116 p
= realloc(p
, want
);
117 if (!p
) bail("out of memory allocating %zu bytes", want
);
118 *sz_inout
= sz
; return (p
);
121 /*----- System utilities --------------------------------------------------*/
126 double whole
= floor(t
);
129 tv
.tv_sec
= whole
; tv
.tv_usec
= floor((t
- whole
)*1.0e6
) + 1;
130 if (select(0, 0, 0, 0, &tv
) < 0) bail_syserr(errno
, "failed to sleep");
134 double tvdiff(const struct timeval
*tv_lo
, const struct timeval
*tv_hi
)
136 return ((tv_hi
->tv_sec
- tv_lo
->tv_sec
) +
137 (tv_hi
->tv_usec
- tv_lo
->tv_usec
)/1.0e6
);
140 int read_line(FILE *fp
, struct buf
*b
)
148 do { buf_putc(b
, ch
); ch
= getc(fp
); } while (ch
!= EOF
&& ch
!= '\n');
153 void carefully_write(int fd
, const void *buf
, size_t sz
)
155 const unsigned char *p
= buf
;
160 n
= write(fd
, p
, sz
);
162 if (errno
== EINTR
) continue;
163 bail_syserr(errno
, "failed to write to output file");
165 if (!n
) bail("unexpected short write to output file");
170 void open_file_on_demand(const char *file
, FILE **fp_inout
, const char *what
)
175 fp
= fopen(file
, "w");
176 if (!fp
) bail_syserr(errno
, "failed to open %s file `%s'", what
, file
);
177 fprintf(fp
, "## %s\n\n", what
);
182 void check_write(FILE *fp
, const char *what
)
185 if (ferror(fp
)) bail_syserr(errno
, "error writing %s file", what
);
188 void carefully_fclose(FILE *fp
, const char *what
)
190 if (fp
&& (ferror(fp
) || fclose(fp
)))
191 bail_syserr(errno
, "error writing %s file", what
);
194 off_t
device_size(int fd
, const char *file
, int *blksz_out
)
200 bail_syserr(errno
, "failed to obtain status for `%s'", file
);
201 if (S_ISREG(st
.st_mode
))
203 else if (S_ISBLK(st
.st_mode
)) {
204 if (ioctl(fd
, BLKGETSIZE64
, &volsz
))
205 bail_syserr(errno
, "failed to get volume size for `%s'", file
);
206 if (ioctl(fd
, BLKSSZGET
, blksz_out
))
207 bail_syserr(errno
, "failed to get block size for `%s'", file
);
209 bail("can't read size for `%s': expected file or block device", file
);
210 return ((off_t
)volsz
);
213 /*----- Progress utilities ------------------------------------------------*/
215 struct progress_state progress
= PROGRESS_STATE_INIT
;
216 static struct banner_progress_item banner_progress
;
218 static void render_banner_progress(struct progress_item
*item
,
219 struct progress_render_state
*render
)
221 struct banner_progress_item
*bi
= (struct banner_progress_item
*)item
;
223 progress_putleft(render
, " %s", bi
->msg
);
224 progress_shownotice(render
, 4, 7);
227 void show_banner(const char *msg
)
229 banner_progress
._base
.render
= render_banner_progress
;
230 progress_additem(&progress
, &banner_progress
._base
);
231 banner_progress
.msg
= msg
;
232 progress_update(&progress
);
235 void hide_banner(void)
237 if (!progress_removeitem(&progress
, &banner_progress
._base
))
238 progress_update(&progress
);
241 /*----- DVD utilities -----------------------------------------------------*/
244 static void logfn(void *p
, dvd_logger_level_t lev
,
245 const char *fmt
, va_list ap
)
248 case DVD_LOGGER_LEVEL_ERROR
:
249 fprintf("%s (libdvdread error): ", prog
);
251 case DVD_LOGGER_LEVEL_WARN
:
252 fprintf("%s (libdvdread warning): ", prog
);
257 vfprintf(stderr
, fmt
, ap
);
260 static const dvd_logger_cb logger
= { logfn
};
263 int open_dvd(const char *device
, int mode
,
264 int *fd_out
, dvd_reader_t
**dvd_out
)
267 dvd_reader_t
*dvd
= 0;
271 fd
= open(device
, mode
);
272 if (fd
>= 0 || errno
!= ENOMEDIUM
) break;
274 show_banner("Waiting for disc to be inserted...");
279 if (bannerp
) hide_banner();
282 moan_syserr(errno
, "failed to open device `%s'", device
);
288 dvd
= DVDOpen2(0, &logger
, device
);
290 dvd
= DVDOpen(device
);
293 moan("failed to open DVD on `%s'", device
);
298 if (fd_out
) { *fd_out
= fd
; fd
= -1; }
299 if (dvd_out
) { *dvd_out
= dvd
; dvd
= 0; }
303 if (fd
>= 0) close(fd
);
308 void store_filename(char *buf
, ident id
)
310 switch (id_kind(id
)) {
312 sprintf(buf
, "#<raw device>");
315 if (!id_title(id
)) sprintf(buf
, "/VIDEO_TS/VIDEO_TS.IFO");
316 else sprintf(buf
, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id
));
319 if (!id_title(id
)) sprintf(buf
, "/VIDEO_TS/VIDEO_TS.BUP");
320 else sprintf(buf
, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id
));
323 if (!id_title(id
)) sprintf(buf
, "/VIDEO_TS/VIDEO_TS.VOB");
325 sprintf(buf
, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id
), id_part(id
));
332 static char *copy_string(char *p
, const char *q
)
334 while (*q
) *p
++ = *q
++;
338 static char *copy_hex(char *p
, const unsigned char *q
, size_t sz
)
341 sprintf(p
, "%02x", *q
);
347 int dvd_id(char *p
, dvd_reader_t
*dvd
, unsigned f
, const char *file
)
350 unsigned char volsetid
[16], discid
[16];
354 rc
= DVDUDFVolumeInfo(dvd
,
355 volid
, sizeof(volid
),
356 volsetid
, sizeof(volsetid
));
358 p
= copy_string(p
, volid
);
360 for (n
= sizeof(volsetid
); n
&& !volsetid
[n
- 1]; n
--);
361 p
= copy_hex(p
, volsetid
, n
);
362 } else if (f
&DIF_MUSTVOLINF
) {
363 if (file
) moan("failed to read volume info for `%s'", file
);
364 else moan("failed to read volume info");
367 p
= copy_string(p
, "<error reading volume info>");
370 rc
= DVDDiscID(dvd
, discid
);
372 p
= copy_hex(p
, discid
, sizeof(discid
));
373 else if (f
&DIF_MUSTIFOHASH
) {
374 if (file
) moan("failed to determine disc id of `%s'", file
);
375 else moan("failed to determine disc id");
378 p
= copy_string(p
, "<error reading disc-id>");
383 /*----- That's all, folks -------------------------------------------------*/