1 /*******************************************************************************
2 
3         Copyright:
4             Copyright (c) 2007 Tango contributors.
5             Some parts copyright (c) 2009-2016 dunnhumby Germany GmbH.
6             All rights reserved.
7 
8         License:
9             Tango Dual License: 3-Clause BSD License / Academic Free License v3.0.
10             See LICENSE_TANGO.txt for details.
11 
12         Version: Feb 2007: Initial release
13 
14         Authors: Deewiant, Maxter, Gregor, Kris
15 
16 *******************************************************************************/
17 
18 module ocean.sys.Environment;
19 
20 import ocean.core.ExceptionDefinitions;
21 import ocean.io.model.IFile;
22 import ocean.io.Path;
23 import ocean.io.FilePath;
24 import ocean.sys.Common;
25 import Text = ocean.text.Util;
26 import ocean.transition;
27 
28 import core.stdc.string;
29 import core.sys.posix.stdlib;
30 
31 private
32 {
33     __gshared extern (C) extern char** environ;
34 }
35 
36 
37 /*******************************************************************************
38 
39         Exposes the system Environment settings, along with some handy
40         utilities
41 
42 *******************************************************************************/
43 
44 struct Environment
45 {
46         public alias cwd directory;
47 
48         /***********************************************************************
49 
50                 Throw an exception
51 
52         ***********************************************************************/
53 
54         private static void exception (istring msg)
55         {
56                 throw new PlatformException (msg);
57         }
58 
59         /***********************************************************************
60 
61             Returns an absolute version of the provided path, where cwd is used
62             as the prefix.
63 
64             The provided path is returned as is if already absolute.
65 
66         ***********************************************************************/
67 
68         static istring toAbsolute(mstring path)
69         {
70             scope fp = new FilePath(path);
71             if (fp.isAbsolute)
72                 return idup(path);
73 
74             fp.absolute(cwd);
75             return fp.toString;
76         }
77 
78         /***********************************************************************
79 
80                 Returns the full path location of the provided executable
81                 file, rifling through the PATH as necessary.
82 
83                 Returns null if the provided filename was not found
84 
85         ***********************************************************************/
86 
87         static FilePath exePath (cstring file)
88         {
89                 auto bin = new FilePath (file);
90 
91                 // is this a directory? Potentially make it absolute
92                 if (bin.isChild && !bin.isAbsolute)
93                     return bin.absolute (cwd);
94 
95                 // rifle through the path (after converting to standard format)
96                 foreach (_pe; Text.patterns (standard(get("PATH").dup), FileConst.SystemPathString))
97                 {
98                     auto pe = assumeUnique(_pe); // only acessible via foreach args
99 
100                     if (bin.path(pe).exists)
101                     {
102                         stat_t stats;
103                         stat(bin.cString.ptr, &stats);
104                         if (stats.st_mode & Octal!("100"))
105                             return bin;
106                     }
107                 }
108                 return null;
109         }
110 
111     /***************************************************************************
112 
113         Returns:
114             the provided 'def' value if the variable does not exist
115 
116     ***************************************************************************/
117 
118     static istring get (cstring variable, istring def = null)
119     {
120         char* ptr = getenv ((variable ~ '\0').ptr);
121 
122         if (ptr is null)
123             return def;
124 
125         return idup(ptr[0 .. strlen(ptr)]);
126     }
127 
128     /***************************************************************************
129 
130         Clears the variable, if value is null or empty
131 
132     ***************************************************************************/
133 
134     static void set (cstring variable, cstring value = null)
135     {
136         int result;
137 
138         if (value.length is 0)
139             unsetenv ((variable ~ '\0').ptr);
140         else
141             result = setenv ((variable ~ '\0').ptr, (value ~ '\0').ptr, 1);
142 
143         if (result != 0)
144             exception (SysError.lastMsg);
145     }
146 
147     /***************************************************************************
148 
149         Get all set environment variables as an associative array.
150 
151     ***************************************************************************/
152 
153     static istring[istring] get ()
154     {
155         istring[istring] arr;
156 
157         for (char** p = environ; *p; ++p)
158         {
159             size_t k = 0;
160             char* str = *p;
161 
162             while (*str++ != '=')
163                 ++k;
164             istring key = idup((*p)[0..k]);
165 
166             k = 0;
167             char* val = str;
168             while (*str++)
169                 ++k;
170             arr[key] = idup(val[0 .. k]);
171         }
172 
173         return arr;
174     }
175 
176     /***************************************************************************
177 
178         Set the current working directory
179 
180     ***************************************************************************/
181 
182     static void cwd (cstring path)
183     {
184         char[512] tmp = void;
185         tmp [path.length] = 0;
186         tmp[0..path.length] = path;
187 
188         if (core.sys.posix.unistd.chdir (tmp.ptr))
189             exception ("Failed to set current directory");
190     }
191 
192     /***************************************************************************
193 
194         Get the current working directory
195 
196     ***************************************************************************/
197 
198     static istring cwd ()
199     {
200         char[512] tmp = void;
201 
202         char *s = core.sys.posix.unistd.getcwd (tmp.ptr, tmp.length);
203         if (s is null)
204             exception ("Failed to get current directory");
205 
206         auto path = s[0 .. strlen(s)+1].dup;
207         if (path[$-2] is '/') // root path has the slash
208             path.length = path.length-1;
209         else
210             path[$-1] = '/';
211         return assumeUnique(path);
212     }
213 }