chiark / gitweb /
dvd-sector-copy.c, lib.[ch]: Move the file hacking functions to the library.
[dvdrip] / lib.c
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
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
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 }