OSDN Git Service

Avoid proliferation of static snprintf() implementations.
[mingw/mingw-org-wsl.git] / mingwrt / mingwex / setenv.c
1 /*
2  * setenv.c
3  *
4  * Implementation of POSIX standard IEEE 1003.1-2001 setenv() function;
5  * may also be invoked inline, as "retval = setenv( varname, NULL, 1 )",
6  * to implement the complementary unsetenv() function.
7  *
8  * $Id$
9  *
10  * Written by Keith Marshall <keith@users.osdn.me>
11  * Copyright (C) 2016, 2021, MinGW.org Project
12  *
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of this software and associated documentation files (the "Software"),
16  * to deal in the Software without restriction, including without limitation
17  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
18  * and/or sell copies of the Software, and to permit persons to whom the
19  * Software is furnished to do so, subject to the following conditions:
20  *
21  * The above copyright notice and this permission notice shall be included
22  * in all copies or substantial portions of the Software.
23  *
24  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
25  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
27  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
30  * DEALINGS IN THE SOFTWARE.
31  *
32  */
33 #define _POSIX_C_SOURCE 200112L
34
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <errno.h>
39
40 int __mingw_setenv( const char *var, const char *value, int overwrite )
41 {
42   /* Core implementation for both setenv() and unsetenv() functions;
43    * at the outset, assume that the requested operation may fail.
44    */
45   int retval = -1;
46
47   /* The specified "var" name MUST be non-NULL, not a zero-length
48    * string, and must not include any '=' character.
49    */
50   if( var && *var && (strchr( var, '=' ) == NULL) )
51   {
52     /* A properly named variable may be added to, removed from,
53      * or modified within the environment, ONLY if "overwrite"
54      * mode is enabled, OR if the named variable does not yet
55      * exist...
56      */
57     if( overwrite || getenv( var ) == NULL )
58     {
59       /* ... in which cases, we convert the specified name and
60        * value into the appropriate form for use with putenv(),
61        * (noting that we accept a NULL "value" as equivalent to
62        * a zero-length string, which renders putenv() as the
63        * equivalent of unsetenv()).
64        */
65       const char *fmt = "%s=%s";
66       const char *val = value ? value : "";
67       char buf[1 + __mingw_snprintf( NULL, 0, fmt, var, val )];
68       __mingw_snprintf( buf, sizeof( buf ), fmt, var, val );
69
70       /* "buf" is now formatted as "var=value", in the form
71        * required by putenv(), but it exists only within our
72        * volatile stack-frame space.  POSIX.1 suggests that we
73        * should copy it to more persistent storage, before it
74        * is passed to putenv(), to associate an environment
75        * pointer with it.  However, we note that Microsoft's
76        * putenv() implementation appears to make such a copy
77        * in any case, so we do not do so; (in fact, if we did
78        * strdup() it (say), then we would leak memory).
79        */
80       if( (retval = putenv( buf )) != 0 )
81         /*
82          * If putenv() returns non-zero, indicating failure, the
83          * most probable explanation is that there wasn't enough
84          * free memory; ensure that errno is set accordingly.
85          */
86         errno = ENOMEM;
87     }
88     else
89       /* The named variable already exists, and overwrite mode
90        * was not enabled; there is nothing to be done.
91        */
92       retval = 0;
93   }
94   else
95     /* The specified environment variable name was invalid.
96      */
97     errno = EINVAL;
98
99   /* Succeed or fail, "retval" has now been set to indicate the
100    * appropriate status for return.
101    */
102   return retval;
103 }
104
105 /* $RCSfile$: end of file */