Lab
Lab
PART B
UNIX PROGRAMMING
1. a) b) Non-recursive shell script that accepts any number of argument and prints them in the Reverse order, (For example, if the script is named rargs, then executing rargs A B C should produce C B A on the standard output). C program that creates a child process to read commands from the standard input and execute them (a minimal implementation of a shell like program). You can assume that no arguments will be passed to the commands to be executed. Shell script that accepts two file names as arguments, checks if the permissions for these files are identical and if the permissions are identical, outputs the common permissions, otherwise outputs each file name followed by its permissions. C program to create a file with 16 bytes of arbitrary data from the beginning and another 16 bytes of arbitrary data from an offset of 48. Display the file contents
2.
a)
b)
3.
a) b)
4.
a)
b)
to demonstrate how the hole in file is handled. Shell function that takes a valid directory names as an argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum value to the standard output C program that accepts valid file names as command line arguments and for each of the arguments, prints the type of the file (Regular file, Directory file, Character special file, Block special file, Symbolic link etc.) Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files(This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India). C program to do the following: Using fork( ) create a child process. The child process prints its own process-id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait( )) and prints its own process-id and the id of its child process and then exits.
COMPILER DESIGN
5. Write a C program to implement the syntax-directed definition of if E then S1 and if E then S1 else S2. (Refer Fig. 8.23 in the text book prescribed for 06CS62 Compiler Design, Alfred V Aho, Ravi Sethi, Jeffrey D Ullman: Compilers- Principles, Techniques and Tools, Addison-Wesley, 2007.) Write a yacc program that accepts a regular expression as input and produce its parse tree as output.
6.
Introduction to lex
The word lexical in the traditional sense means pertaining to words. In terms of programming languages, words are objects like variable names, numbers, keywords etc. Such words are traditionally called tokens. A lexical analyzer, or lexer for short, will take input as a string of individual letters and divide this string into tokens. Additionally, it will filter out whatever separates the tokens (the so-called white-space), i.e., lay-out characters (spaces,newlines etc.) and comments. The lexical analyzer is the first phase of a compiler. Its main task is to read the input characters and produce as output a sequence of tokens that the parser uses for syntax analysis.This interaction, summarized schematically in Fig. 1.1, is commonly implemented by making the lexical analyzer be a subroutine or a co routine of the parser. Several tools have been built for constructing lexical analyzers from special purpose notations based on regular expressions.In this section, we describe a particular tool, called Lex that has been widely used to specify lexical analyzers for a variety of languages. We refer to the tool as Lex compiler, and its input specification as the Lex language.
Lex compiler
lex.yy.c
lex.yy.c
C Compiler
a.out
input stream
a.out
Sequence of tokens
Lex specifications
A Lex program consists of three parts : declarations %% translation rules %% auxiliary procedures The declarations section includes declarations of variables,constants,and regular definitions. The translation rules of a lex program are statements of the form R1 {action1} R2 {action2} .... .... Rn {action n} where each Ri is regular expression and each action i, is a program fragment describing what action the lexical analyzer should take when pattern Ri matches lexeme.Typically, action i will return control to the parser. In Lex actions are written in C;in general,however,they can be in any implementation language. The third section holds whatever auxiliary procedures are needed by the actions.
The parser obtains a string of tokens from the lexical analyzer and verifies that the string can be generated by grammar for the source language. We expect the parser to report any syntax errors in an intelligible fashion. It should also recover from commonly occurring errors so that it can continue processing the remainder of its input. We know that programs can contain errors at many different levels. For example, errors can be 1. Lexical ,such as misspelling an identifier,keyword,or operator. 2. Syntactic,such as arithmetic expression with unbalanced parentheses 3. Sematic,such as an operator applied to an incompatible operand. 4. Logical,such as infinitely recursive call. Often much of the error detection and recovery in a compiler is centered around the syntax analysis phase
LEXICAL CONVENTIONS
The notations for specifying tokens : 1. . Matches any single character except the newline (\n) 2. 3. 4. * Matches zero or more copies of the preceding expression. [ ] A character class which matches any character within the brackets. ^ Matches the beginning of a line as the first character of a regular expression.
5. 6. 7. 8. 9.
$ Matches the end of line as the last character of a regular expression. \ Used to escape metacharacter. + Matches one or more occurrence of the preceding regular expression. For example [0-9]+ matches .12.,.9..but not an empty string. ? Matches zero or one occurrence | Matches either the preceding regular expression or the following expression. For example are | is | because matches any three words.
10. / Matches the preceding regular expression but only if followed by the regular expression. 11. ( ) Groups of series of regular expressions together into a new regular expression. 12. Blanks between tokens are optional, with the exception that keywords must be surrounded by blanks, new lines, the beginning of the program, or the final dot.
$ lex 1a.l $ cc o 1a lex.yy.c -ll $./1a sample.txt Number Number Number Number of of of of characters: 39 spaces: 9 words: 11 lines: 2
Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take a variable for representing a character, line, space and words. %{ int characters=0,lines=0,spaces=0,words=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. To count the number of line the pattern: [\n] .After lexer recognizes the [\n] pattern it should perform the action .Here the action is to increment the line value, so the action is represented by {lines++;} To count the space the pattern : . ..After lexer recognizing the . . pattern it should perform the action. Here the action is to increment the space value, so the action is represented by {spaces++;} To count the words and characters the regular expression : [^\t\n]+. Here ^ matches the beginning of a line as the first character of a regular expression. The tool lex provides an internal variable yyleng which contains the length of the string our lexer recognized. + symbol matches one or more occurrence of the preceding regular expression. So the action is represented by {characters+=yyleng,words++;}
2.
3.
The next section is procedures section, we know that when a program is invoked, the execution starts from the function main( ). We can pass the parameters to the function main( ) whenever the program is invoked and are called command line parameters. To access the command line parameters the function main should have the following format : Syntax : main(int argc, char *argv[]) { -----------}
The function main( ) can take two arguments namely argc and argv where argc must be an integer variable whereas argv is an array of strings.argc indicates the number of parameters passed and argv represents a parameter that is passed to function main. The file should be opened before reading or writing with the help of fopen function Syntax : fopen(char *filename, char *mode) Return values -file pointer if successful. -NULL if unsuccessful.
A lex lexer reads its input from the standard I/O file yyin.The default value of yyin is stdin, since the default input source is standard input. If you to change the source you should mentioned it explicitly. yylex( ) : You call yylex ( ) to start or resume scanning. If a lex action does a return to pass a value to the calling program ,the next call to yylex( ) will continue from the point where it left off. All the code in the rules section is copied into yylex( ). 1b. Program to count the numbers of comment lines in a given C program. Also eliminate them and copy the resulting program into separate file. Program name : 1b.l %{ int comment=0; %} %% "/*"[\n]*.*[\n]*"*/" {comment++;} "/*"[\"*/"]* { fprintf(yyout," "); } %% int main() { yyin=fopen(argv[1],"r"); yyout=fopen(argv[2],"w"); yylex(); printf("Number of comment lines in the given file: %d\n",comment); } Output : $ vi input /* this is a sample input */ void main() { int a,b,c; /* variable declaration */
printf(\n hello); /* code of the program */ } $ lex 1b.l $ cc o 1b lex.yy.c -ll $ ./1b input output Number of comment lines in the given file: 3 $ cat output void main() { int a,b,c; printf(\n hello); } Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take a variable for representing comment line. %{ int comment=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. C style comment line is enclosed with /* and */ characters. To count the numbers of comment line the pattern: "/*"[\n]*.*[\n]*"*/". After lexer recognizes the "/*"[\n]*.*[\n]*"*/" pattern it should perform the action. Here the action is to increment the comment value , so the action is represented by {comment++;}. As you know . (dot) doesn.t match the newline character ,it matches the character. 2. Now to eliminate the comment line and then to copy the remaining content in file the pattern : /*"[\"*/"]* . Here the metacharacter \ is to suppress the character *. After lexer recognizes the pattern it inserts whitespace in the place of comment line and copies the remaining content of the file.
fprintf()function The function is similar to that of printf( ) except the syntax .The Prototype of fprintf is : Syntax : fprintf(fp, "control string" , list) fp : file fpointer associated with the file.
2a. Program to recognize a valid arithmetic expression and to recognize the identifiers and operators present. Print them separately. Program name : 2a.l %{ int operatorcnt=0,identifiercnt=0,bracket=0; %} %% [+] {printf("+");operatorcnt++;} [-] {printf("-");operatorcnt++;} [*] {printf("*");operatorcnt++;} [/] {printf("/");operatorcnt++;} [a-zA-Z0-9]+ { identifiercnt++;} [(] {bracket++;} [)] {bracket--;} %% int main() { printf("Enter the expression:\n"); yylex(); printf("Number of Operators=%d\n", operatorcnt); printf("Number of Identifiers=%d\n",identifiercnt); if(operatorcnt >= identifiercnt || bracket!=0 || identifiercnt ==1) printf("Invalid expression\n"); else printf("Valid expression\n"); } $ lex 2a.l $ cc o 2a lex.yy.c ll $ ./2a Enter the expression : a+b*c +* Number of Operators = 2 Number of Identifiers = 3 ( Press Control-d) Valid expression $ ./2a Enter the exprexssion : (1+2*3 +* Number of Operators = 2
10
Number of Identifiers = 3 {Press Control-d Invalid expression $ ./2a Enter the exprexssion : (1+2*3) +* Number of Operators = 2 Number of Identifiers = 3 {Press Control-d Valid expression Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take variables for representing the operators, identifiers and for brackets. %{ int operatorcnt=0,identifiercnt=0,bracket=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern. 1. To recognize the operators the pattern is : [ + ] ,[ - ],[ * ],[ / ]. After lexer recognizes the pattern it should perform the action .Here the action is to display the operator and to count the operator, so the action is represented by {printf("operator");operatorcnt++;} To recognize the identifiers the pattern is :[a-zA-Z0-9]+ . After lexer recognizes the pattern it should perform the action .Here the action is to increments the identifier value. To recognize the brackets the pattern is [ ( ] and [ )].After lexer recognizes the pattern it should perform the action. Here the action is to increment brackets and decrement the bracket values respectively.
2.
3.
2b. Program to recognize whether a given sentence is simple or compound. Program name : 2b.l %{ int flag=0; %}
11
%% " and " | " or " | " but " | " because " | " than " {flag=1;} %% int main() { printf("Enter the sentence:\n"); yylex(); if(flag==1) printf("Given sentence is compound sentence\n"); else printf("Given sentence is simple sentence\n"); } Output : $ lex 2b.l $ cc o 2b lex.yy.c ll $ ./2b Enter the sentence This is ss lab This is ss lab (Press control-d) Given sentence is simple sentence $ ./2b Enter the sentence I and you Iyou (Press control-d) Given sentence is compund sentence Explanation The first section, the definition section, introduces any initial C program code we want copied into final program. i.e. Take variables for representing the words which leads to a compound statement. %{ int flag=0; %} The next section is the rules section .Each rule is made of two parts: a pattern and an action, separated by white space. The lexer that lex generates will execute the action when it recognizes the pattern.
12
1.
List few words which lead to compound statement. After lexer recognizes the pattern it should perform the action .Here the action is to set the value as it recognizes the words in the given statement Program to recognize and count the number of identifiers in a given input file.
3.
%{ int count=0; %} %% ("int ")|("float ")|("double ")|("char ") { int ch; ch=input(); for(;;) { if(ch==',') { count++; } else if(ch==';') { count++; break; } ch = input(); } } %% int main(int argc, char *argv[]) { yyin=fopen(argv[1],"r"); yylex(); printf("Number of identifiers are :%d\n",count); } Output : $ vi input.txt int main() { int a,b,c; char x,y; printf(hello); } $ lex 3.l $ cc o 3 lex.yy.c ll $ ./3 input.txt Number of identifiers are 5
13
YACC Introduction
The unix utility yacc (Yet Another Compiler Compiler) parses a stream of token, typically generated by lex, according to a user-specified grammar.
14
The rules section contains the grammar of the language you want to parse. This looks like statement : INTEGER = expression | expression ; expression : NUMBER + NUMBER | NUMBER - NUMBER ; This is the general form of context-free grammars, with a set of actions associated with each matching right-hand side. It is a good convention to keep non-terminals (names that can be expanded further) in lower case and terminals (the symbols that are finally matched) in upper case. The terminal symbols get matched with return codes from the lex tokenizer. They are typically defines coming from %token definitions in the yacc program or character values. Compiling and running a simple parser On a UNIX system, yacc takes your grammar and creates y.tab.c, the C Language parser, and y.tab.h, the include file with the token number definitions. Lex creates lex.yy.c,the C language lexer .You need only compile them together with the yacc and lex libraries. The Libraries contain usable default versions of all of the supporting routines, including main( ) that calls the parser yyparse( ) and exits. $ $ $ $ lex filename.l yacc -d filename.y cc lex.yy.c y.tab.c ll ./a.out /* makes lex.yy.c */ /* makes y.tab.c and y.tab.h */ /* compile and link C files */
Execute the following programs using YACC : 4a. Program to recognize a valid arithmetic expression that uses operators +, -, * and /. Lex file-name : 4a.l %{ #include "y.tab.h" %} %% [a-zA-Z][a-zA-Z0-9]* {return ID;} [0-9]+ {return NUMBER;} . {return yytext[0];} \n {return 0;} %%
15
Yacc file-name : 4a.y %token NUMBER ID %left '+''-' %left '*''/' %% expr:expr '+' expr; |expr '-' expr; |expr '*' expr; |expr '/' expr; |'('expr')' |NUMBER |ID ; %% int main() { printf("Enter the Expression\n"); yyparse(); printf("Valid Expression\n"); } int yyerror() { printf("Expression is invalid\n"); exit(0); } Output : $ lex 4a.l $ yacc d 4a.y $ cc o 4a lex.yy.c y.tab.c ll $ ./4a Enter the Expression a+b*c Valid Expression $./4a Enter the Expression a+b*c Expression is invalid Explanation LEXER(lex code) We need a lexer to feed it tokens. The yyparse( ) parser is the high level routine, and calls the lexer whenever it needs a token from the input .As soon as the lexer finds token of interest to the parser ,it return to the parser ,returning the token code as value. Yacc
16
defines the token names in the parser as C preprocessor names in y.tab.h so the lexer can use them. 1. Strings of digits are number ,To match the string of digit the pattern is : [0-9]+. Action is to return the token NUMBER value. 2. Strings of alphabets are identifiers. To match an identifiers the pattern [a-zA-z][a-zA-Z0-9]*. Action is to return the token ID value.
3. . (dot) matches a character. Whenever a lexer matches a token , the text of the token is stored in the null terminated string yytext . This rule says to return any character otherwise not handled as a single character token to the parser. Character token are usually punctuation such as parentheses ,semicolons and single-character operator. If the parser receives a token that it doesn.t know about ,it generates a syntax error, so this rule lets you handle all of the single-character tokens easily while letting yacc.s error checking catch and complain about invalid input. 4. A newline (\n) character returns an end of input token(number zero ) to tell the parser that there is no more to read.
PARSER(Yacc code) The token definition for the number ad identifiers %token NUMBER ID Yacc lets you to specify the operator precedence.s explicitly. %left +- %left */ Each of these declarations defines a level of precedence. That .+.and .-. are left associative and have lower precedence level,.*. and ./. are left associative and have the higher precedence level. Grammar for an valid Expression is as follows expr:expr '+' expr; |expr '-' expr; |expr '*' expr; |expr '/' expr; |'('expr')' |NUMBER |ID yyparse( ) : The entry point to a yacc-generated parser is yyparse ( ).Whenever your programs call yyparse( ) ,the parser attempts to parse an input stream. The parser returns a value of zero if the parse succeeds and non-zero if not. yyerror( ) : Whenever a yacc parser detects a syntax error ,it calls yyerror ( ) to report the error to the user. 4b. Program to recognize a valid variable, which starts with a letter, followed by any number of letters or digits. Lex file-name : 4b.l
17
%{ #include"y.tab.h" %} %% [0-9] {return DIG;} [a-z] {return LET;} . {return yytext[0];} \n {return 0;} /*Logical EOF*/ %% Yacc file-name : 4b.y %token LET %token DIG %% stmt:id {printf("Valid identifier \n");} ; id: letter next | letter {;} ; next: letter next | digit next | letter | digit {;} ; letter: LET {;} ; digit: DIG {;} ; %% int main() { printf("Enter an identifier:"); yyparse(); } int yyerror() { printf("Not a valid identifier\n"); exit(0); } Output : $ lex 4b.l $ yacc d 4b.y $ cc o 4b lex.yy.c y.tab.c ll
18
Explanation LEXER(lex code) 1. To match the digit the pattern is [0-9].Action is to return the token DIG value. 2. To match the letter the pattern is [a-z].Action is to return the token DIG value. PARSER(yacc code) The grammar to recognize a valid identifier statement: id ; id: letter next | letter {;} ; next: letter next | digit next | letter | digit {;} ; letter: LET {;} ; digit: DIG {;} 5a. Program to evaluate an arithmetic expression involving operators +, -, * and . Lex File-name : 5a.l %{ #include"y.tab.h" extern int yylval; %} %% [0-9]+ {yylval=atoi(yytext); return(NUM);} [ \t]; . {return yytext[0];} \n {return 0;} %% Yacc file-name : 5a.y %token NUM
19
%left '+''-' %left '*''/' %% stmt : expr { printf("Result:%d\n",$1);return 0; } ; expr :expr'+'expr {$$=$1+$3;} | expr'-'expr {$$=$1-$3;} | expr'*'expr {$$=$1*$3;} | expr'/'expr {$$=$1/$3;} | '('expr')' {$$=-$2;} | NUM {$$=$1;} ; %% int main() { printf("Enter the expression\n"); yyparse(); } int yyerror() { printf("Invalid input\n"); exit(0); } Output : $ lex 5a.l $ yacc d 5a.y $ cc o 5a lex.yy.c y.tab.c -ll $ ./5a Enter the expression 5+3 Result:8 $./5a Enter the expression 4*5+2 Result:22 Explanation Lexer String of digit is number ,whitespace is ignored. Whenever the lexer returns a token to the parser ,if the toke has an associated value, the lexer must store the value in yylval befor returning. We explicitly declare yylval. Parser The grammar is as follows expr :expr'+'expr {$$=$1+$3;}
20
| | | | | ;
expr'-'expr {$$=$1-$3;} expr'*'expr {$$=$1*$3;} expr'/'expr {$$=$1/$3;} '('expr')' {$$=-$2;} NUM {$$=$1;}
5b. Program to recognize strings .aaab., .abbb., .ab. and .a. using the grammar (an bn , n>= 0). Lex file-name : 5b.l %{ #include"y.tab.h" %} %% a {return A;} b {return B;} . {return yytext[0];} \n {return yytext[0];} %% Yacc file-name : 5b.y %token A B %% str : s'\n' {return 0;} s : A s B ; | ; %% int main() { printf("Enter the string\n"); yyparse(); printf("Valid string"); } int yyerror() { printf("Invalid string"); exit(0); } Output : $ lex 5b.l $ yacc d 5b.y
21
$ cc o 5b lex.yy.c y.tab.c ll $ ./5b Enter the string aaaabbbb valid string $ ./5b Enter the string aabbbb Invalid string Explanation LEXER To match the string .a. the pattern is .a.. Action is to return the token A value . To match the string .b. the pattern is .b.. Action is to return the token B value . PARSER The grammar is as follow: string : s'\n' s:AsB; 6. Program to recognize the grammar (an b, n>=10). Lex file-name : 6.l %{ #include"y.tab.h" %} %% a {return A;} b {return B;} . {return yytext[0];} \n {return yytext[0];} %% Yacc file-name : 6.y %token A B %% str: s'\n' {return 0;} s : A A A A A A A A A A x B ; x : A x | ; %% int main() { printf("Enter the string\n"); yyparse();
22
printf("Valid string"); } int yyerror() { printf("Invalid string"); exit(0); } Output : $ lex 6.l $ yacc d 6.y $ cc o 6 lex.yy.c y.tab.c ll $./6 Enter the string aaaaaaaaaaaab Valid string $./6 Enter the string aab Invalid string Explanation LEXER 1.To match the string .a. the pattern is .a.. Action is to return the token A value . 2.To match the string .b. the pattern is .b.. Action is to return the token B value . PARSER The grammar is as follow: string : s \n s:AAAAAAAAAAxB; x: Ax |;
example.sh
23
The first line is interpreter line. Here, this line specifies the shell we are using i.e Bourne shell A shell script is executed by using the shell command sh as shown below. $sh example.sh Today.s date is : Sat Jan 27 09:10:18 IST 2004 My Shell :/bin/sh Comments In shell scripts comments are written using the hash (#) character as the first character of the comment line. The read Command The read command or statement is the shell.s internal tool for taking the input from the user ,i.e., making scripts interactive. It is used with one or more variables. Input supplied through the standard input is read into the variables.
#!/bin/sh echo Enter the value of x read x echo The value of x is : $x value.sh
When you use a statement like read x the script pauses at that point to take input from the keyboard. Whatever you enter is stored in the variable x. Since this is a form of assignment ,no $ is used before x. To display that value we have to use $ symbol along with variable. Special parameters Used by Shell.
Significance Number of arguments specified in command line. Complete set of positional parameters as a single string. Name of the file or executed command. Positional parameters representing command line arguments. Exit status of last executed command. PID of current shell. PID of the last background job.
24
#!/bin/sh echo The program name : $0 echo The number of arguments specified is : $# echo The arguments are : $* echo Value of $1 and $2 command.sh
$ sh command.sh cse ise The program Name:command.sh The number of arguments specified is :2 The arguments are : cse ise Value of cse and ise The first argument is read by the shell into the parameter $1 ,the second argument into $2.We can use more positional parameters in this way up to $9.(and using the shift command, you can go beyond. The if Conditional This is the simplest of all the branching control structures. It has the following general formats.
i t
f s
Every if is close with corresponding fi ,and you.ll encounter an error of one is not present. If command succeeds ,the sequence of commands following it is executed .If command fails,then the else statement(if present) is executed. Using test and [ ] to evaluate expressions. When you use if to evaluate expressions, you need the test statement because the true or false values returned by expressions can.t be directly handled by if. test Uses certain operators to evaluate the condition and either a true or false exit status,which is then used by if for making decisions.
25
Meaning Equal to Not equal to Greater than Greater than or equal to Less than Less than or equal to
The operators begins with . (hyphen) ,followed by a two-letter string. The operators are quite mnemonic; -eq implies equal to ,-lt less than and so on. Example : $ a=8 ; b=9 ; $ $a .eq $b ; echo $? $1 $ test $a .lt $b $0 expr : Computation expr can perform basic arithmetic operations (+,-,*,/,%). $ a=2 ; b=9 $ c= expr $x + $y ; echo .$c. $ 11 The operands must be enclosed on either side by whitespace. For multiplication we have to use \ (Escaping technique) to prevent the shell from interpreting it as metacharacter. while Looping while statement repeatedly performs a set of instructions until the control command returns a true exit status. The general syntax of this : while condition is true do commands done The commands enclosed by do and done are executed repeatedly as long as condition remains true. The case conditional In case statement ,the statement which matches an expression is executed. The general syntax of the case statement is as follows :
26
case expression in pattern1)command1;; pattern2)command2;; pattern3)command2;; .... esac case first matches expression with pattern1.If match succeeds, the it.s executes command1.If matches fails, the pattern2 is matched ,and so forth. Each command list is terminated with a pair of semicolons, and the entire construct is closed with esac (reverse of case). eval command The use of eval command makes the shell to scan the command line once more, that is, second time and then actually executes the command line. Example : $ b=a $ c=b $ eval echo \$$c $ a The first two statements in this example are assignment statement. When the shell comes cross the third statement, because of eval; it first scans the statements once for any possible pre-evaluation or substitution. Here because of metacharacter \ the first $ is overlooked and the next variable $c gets evaluated resulting b. After this evaluation the third statement will be equivalent to echo $b. Then this statement gets executed as usual by the shell resulting as the answer.
PART B
UNIX PROGRAMMING
1. a) Non-recursive shell script that accepts any number of arguments and prints them in the reverse order.
Filename : 1a.sh echo "number len=$# while [ $len do eval echo len=`expr done of arguments are : $#" -ne 0 ] \$$len $len - 1`
27
Output : $ sh 1a.sh 1 2 3 number of arguments are : 3 3 2 1 $ ./1a.sh rahul raj rani number of arguments are : 3 rani raj rahul Explanation : The special shell parameters $# holds the number of arguments passed in the command line .Assume you are passing three arguments X Y Z .So $# value will be 3. The while loop does the operation still control command returns a true exit status. The use of eval command makes the shell to scan the command line once more, that is, second time and then actually executes the command line. Here because of metacharacter \ the first $ is overlooked and the next variable $len is gets evaluated resulting 3. After this evaluation the statement will be equivalent to echo $3. So the positional parameter $3 value is displayed and so on the remaining positional parameter value is displayed. While evaluating the expression the operands must be enclosed on either side by whitespace. 1. b) C program that creates a child process to read commands from the standard input and execute them ( a minimal implementation of a shell like a program). You can assume that no arguments will be passed to the commands to be executed.
Filename : 1b.c #include<stdio.h> #include<sys/types.h> int main() { char cmd[20]; pid_t pid; int ch; pid=fork(); if(pid == 0) { do { printf("\n Enter the command to be executed : "); scanf("%s",cmd);
28
system(cmd); printf("\n Enter 1 to continue and 0 to exit : "); scanf("%d",&ch); } while(ch!=0); } wait(); } Output : $ cc 1b.c $ ./a.out Enter the command to be executed : date wed Dec 16 11:05:52 IST 2009 Enter 1 to continue and 0 to exit : 1 Enter the command to be executed : cal December 2009 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 Explanation : All processes in a UNIX system ,expect the very first process (Process 0) which is created by the system boot code and remaining are created via the fork system call. is : The fork system call is used to create a child process .The function prototype of fork
#include <unistd.h> pid_t fork(void); Returns : 0 in child, process ID of child in parent, -1 on error The new process created by fork is called the child process. This function is called once but returns twice. The only difference in the returns is that the return value in the child is 0, whereas the return value in the parent is the process ID of the new child. The reason the childs process ID is returned to the parent is that a process can have more than one child, and there is no function that allows a process to obtain the process IDs of its children. The reason fork returns 0 to the child is that a process can have only a single parent, and the child can always call getppid to obtain the process ID of its parent. (Process ID 0 is reserved for use by the kernel, so its not possible for 0 to be the process ID of a child.)
29
System function The system function allows the users to access the standard output or standard input of the executed command. The function prototype of system function. #include <stdlib.h> int system(const char *smdstring); Returns : See below If cmdstring is a null pointer, system returns nonzero only if a command processor is available. Because system is implemented by calling fork, exec, and waitpid, there are three types of return values. 1. 2. 3. If either the fork fails or waitpid returns an error other than EINTR, system returns 1 with errno set to indicate the error. If the exec fails, implying that the shell cant be executed, the return value is as if the shell had executed exit(127). Otherwise, all three functions fork, exec, and waitpidsucceed, and the return value from system is the termination status of the shell, in the format specified for waitpid.
Wait function When a process terminates, either normally or abnormally, the kernel notifies the parent by sending the SIGCHLD signal to the parent. Because the termination of a child is an asynchronous event it can happen at any time while the parent is running this signal is the asynchronous notification from the kernel to the parent. The parent can choose to ignore this signal, or it can provide a function that is called when the signal occurs: a signal handler. The default action for this signal is to be ignored. So we need to be aware that a process that calls wait .The function prototype of wait function #include <sys/wait.h> pid_t wait(int *statloc); Return : process ID, or 1 on error 2. a) Shell script that accepts two file names as arguments, checks if the permissions of these files are identical and if the permissions are identical, outputs the common permission, otherwise outputs each file name followed by its permission.
Filename : 2a.sh ls -l $1 | cut c 1-10 > file1per ls -l $2 | cut -c 1-10 > file2per if cmp file1per file2per then echo "Both the files have same permission" cat file1per else
30
echo "Both the files have different permission" echo "The permission of first file $1 is " cat file1per echo "The permission of second file $2 is " cat file2per fi Output : $cat > file1 this is first file content $cat > file2 this is second file content $sh 2a.sh file1 file2 Both the files have same permission -rw-r--r-$chmod 777 file2 $sh 2a.sh file1 file2 file1per file2per differ: byte 4, line 1 Both the files have different permission The permission of first file file1 is -rw-r--r-The permission of second file file2 is -rwxrwxrwx Explanation : Listing the file attributes is done with ls - l (long) option. This option displays all the 7 attributes of a file - like its permission, links, owner, group owner, size, last modification time and filename. $ ls l total 45 -rw-rr-- 1 root root 65 Dec 16 10:89 input.txt To extract the specific field we need to use simple filter cut follows with .c option with a list of column numbers. Ranges can be specified using the hyphen. To extract the permission field we have use cut c - 1-10. Here we are using pipeline mechanism to redirect the output of ls - l to the simple filter cut. A pipe is general mechanism by using which ,the output of one program is redirected as the input to another program directly without using any temporary files in between. In pipeline , the command on the left of the | must use standard output and the one on the right must use standard input. 2. b) C program to create a file with 16 bytes of arbitary data from the beginning and another 16 bytes of arbitary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled.
31
Filename : 2b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { int fd; char buf1[]="Department of IS"; char buf2[]="Department of CS"; fd=creat("ise",0622); if(fd < 0) { printf("\n Error in creating file"); exit(0); } write(fd,buf1,16); lseek(fd,48,SEEK_SET); write(fd,buf2,16); exit(0); } Output : $cc 2b.c $./a.out $od -c ise 0000000 D 0000020 \0 \0 \0 * 0000060 D 0000100
e \0
p \0
a \0
r \0
t \0
m \0
e n t o \0 \0 \0 \0
f \0
I \0
S \0
Theoretical Explanation :
creat Function A new file can be created by calling the creat function. The function prototype of creat function #include <fcntl.h> int creat(const char *pathname, mode_t mode); Returns : file descriptor opened for write-only if OK, 1 on error write Function Data is written to an open file with the write function.
32
#include <unistd.h> ssize_t write(int filedes, const void *buf, size_t nbytes); Returns: number of bytes written if OK, 1 on error lseek Function Every open file has an associated "current file offset," normally a non-negative integer that measures the number of bytes from the beginning of the file .Read and write operations normally start at the current file offset and cause the offset to be incremented by the number of bytes read or written. By default, this offset is initialized to 0 when a file is opened, unless the O_APPEND option is specified. An open files offset can be set explicitly by calling lseek. The function prototype of lseek function : #include <unistd.h> off_t lseek(int filedes, off_t offset, int whence); Returns: new file offset if OK, 1 on error The interpretation of the offset depends on the value of the whence argument. If whence is SEEK_SET, the files offset is set to offset bytes from the beginning of the file. If whence is SEEK_CUR, the files offset is set to its current value plus the offset. The offset can be positive or negative. If whence is SEEK_END, the files offset is set to the size of the file plus the offset. The offset can be positive or negative. a) Shell script that takes a valid directory names as as argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum valut to the standard output.
3.
Filename : 3a.sh maxsize=`ls -lR $1 | grep '^-' | cut -c 38-43 | sort -n | tail -1` echo "The max size of the file in directort $1 is $maxsize bytes" Output : $ls -l total 12 -rwxr-xr-x -rwxr-xr-x -rwxrwxrwx
$ sh 3a.sh /root/6ise/unix The max size of the file in directort /root/6ise/unix is 366 bytes
33
Explanation : To take the input from the user we have to use read statement with a variable. Recursively to descend all the files in list we need to use ls command with - R option.Also - l is used for long listing. The output of ls command is piped to a terminal using tee command ,as well as to a file. Then further it is piped to the simple filter cut . To extract specific column we need use .c option with a list of column numbers, delimited by a comma. To extract the filesize field we need to use the range 38-43. Then at last the output is redirected to an another file. To display the content of a file we can use cat command. Then the file content is sorted with respect to numerals using sort - n option. Then the sorted output is redirected to an another file. So the last line while have the maximum value ,we can extract that using the filter tail with -1 option from the file. 3. b) C program that accepts valid file names as coomand line arguments and for each of the arguments, prints the type of the file ( Regular file, directory file, character special file, block special file, symbolic link etc ..)
Filename : 3b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main(int argc, char *argv[]) { int i; struct stat buf; for(i=1; i< argc; i++) { printf("%s: ", argv[i]); lstat(argv[i],&buf); if(S_ISREG(buf.st_mode)) printf("file is a regular file\n"); if(S_ISDIR(buf.st_mode)) printf("file is a directory file\n"); if(S_ISCHR(buf.st_mode)) printf("file is a character file\n"); if(S_ISBLK(buf.st_mode)) printf("file is a block file\n"); if(S_ISLNK(buf.st_mode)) printf("file is a symbolic link file\n"); } exit(0); }
34
Output : $cc 3b.c $./a.out /root/6ise/3b.c /root/6ise/3b.c: file is a regular file $./a.out /root/6ise/3b.c /root/6ise /root/6ise/3b.c: file is a regular file /root/6ise: file is a directory file $./a.out /dev/tty /dev/tty: file is a character file Explanation : lstat Function #include <sys/stat.h> int lstat(const char *pathname, struct stat *buf); Return : 0 if OK, 1 on error Given a pathname, the stat function returns a structure of information about the named file. The fstat function obtains information about the file that is already open on the descriptor filedes. The lstat function is similar to stat, but when the named file is a symbolic link, lstat returns information about the symbolic link, not the file referenced by the symbolic link. The second argument is a pointer to a structure that we must supply. The function fills in the structure pointed to by buf. The definition of the structure can differ among implementations, but it could look like
struct stat { mode_t st_mode; /* file type & mode (permissions) */ ino_t st_ino; /* i-node number (serial number) */ dev_t st_dev; /* device number (file system) */ dev_t st_rdev; /* device number for special files */ nlink_t st_nlink; /* number of links */ uid_t st_uid; /* user ID of owner */ gid_t st_gid; /* group ID of owner */ off_t st_size; /* size in bytes, for regular files */ time_t st_atime; /* time of last access */ time_t st_mtime; /* time of last modification */ time_t st_ctime; /* time of last file status change */ blksize_t st_blksize; /* best I/O block size */ blkcnt_t st_blocks; /* number of disk blocks allocated */ };
35
File Types Most files on a UNIX system are either regular files or directories, but there are additional types of files. The types are : 1. Regular file. The most common type of file, which contains data of some form. There is no distinction to the UNIX kernel whether this data is text or binary. Any interpretation of the contents of a regular file is left to the application processing the file. 2. Directory file. A file that contains the names of other files and pointers to information on these files. Any process that has read permission for a directory file can read the contents of the directory, but only the kernel can write directly to a directory file 3. Block special file. A type of file providing buffered I/O access in fixed-size units to devices such as disk drives. 4. Character special file. A type of file providing unbuffered I/O access in variablesized units to devices. All devices on a system are either block special files or character special files. 5. FIFO. A type of file used for communication between processes. Its sometimes called a named pipe. 6. Socket. A type of file used for network communication between processes. A socket can also be used for non-network communication between processes on a single host. 7. Symbolic link. A type of file that points to another file. The type of a file is encoded in the st_mode member of the stat structure. We can determine the file type with the macros shown in below .The argument to each of these macros is the st_mode member from the stat structure. File type macros in <sys/stat.h>
Type of file directory file character special file block special file pipe or FIFO symbolic link socket
4.
a)
Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed,it would recreate the original files.
36
Filename : 4a.sh echo #to bundle,sh this file for i in $* do echo "echo $i 1>&2" echo "cat >$i <<'End of $i'" cat $i echo "End of $i" done Output : $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh 8a.sh 9a.sh a $cat > file1 this is first file $cat > file2 this is second file $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 $sh 4a.sh file1 file2 > new.sh $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $rm file1 rm: remove regular file `file1'? y $rm file2 rm: remove regular file `file2'? y $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh 8a.sh 9a.sh a new.sh $sh new.sh file1 file2 $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $cat file1 this is first file $cat file2 this is second file
37
4.
b)
C program to do the following. Using fork( ) create a child process. The child process prints its own process-id and id of its parent and then exits.The parent process waits for its child to finish(by executing wait( )) and prints its own process-id and the id of its child process and then exits.
Filename : 4b.c #include <sys/types.h> #include <stdio.h> int main() { pid_t pid; if((pid=fork())<0) printf("fork error"); if(pid==0) { printf("\n This is child process "); printf("\n Child PID :%d",getpid()); printf("\n Parent PID :%d\n",getppid()); exit(0); } else { wait(); printf("\n This is parent process"); printf("\n Parent PID :%d",getpid()); printf("\n Child PID :%d",pid); exit(0); } } Output : $cc 4b.c $./a.out This is child process Child PID :3122 Parent PID :3121 This is parent process Parent PID :3121 Child PID :3122 Explanation : Every process has a unique process ID, a non-negative integer. Because the process ID is the only well-known identifier of a process that is always unique, it is often used as a piece of other identifiers, to guarantee uniqueness. Process ID 0 is usually the
38
scheduler process and is often known as the swapper. No program on disk corresponds to this process, which is part of the kernel and is known as a system process. Process ID 1 is usually the init process and is invoked by the kernel at the end of the bootstrap procedure. In addition to the process ID, there are other identifiers for every process. The following functions return these identifiers. #include <unistd.h> pid_t getpid(void); Returns : process ID of calling process pid_t getppid(void); Returns: parent process ID of calling process 5. Write a C program to implement the syntax directed definition of if E then S1 and if E then S1 else S2. /* Input to the program is assumed to be syntactically correct. The expression of if statement, statement for true condition and statement for false condition are enclosed in parenthesis */ #include <stdio.h> #include <stdlib.h> #include <conio.h> #include <string.h> int parsecondition(char[],int,char*,int); void gen(char [],char [],char[],int); int main() { int counter = 0,stlen =0,elseflag=0; char stmt[60]; // contains the input statement char strB[54]; // holds the expression for 'if' condition char strS1[50]; // holds the statement for true condition char strS2[45]; // holds the statement for false condition clrscr(); printf("Format of if statement \n Example ...\n"); printf("if (a<b) then (s=a);\n"); printf("if (a<b) then (s=a) else (s=b);\n\n"); printf("Enter the statement \n"); gets(stmt); stlen = strlen(stmt); counter = counter + 2; // increment over 'if'
39
counter = parsecondition(stmt,counter,strB,stlen); if(stmt[counter]==')') counter++; counter = counter + 3; // increment over 'then' counter = parsecondition(stmt,counter,strS1,stlen); if(stmt[counter+1]==';') { // reached end of statement, generate the output printf("\n Parsing the input statement...."); gen(strB,strS1,strS2,elseflag); getch(); return 0; } if(stmt[counter]==')') counter++; // increment over ')' counter = counter + 3; // increment over 'else' counter = parsecondition(stmt,counter,strS2,stlen); counter = counter + 2; // move to the end of statement if(counter == stlen) { //generate the output elseflag = 1; printf("\n Parsing the input statement...."); gen(strB,strS1,strS2,elseflag); getch(); return 0; } return 0; } /* Function : parsecondition Description : This function parses the statement from the given index to get the statement enclosed in () Input : Statement, index to begin search, string to store the condition, total string length Output : Returns 0 on failure, Non zero counter value on success */ int parsecondition(char input[],int cntr,char *dest,int totallen) {
40
int index = 0,pos = 0; while(input[cntr]!= '(' && cntr <= totallen) cntr++; if(cntr >= totallen) return 0; index = cntr; while (input[cntr]!=')') cntr++; if(cntr >= totallen) return 0; while(index<=cntr) dest[pos++] = input[index++]; dest[pos]='\0'; //null terminate the string return cntr; //non zero value } /* Function : gen () Description : This function generates three address code Input : Expression, statement for true condition, statement for false condition, flag to denote if the 'else' part is present in the statement output :Three address code */ void gen(char B[],char S1[],char S2[],int elsepart) { int Bt =101,Bf = 102,Sn =103; printf("\n\tIf %s goto %d",B,Bt); printf("\n\tgoto %d",Bf); printf("\n%d: ",Bt); printf("%s",S1); if(!elsepart) printf("\n%d: ",Bf); else { printf("\n\tgoto %d",Sn); printf("\n%d: %s",Bf,S2); printf("\n%d:",Sn); } } Output : Format of if statement Example ... if (a<b) then (s=a); if (a<b) then (s=a) else (s=b);
41
Enter the statement if (a<b) then (s=a); Parsing the input statement.... If (a<b) goto 101 goto 102 101: (s=a) 102: Output : Format of if statement Example ... if (a<b) then (s=a); if (a<b) then (s=a) else (s=b); Enter the statement if (a<b) then (x=a) else (x=b); Parsing the input statement.... If (a<b) goto 101 goto 102 101: (x=a) goto 103 102: (x=b) 103: /* ALTERNATE PROGRAM To implement syntax directed translation of if-else statement */ #include <iostream> #include <string> #include <cstring> class SyntaxDirectedTranslator { public: // Input the ifelse statement... void input(); // Parse and extract the different parts...
42
void parse(); // Generate the intermediate code... void generate(); private: std :: string ifelse; char expression[51] , statement1[51] , statement2[51]; };
// // // //
int main ( int argc , char **argv ) { // Create a Translator... SyntaxDirectedTranslator SDT; // Input the statement... SDT.input(); // Parse... SDT.parse(); // Generate code... SDT.generate(); return 0; } void SyntaxDirectedTranslator :: input() { // Enter the statement... std :: cout << "Enter the if-else statement --\n" << "Example : if (expr) then (s1) else (s2)\n"; std :: getline ( std :: cin , ifelse , '\n' ); } void SyntaxDirectedTranslator :: parse() { // Skip the 'if' part... std :: size_t i = 0; while(ifelse[i] == ' ') ++i; i += 2; while(ifelse[i] == ' ') ++i;
43
// Find the expression part... std :: size_t j = 0; while ( ifelse[i] != ')' ) expression[j++] = ifelse[i++]; expression[j++] = ifelse[i++]; expression[j] = '\0'; // Skip the 'then' part... while(ifelse[i] == ' ') ++i; i += 4; while(ifelse[i] == ' ') ++i; // Next, get the 'true' statement... j = 0; while ( ifelse[i] != ')' ) statement1[j++] = ifelse[i++]; statement1[j++] = ifelse[i++]; statement1[j] = '\0'; // Check if else part is there... while(ifelse[i] == ' ') ++i; if ( ifelse[i] == '\0' ) { statement2[0] = '\0'; return; } // Skip the else part... i += 4; while(ifelse[i] == ' ') ++i; // Get the 'false' part... j = 0; while ( ifelse[i] != ')' ) statement2[j++] = ifelse[i++]; statement2[j++] = ifelse[i++]; statement2[j] = '\0'; }
44
void SyntaxDirectedTranslator :: generate() { // Output the generated code... std :: cout << " if " << expression << " goto 101\n" << " goto 102\n" << "101: " << statement1 << std :: endl; if ( strlen ( statement2 ) == 0 ) { std :: cout << "102: \n"; return; } std :: cout << " goto 103\n" << "102: " << statement2 << std :: endl << "103: "; } 6. Write a yacc program that accepts a regular expression as input and produce its parse tree as output
%{ #include<ctype.h> char str[20]; int i=0; %} %token id %left '+''/''*''-' %% E:S {infix_postfix(str);} S:S'+'T |S'-'T |T T:T'*'F| T'/'F |F F:id |'('S')' ; %%
45
{ printf("invalid"); } yylex() { char ch=' '; while(ch!='\n') { ch=getchar(); str[i++]=ch; if(isalpha(ch)) return id; if(ch=='+'||ch=='*'|| ch=='-'||ch=='/') return ch; } str[--i]='\0'; return(0); exit(0); }
void push(char stack[],int *top,char ch) { stack[++(*top)]=ch; } char pop(char stack[],int *top) { return(stack[(*top)--]); } int prec(char ch) { switch(ch) { case '/': case '*': return 2; case '+': case '-': return 1; case '(': return 0; default: return -1; } }
46
void infix_postfix(char infix[]) { int top=-1,iptr=-1,pptr=-1; char postfix[20],stack[20],stksymb,cursymb; push(stack,&top,'\0'); while((cursymb=infix[++iptr])!='\0') { switch(cursymb) { case '(' : push(stack,&top,cursymb); break; case ')' :stksymb=pop(stack,&top); while(stksymb!='(') { postfix[++pptr]=stksymb; stksymb=pop(stack,&top); } break; case '*' : case '/' : case '+' : case '-' : while(prec(stack[top])>=prec(cursymb)) postfix[++pptr]=pop(stack,&top); push(stack,&top,cursymb); break; default : if(isalnum(cursymb)==0) { printf("Error in input!"); exit(0);} postfix[++pptr]=cursymb; } } while(top!=-1) postfix[++pptr]=pop(stack,&top); printf("%s\n",postfix); } Output : Enter the identifier : a+b*c abc*+
47
/* ALTERNATE PROGRAM Yacc program to recognise a regular expression and produce a parse tree as output */ %{ #include <stdio.h> #include <ctype.h> #include <stdlib.h> #include <string.h> /* To store the productions */ #define MAX 100 int getREindex ( const char* ); signed char productions[MAX][MAX]; int count = 0 , i , j; char temp[MAX + MAX] , temp2[MAX + MAX]; %} %token ALPHABET %left '|' %left '.' %nonassoc '*' '+' %% S : re '\n'
{ printf ( "This is the rightmost derivation--\n" ); for ( i = count - 1 ; i >= 0 ; --i ) { if ( i == count - 1 ) { printf ( "\nre => " ); strcpy ( temp , productions[i] ); printf ( "%s" , productions[i] ); } else { printf ( "\n => " ); j = getREindex ( temp ); temp[j] = '\0'; sprintf ( temp2 , "%s%s%s" , temp , productions[i] , (temp + j + 2) ); printf ( "%s" , temp2 ); strcpy ( temp , temp2 ); } } printf ( "\n" );
48
exit ( 0 ); } re : ALPHABET { temp[0] = yylval; temp[1] = '\0'; strcpy ( productions[count++] , temp ); } | | | | | ; %% int main ( int argc , char **argv ) { /* Parse and output the rightmost derivation, from which we can get the parse tree */ yyparse(); return 0; } yylex() { signed char ch = getchar(); yylval = ch; if ( isalpha ( ch ) ) return ALPHABET; return ch; } yyerror() { fprintf ( stderr , "Invalid Regular Expression!!\n" ); exit ( 1 ); } int getREindex ( const int i = strlen ( str for ( ; i >= 0 ; --i if ( str[i] == 'e' return i-1; char *str ) { ) - 1; ) { && str[i-1] == 'r' ) '(' re ')'{ strcpy ( productions[count++] , "(re)" ); } re '*' { strcpy ( productions[count++] , "re*" ); } re '+' { strcpy ( productions[count++] , "re+" ); } re '|' re { strcpy ( productions[count++] , "re | re" ); } re '.' re { strcpy ( productions[count++] , "re . re" ); }
49
} } Operators used | is for ORing . is for concatenating * is Kleene closure a+ is equivalent to a.a* C:\Prog6>a.out a+|b*|(b.c*) This is the rightmost derivation-re => => => => => => => => => => => re | re re | (re) re | (re . re) re | (re . re*) re | (re . c*) re | (b . c*) re | re | (b . c*) re | re* | (b . c*) re | b* | (b . c*) re+ | b* | (b . c*) a+ | b* | (b . c*)
C:\Prog6>a.out a.(b|(a+)) This is the rightmost derivation-re => => => => => => => => re . re re . (re) re . (re | re) re . (re | (re)) re . (re | (re+)) re . (re | (a+)) re . (b | (a+)) a . (b | (a+))
/* Some explanation of the code Yacc generates an LR parser. Because it is LR, it matches productions for the rightmost derivation in REVERSE order. These productions are stored in an array of strings. Once the whole regex expression is matched then the derivation is output in the correct order. While outputting we need to store the current sentential form in the string 'temp'. At each step the rightmost 're' is replaced with the next production. getREindex() returns the position of the rightmost 're'.*/
50
System Programming
Program to recognize and count the number of identifiers in a given input file. Execution of the following programs using YACC. : a. b. Program to recognize a valid arithmetic expression that uses operators +,- ,* and /. Program to recognize a valid variable, which starts with a letter, followed by any number of letters or digits. Program to evaluate an arithmetic expression involving operators +, -, * and . Program to recognize strings aaab, abbb, ab and a using the grammar (ambn, m>0, n>=0).
5)
a. b.
6)
PART B
1) a. Non-recursive shell script that accepts any number of arguments and prints them in a Reverse order, (For example, if the script is named rargs, then rargs A B C should produce C B A on the standard output). C program that creates a child process to read commands from the standard input and execute them (a minimal implementation of a shell like program). You can assume that no arguments will be passed to the commands to be executed. Shell script that accepts two file names as arguments, checks if the permissions for these files are identical and if the permissions are identical, outputs the common permissions, otherwise outputs each file name followed by its permissions.
b.
2)
a.
System Programming
51
b.
C program to create a file with 16 bytes of arbitrary data from the beginning and another 16 bytes of arbitrary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled. Shell function that takes a valid directory names as an argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum value to the standard output. Write a C program which accepts valid file names as command line arguments and for each of the arguments, prints the type of the file (regular file, directory file, character special file, block file, symbolic link etc.). Shell script that accepts path names and creates all the components in that path names as directories. For example, if the script name is mpe, then the command mpe a/b/c/d should create directories a, a/b, a/b/c and a/b/c/d. C program that accepts one command-line argument, executes the arguments as a shell command, determines the time taken by it and prints the time values, Use the times, function and the tms structure. The code need not include error checking. Shell script that accepts valid log-in names as arguments and prints their corresponding home directories. If no arguments are specified, print a suitable error message. C program that accepts valid directory names as a command line argument and lists all the files in the given directory as well as all the subsequent subdirectories. (The solution can be recursive or non-recursive). Shell script to implement terminal locking. It should prompt the user for a password. After accepting the password entered by the user, it must prompt again for password confirmation (to retype the password). If a match occurs, it must lock the terminal and prompt for a password. If the proper password is entered, the terminal must be unlocked. Note the script must be written to disregard BREAK, Control-D etc. No time limit need be implemented for the lock duration. Write a C program to prompt user for the name of an environment variable and print its value if it is defined and a suitable message otherwise; and to repeat the process if user wants it. Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files (This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India). Awk script to delete duplicate lines in a file. The order of original lines must not change.
3)
a.
b.
4)
a.
b.
5)
a.
b.
6)
a.
b.
7)
a.
b.
52
8)
System Programming
a.
Shell script to find and display all the links of a file specified as the first argument to the script. The second argument, which is optional, can be used to specify the directory in which the search is to begin. If this second argument is not present, the search is to begin in current working directory. In either case, the starting directory as well as its subdirectories at all levels must be searched. The script need not include any error checking. PERL script that echoes its command line arguments, one per line after translating all lower case letters to upper case. Shell script to display the calendar for current month with current date replaced by * or ** depending on whether date has one digit or two digits. PERL program to convert unsigned binary number (supplied as argument) to decimal (for example if the argument is 10110 the output should be 22). If an argument is present, it can be a valid binary number and if no argument is present, the program should display an error message. Awk script that folds long line into 40 columns. Thus any line that exceeds 40 Characters must be broken after 40th and is to be continued with the residue. The inputs to be supplied through a text file created by the user. C program to do the following using fork () create a child process. The child process prints its own process id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait ()) and prints its own process id and the id of its child process and then exits.
b. 9) a. b.
10) a.
b.
Note Part A,LEX and YACC Programs are same as given and explained in SYSTEM SOFTWARE AND COMPILER DESIGN LABORATORY
PART B
UNIX PROGRAMMING
1. a) Non-recursive shell script that accepts any number of arguments and prints them in the reverse order.
Filename : 1a.sh echo "number len=$# while [ $len do eval echo len=`expr done of arguments are : $#" -ne 0 ] \$$len $len - 1`
System Programming
53
Output : $ sh 1a.sh 1 2 3 number of arguments are : 3 3 2 1 $ ./1a.sh rahul raj rani number of arguments are : 3 rani raj rahul 1. b) C program that creates a child process to read commands from the standard input and execute them ( a minimal implementation pf a shell like a program). You can assume that no arguments will be passed to the commands to be executed.
Filename : 1b.c #include<stdio.h> #include<sys/types.h> int main() { char cmd[20]; pid_t pid; int ch; pid=fork(); if(pid == 0) { do { printf("\n Enter the command to be executed : "); scanf("%s",cmd); system(cmd); printf("\n Enter 1 to continue and 0 to exit : "); scanf("%d",&ch); } while(ch!=0); } wait(); } Output : $ cc 1b.c
54
System Programming
$ ./a.out Enter the command to be executed : date wed Dec 16 11:05:52 IST 2009 Enter 1 to continue and 0 to exit : 1 Enter the command to be executed : cal December 2009 Su Mo Tu We Th Fr Sa 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 2. a) Shell script that accepts two file names as arguments, checks if the permissions of these files are identical and if the permissions are identical, outputs the common permission, otherwise outputs each file name followed by its permission.
Filename : 2a.sh ls -l $1 | cut c 1-10 > file1per ls -l $2 | cut -c 1-10 > file2per if cmp file1per file2per then echo "Both the files have same permission" cat file1per else echo "Both the files have different permission" echo "The permission of first file $1 is " cat file1per echo "The permission of second file $2 is " cat file2per fi Output : $cat > file1 this is first file content $cat > file2 this is second file content $sh 2a.sh file1 file2 Both the files have same permission -rw-r--r-$chmod 777 file2
System Programming
55
$sh 2a.sh file1 file2 file1per file2per differ: byte 4, line 1 Both the files have different permission The permission of first file file1 is -rw-r--r-The permission of second file file2 is -rwxrwxrwx 2. b) C program to create a file with 16 bytes of arbitary data from the beginning and another 16 bytes of arbitary data from an offset of 48. Display the file contents to demonstrate how the hole in file is handled
Filename : 2b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main() { int fd; char buf1[]="Department of IS"; char buf2[]="Department of CS"; fd=creat("ise",0622); if(fd < 0) { printf("\n Error in creating file"); exit(0); } write(fd,buf1,16); lseek(fd,48,SEEK_SET); write(fd,buf2,16); exit(0); } Output : $cc 2b.c $./a.out $od -c ise 0000000 D 0000020 \0 \0 \0 * 0000060 D 0000100
e \0
p \0
a \0
r \0
t \0
m \0
e \0
n \0
t \0
\0
o \0
f I S \0 \0
56
3.
System Programming
a)
Shell script that takes a valid directory names as as argument and recursively descends all the subdirectories, finds the maximum length of any file in that hierarchy and writes this maximum valut to the standard output.
Filename : 3a.sh maxsize=`ls -lR $1 | grep '^-' | cut -c 38-43 | sort -n | tail -1` echo "The max size of the file in directort $1 is $maxsize bytes" Output : $ls -l total 12 -rwxr-xr-x 1 root root 148 Mar 1 22:17 1a.sh -rwxr-xr-x 1 root root 366 Mar 1 22:17 2a.sh -rwxrwxrwx 1 root root 192 Mar 1 22:17 3a.sh $ sh 3a.sh /root/6ise/unix The max size of the file in directort /root/6ise/unix is 366 bytes 3. b) C program that accepts valid file names as coomand line arguments and for each of the arguments, prints the type of the file ( Regular file, directory file, character special file, block special file, symbolic link etc ..)
Filename : 3b.c #include<sys/types.h> #include<sys/stat.h> #include<fcntl.h> #include<unistd.h> int main(int argc, char *argv[]) { int i; struct stat buf; for(i=1; i< argc; i++) { printf("%s: ", argv[i]); lstat(argv[i],&buf); if(S_ISREG(buf.st_mode)) printf("file is a regular file\n"); if(S_ISDIR(buf.st_mode)) printf("file is a directory file\n"); if(S_ISCHR(buf.st_mode)) printf("file is a character file\n");
System Programming
57
if(S_ISBLK(buf.st_mode)) printf("file is a block file\n"); if(S_ISLNK(buf.st_mode)) printf("file is a symbolic link file\n"); } exit(0); } Output : $cc 3b.c $./a.out /root/6ise/3b.c /root/6ise/3b.c: file is a regular file $./a.out /root/6ise/3b.c /root/6ise /root/6ise/3b.c: file is a regular file /root/6ise: file is a directory file $./a.out /dev/tty /dev/tty: file is a character file 4. a) Write a shell script that accepts path names and creates all the components in that path names as directories. For example, if the script is mpe, then the command mpe a/b/c/d should create directories a, a/b, a/b/c and a/b/c/d.
Filename : 4a.sh if [ $# -le 0 o $# -gt 1 ] then echo Improper Usage : pathname required else mkdir -p $1 fi Output : $ $ $ b $ $ C $ $ d sh 4a.sh a/b/c/d cd a ls cd b ls cd c ls
58
4.
System Programming
b)
Write a C program that accepts one command-line argument, executes the arguments as shell command, determines the time taken by it and prints the time values, Use the times, function and the tms structure. The code need not include error checking.
Filename : 4b.c #include<stdio.h> #include<sys/times.h> #include<unistd.h> #include<time.h> int main(int argc, char *argv[]) { struct tms tms1,tms2; clock_t begin,end; long clktick = sysconf(_SC_CLK_TCK); begin=times(&tms1); system(argv[1]); end=times(&tms2); printf("\n\t Time taken is %f ",(end-begin)/(double)CLK_TCK); printf("\n\t Time taken is %f ",(tms2.tms_utimetms1. tms_utime)/(double)clktick); } Output : $ cc 4b.c $./a.out ls 1a.l 1b.l 2a.l 2b.l 3.l 4a.l 4a.y 4b.l 4b.y 5a.l 5b.y 6 1a.sh 2a.sh 3a.sh 4a.sh 1b.c 2b.c 3b.c 4b.c ./a.out Time taken is 0.010000 Time taken is 0.000000 $ ./a.out cal December 2009 Su Mo Tu 1 6 7 8 13 14 15 20 21 22 27 28 29
We 2 9 16 23 30
Th 3 10 17 24 31
Fr 4 11 18 25
Sa 5 12 19 26
System Programming
59
5.
Shell script that accepts valid log-in names as arguments and prints their corresponding home directories. If no arguments are specified, print a suitable error message. Filename : 5a.sh if [ $# -lt 1 ] then echo " Invalid Arguments....... " exit fi for x in "$@" do if grep "$x" /etc/passwd > file1 then echo" The login name is : $x" echo " The Home directory is : `cut -d ":" -f 6 file1`" else echo " $x is not a valid login name " fi done Output : $ sh 5a.sh cse The login name is : cse The Home directory is : /home/cse $ sh 5a.sh Invalid Arguments....... 5. C program that accepts valid directory names as a command line argument and lists all the files in the given directory as well as all the subsequent subdirectories. (The solution can be recursive or non-recursive). Filename : 5b.c #include<stdio.h. #include<string.h> int main(int argc, char *argv[]) { int i; char str[50]; for(i=1;i<argc;i++) { strcpy(str, ls R ); /* leave space after R */ strcat(str,argv[i]); system(str); } } b)
a)
60
System Programming
Output : $ cc 5b.c $ ./a.out /home/ise 1a.l 1b.l 2a.l 2b.l 3.l 4a.l 4a.y 4b.l 4b.y 5a.l 5b.y 6 1a.sh 2a.sh 3a.sh 4a.sh 1b.c 2b.c 3b.c 4b.c ./a.out a /home/ise/a: b /home/ise/a/b: c /home/ise/a/b/c: d /home/ise/a/b/c/d: 6. a) Shell script to implement terminal locking. It should prompt the user for a password. After accepting the password entered by the user, it must prompt again for password confirmation (to retype the password). If a match occurs, it must lock the terminal and prompt for a password. If the proper password is entered, the terminal must be unlocked. Note the script must be written to disregard BREAK, Control-D etc. No time limit need be implemented for the lock duration.
Filename : 6a.sh trap "" 1 2 3 5 20 clear echo -e "Enter password to lock terminal:" stty -echo read keynew stty echo echo -e "Confirm password:" stty -echo read keyold stty echo if [ $keyold = $keynew ] then echo "Terminal locked!" while [ 1 ] do echo "Retype the password to unlock:" stty -echo read key if [ $key = $keynew ] then
System Programming
61
stty echo echo "Terminal unlocked!" stty sane exit fi echo "Invalid password!" done else echo " Passwords do not match!" fi stty sane Output : $ sh 6a.sh Enter password to lock terminal: Confirm password: Terminal locked! Retype the password to unlock: Invalid password! Retype the password to unlock: Invalid password! Retype the password to unlock: Terminal unlocked! $ sh 6a.sh Enter password to lock terminal: Confirm password: Passwords do not match! 6. b) Write a C program to prompt user for the name of an environment variable and print its value if it is defined and a suitable message otherwise; and to repeat the process if user wants it.
Filename : 6b.c #include<stdio.h> #include<sys/types.h> #include<sys/stat.h> #include<stdlib.h> int main( ) { char name[25]; int i; char *p; do
62
System Programming
{ printf(\n Enter any environment variable :); scanf(%s,name); p=getenv(name); if(p) printf(%s,p); else printf(\n Environment variable not defined); printf(\n Want to continue 1-yes 0-no :\n); scanf(%d,&i); } while(i!=0); } Output : $ cc 6b.c $ ./a.out Enter any environment variable :HOME Root Want to continue 1-yes 0-no :0 7. a) Shell script that accepts file names specified as arguments and creates a shell script that contains this file as well as the code to recreate these files. Thus if the script generated by your script is executed, it would recreate the original files (This is same as the bundle script described by Brain W. Kernighan and Rob Pike in The Unix Programming Environment, Prentice Hall India).
Filename : 7a.sh echo #to bundle,sh this file for i in $* do echo "echo $i 1>&2" echo "cat >$i <<'End of $i'" cat $i echo "End of $i" done Output : $ls 10b.c 1b.c 4a.sh 5a.sh a $cat > file1 this is first file
5b.c
6a.sh
6b.c
7a.sh
8a.sh
9a.sh
System Programming
63
$cat > file2 this is second file $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 $sh 7a.sh file1 file2 > new.sh $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $rm file1 rm: remove regular file `file1'? y $rm file2 rm: remove regular file `file2'? y $ls 10b.c 1b.c 4a.sh 5a.sh 5b.c 6a.sh 6b.c 7a.sh a new.sh $sh new.sh file1 file2 $ls 10b.c 4a.sh 5b.c 6b.c 8a.sh a file2 1b.c 5a.sh 6a.sh 7a.sh 9a.sh file1 new.sh $cat file1 this is first file $cat file2 this is second file 7. b)
8a.sh
9a.sh
Awk script to delete duplicate lines in a file. The order of original lines must not change.
Filename : 7b.awk { found=0 for(i=0;i<nlines;i++) if(lines[i] == $0) { found=1 break } if(!found) { lines[nlines++]=$0 print $0 } }
64
System Programming
Output : $ vi sample.txt ise cse ise ec tc cse $ awk f 7b.awk sample.txt ise cse ec tc 8. a) Shell script to find and display all the links of a file specified as the first argument to the script. The second argument, which is optional, can be used to specify the directory in which the search is to begin. If this second argument is not present, he search is to begin in current working directory. In either case, the starting directory as well as its subdirectories at all levels must be searched. The script need not include any error checking.
Filename : 8a.sh if [ $# -eq 0 ] then echo "Usage:sh 8a.sh[file1] [dir1(optional)]" exit fi if [ -f $1 ] then dir="." if [ $# -eq 2 ] then dir=$2 fi str=`ls -i $1|cut -d " " -f 1` echo "Hard links of $1 are" find $dir -inum $str -print echo "Soft links of $1 are" find $dir -lname $1 -print else echo "The file $1 does not exist" fi
System Programming
65
Output : $ vi file1 $ ln s file1 file2 $ ln file1 file3 $ ln file1 file4 $ sh 8a.sh file1 Hard links of file1 are file3 file4 Soft links of file1 are file2 8. b) PERL script that echoes its command line arguments, one per line after translating all lower case letters to upper case.
Filename : 8b.pl foreach $string (@ARGV) { $string=~tr/a-z/A-Z/; print($string\n); } Output : $perl 8b.pl unix system programming UNIX SYSTEM PROGRAMMING 9. a) Shell script to display the calendar for current month with current date replaced by * or ** depending on whether date has one digit or two digits.
Filename : 9a.sh cal > dayno set `date` x=$3 if [ $x le 9 ] then sed s/ $3 / */ dayno else sed s/ $3/ **/ dayno fi rm dayno
66
System Programming
We 2 9 ** 23 30
Th 3 10 17 24 31
Fr 4 11 18 25
Sa 5 12 19 26
PERL program to convert unsigned binary number (supplied as argument) to decimal (for example if the argument is 10110 the output should be 22). If an argument is present, it can be a valid binary number and if no argument is present, the program should display an error message.
Filename : 9b.pl if(@ARGV==0) { print(Invalid arguments); } else { $num=0; $mul=1; while($ARGV[0] != ) { $num = $num + chop($ARGV[0]) * $mul; $mul = $mul * 2; } print($num\n); } Output : $ perl 9b.pl 101 5 $ perl 9b.pl 111 7 $ perl 9b.pl Invalid arguments 10) a. Awk script that folds long line into 40 columns. Thus any line that exceeds 40 Characters must be broken after 40th and is to be continued with the residue. The inputs to be supplied through a text file created by the user.
System Programming
67
Filename : 10a.awk { x=$0 while(length(x) > 40) { printf(%sX\n,substr(x,1,40)) x=substr(x,41,length(x)-40) } print(%s\n,x); } Output : $vi abc.txt Signals are software interrupts. UNIX uses signals to inform a process of asynchronous events and to handle exception. Signals provide a mechanism for notifying process of systems events. For example, when a user types control C at the terminal. $awk -f 10a.awk abc.tzt Signals are software interrupts. UNIX usX es signals to inform a process of asynchX ronous events and to handle exception. SX ignals provide a mechanism for notifyingX process of systems events. For example,X when a user types control C at the termX inal. 10. b) C program to do the following using fork () create a child process. The child process prints its own process id and id of its parent and then exits. The parent process waits for its child to finish (by executing the wait ()) and prints its own process id and the id of its child process and then exits.
Filename : 10b.c #include <sys/types.h> #include <stdio.h> int main() { pid_t pid; if((pid=fork())<0) printf("fork error"); if(pid==0)
68
System Programming
{ printf("\n This is child process "); printf("\n Child PID :%d",getpid()); printf("\n Parent PID :%d\n",getppid()); exit(0); } else { wait(); printf("\n This is parent process"); printf("\n Parent PID :%d",getpid()); printf("\n Child PID :%d",pid); exit(0); } } Output : $cc 10b.c $./a.out This is child process Child PID :3122 Parent PID :3121 This is parent process Parent PID :3121 Child PID :3122
File Structures
69
2.
3.
4.
5. 6.
7.
8. 9.
10. Write a C++ program to implement B+ tree for a given set of integers and its operations insert ( ), and search ( ). Display the tree. 11. Write a C++ program to store and retrieve student data from file using hashing. Use any collision resolution technique 12. Write a C++ program to reclaim the free space resulting from the deletion of records using linked lists.
70
1.
File Structures
Write a C++ program to read series of names, one per line, from standard input and write these names spelled in reverse order to the standard output using I/O redirection and pipes. Repeat the exercise using an input file specified by the user instead of the standard input and using an output file specified by the user instead of the standard output.
Filename : fs1.cpp #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> void swap(char &x,char &y) { char temp=x; x=y; y=temp; } void reverse(char *name) { int count=strlen(name); for(int i=0,j=count-1;i<count/2;++i,--j) swap(name[i],name[j]); } void main(int argc,char *argv[]) { if(argc==1) { char name[10]; do { cin>>name; reverse(name); cout<<name<<endl; if(cin.eof()) break; }while(1); } else if(argc>2) { char name[20]; fstream fd1,fd2; fd1.open(argv[1],ios::in);
File Structures
71
fd2.open(argv[2],ios::out|ios::app|ios::trunc); do { fd1>>name; reverse(name); cout<<name; fd2<<name<<endl; if(fd1.eof()) break; }while(1); fd1.close(); fd2.close(); } cout<<"usage:"<<argv[0]<<"filename1 filename2"; } Output: C:\TC\BIN>FS1.exe networks skrowten file elif system metsys C:\TC\BIN>edit input networks files system compiler graphics C:\TC\BIN>FS1.exe input output skrowtenselifmetsysrelipmocscihparg C:\TC\BIN>type output skrowten selif metsys relipmoc scihparg C:\TC\BIN>FS1.EXE INPUT usage:FS1.EXE filename1 filename2
72
2.
File Structures
Write a C++ program to read and write and student objects with fixed-length records and the fields delimited by |.implement pack(),unpack(),modify() and search() methods.
#include<stdio.h> #include<stdlib.h> #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> #include<iomanip.h> class student { public: name[15],usn[15],age[5],sem[5],branch[15],buffer[45]; }; student s2[100]; void writeRecord() //Function to add record to file { fstream app; student s; app.open("student.txt",ios::app); //Open file in append mode if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\n Enter the student name = "; cin>>s.name; cout<<"\n Enter the usn = "; cin>>s.usn; cout<<"\n Enter the age = "; cin>>s.age; cout<<"\n Enter the sem = "; cin>>s.sem; cout<<"\n Enter the branch = "; cin>>s.branch; //packing the information strcpy(s.buffer, s.name); strcat(s.buffer,"|"); strcat(s.buffer, s.usn); strcat(s.buffer,"|"); strcat(s.buffer, s.age); strcat(s.buffer,"|"); strcat(s.buffer, s.sem); strcat(s.buffer,"|"); strcat(s.buffer, s.branch); int count=strlen(s.buffer); char
File Structures
73
for(int k=0;k<45-count;k++) strcat(s.buffer,"!"); strcat(s.buffer,"\n"); app<<s.buffer; //writing the packed information to buffer app.close(); } void search() { fstream in; char usn[15], extra[45]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the record's usn you want to search = cin>>usn; student s; //Unpacking the record while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'|'); in.getline(extra,45,'\n'); if(strcmp(s.usn,usn)==0) { cout<<"\nRecord found"; cout<<"\n"<<s.name<<"\t"<<s.usn<<"\t"<<s.age<<"\t"<<s.sem<<"\t"<<s.branch; getch(); return; } } cout<<"\n Record not found"; getch(); return; }
";
74
File Structures
void displayFile() { student s; int c,i; char extra[45]; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\t\tUsn\t\tAge\t\tSem\t\tBranch\n"); while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'!'); in.getline(extra,45,'\n'); printf("\n%s\t\t%s\t\t%s\t\t%s\t\t%s",s.name,s.usn,s.age,s.sem,s.branch); i++; } in.close(); getch(); } void modify() { fstream in; char usn[15],buffer[45],extra[45]; int i,j; student s1[100]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the usn"; cin>>usn;
File Structures
75
i=0; //Loading the file to Main memory while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i]. branch, 15,'\n'); in.getline(extra,45,'\n'); i++; } i--; for(j=0;j<i;j++) { if(strcmp(usn,s1[j].usn)==0) { cout<<"\nThe old values of the record with usn "<<usn<<" are "; cout<<"\nname cout<<"\nusn cout<<"\nage cout<<"\nsem cout<<"\nbranch = = = = = "<< "<< "<< "<< "<< s1[j].name; s1[j].usn; s1[j].age; s1[j].sem; s1[j].branch;
cout<<"\nEnter the new values \n"; cout<<"\nname = "; cin>>s1[j].name; cout<<"\nusn = "; cin>>s1[j].usn; cout<<"\nage = "; cin>>s1[j].age; cout<<"\nsem = "; cin>>s1[j].sem; cout<<"\nbranch= "; cin>>s1[j].branch; break; } } if(j==i) { cout<<"\n Record with usn "<<usn<<" is not present"; getch(); return; } in.close(); fstream out1; out1.open("student.txt",ios::out); if(!out1) { cout<<"\nUnable to open file in output mode";
76
File Structures
getch(); return; } for(j=0;j<i;j++) { strcpy(buffer,s1[j].name); strcat(buffer,"|"); strcat(buffer,s1[j].usn); strcat(buffer,"|"); strcat(buffer,s1[j].age); strcat(buffer,"|"); strcat(buffer,s1[j].sem); strcat(buffer,"|"); strcat(buffer,s1[j].branch); int count=strlen(buffer); for(int k=0;k<45-count;k++) strcat(buffer,"!"); strcat(buffer,"\n"); out1<<buffer; } out1.close(); } void main() { fstream in; fstream out; int ch; out.open("student.txt",ios::out); if(!in) { cout<<"\n\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { clrscr(); cout<<"\n 1: write to file\n 2:display the file" <<"\n 3:modify the file\n 4:search\n 5.exit"; cout<<"\n\n Enter the choice: "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: displayFile();break; case 3: modify();break;
File Structures
77
case 4: search (); break; case 5: exit(0); default: cout<<"\nInvalid input....";break; } } } Output : 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise
1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse
1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:2 Name Usn Age
Sem
Branch
78
File Structures
ajay rahul
1vk07is002 20 1vk07cs045 20
6 6
ise!!!!!!!!!!! cse!!!!!!!!!!!
1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:4 Enter the record's usn you want to search = 1vk07cs045 Record found rahul 1vk07cs045 20 6 cse!!!!!!!!!!! 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:5 C:\TC|BIN>type student.txt ajay|1vk07is002|20|6|ise!!!!!!!!!!! rahul|1vk07cs045|20|6|cse!!!!!!!!!!! 3. Write a C++ program to read and write and student objects with variable length records using any suitable record structure. Implement pack(),unpack(),modify() and search() methods
#include<stdio.h> #include<stdlib.h> #include<iostream.h> #include<fstream.h> #include<conio.h> #include<string.h> #include<iomanip.h> class student { public: char name[15], buffer[100]; }; student s2[100];
usn[15],
age[5],
sem[5],
branch[15],
File Structures
79
void writeRecord() { fstream app; student s; app.open("student.txt",ios::app); //Open file in append mode if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\n Enter the student name = "; cin>>s.name; cout<<"\n Enter the usn = "; cin>>s.usn; cout<<"\n Enter the age = "; cin>>s.age; cout<<"\n Enter the sem = "; cin>>s.sem; cout<<"\n Enter the branch = "; cin>>s.branch; //packing the information strcpy(s.buffer, s.name); strcat(s.buffer,"|"); strcat(s.buffer, s.usn); strcat(s.buffer,"|"); strcat(s.buffer, s.age); strcat(s.buffer,"|"); strcat(s.buffer, s.sem); strcat(s.buffer,"|"); strcat(s.buffer, s.branch);strcat(s.buffer,"\n"); app<<s.buffer; app.close(); } void search() { fstream in; char usn[15], extra[45]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the record's usn you want to search = cin>>usn; student s; //Unpacking the record while(!in.eof()) { //writing the packed information to buffer
";
80
File Structures
in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'\n'); if(strcmp(s.usn,usn)==0) { cout<<"\nRecord found"; cout<<"\n"<<s.name<<"\t"<<s.usn<<"\t"<<s.age<<"\t" <<s.sem<<"\t"<<s.branch; getch(); return; } } cout<<"\n Record not found"; getch(); return; } void displayFile() { student s; int c,i; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\t\tUsn\t\tAge\t\tSem\t\tBranch\n"); while(!in.eof()) { in.getline(s.name,15,'|'); in.getline(s.usn,15,'|'); in.getline(s.age,5,'|'); in.getline(s.sem,5,'|'); in.getline(s.branch,15,'\n'); printf("\n%s\t\t%s\t\t%s\t\t%s\t\t%s",s.name,s.usn, s.age,s.sem,s.branch); i++; } in.close(); getch(); }
File Structures
81
void modify() { fstream in; char usn[15],buffer[45],extra[45]; int i,j; student s1[100]; in.open("student.txt",ios::in); if(!in) { cout<<"\nUnable to open the file in input mode"; getch(); exit(0); } cout<<"\nEnter the usn"; cin>>usn; i=0; //Loading the file to Main memory while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i]. branch, 15,'\n'); i++; } i--; for(j=0;j<i;j++) { if(strcmp(usn,s1[j].usn)==0) { cout<<"\nThe old values of the record with usn "<<usn<<" are "; cout<<"\nname = "<< s1[j].name; cout<<"\nusn = "<< s1[j].usn; cout<<"\nage = "<< s1[j].age; cout<<"\nsem = "<< s1[j].sem; cout<<"\nbranch = "<< s1[j].branch; cout<<"\nEnter the new values \n"; cout<<"\nname = "; cin>>s1[j].name; cout<<"\nusn = "; cin>>s1[j].usn; cout<<"\nage = "; cin>>s1[j].age; cout<<"\nsem = "; cin>>s1[j].sem; cout<<"\nbranch= "; cin>>s1[j].branch; break; }
82
File Structures
} if(j==i) { cout<<"\n Record with usn "<<usn<<" is not present"; getch(); return; } in.close(); fstream out1; out1.open("student.txt",ios::out); if(!out1) { cout<<"\nUnable to open file in output mode"; getch(); return; } for(j=0;j<i;j++) { out1<<s1[j].name<<'|'<<s1[j].usn<<'|'<<s1[j].age<<'|' <<s1[j].sem<<'|'<<s1[j].sem<<'|'<<s1[j].branch<<'\n'; } out1.close(); } void main() { fstream in; fstream out; int ch; out.open("student.txt",ios::out); if(!in) { cout<<"\n\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { clrscr(); cout<<"\n 1: write to file\n 2:display the file" <<"\n 3:modify the file\n 4:search\n 5:exit";
File Structures
83
cout<<"\n\n Enter the choice: "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: displayFile();break; case 3: modify();break; case 4: search (); break; case 5: exit(0); default: cout<<"\nInvalid input....";break; } } } Output : 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise
1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse
84
File Structures
4:search 5.exit Enter the choice:2 Name Usn ajay 1vk07is002 rahul 1vk07cs045 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:4 Enter the record's usn you want to search = Record found rahul 1vk07cs045 20 6 cse 1:write to file 2:display the file 3:modify the file 4:search 5.exit Enter the choice:5 C:\TC|BIN>type student.txt ajay|1vk07is002|20|6|ise rahul|1vk07cs045|20|6|cse 4. Write a c++ program to write student objects with variable-length records using any suitable record structure and to read from this file a student record using RRN. 1vk07cs045
Age 20 20
Sem 6 6
File Structures
85
public: char name[15],usn[15],age[5],sem[5],branch[15], buffer[100]; }; void search() { char usn[15]; int i=0; student s1[100]; cout<<"\nEnter the usn to be searched: "; cin>>usn; fstream in; in.open("student.txt",ios::in); if(!in) { cout<<"\ncannot open the file in output mode"; getch(); exit(0); } i=0; printf("Name\tUsn\tAge\tSem\tBranch\n"); while(!in.eof()) { in.getline(s1[i].name,15,'|'); in.getline(s1[i].usn,15,'|'); in.getline(s1[i].age,5,'|'); in.getline(s1[i].sem,5,'|'); in.getline(s1[i].branch,15,'\n'); i++; } for(int j=0; j<i-1; j++) { if(strcmp(usn,s1[j].usn)==0) { printf("\n Record found"); printf("\n%s\t%s\t%s\t%s\t%s",s1[j].name,s1[j].usn, s1[j].age,s1[j].sem,s1[j].branch); return; } } cout<<"\nRecord not found"; return; } void writeRecord() { fstream app;
86
File Structures
student s; app.open("student.txt",ios::app); if(!app) { cout<<"cannot open the file in output mode"; getch(); exit(0); } cout<<"\nEnter the student name: "; cin>>s.name; cout<<"\nEnter the usn: "; cin>>s.usn; cout<<"\nEnter the age: "; cin>>s.age; cout<<"\nEnter the sem: "; cin>>s.sem; cout<<"\nEnter the branch: "; cin>>s.branch; strcpy(s.buffer,s.name); strcat(s.buffer,"|"); strcat(s.buffer,s.usn); strcat(s.buffer,"|"); strcat(s.buffer,s.age); strcat(s.buffer,"|"); strcat(s.buffer,s.sem); strcat(s.buffer,"|"); strcat(s.buffer,s.branch); strcat(s.buffer,"\n"); app<<s.buffer; app.close(); } void main() { clrscr(); int ch; fstream out; out.open("student.txt",ios::out); if(!out) { cout<<"\nCannot open the file in output mode"; getch(); exit(0); } out.close(); for(;;) { cout<<"\n1:Insert\n2:Search\n3:exit" <<"\nEnter the choice = "; cin>>ch; switch(ch) { case 1: writeRecord();break; case 2: search();break; case 3: exit(0); default: cout<<"\nInvalid option"; }
File Structures
87
} } Output : 1:Insert 2.Search 3.exit Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = ajay usn = 1vk07is002 age = 20 sem = 6 branch = ise
Enter the choice:1 Enter Enter Enter Enter Enter the the the the the student name = rahul usn = 1vk07cs045 age = 20 sem = 6 branch = cse
1:Insert 2.Search 3.exit Enter the choice:2 Enter the usn to be searched:1vk07is007 Record not found 1:Insert 2.Search 3.exit
88
5.
File Structures
Write a C++ program to implement simple index on primary key for a file of student objects. Implement add(),search(),delete() using the index.
#include<iostream.h> #include<string.h> #include<fstream.h> #include<stdlib.h> //Record specification class record { public: char age[5]; char usn[20],name[20],branch[5]; char sem[2]; }rec[20]; char st_no[5]; int no; void retrieve_details() { fstream file2; char name[20],usn[20],branch[5]; char ind[5],age[5],sem[5]; file2.open("record.txt",ios::in); for(int i=0;i<no;i++) //Unpacking record data { file2.getline(ind,5,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,5,'\n'); if(strcmp(ind,st_no)==0) //Required record found - print details { cout<<"\n\n"<<"Student details are: "; cout<<"\n\nUSN: "<<usn<<"\nName: "<<name<<"\nAge: "<<age<<"\nSem: "<<sem<<"\nBranch: "<<branch<<"\n"; } } file2.close(); } void delete_record(char usno[]) {
File Structures
89
int i; fstream file1, file2; char age[5],sem[5],branch[5],usn[20],name[20],ind[5]; file2.open("record.txt",ios::in); for(i=0;i<no;i++) //Unpack records { file2.getline(ind,5,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,5,'\n'); strcpy(rec[i].usn,usn); strcpy(rec[i].name,name); strcpy(rec[i].age,age); strcpy(rec[i].sem,sem); strcpy(rec[i].branch,branch); } int flag=-1; for(i=0;i<no;i++) //Check for the record's existence { if(strcmp(rec[i].usn,usno)==0) flag=i; } if(flag==-1) //Record not found { cout<<"Error !\n"; return; } if(flag==(no-1)) //Delete found record { no--; cout<<"Deleted !\n"; return; } for(i=flag;i<no;i++) { rec[i]=rec[i+1]; } no--; cout<<"\nDeleted !\n"; file2.close(); file1.open("index.txt",ios::out); //Open index and record files file2.open("record.txt",ios::out); //After deletion
90
File Structures
for(i=0;i<no;i++) //Pack index n record data onto files { file1<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); return; } int main() { fstream file1,file2; int ch; char rt_usn[20],st_usn[20]; char ind[2],name[20],age[2],sem[5],branch[5]; int i,flag,flag1; file1.open("index.txt",ios::out); file2.open("record.txt",ios::out); if(!file1 || !file2) { cout<<"File creation Error! \n"; exit(0); } for(;;) { cout<<"\n1: Add Record" <<"\n2: Search Record" <<"\n3: Delete Record" <<"\n4: Display Record" <<"\n5: Exit" <<"\n\n Enter u'r choice :"; cin>>ch; switch(ch) { case 1: cout<<"Enter the no. of students : "; cin>>no; cout<<"Enter the details:\n"; for(i=0;i<no;i++) //Pack data onto the index and record files { //USN is the indexed data cout<<"\nName: "; cin>>rec[i].name; cout<<"Age: "; cin>>rec[i].age; cout<<"USN: "; cin>>rec[i].usn; cout<<"Sem: "; cin>>rec[i].sem; cout<<"Branch: "; cin>>rec[i].branch;
File Structures
91
file1<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); break; case 2: cout<<"Enter USN whose record is to be displayed: "; cin>>st_usn; file1.open("index.txt",ios::in); if(!file1) { cout<<"\nError !\n"; exit(0); } flag1=0; for(i=0;i<no;i++) { file1.getline(rt_usn,20,'|'); //Unpack index file and file1.getline(st_no,4,'\n'); //look for a match in the USN if(strcmp(st_usn,rt_usn)==0) { retrieve_details(); //Retrieve details if index found flag1=1; } } if(!flag1) cout<<"Record search failed!\n"; file1.close(); break; case 3: cout<<"Enter USN whose record is to be deleted: "; cin>>st_usn; file1.open("index.txt", ios::in); if(!file1) { cout<<"Error! \n"; exit(0); } flag=0; for(i=0;i<no;i++) { file1.getline(rt_usn,20,'|'); //Search index file and file1.getline(st_no,4,'\n'); //call del if index found if(strcmp(st_usn, rt_usn)==0) { delete_record(rt_usn);
92
File Structures
flag=1; } } if(!flag) cout<<"Deletion Failed\n"; file1.close(); break; case 4: for(i=0;i<no;i++) { cout<<"\n\n USN: "<<rec[i].usn <<"\n Name: "<<rec[i].name <<"\n Age: "<<rec[i].age <<"\n Sem: "<<rec[i].sem <<"\n Branch: "<<rec[i].branch; } break; case 5:exit(0); default: cout<<"Invalid choice"; exit(0); break; } } } Output : 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice : 1 Enter the no. of students :2 Enter the details: Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045
File Structures
93
Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice : 4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045 Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice :3 Enter USN whose record is to be deleted:1vk07cs045 Deleted ! 1: Add Record 2: Search Record 3: Delete Record 4: Display Record 5: Exit Enter u'r choice :4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise
94
6.
File Structures
Write a C++ program to implement index on secondary key, the name, for a file of student objects. Implement add(),search(),delete() using the secondary index.
#include<iostream.h> #include<string.h> #include<fstream.h> #include<stdlib.h> //using namespace std; class record { public: char age[5]; char usn[20],name[20],branch[5]; char sem[2]; }rec[20],found[20]; char st_no[5],rt_name[20]; int no; void sort_records() { int i,j; record temp; for(i=0;i<no-1;i++) for(j=0;j<no-i-1;j++) if(strcmp(rec[j].name, rec[j+1].name) > 0) { temp=rec[j]; rec[j]=rec[j+1]; rec[j+1]=temp; } } void create_indexfile() { fstream index,index2; int i; index.open("secindex.txt",ios::out); index2.open("record.txt",ios::out); for(i=0;i<no;i++) { index<<rec[i].name<<"|" <<rec[i].usn<<"|"<<i<<"\n"; index2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|"<<rec[i].age<<"|" <<rec[i].sem<<"|"<<rec[i].branch<<"\n";
File Structures
95
} } void retrieve_record(char* index) { fstream file; int i; char ind[2],usn[20],name[20],age[3],sem[3],branch[10]; file.open("record.txt",ios::in); for(i=0;i<no;i++) { file.getline(ind,4,'|'); file.getline(usn,20,'|'); file.getline(name,20,'|'); file.getline(age,4,'|'); file.getline(sem,4,'|'); file.getline(branch,5,'\n'); if(strcmp(index,ind) == 0) cout<<"\nUSN: "<<usn <<"\nName: "<<name <<"\nAge: "<<age <<"\nSem: "<<sem <<"\nBranch: "<<branch; } file.close(); return; } void retrieve_details() { int k=0,i; char name[20],usn[20],ind[2]; char chusn[20]; char index[20][20]; fstream file; file.open("secindex.txt",ios::in); for(i=0;i<no;i++) { file.getline(name,20,'|'); file.getline(usn,20,'|'); file.getline(ind,4,'\n'); if(strcmp(name,rt_name) == 0) { strcpy(found[k].name,name); strcpy(found[k].usn,usn); strcpy(index[k],ind);
96
File Structures
k++; } } file.close(); if(k==1) { retrieve_record(index[0]); return; } else { cout<<"Please choose the candidate's USN: \n"; for(i=0;i<k;i++) cout<<"Name: "<<found[i].name<<" USN: "<<found[i].usn<<endl; } cin>>chusn; for(i=0;i<k;i++) { if(strcmp(chusn,found[i].usn) == 0) { retrieve_record(index[i]); return; } } cout<<"Invalid Entry! \n"; return; } void delete_record(char indx[]) { int i; fstream file1,file2; char age[5],sem[5],branch[5],usn[20],name[20],ind[5]; char index[20][20]; file2.open("record.txt",ios::in); for(i=0;i<no;i++) { file2.getline(ind,4,'|'); file2.getline(usn,20,'|'); file2.getline(name,20,'|'); file2.getline(age,5,'|'); file2.getline(sem,5,'|'); file2.getline(branch,8,'\n'); strcpy(index[i],ind); strcpy(rec[i].usn,usn); strcpy(rec[i].name,name);
File Structures
97
strcpy(rec[i].age,age); strcpy(rec[i].sem,sem); strcpy(rec[i].branch,branch); } int flag=-1; for(i=0;i<no;i++) { if(strcmp(index[i],indx) == 0) flag=i; } if(flag==-1) { cout<<"Error!\n"; return; } if(flag==(no-1)) { no--; cout<<"Deleted!\n"; return; } for(i=flag;i<no;i++) { rec[i]=rec[i+1]; } no--; cout<<"Deleted!\n"; file2.close(); file1.open("secindex.txt",ios::out); file2.open("record.txt",ios::out); for(i=0;i<no;i++) { file1<<rec[i].name<<"|"<<rec[i].usn<<"|"<<i<<"\n"; file2<<i<<"|"<<rec[i].usn<<"|"<<rec[i].name<<"|" <<rec[i].age<<"|"<<rec[i].sem<<"|"<<rec[i].branch<<"\n"; } file1.close(); file2.close(); return; } void delete_index(char* nam) { fstream file;
98
File Structures
int i; int k=0; char name[20],usn[20],ind[5],index[20][20],chusn[20]; file.open("secindex.txt",ios::in); for(i=0;i<no;i++) { file.getline(name,20,'|'); file.getline(usn,20,'|'); file.getline(ind,4,'\n'); if(strcmp(nam,name)==0) { strcpy(found[k].name,name); strcpy(found[k].usn,usn); strcpy(index[k],ind); k++; } } file.close(); if(k==1) { delete_record(index[0]); return; } else { cout<<"Please choose the candidate's USN: \n"; for(i=0;i<k;i++) { cout<<"Name: "<<found[i].name<<" USN: "<<found[i].usn<<endl; } } cin>>chusn; for(i=0;i<k;i++) { if(strcmp(chusn,found[i].usn)==0) { delete_record(index[i]); return; } } cout<<"Invalid Entry!\n"; return; } int main() {
File Structures
99
fstream file1,file2; int ch; char rt_usn[20],st_name[20],st_usn[20]; char ind[2],name[20],age[2],sem[5],branch[5]; int i,flag,flag1; file1.open("index.txt",ios::out); file2.open("record.txt",ios::out); if(!file1 || !file2) { cout<<"File creation Error!\n"; exit(0); } for(;;) { cout<<"\nl:Add Record\n2:Search Record" <<"\n3:Delete Record\n4:Display Record\n5:Exit" <<"\n\nEnter u'r choice :"; cin>>ch; switch(ch) { case 1: cout<<"Enter the no. of students : "; cin>>no; cout<<"Enter the details :\n"; for(i=0;i<no;i++) { cout<<"\nName : "; cin>>rec[i].name; cout<<"Age : "; cin>>rec[i].age; cout<<"USN : "; cin>>rec[i].usn; cout<<"Sem : "; cin>>rec[i].sem; cout<<"Branch : "; cin>>rec[i].branch; } sort_records(); create_indexfile(); file1.close (); file2.close(); break; case 2: cout<<"Enter name of the student whose record is to be displayed\n"; cin>>st_name; file1.open("secindex.txt",ios::in); if(!file1) { cout<<"Error !\n"; exit(0); } flag1=0;
File Structures
101
{ cout<<"\n\nUSN : "<<rec[i].usn <<"\nName: "<<rec[i].name <<"\nAge : "<<rec[i].age <<"\nSem : "<<rec[i].sem <<"\nBranch : "<<rec[i].branch<<"\n"; } break; case 5:exit(0); default: cout<<"Invalid option !\n"; exit(0); break; } } } Output : 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice : 1 Enter the no. of students :2 Enter the details: Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise Name: rahul Age: 20 USN: 1vk07cs045 Sem: 6 Branch: cse 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice :3 Enter USN whose record is to be deleted:1vk07cs045 Deleted ! 1: 2: 3: 4: 5: Add Record Search Record Delete Record Display Record Exit
Enter u'r choice :4 Name: ajay Age: 20 USN: 1vk07is002 Sem: 6 Branch: ise 7. Write a C++ program to read two lists of names and then match the names in the two lists using Consequential Match based on a single loop. Output the names common to both the lists.
File Structures
103
#include<conio.h> #include<fstream.h> #include<iostream.h> void writeLists() { fstream out1,out2; int i,m,n; char name[20]; out1.open("file1.txt",ios::out); out2.open("file2.txt",ios::out); if( (!out1) || (!out2) ) { cout<<"Unable to open one of the list files"; getch(); exit(0); } cout<<"Enter no. of names you want to enter in file1 :"; cin>>m; cout<<"\nEnter the names in ascending order\n"; for(i=0;i<m;i++) { cin>>name; out1<<name; out1<<'\n'; } cout<<"Enter no. of names you want to enter in file2 :"; cin>>n; cout<<"\nEnter the names in ascending order \n"; for(i=0;i<n;i++) { cin>>name; out2<<name; out2<<'\n'; } out1.close(); out2.close(); } void main() { char list1[100][20], list2[100][20]; int i,j,m,n; clrscr(); fstream out1,out2,out3; writeLists();
File Structures
105
getch(); } Output : Enter no. of names you want to enter in file1 : 3 Enter the names in ascending order cse ise tc Enter no. of names you want to enter in file1 : 2 Enter the names in ascending order ec ise cseisetcecise Elements common to both files are: ise 8. Write a C++ program to read k Lists of names and merge them using kway merge algorithm with k = 8.
#include<iostream.h> #include<fstream.h> #include<string.h> #include<conio.h> // Record specification class record { public: char name[20]; char usn[20]; }rec[20]; int no; fstream file[8]; //The first 8 files char fname[8][8] = {"l.txt","2.txt","3.txt","4.txt","5.txt", "6.txt","7.txt","8.txt"};
File Structures
107
} k=4; for(i=0;i<4;i+=2) //Merge and sort the four files onto lll.txt and 222.txt { merge_file(filename[i],filename[i+1],filename[k++]); } //Merge and sort the two files onto the llll.txt file merge_file(filename[4],filename[5],filename[6]); return; } void main() { int i; clrscr(); cout<<"Enter the no. of records : "; cin>>no; cout<<"\nEnter the details : \n"; for(i=0;i<8;i++) //Create 8 files to store the split data file[i].open(fname[i],ios::out); for(i=0;i<no;i++) //Split and pack data onto the files { cout<<"Name :"; cin>>rec[i].name; cout<<"USN : ";cin>>rec[i].usn; file[i%8]<<rec[i].name<<'|'<<rec[i].usn<<"\n"; } for(i=0;i<8;i++) file[i].close(); kwaymerge(); //Merge fstream result; result.open("lll.txt",ios::in); cout<<"\nSorted Records : \n"; char name[20],usn[20]; for(i=0;i<no;i++) //Unpack the sorted records and dispL { result.getline(name,20,'|'); result.getline(usn,20,'\n'); cout<<"\nName : "<<name<<"\nUSN : "<<usn<<"\n"; } getch(); } Output : Enter the no. of records :4
#include<iostream.h> #include<stdio.h> #include<fstream.h> #include<stdlib.h> #include<string.h> class node { public: int a[4]; node * next[4]; node * parent; int size; node(); }; node :: node()
File Structures
109
{ for(int i = 0; i < 4; i++) next[i] = NULL; parent = NULL; size = 0; } class btree { node * root; public: node* findLeaf(int key,int &level); void updateKey(node *p,node *c,int newKey); void search(int key); void insert(int key); void insertIntoNode(node *n,int key,node *address); void promote(node *n,int key,node *address); node* split(node *n); void traverse(node *ptr); btree(); }; void btree :: traverse(node *ptr) { if(ptr == NULL) return; for(int i = 0; i < ptr->size; i++) cout<<ptr->a[i]<<" "; cout<<endl; for(i = 0; i < ptr->size;i++) traverse(ptr->next[i]); } btree :: btree() { root = NULL; } node* btree :: findLeaf(int key,int &level) { node *ptr = root; node *prevptr = NULL; level = 0; int i; while(ptr) { i = 0; level++; while(i < ptr -> size-1 && key > ptr -> a[i]) i++;
File Structures
111
parent->a[i] = newkey; parent->next[i] = child; } } void btree :: insertIntoNode(node *n,int key,node *address) { int i; if( n == NULL) return; for(i = 0; i < n->size; i++) if(n->a[i] == key) return; i = n->size-1; while(i >= 0 && n -> a[i] > key) { n->a[i+1] = n->a[i]; n->next[i+1] = n->next[i]; i--; } i++; n->a[i] = key; n->next[i] = address; n->size++; if( i == n->size-1) updateKey(n->parent,n,key); } void btree :: promote(node *n,int key,node *address) { if( n == NULL) return; if(n -> size < 4) { insertIntoNode(n,key,address); return; } if( n == root) { root = new node; n->parent = root; } node *newptr = split(n); node *t; if(key < n->a[0]) t = newptr; else t = n;
void btree :: insert(int key) { if( root == NULL) { root = new node; root->a[root->size] = key; root->size++; return; } int level; node *leaf = findLeaf(key,level); int i; for(i = 0; i < leaf->size; i++) if(leaf -> a[i] == key) { cout<<"The Key to be inserted already exists"<<endl; return; } promote(leaf,key,NULL); cout<<"---------------\n"; traverse(root); cout<<"----------------\n"; } void btree :: search(int key) { if(root == NULL) { cout<<"The tree Does not exist"<<endl; return; } int level; node *leaf = findLeaf(key,level); int flag = 0; for(int i = 0; i < leaf ->size; i++) if(leaf->a[i] == key) { flag = 1; cout<<"The Key "<<key<<" Exists in the B-Tree at the level"<<level<<endl; }
File Structures
113
if(!flag) cout<<"The Key Searched for was not found"<<endl; } int main() { btree b; int choice = 1,key; while(choice <=2) { cout<<"1.Insert a Key\n"; cout<<"2.Search a key\n"; cout<<"3.Exit\n"; cout<<\n\n Enter ur choice :; cin>>choice; switch(choice) { case 1: cout<<"Enter The Key to be inserted in B-Tree\n"; cin>>key; b.insert(key); break; case 2: cout<<"Enter The key to be searched\n"; cin>>key; b.search(key); break; } } return 0; } Output : 1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1 Enter The Key to be inserted in B-Tree 100 1.Insert a Key 2.Search a key 3.Exit Enter ur choice :1
File Structures
115
#include<stdlib.h> #include<string.h> class node { public: int a[4]; node * next[4]; node * parent; int size; node(); }; class linkleaf { public: node * data; linkleaf *next; linkleaf(); }; linkleaf :: linkleaf() { next = NULL; } node :: node() { for(int i = 0; i < 4; i++) next[i] = NULL; parent = NULL; size = 0; } class btree { node * root; linkleaf *head; int flag; public: node* findLeaf(int key,int &level); void updateKey(node *p,node *c,int newKey); void search(int key); void insert(int key); void insertIntoNode(node *n,int key,node *address); void promote(node *n,int key,node *address); node* split(node *n); void traverse(node *ptr);
File Structures
117
void btree :: traverse(node *ptr) { if(ptr == NULL) return; for(int i = 0; i < ptr->size; i++) cout<<ptr->a[i]<<" "; cout<<endl; for(int j = 0; j < ptr->size; j++) traverse(ptr->next[j]); } btree :: btree() { root = NULL; head = NULL; } node* btree :: findLeaf(int key,int &level) { node *ptr = root; node *prevptr = NULL; level = 0; int i; while(ptr) { i = 0; level++; while(i < ptr -> size-1 && key > ptr -> a[i]) i++; prevptr = ptr; ptr = ptr -> next[i]; } return prevptr; } node* btree :: split(node *n) { int midpoint = (n -> size+1)/2; int newsize = n->size - midpoint; node *newptr = new node; node *child; newptr->parent = n -> parent; int i; for(i = 0; i < midpoint; i++) { newptr->a[i] = n->a[i]; newptr ->next[i] = n->next[i]; n->a[i] = n->a[i+midpoint];
File Structures
119
i--; } i++; n->a[i] = key; n->next[i] = address; n->size++; if( i == n->size-1) updateKey(n->parent,n,key); } void btree :: promote(node *n,int key,node *address) { if( n == NULL) return; if(n -> size < 4) { insertIntoNode(n,key,address); return; } if( n == root) { root = new node; n->parent = root; } node *newptr = split(n); node *t; if(key < n->a[0]) t = newptr; else t = n; insertIntoNode(t,key,address); if(!flag) { connectLeaf(n,newptr);flag = 1;} promote(n->parent,n->a[n->size-1],n); promote(newptr->parent,newptr->a[newptr->size-1],newptr); } void btree :: insert(int key) { flag = 0; if( root == NULL) { root = new node; root->a[root->size] = key; root->size++; head = new linkleaf;
at
the
File Structures
121
cout<<"3.Traverse Leaf\n"; cout<<"4.Exit\n"; cout<<\n enter ur choice :; cin>>choice; switch(choice) { case 1: cout<<"Enter The Key to be inserted in B-Tree\n"; cin>>key; b.insert(key); break; case 2: cout<<"Enter The key to be searched\n"; cin>>key; b.search(key); break; case 3: b.traverseleaf(); break; } } return 0; } Output : 1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 100 1.Insert a Key 2.Search a key 3.Traverse Leaf 4.Exit enter ur choice : 1 Enter The Key to be inserted in B-Tree 50 -------50 100 --------
File Structures
123
#include<iostream.h> //Record specification class node { public: char name[15],usn[15]; node *link; }; node *h[29]; keys - 29 //Array of record pointers equal to size of hash
void insert() { char name[15], usn[15], buffer[50]; fstream out; out.open("student.txt",ios::app); //opening student.txt in append mode if(!out) { cout<<"\nUnable to open the file in append mode"; getch(); return; } cout<<"\nEnter the name = "; cin>>name; cout<<"\nEnter the usn = "; cin>>usn; strcpy(buffer,name); //Packing the record onto the file using '|' as a delimiter strcat(buffer,"|"); strcat(buffer,usn); strcat(buffer,"\n"); // \n delimiter for the record out<<buffer; // appending the packed record onto the file out.close(); } //Insert record into the hash table void hash_insert(char name1[], char usn1[], int hash_key) { node *p,*prev,*curr; p = new node; //dynamically allocate space using 'new' strcpy(p->name,name1); strcpy(p->usn,usn1); p->link=NULL;
File Structures
125
count=count%29; curr=h[count]; if(curr == NULL) { cout<<"\nRecord not found"; getch(); return; } do { if(strcmp(curr->usn,usn)==0) //When the record is found, retrieve { cout<<"\nRecord found : "<<curr->usn<<" "<<curr->name; getch(); return; } else { curr=curr->link; } }while(curr!=NULL); //Search till end of list if(curr==NULL) //End of list reached with no record found { cout<<"\nRecord not found"; getch(); return; } } void main() { int choice; clrscr(); fstream out; out.open("student.txt",ios::out); if(!out) { cout<<"\nUnable to open the file in out mode"; getch(); exit(0); } for(;;) { cout<<"\n1:insert\n2: retrive\n3:exit\nEnter the choice - ";
File Structures
127
20
Record found : rahul 20 12. Write a C++ program to reclaim the free space resulting from the deletion of records using linked lists. #include<stdio.h> #include<conio.h> #include<stdlib.h> #include<string.h> #include<iostream.h> #include<fstream.h> #include<new.h> class node { public: char name[20]; char usn[20]; node *link; }; node *first=NULL; void writeFile() { node *p; char buffer[100]; fstream out; out.open("student.txt", ios::out); if(!out) { cout<<"\n Unable to open the file student.txt in out mode"; getch(); exit(0); } p=first; while(p!=NULL) { strcpy(buffer,p->name); strcat(buffer,"|"); strcat(buffer,p->usn); strcat(buffer,"\n"); out<<buffer; p=p->link; } }
File Structures
129
{ printf("\nThe list is empty. Deletion is not possible"); return; } cout<<"\nEnter the usn to be deleted = "; cin>>usn; if(strcmp(first->usn,usn)==0) { cout<<"\n Record deleted"; del = first; delete del; first=first->link; writeFile(); return; } prev=NULL; curr=first; while( ( strcmp(curr->usn,usn) != 0 ) && curr!=NULL) { prev=curr; curr=curr->link; } if(curr == NULL) { cout<<"\nThe student with usn "<<usn<<" is not present"; return; } prev->link = curr->link; writeFile(); display(); //display the records to the screen } void main() { int ch; clrscr(); for(;;) { cout<<"\n 1-Insert_rear \n 2-Delete_id \n 3-Exit \n Enter choice :"; cin>>ch; switch(ch) { case 1: Insert(); break; case 2: Delete(); break; case 3: exit(0);
131
6.
7.
8. 9.
4. 5. 6.
Introduction to opengl :
GLUT stands for OpenGL Utility Toolkit. Mark J. Kilgard, to enable the construction of OpenGL applications that are truly window system independent, conceived the GLUT library. Thanks to GLUT, we can write applications without having to learn about X windows or Microsoft's own window system. Kilgard implemented the version for X windows, and later Nate Robins ported it to Microsoft Windows. The main function will perform the required initializations and start the event processing loop. All the functions in GLUT have the prefix glut, and those which perform some kind of initialization have the prefix glutInit. The first thing you must do is call the function glutInit. void glutInit(int *argc, char **argv); Parameters : argc - A pointer to the unmodified argc variable from the main function. argv - A pointer to the unmodified argv variable from the main function. After initializing GLUT itself, we're going to define our window. First we establish the window's position, i.e. its top left corner. In order to do this we use the function glutInitWindowPosition. glutInitWindowPosition(int x, int y); Parameters : x - the number of pixels from the left of the screen. -1 is the default value, meaning it is up to the window manager to decide where the window will appear. If not using the default values then you should pick a positive value, preferably one that will fit in your screen. y - the number of pixels from the top of the screen. Note that these parameters are only a suggestion to the window manager. The window returned may be in a different position, although if you choose them wisely you'll usually get what you want. Next we'll choose the window size. In order to do this we use the function glutInitWindowSize. void glutInitWindowSize(int width, int height); Parameters : width - The width of the window height - the height of the window
133
Again the values for width and height are only a suggestion, so avoid choosing negative values. Then you should define the display mode using the function glutInitDisplayMode. void glutInitDisplayMode(unsigned int mode) Parameters : mode - specifies the display mode The mode parameter is a Boolean combination (OR bit wise) of the possible predefined values in the GLUT library. You use mode to specify the color mode, and the number and type of buffers. The predefined constants to specify the color model are : GLUT_RGBA or GLUT_RGB - selects a RGBA window. This is the default color mode. GLUT_INDEX - selects a color index mode. The display mode also allows you to select either a single or double buffer window. The predefined constants for this are: GLUT_SINGLE - single buffer window GLUT_DOUBLE - double buffer window, required to have smooth animation. There is more, you can specify if you want a window with a particular set of buffers. The most common are : 1. GLUT_ACCUM - The accumulation buffer 2. GLUT_STENCIL - The stencil buffer 3. GLUT_DEPTH - The depth buffer So, suppose you want a RGB window, with single buffering, and a depth buffer. All you have to do is to OR all the respective constants in order to create the required display mode. ... glutInitDisplayMode(GLUT_RGB | GLUT_SINGLE | GLUT DEPTH); ... After all the above steps, the window can be created with glutCreateWindow. int glutCreateWindow(char *title); Parameters : title - sets the window title The return value of glutCreateWindow is the window identifier. So now here is a little bit of code to perform all the initializations : #include <GL/glut.h> void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("3D Tech- GLUT Tutorial"); }
135
#include <GL/glut.h> void renderScene(void) { glClear(GL_COLOR_BUFFER_BIT); glBegin(GL_TRIANGLES); glVertex3f(-0.5,-0.5,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.0,0.5,0.0); glEnd(); glFlush(); } void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320); glutCreateWindow("3D Tech- GLUT Tutorial"); glutDisplayFunc(renderScene); glutMainLoop(); } GLUT provides a way to define which function should be called when the window is resized, i.e. to register a callback for recomputing the perspective. Furthermore, this function will also be called when the window is initially created so that even if you're initial window is not square things will look OK. GLUT achieves this using the function glutReshapeFunc. void glutReshapeFunc(void (*func)(int width, int height)); Parameters : func - The name of the function that will be responsible for setting the correct perspective when the window changes size. So the first thing that we must do is to go back to the main function we defined in the previous section and add a call to glutReshapeFunc. Lets call our own function to take care of window resizes changeSize. The code for the main function with the call to glutReshapeFunc added in is: void main(int argc, char **argv) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DEPTH | GLUT_SINGLE | GLUT_RGBA); glutInitWindowPosition(100,100); glutInitWindowSize(320,320);
137
with different values to see what you come up with, the first two parameters are the top right corner, and the last two are the bottom left. Note that these coordinates are relative to the client area of the window, not the screen. If you do try with different values then don't forget that the ratio computed above should also use the new width and height values. The gluPerspective function is part of another library for OpenGL, the OpenGL Utility Library, or GLU. GLU is a standard component of the implementation of OpenGL. The gluPerspective function establishes the perspective parameters. The first one defines the field of view angle in the yz plane, the ratio defines the relation between the width and height of the viewport. The last two parameters define the near and far clipping planes. Anything closer than the near value, or further away than the far value will be clipped away from the scene. Beware with these settings or you may end up not seeing anything at all. Finally, setting the camera. First we set the GL_MODELVIEW as our current matrix. the modelview matrix is where we'll define both the camera settings and the modeling transformations. Before setting the camera it is always healthy to load the identity matrix. this avoids previous transformations to affect the camera settings. The gluLookAt function provides an easy and intuitive way to set the camera position and orientation. Basically it has three groups of parameters, each one is composed of 3 floating point values. The first three values indicate the camera position. The second set of values defines the point we're looking at. Actually it can be any point in our line of sight.The last group indicates the up vector, this is usually set to (0.0, 1.0, 0.0), meaning that the camera's is not tilted. If you want to tilt the camera just play with these values. For example, to see everything upside down try (0.0, -1.0, 0.0). OK, so far so good. We have an OpenGL window with a white triangle. Nothing very exciting, but hey, its a start. Now to complete this part of the GLUT tutorial lets have that triangle spinning. Lets go back to the main function and add some extra stuff. First lets tell GLUT that we want a double buffer. Double buffering allows for smooth animation by keeping the drawing in a back buffer and swapping the back with the front buffer (the visible one) when the rendering is complete. Using double buffering prevents flickering. ... glutInitDisplayMode(GLUT_DEPTH | GLUT_DOUBLE | GLUT_RGBA); ... The second thing we must do is to tell GLUT that when the application is idle the render function should be called. This causes GLUT to keep calling our rendering function therefore enabling animation. GLUT provides a function, glutIdleFunc, that lets you register a callback function to be called when the application is idle. void glutIdleFunc(void (*func)(void)); Parameters : func - The name of the function that will be called whenever the application is idle. In our case, when the application is idle we want to call the previously defined
139
// Perform a rotation around the y axis (0,1,0) // by the amount of degrees defined in the variable angle glRotatef(angle,0.0,1.0,0.0); glBegin(GL_TRIANGLES); glVertex3f(-0.5,-0.5,0.0); glVertex3f(0.5,0.0,0.0); glVertex3f(0.0,0.5,0.0); glEnd(); // discard the modelling transformations // after this the matrix will have only the camera settings. glPopMatrix(); // swapping the buffers causes the rendering above to be // shown glutSwapBuffers(); // finally increase the angle for the next frame angle++; } The glutSwapBuffers function cause the front and back buffers to switch thereby showing what was previously drawn in the back buffer. The syntax is as follows: void glutSwapBuffers(); 1. Program to recursively subdivides a tetrahedron to from 3D Sierpinski gasket. The number of recursive steps is to be specified by the user.
#include <stdlib.h> #include <stdio.h> #include <GL/glut.h> typedef float point[3]; /* initial tetrahedron */ point v[]={{0.0, 0.0, 1.0}, {0.0, 0.942809, -0.33333},{-0.816497, -0.471405, -0.333333}, {0.816497, -0.471405, -0.333333}}; static GLfloat theta[] = {0.0,0.0,0.0}; int n; void triangle( point a, point b, point c)
v1[j]=(a[j]+b[j])/2; v2[j]=(a[j]+c[j])/2; v3[j]=(b[j]+c[j])/2; v1, v2, m-1); v2, v3, m-1); v3, v1, m-1); /* draw triangle at end of recursion
141
void myReshape(int w, int h) { glViewport(0, 0, w, h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if (w <= h) glOrtho(-2.0, 2.0, -2.0 * (GLfloat) h / (GLfloat) w, 2.0 * (GLfloat) h / (GLfloat) w, -10.0, 10.0); else glOrtho(-2.0 * (GLfloat) w / (GLfloat) h, 2.0 * (GLfloat) w / (GLfloat) h, -2.0, 2.0, -10.0, 10.0); glMatrixMode(GL_MODELVIEW); glutPostRedisplay(); }
void main(int argc, char **argv) { printf(" No. of Divisions ? "); scanf("%d",&n); glutInit(&argc, argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB | GLUT_DEPTH); glutInitWindowSize(500, 500); glutCreateWindow("3D Gasket"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glEnable(GL_DEPTH_TEST); glClearColor (0.0, 0.0, 0.0, 0.0); glutMainLoop(); }
143
2.
#include<stdio.h> #include<GL/glut.h> double xmin=50,ymin=50,xmax=100,ymax=100; double xvmin=200,yvmin=200,xvmax=300,yvmax=300; float X0,Y0,X1,Y1; int cliptest(double p,double q,double *t1,double *t2) { double t=q/p; if(p<0.0) { if(t>*t1) *t1=t; if(t>*t2) return(false); } else if(p>0.0) { if(t<*t2) *t2=t; if(t<*t2) return(false); } else if(p==0.0) { if(q<0.0) return(false); } return(true); } void LiangBarskyLineClipAndDraw(double x0,double x1,double y1) { double dx=x1-x0,dy=y1-y0,te=0.0,t1=1.0; glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); if(cliptest(-dx,x0-xmin,&te,&t1)) if(cliptest(dx,xmax-x0,&te,&t1)) if(cliptest(-dy,y0-ymin,&te,&t1)) if(cliptest(dy,ymax-y0,&te,&t1)) y0,double
145
void myinit() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } void main(int argc,char **argv) { printf("Enter end points : "); scanf("%f%f%f%f",&X0,&Y0,&X1,&Y1); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Liang Barsky Line Clipping Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :
#include<stdlib.h> #include<GL/glut.h> GLfloat vertices[]={-1.0,-1.0,-1.0, 1.0,-1.0,-1.0, 1.0,1.0,-1.0, -1.0,1.0,-1.0, -1.0,-1.0,1.0, 1.0,-1.0,1.0, 1.0,1.0,1.0, -1.0,1.0,1.0}; GLfloatnormals[]={-1.0,-1.0,-1.0,1.0,-1.0,-1.0,1.0,1.0,-1.0, -1.0,1.0,-1.0,-1.0,-1.0,1.0,1.0,-1.0,1.0,1.0,1.0,1.0, -1.0,1.0,1.0}; GLfloat colors[]={0.0,0.0,0.0,1.0,0.0,0.0,1.0,1.0,0.0,0.0,1.0,0.0,0.0,0.0,1.0,1.0,0.0,1.0,1.0, 1.0,1.0,0.0,1.0,1.0}; GLubyteCubeIndices[]={0,3,2,1,2,3,7,6,0,4,7,3,1,2,6,5,4,5,6,7, 0,1,5,4}; static GLfloat theta[]={0.0,0.0,0.0}; static GLint axis=2; void display(void) { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); glRotatef(theta[0],1.0,0.0,0.0); glRotatef(theta[1],0.0,1.0,0.0); glRotatef(theta[2],0.0,0.0,1.0); glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE,CubeIndices); glBegin(GL_LINES); glVertex3f(0.0,0.0,0.0); glVertex3f(1.0,1.0,1.0); glEnd(); glFlush(); glutSwapBuffers(); } void spincube() { theta[axis]-=1.0; if(theta[axis]>360.0)theta[axis]-=360.0; glutPostRedisplay(); }
147
void mouse(int btn,int state,int x,int y) { if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) axis=0; if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) axis=1; if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) axis=2; } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h) { g l O r t h o ( - 2 . 0 , 2 . 0 , - 2 . 0 * ( G L f l o a t ) h / (GLfloat)w,2.0*(GLfloat)h/(GLfloat)w,-10.0,10.0); } else { glOrtho(-2.0*(GLfloat)w/(GLfloat)h,2.0*(GLfloat)w/ (GLfloat)h,-2.0,2.0,-10.0,10.0); } glMatrixMode(GL_MODELVIEW); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_DOUBLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(500,500); glutCreateWindow("Rotating Cube"); glutReshapeFunc(myReshape); glutDisplayFunc(display); glutIdleFunc(spincube); glutMouseFunc(mouse); glEnable(GL_DEPTH_TEST); glEnableClientState(GL_COLOR_ARRAY); glEnableClientState(GL_NORMAL_ARRAY); glEnableClientState(GL_VERTEX_ARRAY); glVertexPointer(3,GL_FLOAT,0,vertices); glColorPointer(3,GL_FLOAT,0,colors); glNormalPointer(GL_FLOAT,0,normals); glClearColor(0.0,0.0,0.0,0.0); glColor3f(1.0,1.0,1.0); glutMainLoop(); }
4.
Program to create a house like figure and rotate it about a given fixed point using OpenGL functions.
#include<stdio.h> #include<math.H> #include<GL/glut.h> Glfloat house[3][9]={{150.0,150.0,225.0,300.0,300.0,200.0, 200.0,250.0,250.0},{150.0,250.0,300.0,250.0,150.0,150.0,200.0,200.0,150.0}, {1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0}}; GLfloat rot_mat[3][3]={{0},{0},{0}}; GLfloat result[3][9]={{0},{0},{0}}; GLfloat h=150.0; GLfloat k=150.0; GLfloat theta; void multiply() { int i,j,l; for(i=0;i<3;i++)
149
for(j=0;j<9;j++) { result[i][j]=0; for(l=0;l<3;l++) result[i][j]=result[i][j]+rot_mat[i][l]*house[l][j]; } } void rotate() { GLfloat m,n; m=-h*(cos(theta)-1)+k*(sin(theta)); n=-k*(cos(theta)-1)-h*(sin(theta)); rot_mat[0][0]=cos(theta); rot_mat[0][1]=-sin(theta); rot_mat[0][2]=m; rot_mat[1][0]=sin(theta); rot_mat[1][1]=cos(theta); rot_mat[1][2]=n; rot_mat[2][0]=0; rot_mat[2][1]=0; rot_mat[2][2]=1; multiply(); }
void drawhouse() { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][0],house[1][0]); glVertex2f(house[0][1],house[1][1]); glVertex2f(house[0][3],house[1][3]); glVertex2f(house[0][4],house[1][4]); glEnd(); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][5],house[1][5]); glVertex2f(house[0][6],house[1][6]); glVertex2f(house[0][7],house[1][7]); glVertex2f(house[0][8],house[1][8]); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(house[0][1],house[1][1]);
void drawrotatedhouse() { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][0],result[1][0]); glVertex2f(result[0][1],result[1][1]); glVertex2f(result[0][3],result[1][3]); glVertex2f(result[0][4],result[1][4]); glEnd(); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][5],result[1][5]); glVertex2f(result[0][6],result[1][6]); glVertex2f(result[0][7],result[1][7]); glVertex2f(result[0][8],result[1][8]); glEnd(); glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(result[0][1],result[1][1]); glVertex2f(result[0][2],result[1][2]); glVertex2f(result[0][3],result[1][3]); glEnd(); }
151
void main(int argc,char **argv) { printf("Enter the rotation angle\n"); scanf("%f",&theta); theta=theta*(3.14/180); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("house rotation"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :
#include<stdio.h> #include<GL/glut.h> #define outcode int double xmin=50,ymin=50,xmax=100,ymax=100; double xvmin=200,yvmin=200,xvmax=300,yvmax=300; float X0,Y0,X1,Y1; const int RIGHT=2; const int LEFT=1; const int TOP=8; const int BOTTOM=4; outcode ComputeOutCode(double x,double y); void CohenSutherlandLineClipAndDraw(double x0,double y0,double x1,double y1) { outcode outcode0,outcode1,outcodeOut; bool accept=false,done=false; outcode0=ComputeOutCode(x0,y0); outcode1=ComputeOutCode(x1,y1); do { if(!(outcode0 | outcode1)) { accept=true; done=true; } else if(outcode0 & outcode1) done=true; else { double x,y,m; m=(y1-y0)/(x1-x0); outcodeOut=outcode0?outcode0:outcode1; if(outcodeOut & TOP) { x=x0+(ymax-y0)/m; y=ymax; } else if(outcodeOut & BOTTOM)
153
{ x=x0+(ymin-y0)/m; y=ymin; } else if(outcodeOut & RIGHT) { y=y0+(xmax-x0)*m; x=xmax; } else { y=y0+(xmin-x0)*m; x=xmin; } if(outcodeOut == outcode0) { x0=x; y0=y; outcode0=ComputeOutCode(x0,y0); } else { x1=x; y1=y; outcode1=ComputeOutCode(x1,y1); } } }while(!done); glColor3f(1.0,0.0,0.0); glBegin(GL_LINE_LOOP); glVertex2f(xvmin,yvmin); glVertex2f(xvmax,yvmin); glVertex2f(xvmax,yvmax); glVertex2f(xvmin,yvmax); glEnd(); printf("\n%f %f : %f %f",x0,y0,x1,y1); if(accept) { double sx=(xvmax-xvmin)/(xmax-xmin); double sy=(yvmax-yvmin)/(ymax-ymin); double vx0=xvmin+(x0-xmin)*sx; double vy0=yvmin+(y0-ymin)*sy; double vx1=xvmin+(x1-xmin)*sx; double vy1=yvmin+(y1-ymin)*sy; glColor3f(0.0,0.0,1.0); glBegin(GL_LINES);
155
void main(int argc,char** argv) { printf("Enter end points : "); scanf("%f%f%f%f",&X0,&Y0,&X1,&Y1); glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE | GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Cohen Sutherland Line Clipping Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :
6.
Program to create a cylinder and a parallelepiped by extruding a circle and quadrilateral respectively. Allow the user to specify the circle and the quadrilateral.
157
void parallelopiped(int x1,int x2,int y1,int y2) { glColor3f(0.0,0.0,1.0); glPointSize(2.0); glBegin(GL_LINE_LOOP); glVertex2i(x1,y1); glVertex2i(x1,y2); glVertex2i(x2,y2); glVertex2i(x2,y1); glEnd(); } void parallelopiped_draw() { int x1=200,x2=300,y1=100,y2=175; GLint i,n=40; for(i=0;i<n;i+=2) { parallelopiped(x1+i,x2+i,y1+i,y2+i); } } void myinit(void) { glMatrixMode(GL_PROJECTION); gluOrtho2D(0.0,499.0,0.0,499.0); } void display(void) { glColor3f(1.0,0.0,0.0); glClear(GL_COLOR_BUFFER_BIT); glClearColor(1.0,1.0,1.0,1.0); glPointSize(2.0); cylinder_draw(); parallelopiped_draw(); glFlush(); } void main(int argc,char** argv) { glutInit(&argc,argv); glutInitWindowPosition(0,0); glutInitWindowSize(500,500); glutCreateWindow("cylinder and parallelopiped display by xtruding circle and quadrilateral");
7.
Program, using OpenGL functions, to draw a simple shaded scene consisting of a tea pot on a table. Define suitably the position and properties of the light source along with the properties of the properties of the surfaces of the solid object used in the scene.
#include<stdio.h> #include<GL/glut.h> void wall(double thickness) { //draw thin wall with top=xz-plan,corner at orgin glPushMatrix(); glTranslated(0.5,0.5*thickness,0.5); glScaled(1.0,thickness,1.0); glutSolidCube(1.0); glPopMatrix(); }
159
//draw one table leg void tableLeg(double thick,double len) { glPushMatrix(); glTranslated(0,len/2,0); glScaled(thick,len,thick); glutSolidCube(1.0); glPopMatrix(); } void table(double topWid,double topThick,double legThick,double legLen) { //draw the table -a top and four legs //draw the top first glPushMatrix(); glTranslated(0,legLen,0); glScaled(topWid,topThick,topWid); glutSolidCube(1.0); glPopMatrix(); double dist=0.95*topWid/2.0 - legThick/2.0; glPushMatrix(); glTranslated(dist,0,dist); tableLeg(legThick,legLen); glTranslated(0.0,0.0,-2*dist); tableLeg(legThick,legLen); glTranslated(-2*dist,0,2*dist); tableLeg(legThick,legLen); glTranslated(0,0,-2*dist); tableLeg(legThick,legLen); glPopMatrix(); } void displaySolid(void) { //set properties of the surface material GLfloat mat_ambient[]={1.0f,0.0f,0.0f,0.0f};//gray GLfloat mat_diffuse[]={0.5f,0.5f,0.5f,1.0f}; GLfloat mat_specular[]={1.0f,1.0f,1.0f,1.0f}; GLfloat mat_shininess[]={50.0f}; glMaterialfv(GL_FRONT,GL_AMBIENT,mat_ambient); glMaterialfv(GL_FRONT,GL_DIFFUSE,mat_diffuse); glMaterialfv(GL_FRONT,GL_SPECULAR,mat_specular); glMaterialfv(GL_FRONT,GL_SHININESS,mat_shininess); //set the light source properties GLfloat lightIntensity[]={0.9f,0.9f,0.9f,1.0f};
161
glPopMatrix(); glFlush(); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB|GLUT_DEPTH); glutInitWindowSize(640,480); glutInitWindowPosition(100,100); glutCreateWindow("SIMPLE SHADED SCENE CONSISTING OF A TEA POT ON A TABLE"); glutDisplayFunc(displaySolid); glEnable(GL_LIGHTING); glEnable(GL_LIGHT0); glShadeModel(GL_SMOOTH); glEnable(GL_DEPTH_TEST); glEnable(GL_NORMALIZE); glClearColor(0.1,0.1,0.1,0.0); glViewport(0,0,640,480); glutMainLoop(); } Output :
#include<stdio.h> #include<stdlib.h> #include<GL/glut.h> GLfloat vertices[][3]={{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0},{-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},{1.0,-1.0,1.0}, {1.0,1.0,1.0},{-1.0,1.0,1.0}}; GLfloat normals[][3]={{-1.0,-1.0,-1.0},{1.0,-1.0,-1.0}, {1.0,1.0,-1.0},{-1.0,1.0,-1.0}, {-1.0,-1.0,1.0},{1.0,-1.0,1.0}, {1.0,1.0,1.0},{-1.0,1.0,1.0}}; GLfloat colors[][3]={{0.0,0.0,0.0},{1.0,0.0,0.0}, {1.0,1.0,0.0},{0.0,1.0,0.0}, {0.0,0.0,1.0},{1.0,0.0,1.0}, {1.0,1.0,1.0},{0.0,1.0,1.0}}; void polygon(int a,int b,int c,int d) { glBegin(GL_POLYGON); glColor3fv(colors[a]); glNormal3fv(normals[a]); glVertex3fv(vertices[a]); glColor3fv(colors[b]); glNormal3fv(normals[b]); glVertex3fv(vertices[b]); glColor3fv(colors[c]); glNormal3fv(normals[c]); glVertex3fv(vertices[c]); glColor3fv(colors[d]); glNormal3fv(normals[d]); glVertex3fv(vertices[d]); glEnd(); } void colorcube() { polygon(0,3,2,1); polygon(2,3,7,6); polygon(0,4,7,3); polygon(1,2,6,5); polygon(4,5,6,7); polygon(0,1,5,4); }
163
static GLfloat theta[]={0.0,0.0,0.0}; static GLint axis=2; static GLdouble viewer[]={0.0,0.0,5.0}; void display() { glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); glLoadIdentity(); gluLookAt(viewer[0],viewer[1],viewer[2],0.0,0.0,0.0,0.0,1.0,0.0); glRotatef(theta[0],1.0,0.0,0.0); glRotatef(theta[1],0.0,1.0,0.0); glRotatef(theta[2],0.0,0.0,1.0); colorcube(); glFlush(); glutSwapBuffers(); } void mouse(int btn,int state,int x,int y) { if(btn==GLUT_LEFT_BUTTON && state==GLUT_DOWN) axis=0; if(btn==GLUT_MIDDLE_BUTTON && state==GLUT_DOWN) axis=1; if(btn==GLUT_RIGHT_BUTTON && state==GLUT_DOWN) axis=2; theta[axis]+=2.0; if(theta[axis]>360.0)theta[axis]-=360.0; display(); } void keys(unsigned char key,int x,int y) { if(key=='x') viewer[0]-=1.0; if(key=='X') viewer[0]+=1.0; if(key=='y') viewer[1]-=1.0; if(key=='Y') viewer[1]+=1.0; if(key=='z') viewer[2]-=1.0; if(key=='Z') viewer[2]+=1.0; display(); } void myReshape(int w,int h) { glViewport(0,0,w,h); glMatrixMode(GL_PROJECTION); glLoadIdentity(); if(w<=h) { glFrustum(-2.0,2.0,-2.0*(GLfloat)h/(GLfloat)w,2.0*
165
9.
Program to fill any given polygon using scan-line area filling algorithm. (Use appropriate data structures.)
#include <stdlib.h> #include <stdio.h> #include <GL/glut.h> float x1,x2,x3,x4,y1,y2,y3,y4; void edgedetect(float x1,float y1,float x2,float y2,int *le,int *re) { float mx,x,temp; int i; if((y2-y1)<0) { temp=y1;y1=y2;y2=temp; temp=x1;x1=x2;x2=temp; } if((y2-y1)!=0) mx=(x2-x1)/(y2-y1); else mx=x2-x1; x=x1; for(i=y1;i<=y2;i++) { if(x<(float)le[i]) le[i]=(int)x; if(x>(float)re[i]) re[i]=(int)x; x+=mx; } } void draw_pixel(int x,int y,int value) { glColor3f(0.7,0.5,0.8); glBegin(GL_POINTS); glVertex2i(x,y); glEnd(); } void scanfill(float x1,float y1,float x2,float y2,float x3,float y3,float x4,float y4) { int le[500],re[500];
167
glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(1.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); } void main(int argc, char** argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,500); glutInitWindowPosition(0,0); glutCreateWindow("Filling a Polygon using Algorithm"); glutDisplayFunc(display); myinit(); glutMainLoop(); } Output :
Scan-line
GLfloat x[maxx]={0.0},y[maxy]={0.0}; GLfloat x0=50,y0=50; int i,j; void init() { glClearColor(1.0,1.0,1.0,1.0); glColor3f(1.0,0.0,0.0); glPointSize(5.0); glMatrixMode(GL_PROJECTION); glLoadIdentity(); gluOrtho2D(0.0,499.0,0.0,499.0); glutPostRedisplay(); } void display(void) { glClear(GL_COLOR_BUFFER_BIT); glColor3f(0.0,0.0,1.0); for(i=0;i<maxx;i++) x[i]=x0+i*dx; for(j=0;j<maxy;j++) y[j]=y0+j*dy; glColor3f(0.0,1.0,0.0); for(i=0;i<maxx-1;i++) for(j=0;j<maxy-1;j++) { glColor3f(0.0,0.0,1.0); glBegin(GL_LINE_LOOP); glVertex2f(x[i],y[j]); glVertex2f(x[i],y[j+1]); glVertex2f(x[i+1],y[j+1]); glVertex2f(x[i+1],y[j]); glEnd(); glFlush(); }
169
glFlush(); } void main(int argc,char **argv) { glutInit(&argc,argv); glutInitDisplayMode(GLUT_SINGLE|GLUT_RGB); glutInitWindowSize(500,400); glutCreateWindow("rectangular mesh"); glutDisplayFunc(display); init(); glutMainLoop(); } Output :