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