*: Updated copyright to 2009 and normalized name & email.
[kbuild-mirror.git] / src / kmk / kmkbuiltin / append.c
blobe7e81ea303d0d1ed0300b7a6e8866d64279b0239
1 /* $Id$ */
2 /** @file
3 * kMk Builtin command - append text to file.
4 */
6 /*
7 * Copyright (c) 2005-2009 knut st. osmundsen <bird-kBuild-spamix@anduin.net>
9 * This file is part of kBuild.
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.
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.
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/>
26 /*******************************************************************************
27 * Header Files *
28 *******************************************************************************/
29 #ifndef kmk_builtin_append
30 # include "make.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"
45 /**
46 * Prints the usage and return 1.
48 static int usage(FILE *pf)
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 " -n Insert a newline between the strings.\n"
60 " -N Suppress the trailing newline.\n"
61 " -t Truncate the file instead of appending\n"
62 " -v Output the value(s) for specified variable(s). [builtin only]\n"
64 g_progname, g_progname, g_progname);
65 return 1;
69 /**
70 * Appends text to a textfile, creating the textfile if necessary.
72 int kmk_builtin_append(int argc, char **argv, char **envp)
74 int i;
75 int fFirst;
76 int iFile;
77 FILE *pFile;
78 int fNewline = 0;
79 int fNoTrailingNewline = 0;
80 int fTruncate = 0;
81 int fDefine = 0;
82 int fVariables = 0;
83 int fCommands = 0;
85 g_progname = argv[0];
88 * Parse options.
90 i = 1;
91 while (i < argc
92 && argv[i][0] == '-'
93 && argv[i][1] != '\0' /* '-' is a file */
94 && strchr("-cdnNtv", argv[i][1]) /* valid option char */
97 char *psz = &argv[i][1];
98 if (*psz != '-')
102 switch (*psz)
104 case 'c':
105 if (fVariables)
107 errx(1, "Option '-c' clashes with '-v'.");
108 return usage(stderr);
110 #ifndef kmk_builtin_append
111 fCommands = 1;
112 break;
113 #else
114 errx(1, "Option '-c' isn't supported in external mode.");
115 return usage(stderr);
116 #endif
117 case 'd':
118 if (fVariables)
120 errx(1, "Option '-d' must come before '-v'!");
121 return usage(stderr);
123 fDefine = 1;
124 break;
125 case 'n':
126 fNewline = 1;
127 break;
128 case 'N':
129 fNoTrailingNewline = 1;
130 break;
131 case 't':
132 fTruncate = 1;
133 break;
134 case 'v':
135 if (fCommands)
137 errx(1, "Option '-v' clashes with '-c'.");
138 return usage(stderr);
140 #ifndef kmk_builtin_append
141 fVariables = 1;
142 break;
143 #else
144 errx(1, "Option '-v' isn't supported in external mode.");
145 return usage(stderr);
146 #endif
147 default:
148 errx(1, "Invalid option '%c'! (%s)", *psz, argv[i]);
149 return usage(stderr);
151 } while (*++psz);
153 else if (!strcmp(psz, "-help"))
155 usage(stdout);
156 return 0;
158 else if (!strcmp(psz, "-version"))
159 return kbuild_version(argv[0]);
160 else
161 break;
162 i++;
165 if (i + fDefine >= argc)
167 if (i <= argc)
168 errx(1, "missing filename!");
169 else
170 errx(1, "missing define name!");
171 return usage(stderr);
175 * Open the output file.
177 iFile = i;
178 pFile = fopen(argv[i], fTruncate ? "w" : "a");
179 if (!pFile)
180 return err(1, "failed to open '%s'.", argv[i]);
183 * Start define?
185 if (fDefine)
187 i++;
188 fprintf(pFile, "define %s\n", argv[i]);
192 * Append the argument strings to the file
194 fFirst = 1;
195 for (i++; i < argc; i++)
197 const char *psz = argv[i];
198 size_t cch = strlen(psz);
199 if (!fFirst)
200 fputc(fNewline ? '\n' : ' ', pFile);
201 #ifndef kmk_builtin_append
202 if (fCommands)
204 char *pszOldBuf;
205 unsigned cchOldBuf;
206 char *pchEnd;
208 install_variable_buffer(&pszOldBuf, &cchOldBuf);
210 pchEnd = func_commands(variable_buffer, &argv[i], "commands");
211 fwrite(variable_buffer, 1, pchEnd - variable_buffer, pFile);
213 restore_variable_buffer(pszOldBuf, cchOldBuf);
215 else if (fVariables)
217 struct variable *pVar = lookup_variable(psz, cch);
218 if (!pVar)
219 continue;
220 if ( pVar->recursive
221 && memchr(pVar->value, '$', pVar->value_length))
223 char *pszExpanded = allocated_variable_expand(pVar->value);
224 fwrite(pszExpanded, 1, strlen(pszExpanded), pFile);
225 free(pszExpanded);
227 else
228 fwrite(pVar->value, 1, pVar->value_length, pFile);
230 else
231 #endif
232 fwrite(psz, 1, cch, pFile);
233 fFirst = 0;
237 * End the define?
239 if (fDefine)
241 if (fFirst)
242 fwrite("\nendef", 1, sizeof("\nendef") - 1, pFile);
243 else
244 fwrite("endef", 1, sizeof("endef") - 1, pFile);
248 * Add the final newline (unless supressed) and close the file.
250 if ( ( !fNoTrailingNewline
251 && fputc('\n', pFile) == EOF)
252 || ferror(pFile))
254 fclose(pFile);
255 return errx(1, "error writing to '%s'!", argv[iFile]);
257 if (fclose(pFile))
258 return err(1, "failed to fclose '%s'!", argv[iFile]);
259 return 0;