2. Now we will look at a slightly more useful example:
#!/usr/local/bin/ulpc
int main(int argc,string *argv)
{
int i;
string file_contents;
if(argc<4)
{
perror("Usage: rsif <from> <to> <files>\n");
return 1;
}
for(i=3; i<argc; i++)
{
if(file_contents=read_bytes(argv[i]))
{
if(-1!=strstr(file_contents,argv[1]))
{
write("Processing "+argv[i]+".\n");
file_contents=replace(file_contents,argv[1],argv[2]);
if( mv(argv[i],argv[i]+"~") )
{
write_file(argv[i],file_contents);
}else{
write("Failed to create backup file.\n");
}
}
}
}
return 0;
}
This program is called 'rsif' and comes with the uLPC distribution.
What it does is that it takes two strings and a bunch of files and
replaces every occurance of the first string with the second one in
each of these files. As you might have guessed 'rsif' is short for
Replace String In File. Line by line, this is how the program works:
#!/usr/local/bin/ulpc
Make UNIX run ulpc to interpret this program. Interpret in this case
means to read the program, convert it to an internal representation and
then run the instructions in this internal representation. Note that uLPC
does not use the same low-level representation as for example C does,
instead it uses a simple and compact representation which are parsed by
a C program which actually implements the instructions in that
representation.
int main(int argc,string *argv)
{
Start the function main, it will return an int, and take the command line
arguments into the parameters argc and argv.
int i;
string file_contents;
Declare two temporary variables to use later. The first one 'i' is an
integer, and the second one 'file_contents' is a string.
if(argc<4)
{
perror("Usage: rsif <from> <to> <files>\n");
return 1;
}
If argc is lesser than four it means that the program received less than
three arguments. Since rsif needs at least three arguments we write how
to use rsif to stderr (Standard error channel) using the function perror
and then exit this function with the return value 1. Nothing after the
return will be executed if argc is lesser than 4.
for(i=3; i<argc; i++)
{
This statement starts a loop. (Loop means code repetition) It will first
set i to three, then execute everything within the brackets for as long as
i is lesser than argc. After each time the block between the brackets the
final statement, i++, will be executed. ++ is the increment operator, it
will increase i by one.
if(file_contents=read_bytes(argv[i]))
{
Look closely, the experssion in this if-statement is not a comparison, it
is in fact an assignment. Thus file will be assigned the value returned by
read_bytes. When an assignment is used as an expression it has the same
value as the left hand side of the assignment. (in this case the return
value from read_bytes) So what this does is: it reads the contents of the
file with the filename taken from argv[i] and assigns the contents to the
variable file. If there is no file with that name, zero will be returned
and then the block within the brackets will not be executed.
if(-1!=strstr(file_contents,argv[1]))
{
The function strstr searches for a string in in a string and returns the
first position where it is found and -1 if not. This if statement simply
checks if argv[1] (the 'from' string) is present in the file. If it is
not we won't need to do anything more about this file. The != operator
means 'not equal to'.
write("Processing "+argv[i]+".\n");
Write that we are processing this file to stdout. Stdout means
"Standard output channel" and is normally your screen unless you 'redirect'
it to somewhere else.
file_contents=replace(file_contents,argv[1],argv[2]);
Call the builtin function replace and replace all occurances of the 'from'
string with the 'to' string and assign the new result to the variable
'file_contents'.
if( mv(argv[i],argv[i]+"~") )
{
Try moving the file argv[i] to a backup file by adding a tilde to the end
of the name. Then choose action depending on weather it worked or not.
write_file(argv[i],file_contents);
If it worked we re-create the file argv[i] by writing the string
'file_contents' to it.
}else{
write("Failed to create backup file.\n");
If the mv didn't work we write a message stating so to stdout.
}
}
}
}
return 0;
}
Then we end all the blocks and return zero. A return value of zero from main
indicates success, 1 or more means failiure.