Programming Assignment 1
CS 30200 / ECE 46810
Operating Systems
Spring, 2022
This assignment makes use of the files contained in this zip file.
This assignment is due Wednesday, January 26.
This assignment uses several programming and operating systems concepts that are simple but may be new to you. In this assignment you will use printf's format strings, the command-line, command-line arguments, the standard I/O streams, piping, environment variables, and a configuration file.
In this assignment you will write a C filter program that formats a jumbled stream of input numbers into nicely organized columns. To determine the parameters for the output formatting your program will make use of command-line arguments, environment variables, and a configuration file. To test your program you will use the Windows command-line.
Write a C program called filter.c
that reads from standard input and writes to standard output. The input to your program will be a sequence of positive integers separated by random amounts of white space. The output of your program will be the input numbers grouped and formatted into columns.
Here is an example of a sequence of 91 input numbers.
7038 9643 8101 9718 4451 8252
3817 697 9206 92 1387 8195
6356 1011 347 8981 957 4635
6958 802 3976 1733 1678 7386
9675 9044 5409 8084 2129 9634
1091 1618 9533 6506 8909 5594
8 6148 7382 8137 1435 574
645 2264 1030 8819 2353 1620
6125 3259 7661 2993 2525 3500
8821 4424 1095 3845 354 6962
9715 7373 1428 798 63 1316 4003
7318 1399 4951 1403 8057 106
556 9513 14 2345 7163 7844
1984 2119 8698 4095 3657 2382
6020 2665 2822 9345 6 7504
Here are those 91 numbers grouped into groups of length 14, then formatted into 8 columns with each column being 7 characters wide (including the spaces), and with one blank line between each group of numbers.
7038 9643 8101 9718 4451 8252 3817 697
9206 92 1387 8195 6356 1011
347 8981 957 4635 6958 802 3976 1733
1678 7386 9675 9044 5409 8084
2129 9634 1091 1618 9533 6506 8909 5594
8 6148 7382 8137 1435 574
645 2264 1030 8819 2353 1620 6125 3259
7661 2993 2525 3500 8821 4424
1095 3845 354 6962 9715 7373 1428 798
63 1316 4003 7318 1399 4951
1403 8057 106 556 9513 14 2345 7163
7844 1984 2119 8698 4095 3657
2382 6020 2665 2822 9345 6 7504
The filter.c
program requires three parameters. One parameter determines how many input numbers get grouped together. Another parameter determines the number of output columns. And the third parameter determines how many characters wide each output column is (including space characters). The input numbers should be "right justified" in each output column, which means that all the numbers in a column will line up vertically at their ones place. Each group of numbers will be separated by a blank line.
The default number of output columns for filter.c
is six. If the configuration file filter.cfg
exits in the current directory, then the second integer value in that file overrides the default number of output columns. If there is an environment variable called CS302_COLUMNS
, then the value of that variable overrides the default number of columns and the number of columns set by the configuration file (if it exits). If there is a second command-line argument, then that command-line argument overrides the environment variable (if there is one), the configuration file (if it exits), and the default number of columns.
The integers in an output column should all line up at their ones place. The number of characters from the ones place of one column to the ones place of the next column is called the "width" of a column. The default width for the columns is five. Not all of the integers in a column will have the same number of digits. Each integer in a column will be padded with spaces on the left of the integer to fill up its column. You determine the width of a column by calling printf with an appropriate format string. If the file filter.cfg
exits in the current directory, then the first integer value in that file overrides the default column width. If there is an environment variable called CS302_WIDTH
, then the value of that variable overrides the default column width and the column width set by the configuration file (if it exits). If there is a command-line parameter, then the first command-line parameter overrides the environment variable (if there is one), the configuration file (if it exits), and the default value of the column width.
The input numbers should be combined into groups with the members of each group being formatted into the appropriate number of columns and with a blank line separating each group. In filter.c
the default length of a group should be 10. If the file filter.cfg
exits in the current directory, then the third integer value in that file overrides the default length for groups. If there is an environment variable called CS302_LENGTH
, then the value of that variable overrides the default length and the length set by the configuration file (if it exits). If there is a third command-line parameter, then that command-line parameter overrides the environment variable (if there is one), the configuration file (if it exits), and the default length for groups.
Your program should use the Standard C library function fopen() to open the configuration file filter.cfg
(if it exits). Your program should use the function fscanf() to read the three integer values from the configuration file. To keep things simple, you can assume that if the configuration file exits, then it must contain three positive integer values. The configuration file is a text file, so the "integers" in it are actually strings, but the fscanf() function will automatically convert them to int
values for you.
Your program should use the Standard C Library function getenv()
to see if there are environment variables named CS302_WIDTH
or CS302_COLUMNS
or CS302_LENGTH
. If any of these environment variables exists, then its string value should be converted to an integer value by using the Standard C Library function atoi()
("atoi" is an abbreviation of "ascii to integer").
Your program should get its command-line arguments by using the argc
and argv
parameters to your program's main()
function (see also Chapter 9 from this book or Chapter 18 from this book). Command-line arguments, like environment variables, are always strings. So you need to use atoi()
to convert a command-line argument into an int
value.
Your program should read the sequence of input numbers from standard input by using the Standard C Library function scanf()
(from the scan family of functions) and its associated formatting strings.
Your program should write formatted output numbers to standard output by using the Standard C Library function printf()
and its associated formatting strings. (Hint: You will need to make use of the *
character in your format strings in order to set the appropriate width.)
Formatted input and output is not as hard as it might seem by looking at the last few references. After a few examples, you quickly get the hang of it. Here is a nice printf summary for the Java version of printf, which is similar to the C version.
Here are some more examples. If the input stream to your program looks like this:
7038 9643 8101 9718 4451 8252
3817 697 9206 92 1387 8195
6356 1011 347 8981 957 4635
6958 802 3976 1733 1678 7386
9675 9044 5409 8084 2129 9634
1091 1618 9533 6506 8909 5594
8 6148 7382 8137 1435 574
645 2264 1030 8819 2353 1620
6125 3259 7661 2993 2525 3500
8821 4424 1095 3845 354 6962
9715 7373 1428 798 63 1316 4003
7318 1399 4951 1403 8057 106
556 9513 14 2345 7163 7844
1984 2119 8698 4095 3657 2382
6020 2665 2822 9345 6 7504
then the default way to format this is with six columns of width five and with ten numbers in each group (except for the last group for which there may not be enough input numbers).
7038 9643 8101 9718 4451 8252
3817 697 9206 92
1387 8195 6356 1011 347 8981
957 4635 6958 802
3976 1733 1678 7386 9675 9044
5409 8084 2129 9634
1091 1618 9533 6506 8909 5594
8 6148 7382 8137
1435 574 645 2264 1030 8819
2353 1620 6125 3259
7661 2993 2525 3500 8821 4424
1095 3845 354 6962
9715 7373 1428 798 63 1316
4003 7318 1399 4951
1403 8057 106 556 9513 14
2345 7163 7844 1984
2119 8698 4095 3657 2382 6020
2665 2822 9345 6
7504
On the other hand, if we use five columns of width ten and groups of length 16, then the same 91 input numbers should produce the following output.
7038 9643 8101 9718 4451
8252 3817 697 9206 92
1387 8195 6356 1011 347
8981
957 4635 6958 802 3976
1733 1678 7386 9675 9044
5409 8084 2129 9634 1091
1618
9533 6506 8909 5594 8
6148 7382 8137 1435 574
645 2264 1030 8819 2353
1620
6125 3259 7661 2993 2525
3500 8821 4424 1095 3845
354 6962 9715 7373 1428
798
63 1316 4003 7318 1399
4951 1403 8057 106 556
9513 14 2345 7163 7844
1984
2119 8698 4095 3657 2382
6020 2665 2822 9345 6
7504
In the zip file for this assignment you will find a program called source.c
that you can use to test your program. The program source.c
writes to standard output a stream of random numbers. The numbers are separated by random amounts of white space and there are a random number of random numbers on each line of output. You can test your filter.c
program by "piping" the standard output of source.exe
into the standard input of your filter.exe
. For example, the first output shown just above might have been created by a command like the following.
> source.exe | filter.exe
On the other hand, the second output above could have been produced by the following two shell commands.
> set CS302_LENGTH=16
> source.exe | filter.exe 10 5
or by the following single shell command.
> source.exe | filter.exe 10 5 16
The last two commands used a pipe (the character '|'
). Using a pipe in the last command is equivalent to the following two commands that use I/O redirection.
> source.exe > temp
> filter.exe 10 5 16 < temp
The first command "redirects" the standard output from source
into a temporary file called temp
and then the second command "redirects" the contents of temp
into the standard input of filter
. (How would you save the resulting output from the filter in a file called data.txt
?) The piped version of the command has the advantage of not needing a temporary file.
The source.c
program accepts three (optional) command-line arguments. The first command-line argument is an integer that determines how many lines of output source.exe
should produce. The second command-line argument is an integer that determines how many numbers are on each output line. The third command-line argument is an integer that determines the range of the random numbers (the default range is from 0 to 9,999). So, for example, the following command-line will produce 10 lines of output, with three numbers per line, and the random numbers are all from the range 0 to 499.
> source.exe 10 3 500
The following command-line pipes the randomly generated data directly into the filter.exe
process.
> source.exe 10 3 500 | filter.exe 4 10 20
The following command-line will save the randomly generated data in a file for possible use in testing your filter.exe
program.
> source.exe 10 3 500 > myData.txt
Without any command-line arguments, source.exe
will produce a random number of output lines and each output line will contain a random number of numbers from the range 0 to 9,999.
In the zip file for this assignment you will also find a Windows executable program called filter_demo.exe
(and a Linux/MacOS executable program called filter_demo
) that you can use to demo this assignment on a Windows (respectively Linux or MacOS) computer.
Also in the zip file there are files data.txt
, test_filter.cmd
, and test_results_correct.txt
that help you test your completed version of filter.c
. Once you have filter.c
written and compiled, you can double click on the file test_filter.cmd
which will run your filter.exe
program several times with the data from data.txt
as stdin
and gather all the results into the file test_results.txt
which you can then compare with test_results_correct.txt
. Your test_results.txt
should be exactly the same as test_results_correct.txt
.
Do not try to write filter.c
all at once! Write it in stages. Break the problem down into sub-problems and solve them one at a time. For example, here is an outline of how you might go about attacking this problem.
- First, get your filter to print all of the input numbers in a single column with a single blank line between groups of ten numbers.
- Second, create six columns of output (with the ones places lined up). Be sure to take into consideration that the last group need not have ten numbers and the last row need not have six columns.
- Third, have a command-line argument determine the number of columns.
- Fourth, have the environment variable determine the number of columns.
- Fifth, let a command-line argument or an environment variable determine the length of a group of numbers.
- Sixth, let a command-line argument or an environment variable determine the width of a column.
- Last, check for the configuration file (before checking for the environment variables and the command-line arguments) and, if it exits, have its values override the default values.
If you are new to C and are having trouble, here is another strategy. Write this program in Java and get it debugged. Then translate it from Java into C. Use either C for Java Programmers or C for Java Programmers: A Primer to help you translate from Java to C.
Make sure you test your program under a wide variety of conditions. With and without a configuration file, with and without environment variables, with and without command-line arguments.
When you want to set an environment variable from the command-line, be careful not to use a command like the following, with extra spaces around the =
.
> set CS302_COLUMNS = 7
This creates an environment variable called "CS302_COLUMNS "
(with a trailing space) and gives it the value " 7"
(with a leading space).
When you set an environment variable, it only exits in the command window where you created it. So, for example, you can't create an environment variable in one command prompt window and then run your program from an IDE or an editor or another command prompt window.
Here is a list of the C library functions that you should use (with multiple versions of the documentation for each one).
- printf,
printf,
printf
- scanf,
scanf,
scanf
- fscanf,
fscanf,
fscanf
- fopen,
fopen,
fopen
- getenv,
getenv,
getenv
- atoi,
atoi,
atoi
Turn in a zip file called CS302Hw1Surname.zip
(where Surname
is your last name) containing your version of filter.c
.
This assignment is due Wednesday, January 26.