VirtualBox

source: kBuild/trunk/src/kmk/kmkbuiltin.c@ 3040

Last change on this file since 3040 was 3040, checked in by bird, 8 years ago

kmk_builtin_command: do bourn style argument splitting, not stupid custom stuff.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1/* $Id: kmkbuiltin.c 3040 2017-05-10 13:07:10Z bird $ */
2/** @file
3 * kMk Builtin command execution.
4 */
5
6/*
7 * Copyright (c) 2005-2010 knut st. osmundsen <[email protected]>
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#include <string.h>
30#include <stdlib.h>
31#include <stdio.h>
32#include <ctype.h>
33#include <assert.h>
34#include <sys/stat.h>
35#ifdef _MSC_VER
36# include <io.h>
37#endif
38#include "kmkbuiltin/err.h"
39#include "kmkbuiltin.h"
40
41#ifndef _MSC_VER
42extern char **environ;
43#endif
44
45
46int kmk_builtin_command(const char *pszCmd, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
47{
48 int argc;
49 char **argv;
50 int rc;
51 char *pszzCmd;
52 char *pszDst;
53 int fOldStyle = 0;
54
55 /*
56 * Check and skip the prefix.
57 */
58 if (strncmp(pszCmd, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
59 {
60 fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
61 return 1;
62 }
63
64 /*
65 * Parse arguments.
66 */
67 rc = 0;
68 argc = 0;
69 argv = NULL;
70 pszzCmd = pszDst = (char *)strdup(pszCmd);
71 if (!pszDst)
72 {
73 fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc);
74 return 1;
75 }
76 do
77 {
78 const char * const pszSrcStart = pszCmd;
79 char ch;
80 char chQuote;
81
82 /*
83 * Start new argument.
84 */
85 if (!(argc % 16))
86 {
87 void *pv = realloc(argv, sizeof(char *) * (argc + 17));
88 if (!pv)
89 {
90 fprintf(stderr, "kmk_builtin: out of memory. argc=%d\n", argc);
91 rc = 1;
92 break;
93 }
94 argv = (char **)pv;
95 }
96 argv[argc++] = pszDst;
97 argv[argc] = NULL;
98
99 if (!fOldStyle)
100 {
101 /*
102 * Process the next argument, bourne style.
103 */
104 chQuote = 0;
105 ch = *pszCmd++;
106 do
107 {
108 /* Unquoted mode? */
109 if (chQuote == 0)
110 {
111 if (ch != '\'' && ch != '"')
112 {
113 if (!isspace(ch))
114 {
115 if (ch != '\\')
116 *pszDst++ = ch;
117 else
118 {
119 ch = *pszCmd++;
120 if (ch)
121 *pszDst++ = ch;
122 else
123 {
124 fprintf(stderr, "kmk_builtin: Incomplete escape sequence in argument %d: %s\n",
125 argc, pszSrcStart);
126 rc = 1;
127 break;
128 }
129 }
130 }
131 else
132 break;
133 }
134 else
135 chQuote = ch;
136 }
137 /* Quoted mode */
138 else if (ch != chQuote)
139 {
140 if ( ch != '\\'
141 || chQuote == '\'')
142 *pszDst++ = ch;
143 else
144 {
145 ch = *pszCmd++;
146 if (ch)
147 {
148 if ( ch != '\\'
149 && ch != '"'
150 && ch != '`'
151 && ch != '$'
152 && ch != '\n')
153 *pszDst++ = '\\';
154 *pszDst++ = ch;
155 }
156 else
157 {
158 fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart);
159 rc = 1;
160 break;
161 }
162 }
163 }
164 else
165 chQuote = 0;
166 } while ((ch = *pszCmd++) != '\0');
167 }
168 else
169 {
170 /*
171 * Old style in case we ever need it.
172 */
173 ch = *pszCmd++;
174 if (ch != '"' && ch != '\'')
175 {
176 do
177 *pszDst++ = ch;
178 while ((ch = *pszCmd++) != '\0' && !isspace(ch));
179 }
180 else
181 {
182 chQuote = ch;
183 for (;;)
184 {
185 char *pszEnd = strchr(pszCmd, chQuote);
186 if (pszEnd)
187 {
188 fprintf(stderr, "kmk_builtin: Unbalanced quote in argument %d: %s\n", argc, pszSrcStart);
189 rc = 1;
190 break;
191 }
192 memcpy(pszDst, pszCmd, pszEnd - pszCmd);
193 pszDst += pszEnd - pszCmd;
194 if (pszEnd[1] != chQuote)
195 break;
196 *pszDst++ = chQuote;
197 }
198 }
199 }
200 *pszDst++ = '\0';
201
202 /*
203 * Skip argument separators (IFS=space() for now). Check for EOS.
204 */
205 if (ch != 0)
206 while ((ch = *pszCmd) && isspace(ch))
207 pszCmd++;
208 if (ch == 0)
209 break;
210 } while (rc == 0);
211
212 /*
213 * Execute the command if parsing was successful.
214 */
215 if (rc == 0)
216 rc = kmk_builtin_command_parsed(argc, argv, pChild, ppapszArgvToSpawn, pPidSpawned);
217
218 /* clean up and return. */
219 free(argv);
220 free(pszzCmd);
221 return rc;
222}
223
224
225int kmk_builtin_command_parsed(int argc, char **argv, struct child *pChild, char ***ppapszArgvToSpawn, pid_t *pPidSpawned)
226{
227 const char *pszCmd = argv[0];
228 int iUmask;
229 int rc;
230
231 /*
232 * Check and skip the prefix.
233 */
234 if (strncmp(pszCmd, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
235 {
236 fprintf(stderr, "kmk_builtin: Invalid command prefix '%s'!\n", pszCmd);
237 return 1;
238 }
239 pszCmd += sizeof("kmk_builtin_") - 1;
240
241 /*
242 * String switch on the command (frequent stuff at the top).
243 */
244 iUmask = umask(0);
245 umask(iUmask);
246 if (!strcmp(pszCmd, "append"))
247 rc = kmk_builtin_append(argc, argv, environ);
248 else if (!strcmp(pszCmd, "printf"))
249 rc = kmk_builtin_printf(argc, argv, environ);
250 else if (!strcmp(pszCmd, "echo"))
251 rc = kmk_builtin_echo(argc, argv, environ);
252 else if (!strcmp(pszCmd, "install"))
253 rc = kmk_builtin_install(argc, argv, environ);
254 else if (!strcmp(pszCmd, "kDepIDB"))
255 rc = kmk_builtin_kDepIDB(argc, argv, environ);
256#ifdef KBUILD_OS_WINDOWS
257 else if (!strcmp(pszCmd, "kSubmit"))
258 rc = kmk_builtin_kSubmit(argc, argv, environ, pChild, pPidSpawned);
259#endif
260 else if (!strcmp(pszCmd, "mkdir"))
261 rc = kmk_builtin_mkdir(argc, argv, environ);
262 else if (!strcmp(pszCmd, "mv"))
263 rc = kmk_builtin_mv(argc, argv, environ);
264 else if (!strcmp(pszCmd, "redirect"))
265 rc = kmk_builtin_redirect(argc, argv, environ, pChild, pPidSpawned);
266 else if (!strcmp(pszCmd, "rm"))
267 rc = kmk_builtin_rm(argc, argv, environ);
268 else if (!strcmp(pszCmd, "rmdir"))
269 rc = kmk_builtin_rmdir(argc, argv, environ);
270 else if (!strcmp(pszCmd, "test"))
271 rc = kmk_builtin_test(argc, argv, environ, ppapszArgvToSpawn);
272 /* rarely used commands: */
273 else if (!strcmp(pszCmd, "kDepObj"))
274 rc = kmk_builtin_kDepObj(argc, argv, environ);
275 else if (!strcmp(pszCmd, "chmod"))
276 rc = kmk_builtin_chmod(argc, argv, environ);
277 else if (!strcmp(pszCmd, "cp"))
278 rc = kmk_builtin_cp(argc, argv, environ);
279 else if (!strcmp(pszCmd, "expr"))
280 rc = kmk_builtin_expr(argc, argv, environ);
281 else if (!strcmp(pszCmd, "ln"))
282 rc = kmk_builtin_ln(argc, argv, environ);
283 else if (!strcmp(pszCmd, "md5sum"))
284 rc = kmk_builtin_md5sum(argc, argv, environ);
285 else if (!strcmp(pszCmd, "cmp"))
286 rc = kmk_builtin_cmp(argc, argv, environ);
287 else if (!strcmp(pszCmd, "cat"))
288 rc = kmk_builtin_cat(argc, argv, environ);
289 else if (!strcmp(pszCmd, "sleep"))
290 rc = kmk_builtin_sleep(argc, argv, environ);
291 else if (!strcmp(pszCmd, "dircache"))
292#ifdef KBUILD_OS_WINDOWS
293 rc = kmk_builtin_dircache(argc, argv, environ);
294#else
295 rc = 0;
296#endif
297 else
298 {
299 fprintf(stderr, "kmk_builtin: Unknown command '%s'!\n", pszCmd);
300 return 1;
301 }
302
303 /*
304 * Cleanup.
305 */
306 g_progname = "kmk"; /* paranoia, make sure it's not pointing at a freed argv[0]. */
307 umask(iUmask);
308
309
310 /*
311 * If we've executed a conditional test or something that wishes to execute
312 * some child process, check if the child is a kmk_builtin thing. We recurse
313 * here, both because I'm lazy and because it's easier to debug a problem then
314 * (the call stack shows what's been going on).
315 */
316 if ( !rc
317 && *ppapszArgvToSpawn
318 && !strncmp(**ppapszArgvToSpawn, "kmk_builtin_", sizeof("kmk_builtin_") - 1))
319 {
320 char **argv_new = *ppapszArgvToSpawn;
321 int argc_new = 1;
322 while (argv_new[argc_new])
323 argc_new++;
324
325 assert(argv_new[0] != argv[0]);
326 assert(!*pPidSpawned);
327
328 *ppapszArgvToSpawn = NULL;
329 rc = kmk_builtin_command_parsed(argc_new, argv_new, pChild, ppapszArgvToSpawn, pPidSpawned);
330
331 free(argv_new[0]);
332 free(argv_new);
333 }
334
335 return rc;
336}
337
Note: See TracBrowser for help on using the repository browser.

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette