Advanced C Tutorial (UNIX). All about the real power of C, supplied step by step

Status
Not open for further replies.

timemachine

Boom Bhadam Dhishkyao
This thread will contain the advanced topics in C under UNIX plateform. If you use windows, dont get disappointed because "CYGWIN" is available to give a unix like enviornment in windows. You can search and download it. Rembember you will only need the GCC part.

Let's start with the main concern:

File Access and Directory System Calls



Directory Handling Functions(contained in unistd.h)


This basically involves calling appropriate functions to traverse a directory hierarchy or viewing its contents.


This is a function for changing directory through a program.

Code:
int chdir(char * path);
For eg. it can be used as given in the code

Code:
#include <stdio.h>
#include <unistd.h>



int main(int argc, char *argv)
{
      if(argc<2)
           {

                printf("Usage: <executable name> path");
                exit(1);

           }

      if(chdir(argv[1])!=0)
           {

                printf("Error in chdir\n");
                exit(1);

           }

}


In this code we are applying chdir on the directory which we will pass through a command line argument. If fails, the program will exit with error code 1.



Like this, there is one more function

Code:
char *getwd(char *path);
This function will return the current working directory. path is a string type variable which would be used to store the current working directory. ;)same as the pwd command.

Now the functions which can make the scanning and sorting of directories possible. All the functions stated below are <sys/types.h> and <sys/dir.h>

Code:
scandir(char *dirname, struct direct **namelist, int (*select)(), int (*compar)());
This function reads the directory name and stores in dirname. Then it builds a array of pointers and keep the directory names in that array(here it is namelist).



(*select)() is a pointer to a function which is called with a pointer to a directory entry (defined in <sys/types> and should return a non zero value if the directory entry should be included in the array. If this pointer is NULL, then all the directory entries will be included.

The last argument is the pointer to a routine qsort , which sorts the complete array. If this pointer is null then the array is not sorted.






Code:
[FONT=Verdana]#include <sys/types.h>
#include <sys/dir.h>
#include <sys/param.h>
#include <stdio.h>
 
#define FALSE 0
#define TRUE !FALSE
 
extern  int alphasort();
 
char pathname[MAXPATHLEN];
 
main()   
{ 
    int count,i;
    struct direct **files;
    int file_select();
    if (getwd(pathname) == NULL )
        { 
            printf("Error getting path\n");
            exit(0);
    }
    printf("Current Working Directory = %s\n",pathname);
    count = scandir(pathname, &files, file_select, alphasort);
 
    /* If no files found, make a non-selectable menu item */

    if(count <= 0)
    {         
          printf(``No files in this directory\n'');
      exit(0);
    }

    printf(``Number of files = %d\n'',count);
    for (i=1;i<count+1;++i)
    printf(``%s  '',files[i-1]->d_name);
    printf(``\n''); /* flush buffer */

}
[/FONT]  [FONT=Verdana]int file_select(struct direct   *entry)
[/FONT]
[FONT=Verdana]{[/FONT]
[FONT=Verdana]       if ((strcmp(entry->d_name, ``.'') == 0) ||(strcmp(entry->d_name,``..'') == 0))
[/FONT]
 
[FONT=Verdana]        return (FALSE);
    else
        return (TRUE);
}[/FONT]


scandir returns the current directory (.) and the directory above this (..) as well as all files so we need to check for these and return FALSE so that they are not included in our list.


This program can be furthur modified to find a special type of file. Like if we want to find only the files which contain .h , .c or .o , then we will have to change the file_select function. :cool:(Just minor changes)
It goes like this


Code:
[FONT=Verdana]ptr = rindex(entry->d_name, '.')
if ((ptr != NULL) &&((strcmp(ptr, ``.c'') == 0)||(strcmp(ptr, ``.h'') == 0)|| (strcmp(ptr, ``.o'') == 0) ))
        return (TRUE);[/FONT]
Just add this code to the file_select and then you will be able to get only the files. this can also be done for other file extensions.




This thread is not closed yet. I will post more topics under this thread about the advanced C under unix plateform.




References are taken from the first book I read about this topic. Its name just slipped out of my mind, but i will reference it later in this post.
Any queries, you should ask in this thread.



Thank You
More things will be added soon
 
OP
timemachine

timemachine

Boom Bhadam Dhishkyao
Process Control: <stdlib.h>,<unistd.h>

A process is basically a single running program. It may be a system program (e.g login, update, csh) or program initiated by the user such as a text editor. When UNIX runs a process it gives each process a unique number, it is the process id of the process. The UNIX command ps will list all current processes running on your machine and will list the pid. The C function int getpid() will return the pid of process that called this function.

Running UNIX Commands from C

We can run commands from a C program just as if they were from the UNIX command line by using the system() function.

Code:
[/SIZE][/FONT]
[FONT=Verdana][SIZE=2]int system(char *string) 
[/SIZE][/FONT]
[FONT=Verdana][SIZE=2]

where string can be the name of a unix utility, an executable shell script or a user program. System returns the exit status of the shell. System is prototyped in <stdlib.h>



we can see this by an example. here we will call the ls command from a C program

Code:
main()
{ printf(``Files in Directory are:\n'');
		 system(``ls -l'');
}
[/SIZE][/FONT]   [FONT=Verdana][SIZE=2]


remember the function system is a call that is made up of 3 other system calls: execl(), wait() and fork() (which are prototyed in <unistd>)

execl()



execl stands for execute and leave which means that a process will get executed and then terminated by execl.


It is defined by:

execl(char *path, char *arg0,...,char *argn, 0);



The last parameter must always be 0. It is a NULL terminator. Since the argument list is variable we must have some way of telling C when it is to end. The NULL terminator does this job. where path points to the name of a file holding a command that is to be executed, argo points to a string that is the same as path (or at least its last component.

arg1 ... argn are pointers to arguments for the command and 0 simply marks the end of the (variable) list of arguments.



So we can call a command also by this way

Code:
[SIZE=2]main()
{ printf(``Files in Directory are:\n'');
		 execl(`/bin/ls'',``ls'', ``-l'',0);
}[/SIZE]
[/SIZE][/FONT]   [FONT=Verdana][SIZE=2]

fork()

int fork() turns a single process into 2 identical processes, known as the parent and the child. On success, fork() returns 0 to the child process and returns the process ID of the child process to the parent process. On failure, fork() returns -1 to the parent process, sets errno to indicate the error, and no child process is created.


main()
{ int return_value;

printf("Forking process\n");
fork();
printf("The process id is %d and return value is %d\n",getpid(), return_value);
execl("/bin/ls/","ls","-l",0);
printf("This line is not printed\n");
}
[/code]

The Output of this would be:



Forking process
The process id is 6753 and return value is 0
The process id is 6754 and return value is 0

it will also contain two lists of current directory.
wait()

int wait (int *status_location)

itwill force a parent process to wait for a child process to stop or terminate. wait() return the pid of the child or -1 for an error. The exit status of the child is returned to status_location.

exit()

void exit(int status)

it will terminates the process which calls this function and returns the exit status value. Both UNIX and C (forked) programs can read the status value.

By convention, a status of 0 means normal termination any other value indicates an error or unusual occurrence. Many standard library calls have errors defined in the sys/stat.h header file. We can easily derive our own conventions.



Well, now a complete program of all I have mentioned above

Code:
/* The program asks for UNIX commands to be typed and inputted to a string*/
/* The string is then "parsed" by locating blanks etc. */
/* Each command and sorresponding arguments are put in a args array */
/* execvp is called to execute these commands in child process */
/* spawned by fork() */



#include <stdio.h>
#include <sys/types.h>
#include <unistd.h>

main()
{
    char buf[1024];
    char *args[64];

    for (;;) {
        /*
         * Prompt for and read a command.
         */
        printf("Command: ");

        if (gets(buf) == NULL) {
            printf("\n");
            exit(0);
        }

        /*
         * Split the string into arguments.
         */
        parse(buf, args);

        /*
         * Execute the command.
         */
        execute(args);
    }
}

/*
 * parse--split the command in buf into
 *         individual arguments.
 */
parse(buf, args)
char *buf;
char **args;
{
    while (*buf != NULL) {
        /*
         * Strip whitespace.  Use nulls, so
         * that the previous argument is terminated
         * automatically.
         */
        while ((*buf == ' ') || (*buf == '\t'))
            *buf++ = NULL;

        /*
         * Save the argument.
         */
        *args++ = buf;

        /*
         * Skip over the argument.
         */
        while ((*buf != NULL) && (*buf != ' ') && (*buf != '\t'))
            buf++;
    }

    *args = NULL;
}

/*
 * execute--spawn a child process and execute
 *           the program.
 */
execute(args)
char **args;
{
    int pid, status;

    /*
     * Get a child process.
     */
    if ((pid = fork()) < 0) {
        perror("fork");
        exit(1);

	/* NOTE: perror() produces a short  error  message  on  the  standard
           error describing the last error encountered during a call to
           a system or library function.
       */
    }

    /*
     * The child executes the code inside the if.
     */
    if (pid == 0) {
        execvp(*args, args);
        perror(*args);
        exit(1);

       /* NOTE: The execv() vnd execvp versions of execl() are useful when the
          number  of  arguments is unknown in advance;
          The arguments to execv() and execvp()  are the name
          of the file to be executed and a vector of strings  contain-
          ing  the  arguments.   The last argument string must be fol-
          lowed by a 0 pointer. 

          execlp() and execvp() are called with the same arguments  as
          execl()  and  execv(),  but duplicate the shell's actions in
          searching for an executable file in a list  of  directories.
          The directory list is obtained from the environment.
        */
    }

    /*
     * The parent executes the wait.
     */
    while (wait(&status) != pid)
        /* empty */ ;
}


this program is originally taken from a ebook. Advanced Unix programming

With this example you can now put your Unix or Linux commands work through a program.
Hope you find it helpul.
Wait for another one

 
OP
timemachine

timemachine

Boom Bhadam Dhishkyao
sure....i would......actually it takes a lot of time for the explainations so plzz gimme some time ....
 

[xubz]

"The Cake is a Lie!!"
Wow! Interesting! I loved UNIX C Programming mentioned in the book 'The C Programming Language' by K&R.

Thanks for this :)
 
Status
Not open for further replies.
Top Bottom