gdp / ep / ep_fopen_styled.c @ master
History | View | Annotate | Download (3.72 KB)
1 |
/* vim: set ai sw=8 sts=8 ts=8 :*/
|
---|---|
2 |
|
3 |
/***********************************************************************
|
4 |
** ----- BEGIN LICENSE BLOCK -----
|
5 |
** LIBEP: Enhanced Portability Library (Reduced Edition)
|
6 |
**
|
7 |
** Copyright (c) 2008-2019, Eric P. Allman. All rights reserved.
|
8 |
** Copyright (c) 2015-2019, Regents of the University of California.
|
9 |
** All rights reserved.
|
10 |
**
|
11 |
** Permission is hereby granted, without written agreement and without
|
12 |
** license or royalty fees, to use, copy, modify, and distribute this
|
13 |
** software and its documentation for any purpose, provided that the above
|
14 |
** copyright notice and the following two paragraphs appear in all copies
|
15 |
** of this software.
|
16 |
**
|
17 |
** IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
|
18 |
** SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST
|
19 |
** PROFITS, ARISING OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION,
|
20 |
** EVEN IF REGENTS HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
21 |
**
|
22 |
** REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT
|
23 |
** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
|
24 |
** FOR A PARTICULAR PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION,
|
25 |
** IF ANY, PROVIDED HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO
|
26 |
** OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
|
27 |
** OR MODIFICATIONS.
|
28 |
** ----- END LICENSE BLOCK -----
|
29 |
***********************************************************************/
|
30 |
|
31 |
/*
|
32 |
** Open up a stream that has styling (e.g., colors or fonts)
|
33 |
**
|
34 |
** This is a wrapper around funopen (on BSD and MacOS) or
|
35 |
** fopencookie (on Linux). These two routimes do substantially
|
36 |
** the same thing.
|
37 |
*/
|
38 |
|
39 |
#if __FreeBSD__ || __APPLE__
|
40 |
# define IORESULT_T int |
41 |
# define IOBLOCK_T int |
42 |
#elif __linux__
|
43 |
# define IORESULT_T ssize_t
|
44 |
# define IOBLOCK_T size_t
|
45 |
# define _GNU_SOURCE 1 // required to get fopencookie |
46 |
#else
|
47 |
# error Cannot determine use of funopen vs fopencookie
|
48 |
#endif
|
49 |
|
50 |
#include <ep.h> |
51 |
#include <string.h> |
52 |
#include <stdio.h> |
53 |
#include <sys/errno.h> |
54 |
|
55 |
struct styleinfo
|
56 |
{ |
57 |
FILE *underlying; // underlying file
|
58 |
char *so; // "shift out" string |
59 |
char *si; // "shift in" string |
60 |
}; |
61 |
|
62 |
static IORESULT_T
|
63 |
styled_write(void *cookie, const char *buf, IOBLOCK_T size) |
64 |
{ |
65 |
struct styleinfo *sinf = (struct styleinfo *) cookie; |
66 |
IORESULT_T result = 0;
|
67 |
|
68 |
flockfile(sinf->underlying); |
69 |
while (size > 0) |
70 |
{ |
71 |
const char *p; |
72 |
IOBLOCK_T tlen; |
73 |
|
74 |
tlen = size; |
75 |
p = memchr(buf, '\n', tlen);
|
76 |
if (p != NULL) |
77 |
tlen = p - buf; |
78 |
if (tlen > 0) |
79 |
{ |
80 |
IORESULT_T tres; |
81 |
if (sinf->so != NULL) |
82 |
fputs(sinf->so, sinf->underlying); |
83 |
tres = fwrite(buf, 1, tlen, sinf->underlying);
|
84 |
if (sinf->si != NULL) |
85 |
fputs(sinf->si, sinf->underlying); |
86 |
buf += tlen; |
87 |
size -= tlen; |
88 |
if (tres > 0) |
89 |
result += tres; |
90 |
} |
91 |
if (size > 0 && *buf == '\n') |
92 |
{ |
93 |
fputc(*buf++, sinf->underlying); |
94 |
result++; |
95 |
size--; |
96 |
} |
97 |
} |
98 |
funlockfile(sinf->underlying); |
99 |
fflush(sinf->underlying); |
100 |
return result;
|
101 |
} |
102 |
|
103 |
static int |
104 |
styled_close(void *cookie)
|
105 |
{ |
106 |
struct styleinfo *sinf = (struct styleinfo *) cookie; |
107 |
|
108 |
if (sinf->so != NULL) |
109 |
ep_mem_free(sinf->so); |
110 |
if (sinf->si != NULL) |
111 |
ep_mem_free(sinf->si); |
112 |
ep_mem_free(cookie); |
113 |
return 0; |
114 |
} |
115 |
|
116 |
|
117 |
FILE * |
118 |
ep_fopen_styled(FILE *underlying, |
119 |
const char *so, |
120 |
const char *si) |
121 |
{ |
122 |
FILE *fp; |
123 |
struct styleinfo *sinf = (struct styleinfo *) ep_mem_zalloc(sizeof *sinf); |
124 |
if (sinf == NULL) |
125 |
return NULL; |
126 |
sinf->underlying = underlying; |
127 |
if (so != NULL) |
128 |
sinf->so = strdup(so); |
129 |
if (si != NULL) |
130 |
sinf->si = strdup(si); |
131 |
|
132 |
#if __FreeBSD__ || __APPLE__
|
133 |
{ |
134 |
// BSD/MacOS
|
135 |
fp = funopen(sinf, NULL, &styled_write, NULL, &styled_close); |
136 |
} |
137 |
#elif __linux__
|
138 |
{ |
139 |
// Linux
|
140 |
cookie_io_functions_t iof = |
141 |
{ |
142 |
NULL,
|
143 |
&styled_write, |
144 |
NULL,
|
145 |
&styled_close |
146 |
}; |
147 |
fp = fopencookie(sinf, "w", iof);
|
148 |
} |
149 |
#endif
|
150 |
setlinebuf(fp); |
151 |
return fp;
|
152 |
} |