1 /*
2 * writesubst.cc: Part of GNU CSSC.
3 *
4 * Copyright (C) 2001, 2004, 2007, 2008, 2009, 2010, 2011, 2014, 2019
5 * Free Software Foundation, Inc.
6 *
7 * This program is free software: you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation, either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 *
20 *
21 * sccsfile::write_subst()
22 *
23 */
24
25 #include <config.h>
26 #include <string>
27
28 #include "cssc.h"
29 #include "sccsfile.h"
30 #include "delta.h"
31 #include "ioerr.h"
32
33 // #include "pfile.h"
34 // #include "seqstate.h"
35 // #include "delta-iterator.h"
36 // #include "delta-table.h"
37
38
39 #include <ctype.h>
40
41 using std::string;
42
43 /* Return TRUE if the specified keyword letter should be
44 * expanded in the gotten file. If the y flag is set, it controls the
45 * keyletters which are expanded. If the y flag is not present, all
46 * key letters are expanded. The y flag is a Solaris 8 extension.
47 */
expand_keyletter(char which,const std::set<char> & expanded)48 static bool expand_keyletter(char which, const std::set<char>& expanded)
49 {
50 if (expanded.empty())
51 return true;
52 else
53 return expanded.find(which) != expanded.end();
54 }
55
56
57 /* Write a line of a file after substituting any id keywords in it.
58 Returns true if an error occurs. */
59
60 int
write_subst(const char * start,struct subst_parms * parms,const delta & d,bool force_expansion) const61 sccs_file::write_subst(const char *start,
62 struct subst_parms *parms,
63 const delta& d,
64 bool force_expansion) const
65 {
66 FILE *out = parms->out;
67
68 const char *percent = strchr(start, '%');
69 while (percent != NULL)
70 {
71 char c = percent[1];
72 if (c != '\0' && percent[2] == '%')
73 {
74 if (start != percent
75 && fwrite(start, percent - start, 1, out) != 1)
76 {
77 return 1;
78 }
79
80 int err = 0;
81 if (!force_expansion
82 && false == expand_keyletter(c, flags.substitued_flag_letters))
83 {
84 // We do not expand this key letter. Just emit the raw
85 // characters.
86 err = fputc_failed(fputc('%', out))
87 || fputc_failed(fputc(c, out))
88 || fputc_failed(fputc('%', out));
89
90 if (err)
91 {
92 return 1;
93 }
94 else
95 {
96 start = percent+3;
97 percent = strchr(start, '%');
98 continue;
99 }
100 }
101 percent += 3;
102
103
104
105 // We need to expand the keyletter.
106 switch (c)
107 {
108 const char *s;
109
110 case 'M':
111 {
112 const char *mod = get_module_name().c_str();
113 err = fputs_failed(fputs(mod, out));
114 }
115 break;
116
117 case 'I':
118 err = d.id().print(out);
119 break;
120
121 case 'R':
122 err = d.id().printf(out, 'R', 1);
123 break;
124
125 case 'L':
126 err = d.id().printf(out, 'L', 1);
127 break;
128
129 case 'B':
130 err = d.id().printf(out, 'B', 1);
131 break;
132
133 case 'S':
134 err = d.id().printf(out, 'S', 1);
135 break;
136
137 case 'D':
138 err = parms->now.printf(out, 'D');
139 break;
140
141 case 'H':
142 err = parms->now.printf(out, 'H');
143 break;
144
145 case 'T':
146 err = parms->now.printf(out, 'T');
147 break;
148
149 case 'E':
150 err = d.date().printf(out, 'D');
151 break;
152
153 case 'G':
154 err = d.date().printf(out, 'H');
155 break;
156
157 case 'U':
158 err = d.date().printf(out, 'T');
159 break;
160
161 case 'Y':
162 if (flags.type)
163 {
164 err = fputs_failed(fputs(flags.type->c_str(), out));
165 }
166 break;
167
168 case 'F':
169 err =
170 fputs_failed(fputs(base_part(name.sfile()).c_str(),
171 out));
172 break;
173
174 case 'P':
175 if (1) // introduce new scope...
176 {
177 string path(canonify_filename(name.c_str()));
178 err = fputs_failed(fputs(path.c_str(), out));
179 }
180 break;
181
182 case 'Q':
183 if (flags.user_def)
184 {
185 err = fputs_failed(fputs(flags.user_def->c_str(), out));
186 }
187 break;
188
189 case 'C':
190 err = printf_failed(fprintf(out, "%u",
191 parms->out_lineno));
192 break;
193
194 case 'Z':
195 if (fputc_failed(fputc('@', out))
196 || fputs_failed(fputs("(#)", out)))
197 {
198 err = 1;
199 }
200 else
201 {
202 err = 0;
203 }
204 break;
205
206 case 'W':
207 s = parms->wstring;
208 if (0 == s)
209 {
210 /* At some point I had been told that SunOS 4.1.4
211 * apparently uses a space rather than a tab here.
212 * However, a test on 4.1.4 shows otherwise.
213 *
214 * From: "Carl D. Speare" <carlds@attglobal.net>
215 * Subject: RE: SunOS 4.1.4
216 * To: 'James Youngman' <jay@gnu.org>,
217 * "cssc-users@gnu.org" <cssc-users@gnu.org>
218 * Date: Wed, 11 Jul 2001 01:07:36 -0400
219 *
220 * Ok, here's what I got:
221 *
222 * %W% in a file called test.c expanded to:
223 *
224 * @(#)test.c<TAB>1.1
225 *
226 * Sorry, but my SunOS machine is lacking a network
227 * connection, so I can't bring it over into
228 * mail-land. But, there you are, for what it's
229 * worth.
230 *
231 * --Carl
232 *
233 */
234 s = "%Z" "%%M" "%\t%" "I%";
235 /* NB: strange formatting of the string above is
236 * to preserve it unchanged even if this source code does
237 * itself get checked into SCCS or CSSC.
238 */
239 }
240 else
241 {
242 /* protect against recursion */
243 parms->wstring = 0;
244 }
245 err = write_subst(s, parms, d, true);
246 if (0 == parms->wstring)
247 {
248 parms->wstring = s;
249 }
250 break;
251
252 case 'A':
253 err = write_subst("%Z""%%Y""% %M""% %I"
254 "%%Z""%",
255 parms, d, true);
256 break;
257
258 default:
259 start = percent - 3;
260 percent = percent - 1;
261 continue;
262 }
263
264 parms->found_id = 1;
265
266 if (err)
267 {
268 return 1;
269 }
270 start = percent;
271 }
272 else
273 {
274 percent++;
275 }
276 percent = strchr(percent, '%');
277 }
278
279 return fputs_failed(fputs(start, out));
280 }
281