CSCI 265: Fall 2017 Midterm Sample Solutions

Question Mark
1. Git, merge conflicts
[8 marks]
 
2. Bash, regular expressions
[8 marks]
 
3. Bash scripting
[8 marks]
 
4. Specifications
[8 marks]
 
5. Life cycle models
[8 marks]
 
6. Makefiles
[8 marks]
 
Exam Total

[40 marks]

 

Question 1: Git, merge conflicts coding [8]

The table below show the branch history and (using cat) the contents of files in a repository, ending with a merge attempt that results in a merge conflict. (The linux prompt is shown as > in the table.)

> mkdir Q1
> cd Q1
> git init-db

> vi readme 
> cat readme 
Here is the project readme, 
not very interesting, but it's a dull project. 
> git add . 
> git commit -m "preliminary project repo" 
[master (root-commit) b5025b0] preliminary project repo 
 2 files changed, 2 insertions(+) 
 create mode 100644 readme 
 create mode 100644 typescript 

> git branch expt 
> git checkout expt 
Switched to branch 'expt' 
> vi datafile 
> cat datafile 
Here is the data to be used 
in the expt branch. 
> git add . 
> git commit -m "added data file for testing" 
[expt 7193202] added data file for testing 
 1 file changed, 2 insertions(+) 
 create mode 100644 datafile 

> git checkout master 
Switched to branch 'master' 
> vi datafile 
> cat datafile 
Test data to be used in the master branch 
> git add . 
> git commit -m "set up test data in datafile" 
[master 2a3ba8f] set up test data in datafile 
 1 file changed, 1 insertion(+) 
 create mode 100644 datafile 

> git checkout expt 
Switched to branch 'expt' 
> git merge master 
Auto-merging datafile 
CONFLICT (add/add): Merge conflict in datafile 
Automatic merge failed; fix conflicts and then commit the result. 

First, if you were now to open the conflicted file, show what the contents of the file would look like.

Second, explain how you would resolve/complete the merge if you wanted the file to keep all the contents from both versions.

Sample Solution:
<<<<<<< HEAD 
Here is the data to be used 
in the expt branch. 
======= 
Test data to be used in the master branch 
>>>>>>> master 

To complete the merge, keeping both files' content,
simply remove the lines <<<, ===, and >>> then save.
The merge will complete, and you can add, and commit
as necessary.

Question 2: Bash, regular expressions [8]

Below we show a bash script followed by three separate attempts to run it.

For each of the attempts to run the script, show as precisely as possible, the output the script would produce and briefly explain the results.

#! /bin/bash

# HINT: \b matches a word boundary (like $ and ^ match line boundaries)
pat1='\b[0-9]?[a-z]+'
pat2='[0-9]*[aeiou]+\b'
pat3='123*[a-z]?'

i=1
for arg in $@ ; do
   echo "argument $i is $arg"
   i=$[$i+1]
   if [[ $arg =~ $pat1 ]] ; then
      echo " ... matches pattern 1"
   elif [[ $arg =~ $pat2 ]] ; then
      echo " ... matches pattern 2"
   elif [[ $arg =~ $pat3 ]] ; then
      echo " ... matches pattern 3"
   else
      echo " ... matches no patterns"
   fi
done

# the commands to run are: ./q2.sh ./q2.sh '"12"' 12a ./q2.sh foo 123123a

Sample Solution:

> q2.sh

> q2.sh '"12"' 12a
argument 1 is "12"
 ... matches pattern 3
argument 2 is 12a
 ... matches pattern 2

> q2.sh foo 123123a
argument 1 is foo
 ... matches pattern 1
argument 2 is 123123a
 ... matches pattern 2

Explanation:
Pattern 1 matches any word that starts with 0 or 1 digits
   followed by any number of lowercase alphabetic characters,
   so it effectively matches anything that begins with a digit
   or begins with an a-z.

Pattern 2 matches any word that ends with 0 or more digits
   followed by one or more lowercase vowels (aeiou), so it
   effectively matches anything ending with a vowel.

Pattern 3 matches any word that contains "12" followed by any
   number of 3's and then 0 or 1 lowercase alphabetic characters,
   so it effectively matches anything containing 12.

q2.sh
   has no command line arguments, so never enters the for loop,
   so produces absolutely no output at all.
q2.sh '"12"' 12a
   has two command line arguments, the first is the string "12" (with the quotes)
       and the second is the string 12a
   the first does not match pattern 1 or 2, but does match pattern 3
   the second does not match pattern 1 but does match pattern 2
       (it would also have matched pattern 3, but we never get there)

q2.sh foo 123123a
   has two command line arguments, the first is the string foo,
       and the second is the string 123123a
   the first matches pattern 1
   the second matches pattern 2
       (again, it would also have matched pattern 3, but we never get there)

Question 3: Bash scripting [8]

Write a complete and correct bash script that meets the following specifications:

The script is intended as an organizational aid for students using the csci git repository system.

(i) If run with no arguments, it shows the user a list of all the repositories they have access to on the central csci server, followed by a list of every repository they have in the trash on the central server.

(ii) If run with one or more arguments, it treats those arguments as keywords, and only shows those repositories which contain all the keywords. For example, the command
./showRepos.sh csci265 lab4
would show the user's central repositories and trash that contain both csci265 and lab4, e.g. something like:

Central server trash contents:
csci265/wesselsd/lab04a/2017-10-02_07:41:28

Central server repositories accessible:
 R  	csci265/wesselsd/lab04a
 R W	csci265/lab04a
 R W	csci265/lab04b
HINTS/REMINDERS:
  1. ssh csci info lists everything you have access to in the central repo
  2. ssh csci D list-trash lists what you have in the central repo trash
  3. piping a command output into grep pattern captures all the output lines containing that pattern

Sample Solution:
#! /bin/bash

# get the total output from both ssh commands and store in variables
repoInfo=`ssh csci info`
trashInfo=`ssh csci D list-trash`

# for each command line argument that was supplied,
#     keep only those lines that contain the pattern
# note: the double quotes are necessary around the $tmp and $pattern
#     to maintain whitespace, particularly the newlines,
#     otherwise the echo dumps all the base output into one big line,
#     so grep can't actually filter line-by-line
for pattern in $@; do
   tmp=$repoInfo
   repoInfo=`echo "$tmp" | grep "$pattern"`
   tmp=$trashInfo
   trashInfo=`echo "$tmp" | grep "$pattern"`
done

# display the filtered result
echo "Central repository contents requested:"
echo $repoInfo
echo "Central repository trash listings requested:"
echo $trashInfo

Question 4: Specifications [8]

Critique the specifications for the nameSorter function below, under the assumption that, as this is just a part of a larger program, the code standards and processes, operating environment, and choice of language are already documented elsewhere.

For any problems/weaknesses you have identified, suggest an alternative wording for the specifications that illustrates how the problem/weakness could be fixed.

// function nameSorter
// -------------------
// given an array of names and the array size as parameters,
//    sort the array alphabetically.
// return true if successful, false otherwise
bool nameSorter(string names[], int nameSize)

Sample Solution:

Key issues:
(1) It should be explicitly stated that the function actually modifies the
    contents of the names array, storing the sorted content there.
(2) nameSize is somewhat misleading as a name, since it actually contains
    the size of the array, not the size of a name.
(3) It is unclear what "sorted alphabetically" actually means, and that
    will be difficult to clarify without identifying what a valid name
    looks like.  For example, is the format "J. Doe", "Doe, J." or is
    it something else, and is sorting alphabetically increasing or decreasing?
(4) It is unclear what constitutes an "unsuccessful" sort, and hence when
    a value of false should be returned.  For example, should the function
    return false if nameSize < 0?  if nameSize == 0?  if a null value is
    passed for names?  if the array contains duplicates?  if there are
    duplicate names?  if names contain invalid characters or have an
    invalid format? (and if so, just what *are* the invalid characters
    and invalid formats?)

Possible rewording:
   Given an array of names as strings (in parameter names), and the size of
      the array as an integer (in parameter arraySize), sort the array in
      alphabetically non-decreasing order based on the full content of the
      string provided (e.g. "Fred Jones" comes before "Scoobert Doo").

   The sorted results replace the current contents of the names array.

   Names must consist of one or more printable characters, but must contain
      at least one non-whitespace character.  Duplicate names are possible.

   The function returns false under any of the following conditions:
      - if a null value is passed as the array,
      - if an arraySize less than 1 is passed,
      - if any name does not satisfy the criteria above.
   Under any other circumstances the function returns true when complete.

   The profile for the function is as follows:
      bool nameSorter(string names[], int arraySize);

Question 5: Life cycle models [8]

Given the hypothetical project description below, provide a preliminary recommendation on a software development life cycle model for the project. Justify your recommendation, and discuss its strengths and weaknesses with respect to this specific project.

Project RepoManager

Sample Solution:

Whatever model you picked, your discussion needs to convince me that you have
considered the advantages and disadvantages of your chosen model over the other
available choices, and justifies why you think the advantages outweight the
disadvantages for this specific project.

Some of the key points to address included:

  Concerns going into the project
  - the relatively short time frame (four months, for students who are each
    only available 10 hours per week)
  - the limited amount of supervision/guidance available
  - the lack of clear/detailed requirements at the outset of the project
  - the lack of advanced development experience of the team members
  - the lack of planned/formal interaction with the end user base (other CS students)
  - the possible communication/coordination issues arising from having a team
    of five people with limited contact hours per week

  Strengths going into the project
  - the team members all have direct experience with the tasks the tool is
    meant to automate, and would presumably be end users when it is complete
    (although they do not yet have personal experience with what may be
     expected from the tool by upper level students)
  - the team members are peers, with comperable skills and experience

Question 6: Makefiles [8]

The tables below show the contents of a makefile and the modification times/dates of the relevant files within its directory.

(i) Assuming the user were now to type the command "make all", show the output that would be produced by the makefile. (You may assume that everything that is recompiled does compile cleanly.)

(ii) If the user then typed the commands "make clean" followed by "make", show the output that would be produced by the makefile. (Again assuming there are no compilation errors or warnings.)

# makefile
Compiler=g++
BaseFlags=-Wall -Wextra -DNDebug
DebugFlags=-g
ObjFlags=-c
Dbg=Off
CC=
Obj=obj/stack.o obj/list.o obj/app.o obj/tester.o
Hdrs=hdr/stack.h hdr/defs.h hdr/list.h hdr/tester.h
Src=src/stack.cpp src/list.cpp src/app.cpp src/tester.cpp
Exe=bin/app bin/tester

ifeq (${Dbg},Off)
   CC=${Compiler} ${BaseFlags}
else
   CC=${Compiler} ${BaseFlags} ${DebugFlags}
endif

all:	${Exe}

bin/app: obj/stack.o obj/list.o obj/app.o
	${CC} obj/stack.o obj/list.o obj/app.o -o bin/app

bin/tester: obj/stack.o obj/list.o obj/tester.o
	${CC} obj/stack.o obj/list.o obj/tester.o -o bin/tester

obj/stack.o: src/stack.cpp hdr/stack.h hdr/defs.h
	${CC} ${ObjFlags} src/stack.cpp -o obj/stack.o

obj/list.o: src/list.cpp hdr/list.h hdr/defs.h
	${CC} ${ObjFlags} src/list.cpp -o obj/list.o

obj/app.o: src/app.cpp hdr/list.h hdr/defs.h hdr/stack.h
	${CC} ${ObjFlags} src/app.cpp -o obj/app.o

obj/tester.o: src/tester.cpp hdr/list.h hdr/defs.h hdr/stack.h hdr/tester.h
	${CC} ${ObjFlags} src/tester.cpp -o obj/tester.o

clean:
	rm -f ${Obj}

# file modification dates and times Oct 14 14:16 hdr/tester.h Oct 14 14:18 src/app.cpp Oct 14 14:19 hdr/defs.h Oct 14 14:19 hdr/list.h Oct 14 14:20 src/list.cpp Oct 14 14:20 src/stack.cpp Oct 14 14:26 obj/list.o Oct 14 14:27 obj/tester.o Oct 14 14:28 obj/stack.o Oct 14 14:29 obj/app.o Oct 14 14:30 bin/app Oct 14 14:31 bin/tester Oct 14 14:32 hdr/stack.h Oct 14 14:33 src/tester.cpp

Sample Solution:
g++ -Wall -Wextra -DNDebug -c src/stack.cpp -o obj/stack.o 
g++ -Wall -Wextra -DNDebug -c src/app.cpp -o obj/app.o 
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/app.o -o bin/app 
g++ -Wall -Wextra -DNDebug -c src/tester.cpp -o obj/tester.o 
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/tester.o -o bin/tester 

rm -f obj/stack.o obj/list.o obj/app.o obj/tester.o 

g++ -Wall -Wextra -DNDebug -c src/stack.cpp -o obj/stack.o 
g++ -Wall -Wextra -DNDebug -c src/list.cpp -o obj/list.o 
g++ -Wall -Wextra -DNDebug -c src/app.cpp -o obj/app.o 
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/app.o -o bin/app 
g++ -Wall -Wextra -DNDebug -c src/tester.cpp -o obj/tester.o 
g++ -Wall -Wextra -DNDebug obj/stack.o obj/list.o obj/tester.o -o bin/tester 

Explanation:
   if we look at the file modification dates, we see that stack.h and tester.cpp
      have been modified since the last time we built the .o's and executables
   the only thing that does not actually depend on those two files is list.o,
      everything else winds up being rebuilt in the order dictated by the
      dependency checks in the makefile, completing the recursively called
      .o targets before the executables that depend on them