gdp / ep / ep_fopen_styled.c @ master
History | View | Annotate | Download (3.72 KB)
1 | 355109e1 | Eric Allman | /* vim: set ai sw=8 sts=8 ts=8 :*/
|
---|---|---|---|
2 | |||
3 | /***********************************************************************
|
||
4 | ** ----- BEGIN LICENSE BLOCK -----
|
||
5 | ** LIBEP: Enhanced Portability Library (Reduced Edition)
|
||
6 | **
|
||
7 | c87dd166 | Eric Allman | ** Copyright (c) 2008-2019, Eric P. Allman. All rights reserved.
|
8 | ** Copyright (c) 2015-2019, Regents of the University of California.
|
||
9 | 355109e1 | Eric Allman | ** 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 | 1261c259 | Eric Allman | IORESULT_T result = 0;
|
67 | 355109e1 | Eric Allman | |
68 | flockfile(sinf->underlying); |
||
69 | 1261c259 | Eric Allman | 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 | 355109e1 | Eric Allman | funlockfile(sinf->underlying); |
99 | 1261c259 | Eric Allman | fflush(sinf->underlying); |
100 | ac10a316 | Eric Allman | return result;
|
101 | 355109e1 | Eric Allman | } |
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 | ac10a316 | Eric Allman | FILE *fp; |
123 | 355109e1 | Eric Allman | 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 | ac10a316 | Eric Allman | fp = funopen(sinf, NULL, &styled_write, NULL, &styled_close); |
136 | 355109e1 | Eric Allman | } |
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 | ac10a316 | Eric Allman | fp = fopencookie(sinf, "w", iof);
|
148 | 355109e1 | Eric Allman | } |
149 | #endif
|
||
150 | ac10a316 | Eric Allman | setlinebuf(fp); |
151 | return fp;
|
||
152 | 355109e1 | Eric Allman | } |