source: trunk/src/kmk/kmkbuiltin/common-env-and-cwd-opt.c@ 2912

Last change on this file since 2912 was 2912, checked in by bird, 9 years ago

rewrote kmk_redirect to skip the separate process. Added chache invalidation after directory deletion for addressing kmk rebuild and fetching.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 8.5 KB
Line 
1/* $Id: common-env-and-cwd-opt.c 2912 2016-09-14 13:36:15Z bird $ */
2/** @file
3 * kMk Builtin command - Commmon environment and CWD option handling code.
4 */
5
6/*
7 * Copyright (c) 2007-2016 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#include "config.h"
30#include <stdio.h>
31#include <stdlib.h>
32#include <string.h>
33
34#include "kmkbuiltin.h"
35#include "err.h"
36
37
38/** The environment variable compare function.
39 * We must use case insensitive compare on windows (Path vs PATH). */
40#ifdef KBUILD_OS_WINDOWS
41# define KSUBMIT_ENV_NCMP _strnicmp
42#else
43# define KSUBMIT_ENV_NCMP strncmp
44#endif
45
46
47/**
48 * Handles the --set var=value option.
49 *
50 * @returns 0 on success, non-zero exit code on error.
51 * @param papszEnv The environment vector.
52 * @param pcEnvVars Pointer to the variable holding the number of
53 * environment variables held by @a papszEnv.
54 * @param pcAllocatedEnvVars Pointer to the variable holding max size of the
55 * environment vector.
56 * @param cVerbosity The verbosity level.
57 * @param pszValue The var=value string to apply.
58 */
59int kBuiltinOptEnvSet(char ***ppapszEnv, unsigned *pcEnvVars, unsigned *pcAllocatedEnvVars, int cVerbosity, const char *pszValue)
60{
61 const char *pszEqual = strchr(pszValue, '=');
62 if (pszEqual)
63 {
64 char **papszEnv = *ppapszEnv;
65 unsigned iEnvVar;
66 unsigned cEnvVars = *pcEnvVars;
67 size_t const cchVar = pszEqual - pszValue;
68 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
69 {
70 char *pszCur = papszEnv[iEnvVar];
71 if ( KSUBMIT_ENV_NCMP(pszCur, pszValue, cchVar) == 0
72 && pszCur[cchVar] == '=')
73 {
74 if (cVerbosity > 0)
75 warnx("replacing '%s' with '%s'", papszEnv[iEnvVar], pszValue);
76 free(papszEnv[iEnvVar]);
77 papszEnv[iEnvVar] = strdup(pszValue);
78 if (!papszEnv[iEnvVar])
79 return errx(1, "out of memory!");
80 break;
81 }
82 }
83 if (iEnvVar == cEnvVars)
84 {
85 /* Append new variable. We probably need to resize the vector. */
86 if ((cEnvVars + 2) > *pcAllocatedEnvVars)
87 {
88 *pcAllocatedEnvVars = (cEnvVars + 2 + 0xf) & ~(unsigned)0xf;
89 papszEnv = (char **)realloc(papszEnv, *pcAllocatedEnvVars * sizeof(papszEnv[0]));
90 if (!papszEnv)
91 return errx(1, "out of memory!");
92 *ppapszEnv = papszEnv;
93 }
94 papszEnv[cEnvVars] = strdup(pszValue);
95 if (!papszEnv[cEnvVars])
96 return errx(1, "out of memory!");
97 papszEnv[++cEnvVars] = NULL;
98 *pcEnvVars = cEnvVars;
99 if (cVerbosity > 0)
100 warnx("added '%s'", papszEnv[iEnvVar]);
101 }
102 else
103 {
104 /* Check for duplicates. */
105 for (iEnvVar++; iEnvVar < cEnvVars; iEnvVar++)
106 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszValue, cchVar) == 0
107 && papszEnv[iEnvVar][cchVar] == '=')
108 {
109 if (cVerbosity > 0)
110 warnx("removing duplicate '%s'", papszEnv[iEnvVar]);
111 free(papszEnv[iEnvVar]);
112 cEnvVars--;
113 if (iEnvVar != cEnvVars)
114 papszEnv[iEnvVar] = papszEnv[cEnvVars];
115 papszEnv[cEnvVars] = NULL;
116 iEnvVar--;
117 }
118 }
119 }
120 else
121 return errx(1, "Missing '=': -E %s", pszValue);
122
123 return 0;
124}
125
126
127/**
128 * Handles the --unset var option.
129 *
130 * @returns 0 on success, non-zero exit code on error.
131 * @param papszEnv The environment vector.
132 * @param pcEnvVars Pointer to the variable holding the number of
133 * environment variables held by @a papszEnv.
134 * @param cVerbosity The verbosity level.
135 * @param pszVarToRemove The name of the variable to remove.
136 */
137int kBuiltinOptEnvUnset(char **papszEnv, unsigned *pcEnvVars, int cVerbosity, const char *pszVarToRemove)
138{
139 if (strchr(pszVarToRemove, '=') == NULL)
140 {
141 unsigned cRemoved = 0;
142 size_t const cchVar = strlen(pszVarToRemove);
143 unsigned cEnvVars = *pcEnvVars;
144 unsigned iEnvVar;
145
146 for (iEnvVar = 0; iEnvVar < cEnvVars; iEnvVar++)
147 if ( KSUBMIT_ENV_NCMP(papszEnv[iEnvVar], pszVarToRemove, cchVar) == 0
148 && papszEnv[iEnvVar][cchVar] == '=')
149 {
150 if (cVerbosity > 0)
151 warnx(!cRemoved ? "removing '%s'" : "removing duplicate '%s'", papszEnv[iEnvVar]);
152 free(papszEnv[iEnvVar]);
153 cEnvVars--;
154 if (iEnvVar != cEnvVars)
155 papszEnv[iEnvVar] = papszEnv[cEnvVars];
156 papszEnv[cEnvVars] = NULL;
157 cRemoved++;
158 iEnvVar--;
159 }
160 *pcEnvVars = cEnvVars;
161
162 if (cVerbosity > 0 && !cRemoved)
163 warnx("not found '%s'", pszVarToRemove);
164 }
165 else
166 return errx(1, "Found invalid variable name character '=' in: -U %s", pszVarToRemove);
167 return 0;
168}
169
170
171
172/**
173 * Handles the --chdir dir option.
174 *
175 * @returns 0 on success, non-zero exit code on error.
176 * @param pszCwd The CWD buffer. Contains current CWD on input,
177 * modified by @a pszValue on output.
178 * @param cbCwdBuf The size of the CWD buffer.
179 * @param pszValue The --chdir value to apply.
180 */
181int kBuiltinOptChDir(char *pszCwd, size_t cbCwdBuf, const char *pszValue)
182{
183 size_t cchNewCwd = strlen(pszValue);
184 size_t offDst;
185 if (cchNewCwd)
186 {
187#ifdef HAVE_DOS_PATHS
188 if (*pszValue == '/' || *pszValue == '\\')
189 {
190 if (pszValue[1] == '/' || pszValue[1] == '\\')
191 offDst = 0; /* UNC */
192 else if (pszCwd[1] == ':' && isalpha(pszCwd[0]))
193 offDst = 2; /* Take drive letter from CWD. */
194 else
195 return errx(1, "UNC relative CWD not implemented: cur='%s' new='%s'", pszCwd, pszValue);
196 }
197 else if ( pszValue[1] == ':'
198 && isalpha(pszValue[0]))
199 {
200 if (pszValue[2] == '/'|| pszValue[2] == '\\')
201 offDst = 0; /* DOS style absolute path. */
202 else if ( pszCwd[1] == ':'
203 && tolower(pszCwd[0]) == tolower(pszValue[0]) )
204 {
205 pszValue += 2; /* Same drive as CWD, append drive relative path from value. */
206 cchNewCwd -= 2;
207 offDst = strlen(pszCwd);
208 }
209 else
210 {
211 /* Get current CWD on the specified drive and append value. */
212 int iDrive = tolower(pszValue[0]) - 'a' + 1;
213 if (!_getdcwd(iDrive, pszCwd, cbCwdBuf))
214 return err(1, "_getdcwd(%d,,) failed", iDrive);
215 pszValue += 2;
216 cchNewCwd -= 2;
217 }
218 }
219#else
220 if (*pszValue == '/')
221 offDst = 0;
222#endif
223 else
224 offDst = strlen(pszCwd); /* Relative path, append to the existing CWD value. */
225
226 /* Do the copying. */
227#ifdef HAVE_DOS_PATHS
228 if (offDst > 0 && pszCwd[offDst - 1] != '/' && pszCwd[offDst - 1] != '\\')
229#else
230 if (offDst > 0 && pszCwd[offDst - 1] != '/')
231#endif
232 pszCwd[offDst++] = '/';
233 if (offDst + cchNewCwd >= cbCwdBuf)
234 return errx(1, "Too long CWD: %*.*s%s", offDst, offDst, pszCwd, pszValue);
235 memcpy(&pszCwd[offDst], pszValue, cchNewCwd + 1);
236 }
237 /* else: relative, no change - quitely ignore. */
238 return 0;
239}
240
Note: See TracBrowser for help on using the repository browser.