Coverage Report

Created: 2026-02-14 07:03

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/gdbm/tools/pagerfile.c
Line
Count
Source
1
/* This file is part of GDBM, the GNU data base manager.
2
   Copyright (C) 2024-2025 Free Software Foundation, Inc.
3
4
   GDBM is free software; you can redistribute it and/or modify
5
   it under the terms of the GNU General Public License as published by
6
   the Free Software Foundation; either version 3, or (at your option)
7
   any later version.
8
9
   GDBM is distributed in the hope that it will be useful,
10
   but WITHOUT ANY WARRANTY; without even the implied warranty of
11
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12
   GNU General Public License for more details.
13
14
   You should have received a copy of the GNU General Public License
15
   along with GDBM. If not, see <http://www.gnu.org/licenses/>.   */
16
17
#include "autoconf.h"
18
#include <stdio.h>
19
#include <stdarg.h>
20
#include "gdbmtool.h"
21
22
int
23
pager_flush (struct pagerfile *pfp)
24
2.45M
{
25
2.45M
  if (pfp->bufsize > 0)
26
2.45M
    {
27
2.45M
      if (fwrite (pfp->bufbase, pfp->bufsize, 1, pfp->stream) != 1)
28
0
  return -1;
29
2.45M
      pfp->bufsize = 0;
30
2.45M
    }
31
2.45M
  if (fflush (pfp->stream))
32
0
    return -1;
33
2.45M
  return 0;
34
2.45M
}
35
36
static int
37
pager_checklines (struct pagerfile *pfp)
38
0
{
39
0
  if (pfp->nlines > pfp->maxlines)
40
0
    {
41
0
      FILE *pagfp = popen (pfp->pager, "w");
42
0
      if (!pagfp)
43
0
  {
44
0
    terror (_("cannot run pager `%s': %s"), pfp->pager, strerror (errno));
45
0
    pfp->mode = mode_transparent;
46
0
  }
47
0
      else
48
0
  {
49
0
    pfp->mode = mode_pager;
50
0
    pfp->stream = pagfp;
51
0
  }
52
0
      return pager_flush (pfp);
53
0
    }
54
0
  return 0;
55
0
}
56
57
static ssize_t
58
memccount (char const *str, int c, size_t len)
59
0
{
60
0
  ssize_t n = 0;
61
0
  for (; len > 0; len--, str++)
62
0
    if (*str == c)
63
0
      n++;
64
0
  return n;
65
0
}
66
67
ssize_t
68
pager_write (struct pagerfile *pfp, const char *buffer, size_t size)
69
125k
{
70
125k
  if (pfp->mode != mode_initial)
71
125k
    {
72
125k
      return fwrite (buffer, 1, size, pfp->stream);
73
125k
    }
74
  
75
0
  while (pfp->bufsize + size > pfp->bufmax)
76
0
    pfp->bufbase = e2nrealloc (pfp->bufbase, &pfp->bufmax, 1);
77
0
  memcpy (pfp->bufbase + pfp->bufsize, buffer, size);
78
0
  pfp->bufsize += size;
79
0
  pfp->nlines += memccount (buffer, '\n', size);
80
81
0
  if (pager_checklines (pfp))
82
0
    return -1;
83
  
84
0
  return size;
85
0
}
86
87
ssize_t
88
pager_writez (struct pagerfile *pfp, const char *str)
89
13.5k
{
90
13.5k
  return pager_write (pfp, str, strlen (str));
91
13.5k
}
92
93
int
94
pager_putc (struct pagerfile *pfp, int c)
95
8.62k
{
96
8.62k
  char buf[1];
97
8.62k
  buf[0] = c;
98
8.62k
  return pager_write (pfp, buf, 1);
99
8.62k
}
100
101
ssize_t
102
pager_writeln (struct pagerfile *pfp, const char *str)
103
11.7k
{
104
11.7k
  ssize_t ret = pager_writez (pfp, str);
105
11.7k
  if (ret > 0)
106
11.7k
    {
107
11.7k
      if (pager_write (pfp, "\n", 1) == 1)
108
11.7k
  ret++;
109
11.7k
    }
110
11.7k
  return ret;
111
11.7k
}
112
113
int
114
pager_vprintf (struct pagerfile *pfp, const char *fmt, va_list ap)
115
2.45M
{
116
2.45M
  ssize_t ret;
117
  
118
2.45M
  if (!pfp->bufbase)
119
11.1k
    {
120
11.1k
      if (pfp->bufmax == 0)
121
11.1k
  pfp->bufmax = 512;
122
      
123
11.1k
      pfp->bufbase = ecalloc (1, pfp->bufmax);
124
11.1k
    }
125
  
126
2.45M
  for (;;)
127
2.45M
    {
128
2.45M
      va_list aq;
129
2.45M
      ssize_t n;
130
2.45M
      char *bufptr = pfp->bufbase + pfp->bufsize;
131
2.45M
      size_t buflen = pfp->bufmax - pfp->bufsize;
132
      
133
2.45M
      va_copy (aq, ap);
134
2.45M
      n = vsnprintf (bufptr, buflen, fmt, aq);
135
2.45M
      va_end (aq);
136
2.45M
      if (n < 0 || n >= buflen || !memchr (bufptr, '\0', n + 1))
137
0
  {
138
0
    pfp->bufbase = e2nrealloc (pfp->bufbase, &pfp->bufmax, 1);
139
0
  }
140
2.45M
      else
141
2.45M
  {
142
2.45M
    if (pfp->mode == mode_initial)
143
0
      pfp->nlines += memccount (bufptr, '\n', n);
144
      
145
2.45M
    ret = n;
146
2.45M
    pfp->bufsize += n;
147
2.45M
    break;
148
2.45M
  }
149
2.45M
    }
150
151
2.45M
  if (pfp->mode == mode_initial)
152
0
    ret = pager_checklines (pfp);
153
2.45M
  else
154
2.45M
    ret = pager_flush (pfp);
155
156
2.45M
  return ret;
157
2.45M
}
158
159
int
160
pager_printf (struct pagerfile *pfp, const char *fmt, ...)
161
2.45M
{
162
2.45M
  va_list ap;
163
2.45M
  int ret;
164
  
165
2.45M
  va_start (ap, fmt);
166
2.45M
  ret = pager_vprintf (pfp, fmt, ap);
167
2.45M
  va_end (ap);
168
2.45M
  return ret;
169
2.45M
}
170
171
void
172
pager_close (struct pagerfile *pfp)
173
44.1k
{
174
44.1k
  if (pfp->bufsize)
175
0
    pager_flush (pfp);
176
44.1k
  if (pfp->mode == mode_pager)
177
0
    pclose (pfp->stream);
178
44.1k
  free (pfp->bufbase);
179
44.1k
  free (pfp->pager);
180
44.1k
  free (pfp);
181
44.1k
}
182
183
int
184
pager_error (struct pagerfile *pfp)
185
0
{
186
0
  return ferror (pfp->stream);
187
0
}
188
189
PAGERFILE *
190
pager_open (FILE *stream, size_t maxlines, char const *pager)
191
44.1k
{
192
44.1k
  struct pagerfile *pfp;
193
194
44.1k
  pfp = ecalloc (1, sizeof (*pfp));
195
196
44.1k
  pfp->stream = stream;
197
44.1k
  if (maxlines > 0 && pager)
198
0
    {
199
0
      pfp->pager = estrdup (pager);
200
0
      pfp->mode = mode_initial;
201
0
      pfp->maxlines = maxlines;
202
0
    }
203
44.1k
  else
204
44.1k
    pfp->mode = mode_transparent;
205
44.1k
  return pfp;
206
44.1k
}
207
208
PAGERFILE *
209
pager_create (char const *pager)
210
0
{
211
0
  struct pagerfile *pfp;
212
0
  FILE *pagfp = popen (pager, "w");
213
0
  if (!pagfp)
214
0
    {
215
0
      terror (_("cannot run command `%s': %s"), pager, strerror (errno));
216
0
      return NULL;
217
0
    }
218
0
  pfp = ecalloc (1, sizeof (*pfp));
219
0
  pfp->pager = estrdup (pager);
220
0
  pfp->mode = mode_pager;
221
0
  pfp->stream = pagfp;
222
0
  return pfp;
223
0
}