How to read environment variable in Glibc code - c

I want to disable/enable printf() output to screen by reading an environment variable, similar to how LD_DEBUG works.
I want to control ./stdio-common/printf.c.
So if in environment variable says disable printf() it call
int
__printf (const char *format, ...)
{
return done;
}
else it executes the original code. How would I implement this?

Use getenv. See getenv(3) for details.

The recommended way is to use the solution provided by ANSI as getenv() function for maximum portability:
#include <stdlib.h>
#include <stdio.h>
int main(void)
{
char * env = getenv(“PROMPT”));
if(env)
puts(env);
else
puts(“The environmental variable not available”);
return 0;
}
There are other non-standard ways of doing the same which is not recommended.
The third argument to main() could be char **envp is used widely to get the information about the environment and is non-standard.
int main(int argc, char **argv, char **envp)
{
while(*envp)
printf("%s\n",*envp++);
}
Using the third argument in main() is not strictly conforming to standard.
There is another widely used non-standard way of accessing the environmental variables and that is through the environ external variable.
int i=0;
extern char ** environ;
while(environ[i])
printf("\n%s",environ[i++]);
NOTE: The examples are in-complete and lacks error handling.

Related

Statement: " There must be at least one statement in the executable part in main function."

My textbook mentions: There must be at least one statement in the executable part of main function.
1)
#include <stdio.h>
void main(){ int c; }
2)
#include <stdio.h>
void main(){ int c; c=0; }
The above two codes result in runtime error.
3)
#include <stdio.h>
void main(){
int c; c=5; printf("%d",c); }
The above code runs fine. What is the possible reason?
First,
1 The function called at program startup is named main. The implementation declares no
prototype for this function. It shall be defined with a return type of int and with no
parameters: int main(void) { /* ... */ } or with two parameters (referred to here as argc and argv, though any names may be
used, as they are local to the function in which they are declared):
int main(int argc, char *argv[]) { /* ... */ }
or equivalent;10) or in some other implementation-defined manner.
C 2011 Online Draft, §5.1.2.2.1 Program Startup
Unless your compiler documentation specifically lists it as a valid signature, using void main() leads to undefined behavior, which may be where your runtime errors are coming from.
Secondly, the current C standard does not require that main contain any executable statements.

Is there a way to determine if LC_CTYPE is set in C?

Using C, is there a way to find out if LC_CTYPE is set? I am rewriting printf and my %lc needs to work differently depending on if the locale is set.
LC_CTYPE is an environment variable. You can use any of the normal methods of accessing environment variables, which differ based on platform. For example, POSIX's third envp argument to main:
int main(int argc, char **argv, char **envp);
or the standard C89 getenv() function:
char *getenv(const char *name);
For example:
#include <stdlib.h>
char const *get_lc_ctype()
{
return getenv("LC_CTYPE");
}
Be careful not to modify strings returned by getenv(3), that is undefined behaviour. If you want to set LC_CTYPE, you should use the (POSIX-standardised but not C-standardised) setenv(3):
int set_lc_ctype(char const *new)
{
return setenv("LC_CTYPE", new, 1);
}
A generic way is to use 'setlocale()'.
From the man page:
If locale is an empty string, "", each part of the locale that should be modified is set according to the
environment variables.
Thus, you get LC_TYPE by
#include <locale.h>
// ...
char* lc_type= setlocale(LC_CTYPE, "");

How to pointer reference dynamic sized pointer to array?

I want to be able to reference variable sized array with a global pointer. But what kind of pointer do I use that will work with variable sizes of the array? In the example below, assume N will only be known at runtime (could be an argument for example) so compile time solutions won't work.
What I want to achieve:
main.c
some_sort_of_pointer *x;
main()
{
int N=256; //or N=64 or whatever
char (*LC)[N];
LC=malloc(1024);
x=LC;
memcpy(x[2],"hello world",11);
x[0][176]=123;
dostuff();
}
I'm sure there's an easy obvious way to do this but I can't seem to nail it. My first attempt at asking this was a mess so this time I'm hoping it's clear what I want to achieve.
OS Centos 6.5
compiler GCC 4.8 (using C99)
As at compile time the type to be referenced isn't given, a void pointer might help.
However only storing an untyped reference (what void * in fact is is) is not enough, as it is essential to also know the size of the (VL)array. So the latter also needs to be stored globally, as it can not be pulled from the memory referenced.
An example how this can be achieve is given below:
main.h:
#include <stdlib.h> /* for size_t */
struct VLA_descriptor
{
void * p;
size_t s;
}
extern struct VLA_descriptor vla_descriptor;
foo.h:
void foo(void);
foo.c:
#include "main.h"
#include "foo.h
void foo(void)
{
char (*p)[vla_descriptor.s] = vla_descriptor.p;
/* Do something with the VLA reference p. */
}
main.c:
#include "main.h"
#include "foo.h"
struct VLA_descriptor vla_descriptor = {0};
int main(int argc, char ** argv)
{
size_t s = atoi(argv[1]);
char (*p)[s] = malloc(s);
vla_descriptor.p = p;
vla_descriptor.s = s;
foo();
... /* Free stuff and return. */
}
Error checking had been omitted in this example's code for the sake of readability.
With much thanks to #alk (and everyone else who responded) I think I have the closest I'm going to get to what I'm looking for:
void *LC
int LCS;
int main(int argc, char **argv) {
LCS=256;
LC=malloc(1024)
memcpy(((char(*)[LCS])LC)[2],"hello world",11);
((char(*)[LCS])LC)[0][176]=123;
printf("%d %s\n",((char(*)[LCS])LC)[0][176],&((char(*)[LCS])LC)[2]);
}
((char(*)[LCS])LC) is the equivalent of a what I wanted. It's similar to #alk's idea and does require 2 globals but it means I can use it in functions without having to declare a new variable. I've credited #alk with the answer as what he posted gave me 90% of what I needed.
Though if anyone can reduce ((char(*)[LCS])LC) to a single global, I would be excited to see it :)

How to use scanf() without including stdio.h

Is there any possible methods to write a C program without including stdio.h as a header file. It was suggested that it can be implemented by declaring extern int scanf(char* format, ...);
#include <stdio.h> //I want this same code to work without including this line
int main ()
{
char str [80];
scanf ("%s",str);
return 0;
}
You can declare the scanf function with:
extern int scanf(const char *format, ...);
The extern keyword is optional but I like to include it as a reminder of the fact that the function is defined elsewhere.
Your example would then look like:
extern int scanf(const char *format, ...);
int main ()
{
char str [80];
scanf ("%s",str);
return 0;
}
In C-89, that code would compile without the #include, as function prototypes are optional.
Having said which, it comes under the list of 'really bad things to do' - scanf may be a macro, it might have one or more required parameters, ...
So you can do it, but it's like driving at night without any lights. You're liable to crash, even if you think you know the road.

where is the definition of extern char **environ?

we can get the environment variable in C like this:
extern char **environ;
int main(int argc, char *argv[])
{
int count = 0;
printf("\n");
while(environ[count] != NULL)
{
printf("[%s] :: ", environ[count]);
count++;
}
return 0;
}
but where is the defination of environ? I can't find that in unistd.h. and how does it work?
environ is defined as a global variable in the Glibc source file posix/environ.c.
Have you tried declaring envp as parameter to main?
int main (int argc, char *argv[], char *envp[])
http://www.gnu.org/software/libc/manual/html_node/Program-Arguments.html#Program-Arguments
man:
This variable must be declared in the user program, but is declared in the header file unistd.h in case the header files came from libc4 or libc5, and in case they came from glibc and _GNU_SOURCE was defined.
On POSIX systems, the identifier
extern char **environ;
does not have to be defined in any header. As noted in #triclosn's answer to this question, "This variable must be declared in the user program ..."
Per POSIX 7 Environment Variables:
The value of an environment variable is a string of characters. For a C-language program, an array of strings called the environment shall be made available when a process begins. The array is pointed to by the external variable environ, which is defined as:
extern char **environ;
There is no POSIX requirement that the environ variable be declared in any header file, so on a POSIX-compliant system it's just available should you wish to declare it in your code.

Resources