/src/ghostpdl/contrib/pcl3/eprn/pagecount.c
Line | Count | Source (jump to first uncovered line) |
1 | | /****************************************************************************** |
2 | | File: $Id: pagecount.c,v 1.6 2000/10/07 17:48:49 Martin Rel $ |
3 | | Contents: Simple (page) count file facility on UNIX |
4 | | Author: Martin Lottermoser, Greifswaldstrasse 28, 38124 Braunschweig, |
5 | | Germany. E-mail: Martin.Lottermoser@t-online.de. |
6 | | |
7 | | ******************************************************************************* |
8 | | * * |
9 | | * Copyright (C) 1997, 1998, 2000 by Martin Lottermoser * |
10 | | * All rights reserved * |
11 | | * * |
12 | | ******************************************************************************/ |
13 | | |
14 | | /* This file should be ignored under windows */ |
15 | | #ifdef _MSC_VER |
16 | | int dummy; |
17 | | #else |
18 | | |
19 | | /*****************************************************************************/ |
20 | | |
21 | | #ifndef _XOPEN_SOURCE |
22 | | #define _XOPEN_SOURCE 500 |
23 | | #endif |
24 | | |
25 | | #include "std.h" |
26 | | |
27 | | /* Standard headers */ |
28 | | #include <errno.h> |
29 | | #include <stdio.h> |
30 | | #include <stdlib.h> |
31 | | #include <string.h> |
32 | | #include <sys/types.h> |
33 | | #include <unistd.h> |
34 | | #include <fcntl.h> |
35 | | |
36 | | #include "gp.h" |
37 | | |
38 | | /* Specific headers */ |
39 | | #include "pagecount.h" |
40 | | |
41 | | /*****************************************************************************/ |
42 | | |
43 | 0 | #define ERRPREFIX "?-E Pagecount module: " |
44 | 0 | #define WARNPREFIX "?-W Pagecount module: " |
45 | | |
46 | | /****************************************************************************** |
47 | | |
48 | | Function: lock_file |
49 | | |
50 | | This function locks the specified file 'f' with a lock of type 'lock_type'. |
51 | | 'filename' is merely used for error messages. |
52 | | |
53 | | The function returns zero on success and issues error messages on stderr |
54 | | if it fails. |
55 | | |
56 | | ******************************************************************************/ |
57 | | |
58 | | static int lock_file(const char *filename, gp_file *f, int lock_type) |
59 | 0 | { |
60 | 0 | int |
61 | 0 | fd, |
62 | 0 | rc, |
63 | 0 | tries; |
64 | 0 | struct flock cmd; |
65 | | |
66 | | /* Obtain file descriptor */ |
67 | 0 | fd = fileno(gp_get_file(f)); |
68 | 0 | if (fd == -1) { |
69 | 0 | fprintf(stderr, ERRPREFIX "Cannot obtain file descriptor (%s).\n", |
70 | 0 | strerror(errno)); |
71 | 0 | gp_fclose(f); |
72 | 0 | return -1; |
73 | 0 | } |
74 | | |
75 | | /* Lock the file */ |
76 | 0 | cmd.l_type = lock_type; |
77 | 0 | cmd.l_whence = SEEK_SET; /* 'start' is interpreted from start of file */ |
78 | 0 | cmd.l_start = 0; |
79 | 0 | cmd.l_len = 0; /* until EOF */ |
80 | 0 | tries = 1; |
81 | 0 | while ((rc = fcntl(fd, F_SETLK, &cmd)) != 0 && tries < 3) { |
82 | 0 | tries++; |
83 | 0 | sleep(1); |
84 | 0 | } |
85 | 0 | if (rc != 0) { |
86 | 0 | fprintf(stderr, ERRPREFIX |
87 | 0 | "Cannot obtain lock on page count file `%s' after %d attempts.\n", |
88 | 0 | filename, tries); |
89 | 0 | return -1; |
90 | 0 | } |
91 | | |
92 | 0 | return 0; |
93 | 0 | } |
94 | | |
95 | | /****************************************************************************** |
96 | | |
97 | | Function: read_count |
98 | | |
99 | | This function reads the contents of the open page count file. |
100 | | |
101 | | ******************************************************************************/ |
102 | | |
103 | | static int read_count(const gs_memory_t *mem, const char *filename, gp_file *f, unsigned long *count) |
104 | 0 | { |
105 | 0 | char text[32]; |
106 | 0 | char *t = text; |
107 | 0 | while (t-text < sizeof(text)-1) { |
108 | 0 | int c = gp_fgetc(f); |
109 | 0 | if (c < '0' || c > '9') { |
110 | 0 | if (c < 0 || t != text) |
111 | 0 | break; |
112 | 0 | } else |
113 | 0 | *t++ = c; |
114 | 0 | } |
115 | 0 | *t++ = 0; |
116 | 0 | if (sscanf(text, "%lu", count) != 1) { |
117 | 0 | if (gp_feof(f) && !gp_ferror(f)) *count = 0; /* Empty file */ |
118 | 0 | else { |
119 | 0 | errprintf(mem, ERRPREFIX "Strange contents in page count file `%s'.\n", |
120 | 0 | filename); |
121 | 0 | return -1; |
122 | 0 | } |
123 | 0 | } |
124 | | |
125 | 0 | return 0; |
126 | 0 | } |
127 | | |
128 | | /****************************************************************************** |
129 | | |
130 | | Function: pcf_getcount |
131 | | |
132 | | This routine reads the page count file 'filename' and returns the count read |
133 | | in '*count'. If the file does not exist, the value 0 is assumed. |
134 | | |
135 | | The function returns zero on success. On error, a message will have been |
136 | | issued on stderr. |
137 | | |
138 | | ******************************************************************************/ |
139 | | |
140 | | int pcf_getcount(const gs_memory_t *mem, const char *filename, unsigned long *count) |
141 | 0 | { |
142 | 0 | gp_file *f; |
143 | | |
144 | | /* Should we use a page count file? */ |
145 | 0 | if (filename == NULL || *filename == '\0' || count == NULL) return 0; |
146 | | |
147 | | /* If the file does not exist, the page count is taken to be zero. */ |
148 | 0 | if (access(filename, F_OK) != 0) { |
149 | 0 | *count = 0; |
150 | 0 | return 0; |
151 | 0 | } |
152 | | |
153 | | /* Open the file */ |
154 | 0 | if ((f = gp_fopen(mem, filename, "r")) == NULL) { |
155 | 0 | errprintf(mem, ERRPREFIX "Cannot open page count file `%s': %s.\n", |
156 | 0 | filename, strerror(errno)); |
157 | 0 | return -1; |
158 | 0 | } |
159 | | |
160 | | /* Lock the file for reading (shared lock) */ |
161 | 0 | if (lock_file(filename, f, F_RDLCK) != 0) { |
162 | 0 | gp_fclose(f); |
163 | 0 | return 1; |
164 | 0 | } |
165 | | |
166 | | /* Read the contents */ |
167 | 0 | if (read_count(mem, filename, f, count) != 0) { |
168 | 0 | gp_fclose(f); |
169 | 0 | return -1; |
170 | 0 | } |
171 | | |
172 | | /* Close the file, releasing the lock */ |
173 | 0 | gp_fclose(f); |
174 | |
|
175 | 0 | return 0; |
176 | 0 | } |
177 | | |
178 | | /****************************************************************************** |
179 | | |
180 | | Function: pcf_inccount |
181 | | |
182 | | This function opens the page count file 'filename' and increases the number |
183 | | stored there by 'by'. If the file does not exist it will be created and |
184 | | treated as if had contained 0. |
185 | | |
186 | | The function returns zero on success and issues error messages on stderr if |
187 | | it fails. |
188 | | |
189 | | ******************************************************************************/ |
190 | | |
191 | | int pcf_inccount(const gs_memory_t *mem, const char *filename, unsigned long by) |
192 | 0 | { |
193 | 0 | gp_file *f; |
194 | 0 | int rc; |
195 | 0 | unsigned long count; |
196 | | |
197 | | /* Should we use a page count file? */ |
198 | 0 | if (filename == NULL || *filename == '\0') return 0; |
199 | | |
200 | | /* Open the file. We need to access the old contents: this excludes the "w", |
201 | | "a" and "w+" modes. The operation should create the file if it doesn't |
202 | | exist: this excludes the "r" and "r+" modes. Hence the only choice is "a+". |
203 | | Note that this procedure makes it unavoidable to accept an empty file as |
204 | | being valid. This is, however, anyway necessary because of the fopen() and |
205 | | fcntl() calls being not in one transaction. |
206 | | */ |
207 | 0 | if ((f = gp_fopen(mem, filename, "a+")) == NULL) { |
208 | 0 | errprintf(mem, ERRPREFIX "Cannot open page count file `%s': %s.\n", |
209 | 0 | filename, strerror(errno)); |
210 | 0 | return 1; |
211 | 0 | } |
212 | | |
213 | | /* Lock the file for writing (exclusively) */ |
214 | 0 | if (lock_file(filename, f, F_WRLCK) != 0) { |
215 | 0 | gp_fclose(f); |
216 | 0 | return 1; |
217 | 0 | } |
218 | | |
219 | | /* Reposition on the beginning. fopen() with "a" as above opens the file at |
220 | | EOF. */ |
221 | 0 | if (gp_fseek(f, 0L, SEEK_SET) != 0) { |
222 | 0 | errprintf(mem, ERRPREFIX "fseek() failed on `%s': %s.\n", |
223 | 0 | filename, strerror(gp_ferror(f))); |
224 | 0 | gp_fclose(f); |
225 | 0 | return 1; |
226 | 0 | } |
227 | | |
228 | | /* Read the contents */ |
229 | 0 | if (read_count(mem, filename, f, &count) != 0) { |
230 | 0 | gp_fclose(f); |
231 | 0 | return -1; |
232 | 0 | } |
233 | | |
234 | | /* Rewrite the file */ |
235 | 0 | rc = 0; |
236 | 0 | { |
237 | 0 | gp_file *f1 = gp_fopen(mem, filename, "w"); |
238 | |
|
239 | 0 | if (f1 == NULL) { |
240 | 0 | errprintf(mem, ERRPREFIX |
241 | 0 | "Error opening page count file `%s' a second time: %s.\n", |
242 | 0 | filename, strerror(errno)); |
243 | 0 | rc = 1; |
244 | 0 | } |
245 | 0 | else { |
246 | 0 | if (gp_fprintf(f1, "%lu\n", count + by) < 0) { |
247 | 0 | errprintf(mem, ERRPREFIX "Error writing to `%s': %s.\n", |
248 | 0 | filename, strerror(gp_ferror(f1))); |
249 | 0 | rc = -1; |
250 | 0 | } |
251 | 0 | if (gp_fclose(f1) != 0) { |
252 | 0 | errprintf(mem, |
253 | 0 | ERRPREFIX "Error closing `%s' after writing: %s.\n", |
254 | 0 | filename, strerror(gp_ferror(f1))); |
255 | 0 | rc = -1; |
256 | 0 | } |
257 | 0 | } |
258 | 0 | } |
259 | | |
260 | | /* Close the file (this releases the lock) */ |
261 | 0 | if (gp_fclose(f) != 0) |
262 | 0 | errprintf(mem, WARNPREFIX "Error closing `%s': %s.\n", |
263 | 0 | filename, strerror(gp_ferror(f))); |
264 | |
|
265 | 0 | return rc; |
266 | 0 | } |
267 | | |
268 | | #ifdef TEST |
269 | | /****************************************************************************** |
270 | | |
271 | | Function: main |
272 | | |
273 | | This routine can be used for testing. |
274 | | |
275 | | ******************************************************************************/ |
276 | | |
277 | | int main(int argc, char **argv) |
278 | | { |
279 | | const char *filename = "pages.count"; |
280 | | int rc; |
281 | | unsigned long |
282 | | by = 1, |
283 | | count = 0; |
284 | | |
285 | | if (argc > 1) { |
286 | | if (sscanf(argv[1], "%lu", &by) != 1) { |
287 | | fprintf(stderr, ERRPREFIX "Illegal number: `%s'.\n", argv[1]); |
288 | | exit(EXIT_FAILURE); |
289 | | } |
290 | | if (argc > 2) filename = argv[2]; |
291 | | if (argc > 3) { |
292 | | fprintf(stderr, ERRPREFIX "Too many arguments.\n"); |
293 | | exit(EXIT_FAILURE); |
294 | | } |
295 | | } |
296 | | |
297 | | rc = pcf_getcount(filename, &count); |
298 | | if (rc == 0) |
299 | | printf("Initial count returned by pcf_getcount(): %lu.\n", count); |
300 | | else fprintf(stderr, "? Error from pcf_getcount(), return code is %d.\n", rc); |
301 | | |
302 | | rc = pcf_inccount(filename, by); |
303 | | |
304 | | exit(rc == 0? EXIT_SUCCESS: EXIT_FAILURE); |
305 | | } |
306 | | |
307 | | #endif /* TEST */ |
308 | | |
309 | | #endif /* _MSC_VER */ |