source: trunk/src/kmk/kmkbuiltin/append.c@ 3140

Last change on this file since 3140 was 3140, checked in by bird, 7 years ago

kmk: Merged in changes from GNU make 4.2.1 (2e55f5e4abdc0e38c1d64be703b446695e70b3b6 / https://git.savannah.gnu.org/git/make.git).

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.9 KB
Line 
1/* $Id: append.c 3140 2018-03-14 21:28:10Z bird $ */
2/** @file
3 * kMk Builtin command - append text to file.
4 */
5
6/*
7 * Copyright (c) 2005-2010 knut st. osmundsen <bird-kBuild-spamx@anduin.net>
8 *
9 * This file is part of kBuild.
10 *
11 * kBuild is free software; you can redistribute it and/or modify
12 * it under the terms of the GNU General Public License as published by
13 * the Free Software Foundation; either version 3 of the License, or
14 * (at your option) any later version.
15 *
16 * kBuild is distributed in the hope that it will be useful,
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 * GNU General Public License for more details.
20 *
21 * You should have received a copy of the GNU General Public License
22 * along with kBuild. If not, see <http://www.gnu.org/licenses/>
23 *
24 */
25
26/*******************************************************************************
27* Header Files *
28*******************************************************************************/
29#ifndef kmk_builtin_append
30# include "makeint.h"
31# include "filedef.h"
32# include "variable.h"
33#else
34# include "config.h"
35#endif
36#include <string.h>
37#include <stdio.h>
38#ifdef HAVE_ALLOCA_H
39# include <alloca.h>
40#endif
41#include "err.h"
42#include "kmkbuiltin.h"
43
44
45/**
46 * Prints the usage and return 1.
47 */
48static int usage(FILE *pf)
49{
50 fprintf(pf,
51 "usage: %s [-dcnNtv] file [string ...]\n"
52 " or: %s --version\n"
53 " or: %s --help\n"
54 "\n"
55 "Options:\n"
56 " -d Enclose the output in define ... endef, taking the name from\n"
57 " the first argument following the file name.\n"
58 " -c Output the command for specified target(s). [builtin only]\n"
59 " -i look for --insert-command=trg and --insert-variable=var. [builtin only]\n"
60 " -n Insert a newline between the strings.\n"
61 " -N Suppress the trailing newline.\n"
62 " -t Truncate the file instead of appending\n"
63 " -v Output the value(s) for specified variable(s). [builtin only]\n"
64 ,
65 g_progname, g_progname, g_progname);
66 return 1;
67}
68
69
70/**
71 * Appends text to a textfile, creating the textfile if necessary.
72 */
73int kmk_builtin_append(int argc, char **argv, char **envp)
74{
75 int i;
76 int fFirst;
77 int iFile;
78 FILE *pFile;
79 int fNewline = 0;
80 int fNoTrailingNewline = 0;
81 int fTruncate = 0;
82 int fDefine = 0;
83 int fVariables = 0;
84 int fCommands = 0;
85 int fLookForInserts = 0;
86
87 g_progname = argv[0];
88
89 /*
90 * Parse options.
91 */
92 i = 1;
93 while (i < argc
94 && argv[i][0] == '-'
95 && argv[i][1] != '\0' /* '-' is a file */
96 && strchr("-cdinNtv", argv[i][1]) /* valid option char */
97 )
98 {
99 char *psz = &argv[i][1];
100 if (*psz != '-')
101 {
102 do
103 {
104 switch (*psz)
105 {
106 case 'c':
107 if (fVariables)
108 {
109 errx(1, "Option '-c' clashes with '-v'.");
110 return usage(stderr);
111 }
112#ifndef kmk_builtin_append
113 fCommands = 1;
114 break;
115#else
116 errx(1, "Option '-c' isn't supported in external mode.");
117 return usage(stderr);
118#endif
119 case 'd':
120 if (fVariables)
121 {
122 errx(1, "Option '-d' must come before '-v'!");
123 return usage(stderr);
124 }
125 fDefine = 1;
126 break;
127 case 'i':
128 if (fVariables || fCommands)
129 {
130 errx(1, fVariables ? "Option '-i' clashes with '-v'." : "Option '-i' clashes with '-c'.");
131 return usage(stderr);
132 }
133#ifndef kmk_builtin_append
134 fLookForInserts = 1;
135 break;
136#else
137 errx(1, "Option '-C' isn't supported in external mode.");
138 return usage(stderr);
139#endif
140 case 'n':
141 fNewline = 1;
142 break;
143 case 'N':
144 fNoTrailingNewline = 1;
145 break;
146 case 't':
147 fTruncate = 1;
148 break;
149 case 'v':
150 if (fCommands)
151 {
152 errx(1, "Option '-v' clashes with '-c'.");
153 return usage(stderr);
154 }
155#ifndef kmk_builtin_append
156 fVariables = 1;
157 break;
158#else
159 errx(1, "Option '-v' isn't supported in external mode.");
160 return usage(stderr);
161#endif
162 default:
163 errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
164 return usage(stderr);
165 }
166 } while (*++psz);
167 }
168 else if (!strcmp(psz, "-help"))
169 {
170 usage(stdout);
171 return 0;
172 }
173 else if (!strcmp(psz, "-version"))
174 return kbuild_version(argv[0]);
175 else
176 break;
177 i++;
178 }
179
180 if (i + fDefine >= argc)
181 {
182 if (i <= argc)
183 errx(1, "missing filename!");
184 else
185 errx(1, "missing define name!");
186 return usage(stderr);
187 }
188
189 /*
190 * Open the output file.
191 */
192 iFile = i;
193 pFile = fopen(argv[i], fTruncate ? "w" : "a");
194 if (!pFile)
195 return err(1, "failed to open '%s'", argv[i]);
196
197 /*
198 * Start define?
199 */
200 if (fDefine)
201 {
202 i++;
203 fprintf(pFile, "define %s\n", argv[i]);
204 }
205
206 /*
207 * Append the argument strings to the file
208 */
209 fFirst = 1;
210 for (i++; i < argc; i++)
211 {
212 const char *psz = argv[i];
213 size_t cch = strlen(psz);
214 if (!fFirst)
215 fputc(fNewline ? '\n' : ' ', pFile);
216#ifndef kmk_builtin_append
217 if (fCommands)
218 {
219 char *pszOldBuf;
220 unsigned cchOldBuf;
221 char *pchEnd;
222
223 install_variable_buffer(&pszOldBuf, &cchOldBuf);
224
225 pchEnd = func_commands(variable_buffer, &argv[i], "commands");
226 fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
227
228 restore_variable_buffer(pszOldBuf, cchOldBuf);
229 }
230 else if (fVariables)
231 {
232 struct variable *pVar = lookup_variable(psz, cch);
233 if (!pVar)
234 continue;
235 if ( !pVar->recursive
236 || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
237 fwrite(pVar->value, 1, pVar->value_length, pFile);
238 else
239 {
240 char *pszExpanded = allocated_variable_expand(pVar->value);
241 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
242 free(pszExpanded);
243 }
244 }
245 else if (fLookForInserts && strncmp(psz, "--insert-command=", 17) == 0)
246 {
247 char *pszOldBuf;
248 unsigned cchOldBuf;
249 char *pchEnd;
250
251 install_variable_buffer(&pszOldBuf, &cchOldBuf);
252
253 psz += 17;
254 pchEnd = func_commands(variable_buffer, (char **)&psz, "commands");
255 fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
256
257 restore_variable_buffer(pszOldBuf, cchOldBuf);
258 }
259 else if (fLookForInserts && strncmp(psz, "--insert-variable=", 18) == 0)
260 {
261 struct variable *pVar = lookup_variable(psz + 18, cch);
262 if (!pVar)
263 continue;
264 if ( !pVar->recursive
265 || IS_VARIABLE_RECURSIVE_WITHOUT_DOLLAR(pVar))
266 fwrite(pVar->value, 1, pVar->value_length, pFile);
267 else
268 {
269 char *pszExpanded = allocated_variable_expand(pVar->value);
270 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
271 free(pszExpanded);
272 }
273 }
274 else
275#endif
276 fwrite(psz, 1, cch, pFile);
277 fFirst = 0;
278 }
279
280 /*
281 * End the define?
282 */
283 if (fDefine)
284 {
285 if (fFirst)
286 fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile);
287 else
288 fwrite("endef", 1, sizeof("endef") - 1, pFile);
289 }
290
291 /*
292 * Add the final newline (unless supressed) and close the file.
293 */
294 if ( ( !fNoTrailingNewline
295 && fputc('\n', pFile) == EOF)
296 || ferror(pFile))
297 {
298 fclose(pFile);
299 return errx(1, "error writing to '%s'!", argv[iFile]);
300 }
301 if (fclose(pFile))
302 return err(1, "failed to fclose '%s'!", argv[iFile]);
303 return 0;
304}
305
Note: See TracBrowser for help on using the repository browser.