Lab: C & POSIX

Assigned:
Tuesday, Jan 23, 2018
Due:
Tuesday, Jan 30, 2018 by 10:30pm
Collaboration:
Work with your assigned partner for this lab. You can use online resources for your lab, provided they do not provide complete answers and you cite them in your code. If you do not know whether it is acceptable use a specific resource you can always ask me.

Introduction

Many of you haven’t used the C programming language since CSC 161, so there’s a good chance you’ll feel a little rusty. After working with more modern languages like Java or Ruby, it’s easy to forget what it was like to live in the anything-goes, hoist yourself by your bootstraps world of C programming. By modern standards, the functionality built into C and its standard library is minimal and a bit cumbersome. This lack of built-in functionality often means you’ll be implementing your own basic functionality, which gives you an incredible degree of control over what your program does and how it does it. At the risk of perpetuating a cliche, I’ll emphasize that with great power comes great responsibility.

You aren’t completely on your own with C, though. The C language has been closely matched with the POSIX standard library, which provides quite a few handy utilities that are certainly worth using. The purpose of this lab is to help you regain some familiarity with the C programming language and get a sense of what’s available for reuse rather than reimplementation.

Groups

Group information is no longer available for this course.

Getting Started

Yesterday, you used git entirely through GitHub’s web interface. From now on, we’ll mostly use git using the command line git tool. Go to the GitHub project for this lab, https://github.com/csc213/c-and-posix, create a fork, and add your lab partner as a collaborator just as you did yesterday.

On your fork (not the main repository page), click the “SSH” drop-down button just above the list of files and select “HTTPS”. Copy the contents of the text field to the right and open a terminal. In your terminal, use the cd and mkdir commands to create/move to a directory where you would like to make a local copy of the repository. Once you’re there, run the command git clone <paste the URL you copied here>. Git will ask for your GitHub username and password, work for a few seconds, and then you’ll have a local copy of the repository.

While this local copy is different from a fork (GitHub doesn’t have a page for it) it works in much the same way. You can make changes to your code locally and commit them to the repository. Once you are ready to publish these changes, you can push them up to GitHub. If your partner has made changes and pushed them, you can pull them from GitHub to your local copy. Finally, once you have committed and pushed all your changes, you can create a pull request from your GitHub fork to send me a list of changes you would like me to accept (or, in this case, to grade and not accept into my starter code).

Connecting to GitHub

While checking out your code with HTTPS works fine for now, you’ll be prompted for your username and password on every checkout. A better long-term approach would be to create a private key and associate it with your GitHub account by following the steps at documented at https://help.github.com/articles/connecting-to-github-with-ssh/.

Git Reference

The git project has good documentation ranging from basic git commands to very complex issues that come up in large projects. There is also a useful guide for GitHub’s workflow, which extends the basic functionality of git with some good practices and a handy web interface. You’ve already seen this with yesterday’s mini lab, but there are plenty of details we skipped over.

There are many other git guides in GitHub’s bootcamp, which are of varying quality. If you find yourself really stuck using git, odds are I can help you figure it out; don’t spend more than a few minutes resolving a git-related issue before you ask for help.

Part A: Shuffling a Deck of Cards

The code you checked out should have three directories, one for each part of this lab, along with some Makefiles, a README, and a file called common.mk. Take a look at the contents of each Makefile, including the one in the top directory. This is a pattern that makes it easy to build multi-directory and multi-source file projects. You can ignore the “magic” in common.mk for now, but I’d be happy to tell you about it if you’re interested.

To build your code, type make in the partA directory (or at the top level to build everything). This will create an executable in each directory, along with an obj directory to hold the intermediate files used for compilation. Type make clean if you want to get rid of all the intermediate files; this is a common step before you commit things to git because you generally won’t want to commit generated files, only source code.

One key thing to remember about C is that types are more of a suggestion than a rule; chars are just numbers that, by convention, correspond to specific characters. There are quite a few nice built-in characters like the following suits of cards: ♥, ♦, ♣, and ♠. Use these characters to print out all of the cards in a deck (2–10, Jack, Queen, King, and Ace of each suit). You are welcome to print the cards in any format you like; one common format is K♥, 2♠, etc. Hint: Assign a number to each unique card so you can print it easily. You don’t need to use a lookup table here if you can come up with a nice formula to turn a number between 0 and 51 into a specific card.

Once you’ve changed at least one file, run the command git status in your copy of the repository. This will tell you what has changed, and if there are any unrecognized files. The command git add <filename> will move changes up into the “changes staged for commit” section, which means those changes will be committed to your local repository when you run the command git commit -m "informative commit message here". Instead of staging changes, you can just commit everything that has changed with the command git commit -a -m "informative commit message here" (the -a flag is the only difference).

Be sure to commit frequently, and periodically run git push to send your changes back up to GitHub. You’ll probably be asked to specify your name and email address before you do this the first time; just follow git’s directions and this should all work out.

Once you can print the entire deck, change your program so it will print a shuffled deck. Make sure your implementation gives a new shuffled order on every run! Use the rand function to generate random numbers. Use the command man 3 rand to read about it, or go to this web-based manpage viewer: linux.die.net.

Part B: Using a Timer

For this part, you will be writing a procedure called every that takes three arguments: the number of times to run a function, the number of milliseconds between calls to that function, and the function itself. For example, if I call every(10, 500, myfun), there should be ten calls to the function myfun each starting 500ms apart. You do not need to account for the time myfun takes to run. For example, if myfun takes 100ms, you would still wait 500ms between calls (so each call starts at a 600ms interval). You will likely need to use the nanosleep function for this part of the lab.

If you are looking for an additional challenge, implement a version of every that runs in the background. You’ll need to use timer_create and signal to do this. One nice perk of this approach is that you can have multiple “tasks” running with every at any given time.

Part C: Counting Words

Use the fgets function to read a string from user input (a file named stdin), and count the number of words in the input. For simplicity, a “word” is any non-empty sequence of characters bounded by whitespace (space, tab, or line break) or the beginning/end of the input. Use strtok, strsep, or a similar POSIX function to implement your word counting utility; solutions that do not use POSIX functions for at least some of the word counting process will not receive full credit!

Once you have it working, you should have your word counting utility print out the number of words using printf. You can test it with a command line invocation like this one:

$ echo "the quick brown fox jumps over the lazy dog" | ./mywc
9

There is no upper limit on the length of the input to your program. You can use fgets to read in some fixed-size chunk of input, count the words in that chunk, then read more input and continue counting. Be careful when combining word counts for fragments, as the fragment boundary may fall in the middle of a word.

Wrapping Up

Once you’re done, double check to make sure you’ve committed all your changes and pushed those commits to GitHub. Once everything is in your repository on GitHub, submit a pull request just like you did with the first mini-lab.