~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Wine Cross Reference
wine/dlls/kernel32/environ.c

Version: ~ [ wine-1.5.30 ] ~ [ wine-1.5.29 ] ~ [ wine-1.5.28 ] ~ [ wine-1.5.27 ] ~ [ wine-1.5.26 ] ~ [ wine-1.5.25 ] ~ [ wine-1.5.24 ] ~ [ wine-1.5.23 ] ~ [ wine-1.5.22 ] ~ [ wine-1.5.21 ] ~ [ wine-1.5.20 ] ~ [ wine-1.5.19 ] ~ [ wine-1.5.18 ] ~ [ wine-1.5.17 ] ~ [ wine-1.5.16 ] ~ [ wine-1.5.15 ] ~ [ wine-1.5.14 ] ~ [ wine-1.5.13 ] ~ [ wine-1.5.12 ] ~ [ wine-1.5.11 ] ~ [ wine-1.5.10 ] ~ [ wine-1.5.9 ] ~ [ wine-1.5.8 ] ~ [ wine-1.5.7 ] ~ [ wine-1.4.1 ] ~ [ wine-1.5.6 ] ~ [ wine-1.5.5 ] ~ [ wine-1.5.4 ] ~ [ wine-1.5.3 ] ~ [ wine-1.5.2 ] ~ [ wine-1.5.1 ] ~ [ wine-1.5.0 ] ~ [ wine-1.4 ] ~ [ wine-1.4-rc6 ] ~ [ wine-1.4-rc5 ] ~ [ wine-1.4-rc4 ] ~ [ wine-1.4-rc3 ] ~ [ wine-1.4-rc2 ] ~ [ wine-1.4-rc1 ] ~ [ wine-1.3.37 ] ~ [ wine-1.3.36 ] ~ [ wine-1.3.35 ] ~ [ wine-1.3.34 ] ~ [ wine-1.3.33 ] ~ [ wine-1.3.32 ] ~ [ wine-1.3.31 ] ~ [ wine-1.3.30 ] ~ [ wine-1.3.29 ] ~ [ wine-1.3.28 ] ~ [ wine-1.3.27 ] ~ [ wine-1.3.26 ] ~ [ wine-1.3.25 ] ~ [ wine-1.3.24 ] ~ [ wine-1.3.23 ] ~ [ wine-1.3.22 ] ~ [ wine-1.3.21 ] ~ [ wine-1.3.20 ] ~ [ wine-1.3.19 ] ~ [ wine-1.3.18 ] ~ [ wine-1.2.3 ] ~ [ wine-1.3.17 ] ~ [ wine-1.3.16 ] ~ [ wine-1.3.15 ] ~ [ wine-1.3.14 ] ~ [ wine-1.3.13 ] ~ [ wine-1.3.12 ] ~ [ wine-1.3.11 ] ~ [ wine-1.3.10 ] ~ [ wine-1.3.9 ] ~ [ wine-1.2.2 ] ~ [ wine-1.3.8 ] ~ [ wine-1.3.7 ] ~ [ wine-1.3.6 ] ~ [ wine-1.3.5 ] ~ [ wine-1.2.1 ] ~ [ wine-1.3.4 ] ~ [ wine-1.3.3 ] ~ [ wine-1.3.2 ] ~ [ wine-1.3.1 ] ~ [ wine-1.3.0 ] ~ [ wine-1.2 ] ~ [ wine-1.2-rc7 ] ~ [ wine-1.2-rc6 ] ~ [ wine-1.2-rc5 ] ~ [ wine-1.2-rc4 ] ~ [ wine-1.2-rc3 ] ~ [ wine-1.2-rc2 ] ~ [ wine-1.2-rc1 ] ~ [ wine-1.1.44 ] ~ [ wine-1.1.43 ] ~ [ wine-1.1.42 ] ~ [ wine-1.1.41 ] ~ [ wine-1.1.40 ] ~ [ wine-1.1.39 ] ~ [ wine-1.1.38 ] ~ [ wine-1.1.37 ] ~ [ wine-1.1.36 ] ~ [ wine-1.1.35 ] ~ [ wine-1.1.34 ] ~ [ wine-1.1.33 ] ~ [ wine-1.1.32 ] ~ [ wine-1.1.31 ] ~ [ wine-1.1.30 ] ~ [ wine-1.1.29 ] ~ [ wine-1.1.28 ] ~ [ wine-1.1.27 ] ~ [ wine-1.1.26 ] ~ [ wine-1.1.25 ] ~ [ wine-1.1.24 ] ~ [ wine-1.1.23 ] ~ [ wine-1.1.22 ] ~ [ wine-1.1.21 ] ~ [ wine-1.1.20 ] ~ [ wine-1.1.19 ] ~ [ wine-1.1.18 ] ~ [ wine-1.1.17 ] ~ [ wine-1.1.16 ] ~ [ wine-1.1.15 ] ~ [ wine-1.1.14 ] ~ [ wine-1.1.13 ] ~ [ wine-1.1.12 ] ~ [ wine-1.1.11 ] ~ [ wine-1.1.10 ] ~ [ wine-1.1.9 ] ~ [ wine-1.1.8 ] ~ [ wine-1.1.7 ] ~ [ wine-1.0.1 ] ~ [ wine-1.1.6 ] ~ [ wine-1.1.5 ] ~ [ wine-1.1.4 ] ~ [ wine-1.1.3 ] ~ [ wine-1.1.2 ] ~ [ wine-1.1.1 ] ~ [ wine-1.1.0 ] ~ [ wine-1.0 ] ~

  1 /*
  2  * Process environment management
  3  *
  4  * Copyright 1996, 1998 Alexandre Julliard
  5  *
  6  * This library is free software; you can redistribute it and/or
  7  * modify it under the terms of the GNU Lesser General Public
  8  * License as published by the Free Software Foundation; either
  9  * version 2.1 of the License, or (at your option) any later version.
 10  *
 11  * This library is distributed in the hope that it will be useful,
 12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 14  * Lesser General Public License for more details.
 15  *
 16  * You should have received a copy of the GNU Lesser General Public
 17  * License along with this library; if not, write to the Free Software
 18  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 19  */
 20 
 21 #include "config.h"
 22 #include "wine/port.h"
 23 
 24 #include <stdarg.h>
 25 #include <stdlib.h>
 26 #include <string.h>
 27 #include <assert.h>
 28 
 29 #include "ntstatus.h"
 30 #define WIN32_NO_STATUS
 31 #include "windef.h"
 32 #include "winbase.h"
 33 #include "winerror.h"
 34 #include "wine/library.h"
 35 #include "winternl.h"
 36 #include "wine/unicode.h"
 37 #include "wine/debug.h"
 38 
 39 #include "kernel_private.h"
 40 
 41 WINE_DEFAULT_DEBUG_CHANNEL(environ);
 42 
 43 /* Notes:
 44  * - contrary to Microsoft docs, the environment strings do not appear
 45  *   to be sorted on Win95 (although they are on NT); so we don't bother
 46  *   to sort them either.
 47  */
 48 
 49 static STARTUPINFOW startup_infoW;
 50 static STARTUPINFOA startup_infoA;
 51 
 52 
 53 /***********************************************************************
 54  *           GetCommandLineA      (KERNEL32.@)
 55  *
 56  * WARNING: there's a Windows incompatibility lurking here !
 57  * Win32s always includes the full path of the program file,
 58  * whereas Windows NT only returns the full file path plus arguments
 59  * in case the program has been started with a full path.
 60  * Win9x seems to have inherited NT behaviour.
 61  *
 62  * Note that both Start Menu Execute and Explorer start programs with
 63  * fully specified quoted app file paths, which is why probably the only case
 64  * where you'll see single file names is in case of direct launch
 65  * via CreateProcess or WinExec.
 66  *
 67  * Perhaps we should take care of Win3.1 programs here (Win32s "feature").
 68  *
 69  * References: MS KB article q102762.txt (special Win32s handling)
 70  */
 71 LPSTR WINAPI GetCommandLineA(void)
 72 {
 73     static char *cmdlineA;  /* ASCII command line */
 74     
 75     if (!cmdlineA) /* make an ansi version if we don't have it */
 76     {
 77         ANSI_STRING     ansi;
 78         RtlAcquirePebLock();
 79 
 80         cmdlineA = (RtlUnicodeStringToAnsiString( &ansi, &NtCurrentTeb()->Peb->ProcessParameters->CommandLine, TRUE) == STATUS_SUCCESS) ?
 81             ansi.Buffer : NULL;
 82         RtlReleasePebLock();
 83     }
 84     return cmdlineA;
 85 }
 86 
 87 /***********************************************************************
 88  *           GetCommandLineW      (KERNEL32.@)
 89  */
 90 LPWSTR WINAPI GetCommandLineW(void)
 91 {
 92     return NtCurrentTeb()->Peb->ProcessParameters->CommandLine.Buffer;
 93 }
 94 
 95 
 96 /***********************************************************************
 97  *           GetEnvironmentStringsA   (KERNEL32.@)
 98  *           GetEnvironmentStrings    (KERNEL32.@)
 99  */
100 LPSTR WINAPI GetEnvironmentStringsA(void)
101 {
102     LPWSTR      ptrW;
103     unsigned    len, slen;
104     LPSTR       ret, ptrA;
105 
106     RtlAcquirePebLock();
107 
108     len = 1;
109 
110     ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
111     while (*ptrW)
112     {
113         slen = strlenW(ptrW) + 1;
114         len += WideCharToMultiByte( CP_ACP, 0, ptrW, slen, NULL, 0, NULL, NULL );
115         ptrW += slen;
116     }
117 
118     if ((ret = HeapAlloc( GetProcessHeap(), 0, len )) != NULL)
119     {
120         ptrW = NtCurrentTeb()->Peb->ProcessParameters->Environment;
121         ptrA = ret;
122         while (*ptrW)
123         {
124             slen = strlenW(ptrW) + 1;
125             WideCharToMultiByte( CP_ACP, 0, ptrW, slen, ptrA, len, NULL, NULL );
126             ptrW += slen;
127             ptrA += strlen(ptrA) + 1;
128         }
129         *ptrA = 0;
130     }
131 
132     RtlReleasePebLock();
133     return ret;
134 }
135 
136 
137 /***********************************************************************
138  *           GetEnvironmentStringsW   (KERNEL32.@)
139  */
140 LPWSTR WINAPI GetEnvironmentStringsW(void)
141 {
142     return NtCurrentTeb()->Peb->ProcessParameters->Environment;
143 }
144 
145 
146 /***********************************************************************
147  *           FreeEnvironmentStringsA   (KERNEL32.@)
148  */
149 BOOL WINAPI FreeEnvironmentStringsA( LPSTR ptr )
150 {
151     return HeapFree( GetProcessHeap(), 0, ptr );
152 }
153 
154 
155 /***********************************************************************
156  *           FreeEnvironmentStringsW   (KERNEL32.@)
157  */
158 BOOL WINAPI FreeEnvironmentStringsW( LPWSTR ptr )
159 {
160     return TRUE;
161 }
162 
163 
164 /***********************************************************************
165  *           GetEnvironmentVariableA   (KERNEL32.@)
166  */
167 DWORD WINAPI GetEnvironmentVariableA( LPCSTR name, LPSTR value, DWORD size )
168 {
169     UNICODE_STRING      us_name;
170     PWSTR               valueW;
171     DWORD               ret;
172 
173     if (!name || !*name)
174     {
175         SetLastError(ERROR_ENVVAR_NOT_FOUND);
176         return 0;
177     }
178 
179     if (!(valueW = HeapAlloc(GetProcessHeap(), 0, size * sizeof(WCHAR))))
180         return 0;
181 
182     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
183     SetLastError(0);
184     ret = GetEnvironmentVariableW( us_name.Buffer, valueW, size);
185     if (ret && ret < size)
186     {
187         WideCharToMultiByte( CP_ACP, 0, valueW, ret + 1, value, size, NULL, NULL );
188     }
189     /* this is needed to tell, with 0 as a return value, the difference between:
190      * - an error (GetLastError() != 0)
191      * - returning an empty string (in this case, we need to update the buffer)
192      */
193     if (ret == 0 && size && GetLastError() == 0)
194         value[0] = '\0';
195 
196     RtlFreeUnicodeString( &us_name );
197     HeapFree(GetProcessHeap(), 0, valueW);
198 
199     return ret;
200 }
201 
202 
203 /***********************************************************************
204  *           GetEnvironmentVariableW   (KERNEL32.@)
205  */
206 DWORD WINAPI GetEnvironmentVariableW( LPCWSTR name, LPWSTR val, DWORD size )
207 {
208     UNICODE_STRING      us_name;
209     UNICODE_STRING      us_value;
210     NTSTATUS            status;
211     unsigned            len;
212 
213     TRACE("(%s %p %u)\n", debugstr_w(name), val, size);
214 
215     if (!name || !*name)
216     {
217         SetLastError(ERROR_ENVVAR_NOT_FOUND);
218         return 0;
219     }
220 
221     RtlInitUnicodeString(&us_name, name);
222     us_value.Length = 0;
223     us_value.MaximumLength = (size ? size - 1 : 0) * sizeof(WCHAR);
224     us_value.Buffer = val;
225 
226     status = RtlQueryEnvironmentVariable_U(NULL, &us_name, &us_value);
227     len = us_value.Length / sizeof(WCHAR);
228     if (status != STATUS_SUCCESS)
229     {
230         SetLastError( RtlNtStatusToDosError(status) );
231         return (status == STATUS_BUFFER_TOO_SMALL) ? len + 1 : 0;
232     }
233     if (size) val[len] = '\0';
234 
235     return us_value.Length / sizeof(WCHAR);
236 }
237 
238 
239 /***********************************************************************
240  *           SetEnvironmentVariableA   (KERNEL32.@)
241  */
242 BOOL WINAPI SetEnvironmentVariableA( LPCSTR name, LPCSTR value )
243 {
244     UNICODE_STRING      us_name;
245     BOOL                ret;
246 
247     if (!name)
248     {
249         SetLastError(ERROR_ENVVAR_NOT_FOUND);
250         return 0;
251     }
252 
253     RtlCreateUnicodeStringFromAsciiz( &us_name, name );
254     if (value)
255     {
256         UNICODE_STRING      us_value;
257 
258         RtlCreateUnicodeStringFromAsciiz( &us_value, value );
259         ret = SetEnvironmentVariableW( us_name.Buffer, us_value.Buffer );
260         RtlFreeUnicodeString( &us_value );
261     }
262     else ret = SetEnvironmentVariableW( us_name.Buffer, NULL );
263 
264     RtlFreeUnicodeString( &us_name );
265 
266     return ret;
267 }
268 
269 
270 /***********************************************************************
271  *           SetEnvironmentVariableW   (KERNEL32.@)
272  */
273 BOOL WINAPI SetEnvironmentVariableW( LPCWSTR name, LPCWSTR value )
274 {
275     UNICODE_STRING      us_name;
276     NTSTATUS            status;
277 
278     TRACE("(%s %s)\n", debugstr_w(name), debugstr_w(value));
279 
280     if (!name)
281     {
282         SetLastError(ERROR_ENVVAR_NOT_FOUND);
283         return 0;
284     }
285 
286     RtlInitUnicodeString(&us_name, name);
287     if (value)
288     {
289         UNICODE_STRING      us_value;
290 
291         RtlInitUnicodeString(&us_value, value);
292         status = RtlSetEnvironmentVariable(NULL, &us_name, &us_value);
293     }
294     else status = RtlSetEnvironmentVariable(NULL, &us_name, NULL);
295 
296     if (status != STATUS_SUCCESS)
297     {
298         SetLastError( RtlNtStatusToDosError(status) );
299         return FALSE;
300     }
301     return TRUE;
302 }
303 
304 
305 /***********************************************************************
306  *           ExpandEnvironmentStringsA   (KERNEL32.@)
307  *
308  * See ExpandEnvironmentStringsW.
309  *
310  * Note: overlapping buffers are not supported; this is how it should be.
311  * FIXME: return value is wrong for MBCS
312  */
313 DWORD WINAPI ExpandEnvironmentStringsA( LPCSTR src, LPSTR dst, DWORD count )
314 {
315     UNICODE_STRING      us_src;
316     PWSTR               dstW = NULL;
317     DWORD               ret;
318 
319     RtlCreateUnicodeStringFromAsciiz( &us_src, src );
320     if (count)
321     {
322         if (!(dstW = HeapAlloc(GetProcessHeap(), 0, count * sizeof(WCHAR))))
323             return 0;
324         ret = ExpandEnvironmentStringsW( us_src.Buffer, dstW, count);
325         if (ret)
326             WideCharToMultiByte( CP_ACP, 0, dstW, ret, dst, count, NULL, NULL );
327     }
328     else ret = ExpandEnvironmentStringsW( us_src.Buffer, NULL, 0);
329 
330     RtlFreeUnicodeString( &us_src );
331     HeapFree(GetProcessHeap(), 0, dstW);
332 
333     return ret;
334 }
335 
336 
337 /***********************************************************************
338  *           ExpandEnvironmentStringsW   (KERNEL32.@)
339  *
340  * Replaces references to environment variables of the form '%EnvVar%'
341  * by their value. If the environment variable does not exist, then the
342  * reference is left as is.
343  *
344  * PARAMS
345  *  src       [I] The string to be expanded.
346  *  dst       [O] The buffer in which to put the expanded string.
347  *  len       [I] The buffer size, in characters.
348  *
349  * RETURNS
350  *  The number of characters copied into the buffer. If the buffer is
351  *  too small, then the required buffer size, in characters including the
352  *  trailing '\0', is returned.
353  *  If the function fails for some other reason, then it returns 0.
354  */
355 DWORD WINAPI ExpandEnvironmentStringsW( LPCWSTR src, LPWSTR dst, DWORD len )
356 {
357     UNICODE_STRING      us_src;
358     UNICODE_STRING      us_dst;
359     NTSTATUS            status;
360     DWORD               res;
361 
362     TRACE("(%s %p %u)\n", debugstr_w(src), dst, len);
363 
364     RtlInitUnicodeString(&us_src, src);
365 
366     /* make sure we don't overflow the maximum UNICODE_STRING size */
367     if (len > UNICODE_STRING_MAX_CHARS)
368         len = UNICODE_STRING_MAX_CHARS;
369 
370     us_dst.Length = 0;
371     us_dst.MaximumLength = len * sizeof(WCHAR);
372     us_dst.Buffer = dst;
373 
374     res = 0;
375     status = RtlExpandEnvironmentStrings_U(NULL, &us_src, &us_dst, &res);
376     res /= sizeof(WCHAR);
377     if (status != STATUS_SUCCESS)
378     {
379         SetLastError( RtlNtStatusToDosError(status) );
380         if (status != STATUS_BUFFER_TOO_SMALL) return 0;
381         if (len && dst) dst[len - 1] = '\0';
382     }
383 
384     return res;
385 }
386 
387 
388 /***********************************************************************
389  *           GetStdHandle    (KERNEL32.@)
390  */
391 HANDLE WINAPI GetStdHandle( DWORD std_handle )
392 {
393     switch (std_handle)
394     {
395         case STD_INPUT_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdInput;
396         case STD_OUTPUT_HANDLE: return NtCurrentTeb()->Peb->ProcessParameters->hStdOutput;
397         case STD_ERROR_HANDLE:  return NtCurrentTeb()->Peb->ProcessParameters->hStdError;
398     }
399     SetLastError( ERROR_INVALID_HANDLE );
400     return INVALID_HANDLE_VALUE;
401 }
402 
403 
404 /***********************************************************************
405  *           SetStdHandle    (KERNEL32.@)
406  */
407 BOOL WINAPI SetStdHandle( DWORD std_handle, HANDLE handle )
408 {
409     switch (std_handle)
410     {
411         case STD_INPUT_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdInput = handle;  return TRUE;
412         case STD_OUTPUT_HANDLE: NtCurrentTeb()->Peb->ProcessParameters->hStdOutput = handle; return TRUE;
413         case STD_ERROR_HANDLE:  NtCurrentTeb()->Peb->ProcessParameters->hStdError = handle;  return TRUE;
414     }
415     SetLastError( ERROR_INVALID_HANDLE );
416     return FALSE;
417 }
418 
419 /***********************************************************************
420  *              GetStartupInfoA         (KERNEL32.@)
421  */
422 VOID WINAPI GetStartupInfoA( LPSTARTUPINFOA info )
423 {
424     *info = startup_infoA;
425 }
426 
427 
428 /***********************************************************************
429  *              GetStartupInfoW         (KERNEL32.@)
430  */
431 VOID WINAPI GetStartupInfoW( LPSTARTUPINFOW info )
432 {
433     *info = startup_infoW;
434 }
435 
436 /******************************************************************
437  *              ENV_CopyStartupInformation (internal)
438  *
439  * Creates the STARTUPINFO information from the ntdll information
440  */
441 void ENV_CopyStartupInformation(void)
442 {
443     RTL_USER_PROCESS_PARAMETERS* rupp;
444     ANSI_STRING         ansi;
445 
446     RtlAcquirePebLock();
447     
448     rupp = NtCurrentTeb()->Peb->ProcessParameters;
449 
450     startup_infoW.cb                   = sizeof(startup_infoW);
451     startup_infoW.lpReserved           = NULL;
452     startup_infoW.lpDesktop            = rupp->Desktop.Buffer;
453     startup_infoW.lpTitle              = rupp->WindowTitle.Buffer;
454     startup_infoW.dwX                  = rupp->dwX;
455     startup_infoW.dwY                  = rupp->dwY;
456     startup_infoW.dwXSize              = rupp->dwXSize;
457     startup_infoW.dwYSize              = rupp->dwYSize;
458     startup_infoW.dwXCountChars        = rupp->dwXCountChars;
459     startup_infoW.dwYCountChars        = rupp->dwYCountChars;
460     startup_infoW.dwFillAttribute      = rupp->dwFillAttribute;
461     startup_infoW.dwFlags              = rupp->dwFlags;
462     startup_infoW.wShowWindow          = rupp->wShowWindow;
463     startup_infoW.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
464     startup_infoW.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
465     startup_infoW.hStdInput            = rupp->hStdInput;
466     startup_infoW.hStdOutput           = rupp->hStdOutput;
467     startup_infoW.hStdError            = rupp->hStdError;
468 
469     startup_infoA.cb                   = sizeof(startup_infoA);
470     startup_infoA.lpReserved           = NULL;
471     startup_infoA.lpDesktop = RtlUnicodeStringToAnsiString( &ansi, &rupp->Desktop, TRUE ) == STATUS_SUCCESS ?
472         ansi.Buffer : NULL;
473     startup_infoA.lpTitle = RtlUnicodeStringToAnsiString( &ansi, &rupp->WindowTitle, TRUE ) == STATUS_SUCCESS ?
474         ansi.Buffer : NULL;
475     startup_infoA.dwX                  = rupp->dwX;
476     startup_infoA.dwY                  = rupp->dwY;
477     startup_infoA.dwXSize              = rupp->dwXSize;
478     startup_infoA.dwYSize              = rupp->dwYSize;
479     startup_infoA.dwXCountChars        = rupp->dwXCountChars;
480     startup_infoA.dwYCountChars        = rupp->dwYCountChars;
481     startup_infoA.dwFillAttribute      = rupp->dwFillAttribute;
482     startup_infoA.dwFlags              = rupp->dwFlags;
483     startup_infoA.wShowWindow          = rupp->wShowWindow;
484     startup_infoA.cbReserved2          = rupp->RuntimeInfo.MaximumLength;
485     startup_infoA.lpReserved2          = rupp->RuntimeInfo.MaximumLength ? (void*)rupp->RuntimeInfo.Buffer : NULL;
486     startup_infoA.hStdInput            = rupp->hStdInput;
487     startup_infoA.hStdOutput           = rupp->hStdOutput;
488     startup_infoA.hStdError            = rupp->hStdError;
489 
490     RtlReleasePebLock();
491 }
492 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.