Commit | Line | Data |
---|---|---|
dc53ebfa MW |
1 | #include "lib.h" |
2 | ||
3 | const char *prog = "<unset>"; | |
4 | ||
5 | void set_prog(const char *p) | |
6 | { const char *q = strrchr(p, '/'); prog = q ? q + 1 : p; } | |
7 | ||
8 | void vmoan(const char *fmt, va_list ap) | |
9 | { fprintf(stderr, "%s: ", prog); vfprintf(stderr, fmt, ap); } | |
10 | ||
11 | __attribute__((format(printf, 1, 2))) | |
12 | void moan(const char *fmt, ...) | |
13 | { | |
14 | va_list ap; | |
15 | ||
16 | va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); | |
17 | fputc('\n', stderr); | |
18 | } | |
19 | ||
20 | __attribute__((noreturn, format(printf, 1, 2))) | |
21 | void bail(const char *fmt, ...) | |
22 | { | |
23 | va_list ap; | |
24 | ||
25 | va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); | |
26 | fputc('\n', stderr); | |
27 | exit(2); | |
28 | } | |
29 | ||
30 | __attribute__((noreturn, format(printf, 2, 3))) | |
31 | void bail_syserr(int err, const char *fmt, ...) | |
32 | { | |
33 | va_list ap; | |
34 | ||
35 | va_start(ap, fmt); vmoan(fmt, ap); va_end(ap); | |
36 | if (err) fprintf(stderr, ": %s", strerror(errno)); | |
37 | fputc('\n', stderr); | |
38 | exit(2); | |
39 | } | |
40 | ||
41 | void sit(double t) | |
42 | { | |
43 | struct timeval tv; | |
44 | double whole = floor(t); | |
45 | ||
46 | if (t) { | |
47 | tv.tv_sec = whole; tv.tv_usec = floor((t - whole)*1.0e6) + 1; | |
48 | if (select(0, 0, 0, 0, &tv) < 0) bail_syserr(errno, "failed to sleep"); | |
49 | } | |
50 | } | |
51 | ||
00a5be1d MW |
52 | void carefully_write(int fd, const void *buf, size_t sz) |
53 | { | |
54 | const unsigned char *p = buf; | |
55 | ssize_t n; | |
56 | ||
57 | if (fd < 0) return; | |
58 | while (sz) { | |
59 | n = write(fd, p, sz); | |
60 | if (n < 0) { | |
61 | if (errno == EINTR) continue; | |
62 | bail_syserr(errno, "failed to write to output file"); | |
63 | } | |
64 | if (!n) bail("unexpected short write to output file"); | |
65 | p += n; sz -= n; | |
66 | } | |
67 | } | |
68 | ||
69 | void open_file_on_demand(const char *file, FILE **fp_inout, const char *what) | |
70 | { | |
71 | FILE *fp; | |
72 | ||
73 | if (!*fp_inout) { | |
74 | fp = fopen(file, "w"); | |
75 | if (!fp) bail_syserr(errno, "failed to open %s file `%s'", what, file); | |
76 | fprintf(fp, "## %s\n\n", what); | |
77 | *fp_inout = fp; | |
78 | } | |
79 | } | |
80 | ||
81 | void check_write(FILE *fp, const char *what) | |
82 | { | |
83 | fflush(fp); | |
84 | if (ferror(fp)) bail_syserr(errno, "error writing %s file", what); | |
85 | } | |
86 | ||
87 | void carefully_fclose(FILE *fp, const char *what) | |
88 | { | |
89 | if (fp && (ferror(fp) || fclose(fp))) | |
90 | bail_syserr(errno, "error writing %s file", what); | |
91 | } | |
92 | ||
dc53ebfa MW |
93 | void store_filename(char *buf, ident id) |
94 | { | |
95 | switch (id_kind(id)) { | |
96 | case RAW: | |
97 | sprintf(buf, "#<raw device>"); | |
98 | break; | |
99 | case IFO: | |
100 | if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.IFO"); | |
101 | else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.IFO", id_title(id)); | |
102 | break; | |
103 | case BUP: | |
104 | if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.BUP"); | |
105 | else sprintf(buf, "/VIDEO_TS/VTS_%02u_0.BUP", id_title(id)); | |
106 | break; | |
107 | case VOB: | |
108 | if (!id_title(id)) sprintf(buf, "/VIDEO_TS/VIDEO_TS.VOB"); | |
109 | else | |
110 | sprintf(buf, "/VIDEO_TS/VTS_%02u_%u.VOB", id_title(id), id_part(id)); | |
111 | break; | |
112 | default: | |
113 | abort(); | |
114 | } | |
115 | } | |
116 | ||
117 | struct progress_state progress = PROGRESS_STATE_INIT; | |
118 | static struct banner_progress_item banner_progress; | |
119 | ||
120 | static void render_banner_progress(struct progress_item *item, | |
121 | struct progress_render_state *render) | |
122 | { | |
123 | struct banner_progress_item *bi = (struct banner_progress_item *)item; | |
124 | ||
125 | progress_putleft(render, " %s", bi->msg); | |
126 | progress_shownotice(render, 4, 7); | |
127 | } | |
128 | ||
129 | void show_banner(const char *msg) | |
130 | { | |
131 | banner_progress._base.render = render_banner_progress; | |
132 | progress_additem(&progress, &banner_progress._base); | |
133 | banner_progress.msg = msg; | |
134 | progress_update(&progress); | |
135 | } | |
136 | ||
137 | void hide_banner(void) | |
138 | { | |
139 | if (!progress_removeitem(&progress, &banner_progress._base)) | |
140 | progress_update(&progress); | |
141 | } | |
142 | ||
143 | #ifdef notdef | |
144 | static void logfn(void *p, dvd_logger_level_t lev, | |
145 | const char *fmt, va_list ap) | |
146 | { | |
147 | switch (lev) { | |
148 | case DVD_LOGGER_LEVEL_ERROR: | |
149 | fprintf("%s (libdvdread error): ", prog); | |
150 | break; | |
151 | case DVD_LOGGER_LEVEL_WARN: | |
152 | fprintf("%s (libdvdread warning): ", prog); | |
153 | break; | |
154 | default: | |
155 | return; | |
156 | } | |
157 | vfprintf(stderr, fmt, ap); | |
158 | fputc('\n', stderr); | |
159 | } | |
160 | static const dvd_logger_cb logger = { logfn }; | |
161 | #endif | |
162 | ||
163 | void open_dvd(const char *device, int *fd_out, dvd_reader_t **dvd_out) | |
164 | { | |
165 | int fd; | |
166 | dvd_reader_t *dvd; | |
167 | int bannerp = 0; | |
168 | ||
169 | for (;;) { | |
170 | fd = open(device, O_RDONLY); | |
171 | if (fd >= 0 || errno != ENOMEDIUM) break; | |
172 | if (!bannerp) { | |
173 | show_banner("Waiting for disc to be inserted..."); | |
174 | bannerp = 1; | |
175 | } | |
176 | sit(0.2); | |
177 | } | |
178 | if (bannerp) hide_banner(); | |
179 | if (fd < 0) bail_syserr(errno, "failed to open device `%s'", device); | |
180 | if (dvd_out) { | |
181 | #ifdef notdef | |
182 | dvd = DVDOpen2(0, &logger, device); | |
183 | #else | |
184 | dvd = DVDOpen(device); | |
185 | #endif | |
186 | if (!dvd) bail("failed to open DVD on `%s'", device); | |
187 | *dvd_out = dvd; | |
188 | } | |
189 | if (fd_out) *fd_out = fd; | |
190 | else close(fd); | |
191 | } |