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

Last change on this file since 2015 was 2015, checked in by bird, 17 years ago

kmk_append: added a new option '-N' for suppressing the trailing new line. Fixes #53.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.0 KB
Line 
1/* $Id: append.c 2015 2008-11-01 22:16:55Z bird $ */
2/** @file
3 * kMk Builtin command - append text to file.
4 */
5
6/*
7 * Copyright (c) 2005-2008 knut st. osmundsen <bird-kBuild-spam@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 2 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, write to the Free Software
23 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
24 *
25 */
26
27#include <string.h>
28#include <stdio.h>
29#include "err.h"
30#include "kmkbuiltin.h"
31#ifndef kmk_builtin_append
32# include "make.h"
33# include "filedef.h"
34# include "variable.h"
35#endif
36
37
38/**
39 * Prints the usage and return 1.
40 */
41static int usage(FILE *pf)
42{
43 fprintf(pf,
44 "usage: %s [-dcnNtv] file [string ...]\n"
45 " or: %s --version\n"
46 " or: %s --help\n"
47 "\n"
48 "Options:\n"
49 " -d Enclose the output in define ... endef, taking the name from\n"
50 " the first argument following the file name.\n"
51 " -c Output the command for specified target(s). [builtin only]\n"
52 " -n Insert a new line between the strings.\n"
53 " -N Suppress the trailing new line.\n"
54 " -t Truncate the file instead of appending\n"
55 " -v Output the value(s) for specified variable(s). [builtin only]\n"
56 ,
57 g_progname, g_progname, g_progname);
58 return 1;
59}
60
61
62/**
63 * Appends text to a textfile, creating the textfile if necessary.
64 */
65int kmk_builtin_append(int argc, char **argv, char **envp)
66{
67 int i;
68 int fFirst;
69 int iFile;
70 FILE *pFile;
71 int fNewLine = 0;
72 int fNoTrailingNewLine = 0;
73 int fTruncate = 0;
74 int fDefine = 0;
75 int fVariables = 0;
76 int fCommands = 0;
77
78 g_progname = argv[0];
79
80 /*
81 * Parse options.
82 */
83 i = 1;
84 while (i < argc
85 && argv[i][0] == '-'
86 && argv[i][1] != '\0' /* '-' is a file */
87 && strchr("-cdnNtv", argv[i][1]) /* valid option char */
88 )
89 {
90 char *psz = &argv[i][1];
91 if (*psz != '-')
92 {
93 do
94 {
95 switch (*psz)
96 {
97 case 'c':
98 if (fVariables)
99 {
100 errx(1, "Option '-c' clashes with '-v'.");
101 return usage(stderr);
102 }
103#ifndef kmk_builtin_append
104 fCommands = 1;
105 break;
106#else
107 errx(1, "Option '-c' isn't supported in external mode.");
108 return usage(stderr);
109#endif
110 case 'd':
111 if (fVariables)
112 {
113 errx(1, "Option '-d' must come before '-v'!");
114 return usage(stderr);
115 }
116 fDefine = 1;
117 break;
118 case 'n':
119 fNewLine = 1;
120 break;
121 case 'N':
122 fNoTrailingNewLine = 1;
123 break;
124 case 't':
125 fTruncate = 1;
126 break;
127 case 'v':
128 if (fCommands)
129 {
130 errx(1, "Option '-v' clashes with '-c'.");
131 return usage(stderr);
132 }
133#ifndef kmk_builtin_append
134 fVariables = 1;
135 break;
136#else
137 errx(1, "Option '-v' isn't supported in external mode.");
138 return usage(stderr);
139#endif
140 default:
141 errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
142 return usage(stderr);
143 }
144 } while (*++psz);
145 }
146 else if (!strcmp(psz, "-help"))
147 {
148 usage(stdout);
149 return 0;
150 }
151 else if (!strcmp(psz, "-version"))
152 return kbuild_version(argv[0]);
153 else
154 break;
155 i++;
156 }
157
158 if (i + fDefine >= argc)
159 {
160 if (i <= argc)
161 errx(1, "missing filename!");
162 else
163 errx(1, "missing define name!");
164 return usage(stderr);
165 }
166
167 /*
168 * Open the output file.
169 */
170 iFile = i;
171 pFile = fopen(argv[i], fTruncate ? "w" : "a");
172 if (!pFile)
173 return err(1, "failed to open '%s'.", argv[i]);
174
175 /*
176 * Start define?
177 */
178 if (fDefine)
179 {
180 i++;
181 fprintf(pFile, "define %s\n", argv[i]);
182 }
183
184 /*
185 * Append the argument strings to the file
186 */
187 fFirst = 1;
188 for (i++; i < argc; i++)
189 {
190 const char *psz = argv[i];
191 size_t cch = strlen(psz);
192 if (!fFirst)
193 fputc(fNewLine ? '\n' : ' ', pFile);
194#ifndef kmk_builtin_append
195 if (fCommands)
196 {
197 char *pszOldBuf;
198 unsigned cchOldBuf;
199 char *pchEnd;
200
201 install_variable_buffer(&pszOldBuf, &cchOldBuf);
202
203 pchEnd = func_commands(variable_buffer, &argv[i], "commands");
204 fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
205
206 restore_variable_buffer(pszOldBuf, cchOldBuf);
207 }
208 else if (fVariables)
209 {
210 struct variable *pVar = lookup_variable(psz, cch);
211 if (!pVar)
212 continue;
213 if ( pVar->recursive
214 && memchr(pVar->value, '$', pVar->value_length))
215 {
216 char *pszExpanded = allocated_variable_expand(pVar->value);
217 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
218 free(pszExpanded);
219 }
220 else
221 fwrite(pVar->value, 1, pVar->value_length, pFile);
222 }
223 else
224#endif
225 fwrite(psz, 1, cch, pFile);
226 fFirst = 0;
227 }
228
229 /*
230 * End the define?
231 */
232 if (fDefine)
233 {
234 if (fFirst)
235 fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile);
236 else
237 fwrite("endef", 1, sizeof("endef") - 1, pFile);
238 }
239
240 /*
241 * Add the final newline (unless supressed) and close the file.
242 */
243 if ( ( !fNoTrailingNewLine
244 && fputc('\n', pFile) == EOF)
245 || ferror(pFile))
246 {
247 fclose(pFile);
248 return errx(1, "error writing to '%s'!", argv[iFile]);
249 }
250 if (fclose(pFile))
251 return err(1, "failed to fclose '%s'!", argv[iFile]);
252 return 0;
253}
254
Note: See TracBrowser for help on using the repository browser.