Coverage Report

Created: 2025-06-24 07:01

/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 */