Chapter 8 of POSIX standard define a list of commonly used environment variables "that are frequently exported by widely used command interpreters and applications".
However I cannot find any C header providing their names in any of my unix-like systems.
I'm looking for something like:
#define ENV_PATH "PATH"
#define ENV_USER "USER"
#define ENV_IFS "IFS"
...
Where I can find such header? Any OS-specific header would work: I just don't want to invent names for the constants myself.
edit
If you are used to only mainstream operating systems, you might ask: why you want to use constants here? $PATH is always $PATH everywhere!
This is not actually true.
In Plan 9 from Bell Labs, environment variables are usually lowercase (apparently due to aesthetics).
In Jehanne, a new operating system derived by Plan 9, I'm reconsidering this design choice, to ease the integration of POSIX tools. However, since I like the lowercase environment variables, I'd like to be able to easily switch back to lowercase names when Jehanne will be "the one true operating system" :-D
As stated in the comments, there is no header file that provides any POSIX-specified list of environment variables used by applications and utilities.
A list of "certain variables that are frequently exported by widely used command interpreters and applications" can be found at http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap08.html#tag_08. (The actual environment variable list requires reformatting but here it is anyway...)
It is unwise to conflict with certain variables that are frequently
exported by widely used command interpreters and applications:
ARFLAGS IFS MAILPATH PS1
CC LANG MAILRC PS2
CDPATH LC_ALL MAKEFLAGS PS3
CFLAGS LC_COLLATE MAKESHELL PS4
CHARSET LC_CTYPE MANPATH PWD
COLUMNS LC_MESSAGES MBOX RANDOM
DATEMSK LC_MONETARY MORE SECONDS
DEAD LC_NUMERIC MSGVERB SHELL
EDITOR LC_TIME NLSPATH TERM
ENV LDFLAGS NPROC TERMCAP
EXINIT LEX OLDPWD TERMINFO
FC LFLAGS OPTARG TMPDIR
FCEDIT LINENO OPTERR TZ
FFLAGS LINES OPTIND USER
GET LISTER PAGER VISUAL
GFLAGS LOGNAME PATH YACC
HISTFILE LPDEST PPID YFLAGS
HISTORY MAIL PRINTER
HISTSIZE MAILCHECK PROCLANG
HOME MAILER PROJECTDIR
To access the value of an environment variable, use the getenv() function.
The exec() function documentation specifies the char **environ variable:
In addition, the following variable, which must be declared by the
user if it is to be used directly:
extern char **environ;
is initialized as a pointer to an array of character pointers to the
environment strings. The argv and environ arrays are each terminated
by a null pointer. . The null pointer terminating the argv array is not counted in argc.
Applications can change the entire environment in a single operation
by assigning the environ variable to point to an array of character
pointers to the new environment strings. After assigning a new value
to environ, applications should not rely on the new environment
strings remaining part of the environment, as a call to getenv(),
putenv(), setenv(), unsetenv(), or
any function that is dependent on an environment variable may, on
noticing that environ has changed, copy the environment strings to a
new array and assign environ to point to it.
Any application that directly modifies the pointers to which the
environ variable points has undefined behavior.
Conforming multi-threaded applications shall not use the environ
variable to access or modify any environment variable while any other
thread is concurrently modifying any environment variable. A call to
any function dependent on any environment variable shall be considered
a use of the environ variable to access that environment variable.
You can do something like that and in get_env_variables function you modify what you want. Just create something like a strncmp function for check if you want to modify this variable or not.
int main(int ac, char **av, char **env){
int i = 0;
while (env[i] != NULL){
env[i] = get_env_variables(env[i]);
i++;
}
}
char *get_env_variables(char *str) {
// PUT SOME CODE HERE
}
EDIT : don't forgot to return new env[i].
Related
I'm new to programming and when trying to write a program in C with Turkish characters in it, the characters are not correct on terminal. Using setlocale(LC_ALL, "Turkish"); works but am I going to write this code everytime a write a new program? Is there a way to "force" this by default so I can get rid of this process?
The C Standard §7.11.1.1 The setlocale function ¶3-4 says:
A value of "C" for locale specifies the minimal environment for C translation; a value of "" for locale specifies the locale-specific native environment. Other implementation-defined strings may be passed as the second argument to setlocale.
At program startup, the equivalent of
setlocale(LC_ALL, "C");
is executed.
Consequently, if you want a different locale to be in use, you have to override this with an explicit call to setlocale().
The POSIX specification of setlocale() conforms to the C standard but also extends it, specify that the second argument can be:
"POSIX"
[CX] ⌦ Specifies the minimal environment for C-language translation called the POSIX locale. The POSIX locale is the default global locale at entry to main(). ⌫
"C"
Equivalent to "POSIX".
""
Specifies an implementation-defined native environment. [CX] ⌦ The determination of the name of the new locale for the specified category depends on the value of the associated environment variables, LC_* and LANG; see XBD Locale and Environment Variables. ⌫
A null pointer
Directs setlocale() to query the current global locale setting and return the name of the locale if category is not LC_ALL, or a string which encodes the locale name(s) for all of the individual categories if category is LC_ALL.
This means that if you write setlocale(LC_ALL, ""); at the start of main(), all users of the program stand the maximum chance of being able to use their preferred locale.
I have a program test.c
int global_var=10;
printf("Done");
i did
gcc -g test.c -o test
My query is
Is there a way i can get the variable name as argument (say "global_var") and print the value.
Thanks
No, C doesn't have introspection. Once the compiler has generated code, the program can not look up variable names.
The way these things are usually solved is by having a collection of all special variables that needs to be looked up by name, containing both the actual name as a string and the variable it self.
Usually it's an array of structures, something like
struct
{
const char *name;
int value;
} variables[] = {
{ "global_var", 10 }
};
The program can then look through the array variables to search for "global_var" and use (or change) the value in the structure.
General answer: No. There is no connection between a variable name and its string representation (you can get the string representation of a variable name at compile time with the preprocessor, though).
For identifiers with external linkage, there are (platform-dependent) ways: See e.g. dlsym for POSIX systems.
You can compile with debugging information and access (most) variables by names from input. Unless you really write something like a debugger, this would be a horrible design, however (and even then, you don’t access the variables used in the debugger itself but of the programme being debugged).
Finally, you could implement your own lookup table mapping from string representations to values.
No.
We only have variable names so humans don't get confused .
After your program gets turned into assembly and eventually machine code, the computer doesn't care what you name your variables.
Alternatively you could use a structure in which you would store the value and the name as a string:
struct tag_name {
char *member1;
int member2;
};
In general, it is not possible to access at runtime global variables by name. Sometimes, it might depend upon the operating system, and how the compiler is invoked. I still assume you want to dereference a global variable, and you know its type.
Then on Linux and some other systems, you could use dlopen(3) with a NULL path (to get a handle for the executable), then use dlsym on the global variable name to get its address; you can then cast that void* pointer to a pointer of the appropriate type and dereference it. Notice that you need to know the type (or at least have a convention to encode the type of the variable in its name; C++ is doing that with name mangling). If you compiled and linked with debug information (i.e. with gcc -g) the type information is in its DWARF sections of your ELF executable, so there is some way to get it.
This works if you link your executable using -rdynamic and with -ldl
Another possibility might be to customize your recent GCC with your own MELT extension which would remember and later re-use some of the compiler internal representations (i.e. the GCC Tree-s related to global variables). Use MELT register_finish_decl_first function to register a handler on declarations. But this will require some work (in coding your MELT extension).
using preprocessor tricks
You could use (portable) preprocessor tricks to achieve your goals (accessing variable by name at runtime).
The simplest way might be to define and follow your own conventions. For example you could have your own globvar.def header file containing just lines like
/* file globvar.def */
MY_GLOBAL_VARIABLE(globalint,int)
MY_GLOBAL_VARIABLE(globalint2,int)
MY_GLOBAL_VARIABLE(globalstr,char*)
#undef MY_GLOBAL_VARIABLE
And you adopt the convention that all global variables are in the above globvar.def file. Then you would #include "globvar.def" several times. For instance, in your global header, expand MY_GLOBAL_VARIABLE to some extern declaration:
/* in yourheader.h */
#define MY_GLOBAL_VARIABLE(Nam,Typ) extern Typ Nam;
#include "globvar.def"
In your main.c you'll need a similar trick to declare your globals.
Elsewhere you might define a function to get integer variables by name:
/* return the address of global int variable or else NULL */
int* global_int_var_by_name (const char*name) {
#define MY_GLOBAL_VARIABLE(Nam,Typ) \
if (!strcmp(#Typ,"int") && !strcmp(name,#Nam)) return (int*)&Nam;
#include "globvar.def"
return NULL;
}
etc etc... I'm using stringification of macro arguments.
Such preprocessor tricks are purely standard C and would work with any C99 compliant compiler.
Is environ variable (as of POSIX) available (at least for reading) in major Windows C compilers?
I know that execve is available on Windows: https://en.wikipedia.org/wiki/Exec_(system_call)
But I am unsure if environ is available, too.
environ should be available, but is deprecated and you should use the more secure methods.
The execXX() calls are available, but fork() isn't, so effectively the exec functions are rendered useless.
You can use CreateProcessA for similar effect, and have the ability to set up environments and pipes cleanly.
Just to acknowledge #eryksun 's concerns: You do need to consider which character set you are using before using any Microsoft "A" file (and other O/S) APIs. It is simplest if you can do all your code using 16bit unicode, as that is the underlying type for NT, Windows 7, Windows 10. On unix and mac, you can make assumptions that utf-8 is the 8-bit character set of choice, but that has yet to happen for windows, and of course "backward compatibility". If you are using any of the "unix-like" M/S API, you should already be making the same design decisions, though, so should already have an answer.
The following program will print the environment variables.
#include <stdio.h>
int main(int argc, char *argv[], char *env[]){
int e = 0;
while (env[e] != NULL) {
printf("%s\n", env[e++]);
}
}
EDIT: I was wrong; looks like the MSVC runtime library does include support for environ (though deprecated) after all. I will leave my previous answer below if anyone is interested in alternative methods.
Not that I'm aware of, but, if you want to access the environment-variables on Windows, you have some options:
Declare main or wmain with the following signature:
int (w)main(int argc, char/wchar_t *argv[], char/wchar_t *envp[])
This is defined in the C Standard as a pointer to the environment block, if applicable:
§ J.5.1:
In a hosted environment, the main function receives a third argument, char *envp[],
that points to a null-terminated array of pointers to char, each of which points to a string
that provides information about the environment for this execution of the program
(5.1.2.2.1).
Use the Windows API function GetEnvironmentVariable(A|W) to get an individual environment variable, or GetEnvironmentStrings to get the entire environment array.
The standard C function getenv.
My school wants me to implement the setenv() standard c library function's behavior. I'm not allowed to use setenv() for this implementation. How can I do that?
On many implementations of the C programming language and especially on POSIX, the environment is accessible from the environ global variable. You may need to declare it manually as it's not declared in any standard header file:
extern char **environ;
environ points to a NULL terminated array of pointers to variable=value strings. For example, if your environment has the variables foo, bar, and baz, the entries in environ might be:
environ[0] = "foo=a";
environ[1] = "bar=b";
environ[2] = "baz=c";
environ[3] = NULL;
To alter the environment without using the setenv() or putenv() functions, check if the key you want to set already exists. If it does, overwrite the entry for that key. Else you need to copy the content of environ into a new array and add the new entry to its end. You can use malloc() or calloc() and memcpy() for this purpose. Since this is homework, I'm not going to supply further details.
I have a program test.c
int global_var=10;
printf("Done");
i did
gcc -g test.c -o test
My query is
Is there a way i can get the variable name as argument (say "global_var") and print the value.
Thanks
No, C doesn't have introspection. Once the compiler has generated code, the program can not look up variable names.
The way these things are usually solved is by having a collection of all special variables that needs to be looked up by name, containing both the actual name as a string and the variable it self.
Usually it's an array of structures, something like
struct
{
const char *name;
int value;
} variables[] = {
{ "global_var", 10 }
};
The program can then look through the array variables to search for "global_var" and use (or change) the value in the structure.
General answer: No. There is no connection between a variable name and its string representation (you can get the string representation of a variable name at compile time with the preprocessor, though).
For identifiers with external linkage, there are (platform-dependent) ways: See e.g. dlsym for POSIX systems.
You can compile with debugging information and access (most) variables by names from input. Unless you really write something like a debugger, this would be a horrible design, however (and even then, you don’t access the variables used in the debugger itself but of the programme being debugged).
Finally, you could implement your own lookup table mapping from string representations to values.
No.
We only have variable names so humans don't get confused .
After your program gets turned into assembly and eventually machine code, the computer doesn't care what you name your variables.
Alternatively you could use a structure in which you would store the value and the name as a string:
struct tag_name {
char *member1;
int member2;
};
In general, it is not possible to access at runtime global variables by name. Sometimes, it might depend upon the operating system, and how the compiler is invoked. I still assume you want to dereference a global variable, and you know its type.
Then on Linux and some other systems, you could use dlopen(3) with a NULL path (to get a handle for the executable), then use dlsym on the global variable name to get its address; you can then cast that void* pointer to a pointer of the appropriate type and dereference it. Notice that you need to know the type (or at least have a convention to encode the type of the variable in its name; C++ is doing that with name mangling). If you compiled and linked with debug information (i.e. with gcc -g) the type information is in its DWARF sections of your ELF executable, so there is some way to get it.
This works if you link your executable using -rdynamic and with -ldl
Another possibility might be to customize your recent GCC with your own MELT extension which would remember and later re-use some of the compiler internal representations (i.e. the GCC Tree-s related to global variables). Use MELT register_finish_decl_first function to register a handler on declarations. But this will require some work (in coding your MELT extension).
using preprocessor tricks
You could use (portable) preprocessor tricks to achieve your goals (accessing variable by name at runtime).
The simplest way might be to define and follow your own conventions. For example you could have your own globvar.def header file containing just lines like
/* file globvar.def */
MY_GLOBAL_VARIABLE(globalint,int)
MY_GLOBAL_VARIABLE(globalint2,int)
MY_GLOBAL_VARIABLE(globalstr,char*)
#undef MY_GLOBAL_VARIABLE
And you adopt the convention that all global variables are in the above globvar.def file. Then you would #include "globvar.def" several times. For instance, in your global header, expand MY_GLOBAL_VARIABLE to some extern declaration:
/* in yourheader.h */
#define MY_GLOBAL_VARIABLE(Nam,Typ) extern Typ Nam;
#include "globvar.def"
In your main.c you'll need a similar trick to declare your globals.
Elsewhere you might define a function to get integer variables by name:
/* return the address of global int variable or else NULL */
int* global_int_var_by_name (const char*name) {
#define MY_GLOBAL_VARIABLE(Nam,Typ) \
if (!strcmp(#Typ,"int") && !strcmp(name,#Nam)) return (int*)&Nam;
#include "globvar.def"
return NULL;
}
etc etc... I'm using stringification of macro arguments.
Such preprocessor tricks are purely standard C and would work with any C99 compliant compiler.