feat: added files
This commit is contained in:
		
							parent
							
								
									11f28060e7
								
							
						
					
					
						commit
						a39e2d1aaf
					
				
							
								
								
									
										20
									
								
								course_tools/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								course_tools/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,20 @@
 | 
				
			||||||
 | 
					# CSE 320 Fall 2020 Course Tools
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Run the script to install the 320 course tools and packages.
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					$ bash vm-setup.sh
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The script will ask for sudo privileges to install packages.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**NOTE THIS TOOL RUNS APT UPGRADE**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once the script has been run, read the comments at the end of the script
 | 
				
			||||||
 | 
					in order to install packages into the Sublime Text editor.  The commented
 | 
				
			||||||
 | 
					commands in the script are an old version of an automatic installation
 | 
				
			||||||
 | 
					procedure, which doesn't work any more.  What you should do instead is to
 | 
				
			||||||
 | 
					first manually install "Package Control", then "SublimeLinter", "SublimeLinter-gcc",
 | 
				
			||||||
 | 
					and "TrailingSpaces".  Then, copy file `SublimeLinter.sublime-settings` to
 | 
				
			||||||
 | 
					directory `~/.config/sublime-text-3/Packages/User` as described in the
 | 
				
			||||||
 | 
					comments.
 | 
				
			||||||
							
								
								
									
										15
									
								
								course_tools/SublimeLinter.sublime-settings
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										15
									
								
								course_tools/SublimeLinter.sublime-settings
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,15 @@
 | 
				
			||||||
 | 
					// SublimeLinter Settings - User
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
					    "delay":0.25,
 | 
				
			||||||
 | 
					    "linters":{
 | 
				
			||||||
 | 
					        "gcc":{
 | 
				
			||||||
 | 
					            "disable":false,
 | 
				
			||||||
 | 
					            "c_executable":"gcc",
 | 
				
			||||||
 | 
					            "args":["-Wall"],
 | 
				
			||||||
 | 
					            "I":[
 | 
				
			||||||
 | 
					                "${file_path}/../include",
 | 
				
			||||||
 | 
					                "${project_path}/include"
 | 
				
			||||||
 | 
					            ]
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										132
									
								
								course_tools/boxfort-commit-ac0507b
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										132
									
								
								course_tools/boxfort-commit-ac0507b
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,132 @@
 | 
				
			||||||
 | 
					From ac0507b3f45fe58100b528baeb8ca04270b4a8ff Mon Sep 17 00:00:00 2001
 | 
				
			||||||
 | 
					From: "Franklin \"Snaipe\" Mathieu" <me@snai.pe>
 | 
				
			||||||
 | 
					Date: Mon, 23 Mar 2020 05:52:23 +0000
 | 
				
			||||||
 | 
					Subject: timeout-posix: fix race condition
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The posix timeout code was racy -- if a timeout was created, and
 | 
				
			||||||
 | 
					cancelled before the watchdog had any chance to run (because the worker
 | 
				
			||||||
 | 
					would exit too quickly, or because the thread would not be scheduled
 | 
				
			||||||
 | 
					quickly enough). This, in turn, made the watchdog wait forever for the
 | 
				
			||||||
 | 
					timeout queue to be nonempty.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This fixes the race by preventing the watchdog from ever waiting for the
 | 
				
			||||||
 | 
					queue to fill up -- it's actually not possible for the queue to be
 | 
				
			||||||
 | 
					empty during initialization, because the watchdog thread will be made to
 | 
				
			||||||
 | 
					wait for the initialization lock to be released. This means that the
 | 
				
			||||||
 | 
					only time where the queue is empty is when the watchdog has been
 | 
				
			||||||
 | 
					started, but the worker already exited/the timeout was cancelled.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In addition, this fix simplifies slightly the way that the watchdog is
 | 
				
			||||||
 | 
					collected -- we no longer try to join the thread, but we make it
 | 
				
			||||||
 | 
					detached from the get go.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This addresses Snaipe/Criterion#345.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					diff --git a/src/timeout-posix.c b/src/timeout-posix.c
 | 
				
			||||||
 | 
					index 53bd181..2e9a210 100644
 | 
				
			||||||
 | 
					--- a/src/timeout-posix.c
 | 
				
			||||||
 | 
					+++ b/src/timeout-posix.c
 | 
				
			||||||
 | 
					@@ -22,13 +22,13 @@
 | 
				
			||||||
 | 
					  * THE SOFTWARE.
 | 
				
			||||||
 | 
					  */
 | 
				
			||||||
 | 
					 #include <assert.h>
 | 
				
			||||||
 | 
					+#include <errno.h>
 | 
				
			||||||
 | 
					 #include <pthread.h>
 | 
				
			||||||
 | 
					-#include <time.h>
 | 
				
			||||||
 | 
					+#include <signal.h>
 | 
				
			||||||
 | 
					 #include <stdint.h>
 | 
				
			||||||
 | 
					 #include <stdlib.h>
 | 
				
			||||||
 | 
					-#include <errno.h>
 | 
				
			||||||
 | 
					-#include <signal.h>
 | 
				
			||||||
 | 
					 #include <string.h>
 | 
				
			||||||
 | 
					+#include <time.h>
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 #include "config.h"
 | 
				
			||||||
 | 
					 #include "sandbox.h"
 | 
				
			||||||
 | 
					@@ -48,11 +48,9 @@ static struct {
 | 
				
			||||||
 | 
					     int thread_active;
 | 
				
			||||||
 | 
					     pthread_mutex_t sync;
 | 
				
			||||||
 | 
					     pthread_cond_t cond;
 | 
				
			||||||
 | 
					-    pthread_cond_t termcond;
 | 
				
			||||||
 | 
					 } self = {
 | 
				
			||||||
 | 
					     .sync = PTHREAD_MUTEX_INITIALIZER,
 | 
				
			||||||
 | 
					     .cond = PTHREAD_COND_INITIALIZER,
 | 
				
			||||||
 | 
					-    .termcond = PTHREAD_COND_INITIALIZER,
 | 
				
			||||||
 | 
					 };
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 static int timespec_cmp(struct timespec *a, struct timespec *b)
 | 
				
			||||||
 | 
					@@ -96,8 +94,6 @@ static void to_timespec(double timeout, struct timespec *timeo)
 | 
				
			||||||
 | 
					 static void *timeout_killer_fn(void *nil)
 | 
				
			||||||
 | 
					 {
 | 
				
			||||||
 | 
					     pthread_mutex_lock(&self.sync);
 | 
				
			||||||
 | 
					-    while (!self.requests)
 | 
				
			||||||
 | 
					-        pthread_cond_wait(&self.cond, &self.sync);
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     struct bxfi_timeout_request *req;
 | 
				
			||||||
 | 
					     for (;;) {
 | 
				
			||||||
 | 
					@@ -125,7 +121,7 @@ static void *timeout_killer_fn(void *nil)
 | 
				
			||||||
 | 
					         free(req);
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					 end:
 | 
				
			||||||
 | 
					-    pthread_cond_broadcast(&self.termcond);
 | 
				
			||||||
 | 
					+    self.thread_active = 0;
 | 
				
			||||||
 | 
					     pthread_mutex_unlock(&self.sync);
 | 
				
			||||||
 | 
					     return nil;
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					@@ -137,10 +133,6 @@ void bxfi_reset_timeout_killer(void)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     memcpy(&self.sync, &mutex, sizeof (mutex));
 | 
				
			||||||
 | 
					     memcpy(&self.cond, &cond, sizeof (cond));
 | 
				
			||||||
 | 
					-    memcpy(&self.termcond, &cond, sizeof (cond));
 | 
				
			||||||
 | 
					-
 | 
				
			||||||
 | 
					-    if (self.requests)
 | 
				
			||||||
 | 
					-        pthread_join(self.thread, NULL);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					 int bxfi_push_timeout(struct bxfi_sandbox *instance, double timeout)
 | 
				
			||||||
 | 
					@@ -159,10 +151,16 @@ int bxfi_push_timeout(struct bxfi_sandbox *instance, double timeout)
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     pthread_mutex_lock(&self.sync);
 | 
				
			||||||
 | 
					     if (!self.requests) {
 | 
				
			||||||
 | 
					-        if (self.thread_active)
 | 
				
			||||||
 | 
					-            pthread_join(self.thread, NULL);
 | 
				
			||||||
 | 
					+        pthread_attr_t attrs;
 | 
				
			||||||
 | 
					+        if ((rc = pthread_attr_init(&attrs)) == -1) {
 | 
				
			||||||
 | 
					+            rc = -errno;
 | 
				
			||||||
 | 
					+            goto error;
 | 
				
			||||||
 | 
					+        }
 | 
				
			||||||
 | 
					+        pthread_attr_setdetachstate(&attrs, PTHREAD_CREATE_DETACHED);
 | 
				
			||||||
 | 
					+
 | 
				
			||||||
 | 
					         self.thread_active = 1;
 | 
				
			||||||
 | 
					-        rc = -pthread_create(&self.thread, NULL, timeout_killer_fn, NULL);
 | 
				
			||||||
 | 
					+        rc = -pthread_create(&self.thread, &attrs, timeout_killer_fn, NULL);
 | 
				
			||||||
 | 
					+        pthread_attr_destroy(&attrs);
 | 
				
			||||||
 | 
					         if (rc)
 | 
				
			||||||
 | 
					             goto error;
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					@@ -177,7 +175,6 @@ int bxfi_push_timeout(struct bxfi_sandbox *instance, double timeout)
 | 
				
			||||||
 | 
					     *nptr = req;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					     pthread_cond_broadcast(&self.cond);
 | 
				
			||||||
 | 
					-    pthread_cond_broadcast(&self.termcond);
 | 
				
			||||||
 | 
					     pthread_mutex_unlock(&self.sync);
 | 
				
			||||||
 | 
					     return 0;
 | 
				
			||||||
 | 
					 
 | 
				
			||||||
 | 
					@@ -204,17 +201,6 @@ void bxfi_cancel_timeout(struct bxfi_sandbox *instance)
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					     if (cancelled) {
 | 
				
			||||||
 | 
					         pthread_cond_broadcast(&self.cond);
 | 
				
			||||||
 | 
					-        if (!self.requests) {
 | 
				
			||||||
 | 
					-            while (self.cancelled && !self.requests)
 | 
				
			||||||
 | 
					-                pthread_cond_wait(&self.termcond, &self.sync);
 | 
				
			||||||
 | 
					-            if (self.requests)
 | 
				
			||||||
 | 
					-                goto end;
 | 
				
			||||||
 | 
					-            if (self.thread_active) {
 | 
				
			||||||
 | 
					-                pthread_join(self.thread, NULL);
 | 
				
			||||||
 | 
					-                self.thread_active = 0;
 | 
				
			||||||
 | 
					-            }
 | 
				
			||||||
 | 
					-        }
 | 
				
			||||||
 | 
					     }
 | 
				
			||||||
 | 
					-end:
 | 
				
			||||||
 | 
					     pthread_mutex_unlock(&self.sync);
 | 
				
			||||||
 | 
					 }
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								course_tools/criterion.zip
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								course_tools/criterion.zip
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										231
									
								
								course_tools/git-submit
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										231
									
								
								course_tools/git-submit
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,231 @@
 | 
				
			||||||
 | 
					#!/usr/bin/env python3
 | 
				
			||||||
 | 
					import requests
 | 
				
			||||||
 | 
					from requests import get
 | 
				
			||||||
 | 
					from requests.exceptions import ConnectTimeout, ConnectionError, HTTPError
 | 
				
			||||||
 | 
					from requests.packages.urllib3.exceptions import InsecureRequestWarning
 | 
				
			||||||
 | 
					from datetime import datetime
 | 
				
			||||||
 | 
					from signal import signal, SIGINT, SIGTSTP, SIG_IGN
 | 
				
			||||||
 | 
					from subprocess import run, PIPE
 | 
				
			||||||
 | 
					from shlex import split
 | 
				
			||||||
 | 
					from argparse import ArgumentParser
 | 
				
			||||||
 | 
					from sys import exit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					RED = '\033[1;31m'
 | 
				
			||||||
 | 
					GRE = '\033[1;32m'
 | 
				
			||||||
 | 
					YEL = '\033[0;33m'
 | 
				
			||||||
 | 
					BLU = '\033[1;34m'
 | 
				
			||||||
 | 
					PUR = '\033[1;35m'
 | 
				
			||||||
 | 
					CYA = '\033[1;36m'
 | 
				
			||||||
 | 
					BOLD = '\033[1m'
 | 
				
			||||||
 | 
					DEF = '\033[0m'
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BASE_URL = 'https://cse320.starkeffect.com:3000/submit'
 | 
				
			||||||
 | 
					server_timeout = None
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def yn_prompt():
 | 
				
			||||||
 | 
					    prompt = input('{}Continue? Please enter Y/n{}: '.format(PUR, DEF))
 | 
				
			||||||
 | 
					    while prompt != 'Y' and prompt.lower() != 'n':
 | 
				
			||||||
 | 
					        prompt = input('{}Continue? Please enter Y/n{}: '.format(PUR, DEF))
 | 
				
			||||||
 | 
					    if prompt != 'Y':
 | 
				
			||||||
 | 
					        print('{}Aborting...{}'.format(YEL, DEF))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def first_api_call():
 | 
				
			||||||
 | 
					    global server_timeout
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        res = get(BASE_URL + '/timeout', params=None, timeout=15, verify=False)
 | 
				
			||||||
 | 
					        res_json = res.json()
 | 
				
			||||||
 | 
					        server_timeout = res_json['timeout']
 | 
				
			||||||
 | 
					    except (ConnectionError, ConnectTimeout, HTTPError):
 | 
				
			||||||
 | 
					        print('Error connecting to the server. Try again. (FIRST_SERVER_CALL)')
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def initial_message():
 | 
				
			||||||
 | 
					    print('Only commits made from master or merged into master will be ',
 | 
				
			||||||
 | 
					          'considered. If you would like to submit a commit from a different ',
 | 
				
			||||||
 | 
					          'branch, please merge the branch into master first.')
 | 
				
			||||||
 | 
					    yn_prompt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def api_call(endpoint, query):
 | 
				
			||||||
 | 
					    global server_timeout
 | 
				
			||||||
 | 
					    try:
 | 
				
			||||||
 | 
					        res = get(BASE_URL + endpoint, params=query, timeout=server_timeout,
 | 
				
			||||||
 | 
					                verify=False)
 | 
				
			||||||
 | 
					    except (ConnectionError, ConnectTimeout, HTTPError):
 | 
				
			||||||
 | 
					        print('Error connecting to the server. Try again. ',
 | 
				
			||||||
 | 
					              '(SERVER_CONNECTION_ERROR)')
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					    res_json = res.json()
 | 
				
			||||||
 | 
					    if 'errmsg' in res_json:
 | 
				
			||||||
 | 
					        print(res_json['errmsg'])
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					    return res_json
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def validate_git_directory():
 | 
				
			||||||
 | 
					    cmd = split('git remote show origin')
 | 
				
			||||||
 | 
					    proc = run(cmd, stdout=PIPE)
 | 
				
			||||||
 | 
					    if proc.returncode:
 | 
				
			||||||
 | 
					        exit(proc.returncode)
 | 
				
			||||||
 | 
					    # You are not expected to understand this
 | 
				
			||||||
 | 
					    return [line for line in proc.stdout.decode().split('\n') if
 | 
				
			||||||
 | 
					            line.strip().startswith('Push')][0].split('/')[-1].split('.')[0]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def validate_commit(commit):
 | 
				
			||||||
 | 
					    # check current user branch
 | 
				
			||||||
 | 
					    branch_cmd = split('git rev-parse --abbrev-ref HEAD')
 | 
				
			||||||
 | 
					    branch_proc = run(branch_cmd, stdout=PIPE, stderr=PIPE)
 | 
				
			||||||
 | 
					    if branch_proc.returncode:
 | 
				
			||||||
 | 
					        print('{}Error{}: Uninitialized repository. Please initialize your repo.'.format(RED, DEF))
 | 
				
			||||||
 | 
					        exit(branch_proc.returncode)
 | 
				
			||||||
 | 
					    current_branch = [line for line in branch_proc.stdout.decode().split('\n')][0]
 | 
				
			||||||
 | 
					    if not current_branch == 'master':
 | 
				
			||||||
 | 
					        print('{}Error{}: Run git submit from the master branch'.format(RED, DEF))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					    # check branch commit was made from
 | 
				
			||||||
 | 
					    if not commit == 'master':
 | 
				
			||||||
 | 
					        if len(commit) < 8:
 | 
				
			||||||
 | 
					            print('{}Error{}: Use at least the first 8 characters of the commit hash.'.format(RED, DEF))
 | 
				
			||||||
 | 
					            exit(1)
 | 
				
			||||||
 | 
					        commit_branch_cmd = split('git branch --contains {}'.format(commit))
 | 
				
			||||||
 | 
					        commit_branch_proc = run(commit_branch_cmd, stdout=PIPE, stderr=PIPE)
 | 
				
			||||||
 | 
					        if commit_branch_proc.returncode:
 | 
				
			||||||
 | 
					            print('{}Error{}: The specified commit hash is invalid.'.format(RED, DEF))
 | 
				
			||||||
 | 
					            exit(commit_branch_proc.returncode)
 | 
				
			||||||
 | 
					        branches = [branch for branch in commit_branch_proc.stdout.decode().split('\n')]
 | 
				
			||||||
 | 
					        on_master = False
 | 
				
			||||||
 | 
					        for branch in branches:
 | 
				
			||||||
 | 
					            branch_name = [word.strip() for word in branch.split('*')][-1]
 | 
				
			||||||
 | 
					            if branch_name == 'master':
 | 
				
			||||||
 | 
					                on_master = True
 | 
				
			||||||
 | 
					        if not on_master:
 | 
				
			||||||
 | 
					            print('{}Error{}: The submitted commit should be from master. Merge the branch with the commit into master.'.format(RED, DEF))
 | 
				
			||||||
 | 
					            exit(1)
 | 
				
			||||||
 | 
					    cmd = "bash -c 'git log --branches=master* --not --remotes --pretty=oneline'"
 | 
				
			||||||
 | 
					    proc = run(cmd, stdout=PIPE, shell=True)
 | 
				
			||||||
 | 
					    if proc.returncode:
 | 
				
			||||||
 | 
					        print(proc.stdout)
 | 
				
			||||||
 | 
					        exit(proc.returncode)
 | 
				
			||||||
 | 
					    elif commit == 'master' and proc.stdout:
 | 
				
			||||||
 | 
					        print('{}Error{}: Push your commits to the remote using: git push'.format(RED, DEF))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					    elif commit in proc.stdout.decode():
 | 
				
			||||||
 | 
					        print('{}Error{}: Push your commits to the remote using: git push'.format(RED, DEF))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def validate_tag(tag):
 | 
				
			||||||
 | 
					    response = api_call('/verify/{}'.format(tag), None)
 | 
				
			||||||
 | 
					    if 'err' in response:
 | 
				
			||||||
 | 
					        print('{}Error{}: {}'.format(RED, DEF, response['err']))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					    if not response['valid']:
 | 
				
			||||||
 | 
					        print('{}Error{}: {}'.format(RED, DEF, response['msg']))
 | 
				
			||||||
 | 
					        exit(1)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def check_for_resubmission(args):
 | 
				
			||||||
 | 
					    status = api_call('/status', args)
 | 
				
			||||||
 | 
					    print('{}Submission Time{}: {}'.format(BLU, DEF, status['time']))
 | 
				
			||||||
 | 
					    if status['submitted']:
 | 
				
			||||||
 | 
					        print('{}Resubmitting Homework{}: {} -- Are you {}sure{} you wish to resubmit '
 | 
				
			||||||
 | 
					              '(this may result in lateday penalties)?'.format(YEL, DEF, CYA + args['tag'] + DEF, BOLD, DEF))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print('{}Submitting Homework{}: {} -- Are you {}sure{}? '
 | 
				
			||||||
 | 
					              .format(YEL, DEF, CYA + args['tag'] + DEF, BOLD, DEF))
 | 
				
			||||||
 | 
					    yn_prompt()
 | 
				
			||||||
 | 
					    return status['submitted'], status['time']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def confirm_repo_state():
 | 
				
			||||||
 | 
					    run(split('git -c color.status=always status'))
 | 
				
			||||||
 | 
					    print('{}Current Repo State{}: Are you {}sure{} you have committed and pushed all the files needed '
 | 
				
			||||||
 | 
					          '(such as .h files)?'.format(YEL, DEF, BOLD, DEF))
 | 
				
			||||||
 | 
					    yn_prompt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def confirm_commit(commit):
 | 
				
			||||||
 | 
					    cmd = split('git --no-pager -c color.ui=always show {} --pretty=fuller --quiet'.format(commit))
 | 
				
			||||||
 | 
					    proc = run(cmd)
 | 
				
			||||||
 | 
					    if proc.returncode:
 | 
				
			||||||
 | 
					        exit(proc.returncode)
 | 
				
			||||||
 | 
					    print('{}Submission Commit{}: Are you {}sure{} this is the commit you wish to submit?'.format(YEL, DEF, BOLD, DEF))
 | 
				
			||||||
 | 
					    yn_prompt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def confirm_submission(tag):
 | 
				
			||||||
 | 
					    print('{}Confirm Submission{}: Are you {}sure{} you want to submit {}? Your previous submission (if any) will be '
 | 
				
			||||||
 | 
					          '{}overwritten{}!'.format(YEL, DEF, BOLD, DEF, CYA + tag + DEF, BOLD, DEF))
 | 
				
			||||||
 | 
					    yn_prompt()
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def trigger_submission(args):
 | 
				
			||||||
 | 
					    info = api_call('', args)
 | 
				
			||||||
 | 
					    return info['late'], info['lateDays']
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def submission_info(**kwargs):
 | 
				
			||||||
 | 
					    run(split('git pull --quiet'))
 | 
				
			||||||
 | 
					    late = kwargs['late']
 | 
				
			||||||
 | 
					    tag = kwargs['tag']
 | 
				
			||||||
 | 
					    resubmit = kwargs['submit']
 | 
				
			||||||
 | 
					    late_days = kwargs['days']
 | 
				
			||||||
 | 
					    attempt_time = kwargs['time']
 | 
				
			||||||
 | 
					    if late:
 | 
				
			||||||
 | 
					        print('{}Urgent{}: {} was overdue. You did not have enough late days remaining.'.format(RED, DEF, tag))
 | 
				
			||||||
 | 
					        print('{}Info{}: You have {} lateday(s) remaining.'.format(BLU, DEF, late_days))
 | 
				
			||||||
 | 
					        if resubmit:
 | 
				
			||||||
 | 
					            print('{}Alert{}: Your last submission will be taken into consideration.'.format(YEL, DEF))
 | 
				
			||||||
 | 
					        else:
 | 
				
			||||||
 | 
					            print('{}Urgent{}: You will be given an automatic zero for this assignment. Please meet your Professor\n'
 | 
				
			||||||
 | 
					                  'after lecture or during office hours or please email us at cse320@cs.stonybrook.edu with\n'
 | 
				
			||||||
 | 
					                  '{}[CSE320] - {} Overdue{} as the subject.'.format(RED, DEF, BLU, tag, DEF))
 | 
				
			||||||
 | 
					    else:
 | 
				
			||||||
 | 
					        print('{}Success{}: {} submission successful. Your assignment was submitted on {}.'
 | 
				
			||||||
 | 
					              .format(GRE, DEF, tag, attempt_time))
 | 
				
			||||||
 | 
					        print('{}Info{}: You have {} lateday(s) remaining.'.format(BLU, DEF, late_days))
 | 
				
			||||||
 | 
					        print('Thank you for submitting your homework! We are working hard to get your grades out as soon as possible.')
 | 
				
			||||||
 | 
					        print('If you have any concerns please email us at cse320@cs.stonybrook.edu with {}[{}]{} in the subject.'
 | 
				
			||||||
 | 
					              .format(BLU, tag, DEF))
 | 
				
			||||||
 | 
					    print('{}The CSE 320 Team{}'.format(PUR, DEF))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					def main(arg_parser):
 | 
				
			||||||
 | 
					    requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
 | 
				
			||||||
 | 
					    first_api_call()
 | 
				
			||||||
 | 
					    initial_message()
 | 
				
			||||||
 | 
					    net_id = validate_git_directory()
 | 
				
			||||||
 | 
					    args = arg_parser.parse_args()
 | 
				
			||||||
 | 
					    attempt_time = datetime.now()
 | 
				
			||||||
 | 
					    validate_tag(args.TAG)
 | 
				
			||||||
 | 
					    validate_commit(args.commit)
 | 
				
			||||||
 | 
					    resubmit, time = check_for_resubmission({'tag': args.TAG, 'repo': net_id, 'attemptTime': attempt_time.isoformat()})
 | 
				
			||||||
 | 
					    confirm_repo_state()
 | 
				
			||||||
 | 
					    confirm_commit(args.commit)
 | 
				
			||||||
 | 
					    confirm_submission(args.TAG)
 | 
				
			||||||
 | 
					    signal(SIGINT, SIG_IGN)
 | 
				
			||||||
 | 
					    signal(SIGTSTP, SIG_IGN)
 | 
				
			||||||
 | 
					    late, late_days = trigger_submission({'tag': args.TAG, 'repo': net_id, 'commit': args.commit})
 | 
				
			||||||
 | 
					    submission_info(tag=args.TAG, time=time, submit=resubmit, late=late, days=late_days)
 | 
				
			||||||
 | 
					    exit(0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class GitArgParser(ArgumentParser):
 | 
				
			||||||
 | 
					    def error(self, message):
 | 
				
			||||||
 | 
					        print('{}Error{}: {}'.format(RED, DEF, message))
 | 
				
			||||||
 | 
					        self.print_help()
 | 
				
			||||||
 | 
					        exit(2)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if __name__ == '__main__':
 | 
				
			||||||
 | 
					    parser = GitArgParser(prog='git submit', description='Submit your homework assignment using git.')
 | 
				
			||||||
 | 
					    parser.add_argument('TAG', type=str, help='The homework you wish to submit. Can have one of the following values: '
 | 
				
			||||||
 | 
					                                              'hw0, hw1, hw2, hw3, hw4, hw5')
 | 
				
			||||||
 | 
					    parser.add_argument('-c', dest='commit', type=str, required=False, default='master',
 | 
				
			||||||
 | 
					                        help='Used if you wish to submit a commit that is not the latest. COMMIT is the SHA value of '
 | 
				
			||||||
 | 
					                             'your commit.')
 | 
				
			||||||
 | 
					    main(parser)
 | 
				
			||||||
							
								
								
									
										124
									
								
								course_tools/vm-setup.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										124
									
								
								course_tools/vm-setup.sh
									
									
									
									
									
										Executable file
									
								
							| 
						 | 
					@ -0,0 +1,124 @@
 | 
				
			||||||
 | 
					#! /usr/bin/env bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo
 | 
				
			||||||
 | 
					if hash figlet 2> /dev/null; then
 | 
				
			||||||
 | 
					    echo "320 Setup" | figlet -f banner
 | 
				
			||||||
 | 
					else
 | 
				
			||||||
 | 
					    echo "320 Setup"
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					echo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Updating..."
 | 
				
			||||||
 | 
					# General updates
 | 
				
			||||||
 | 
					sudo apt-get update -y
 | 
				
			||||||
 | 
					echo "Graphics issues from 8/2021 now fixed with VirtualBox 6.1.27 or later -- doing apt-get upgrade"
 | 
				
			||||||
 | 
					sudo apt-get upgrade -y
 | 
				
			||||||
 | 
					sudo apt-get autoremove -y 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Extras
 | 
				
			||||||
 | 
					sudo apt-get install -y figlet terminator htop dialog wget tree 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "vm-tools" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y open-vm-tools-desktop 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Git" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y git 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Gitk" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y gitk 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo Git Submit | figlet -f mini
 | 
				
			||||||
 | 
					mkdir -p $HOME/.local
 | 
				
			||||||
 | 
					mkdir -p $HOME/.local/bin
 | 
				
			||||||
 | 
					cp -p git-submit $HOME/.local/bin
 | 
				
			||||||
 | 
					chmod +x $HOME/.local/bin/git-submit
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Readline" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y libreadline-dev readline-doc 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Clang" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y clang 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "GDB" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y gdb cgdb 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Valgrind" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y valgrind 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "GCC and tools" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y gcc make binutils 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "POSIX man pages" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y manpages-posix-dev 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Ncurses" | figlet -f mini
 | 
				
			||||||
 | 
					sudo apt-get install -y libncurses-dev 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					echo "Installing..."
 | 
				
			||||||
 | 
					echo "Criterion" | figlet -f mini
 | 
				
			||||||
 | 
					#sudo add-apt-repository -y ppa:snaipewastaken/ppa
 | 
				
			||||||
 | 
					#sudo apt-get update
 | 
				
			||||||
 | 
					#sudo apt-get install -y criterion-dev
 | 
				
			||||||
 | 
					sudo unzip -d / criterion.zip
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					dialog --keep-tite --title "Sublime Text"  --yesno "Do you want to install Sublime with plugins?" 5 50
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					if [ $? -eq 0 ]; then
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # Add Sublime key
 | 
				
			||||||
 | 
					    wget -qO - https://download.sublimetext.com/sublimehq-pub.gpg | sudo apt-key add - 2>&1 > /dev/null
 | 
				
			||||||
 | 
					    echo "deb https://download.sublimetext.com/ apt/stable/" | sudo tee /etc/apt/sources.list.d/sublime-text.list 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    sudo apt-get update -y
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    echo "Installing..."
 | 
				
			||||||
 | 
					    echo "Sublime Editor" | figlet -f mini
 | 
				
			||||||
 | 
					    sudo apt-get install sublime-text 2>&1 > /dev/null
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    mkdir -p "$HOME/.config"
 | 
				
			||||||
 | 
					    mkdir -p "$HOME/.config/sublime-text-3"
 | 
				
			||||||
 | 
					    mkdir -p "$HOME/.config/sublime-text-3/Installed Packages"
 | 
				
			||||||
 | 
					    mkdir -p "$HOME/.config/sublime-text-3/Packages"
 | 
				
			||||||
 | 
					    mkdir -p "$HOME/.config/sublime-text-3/Packages/User"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    # EWS (8/8/2020)
 | 
				
			||||||
 | 
					    # The following configuration is somewhat obsolete, and in any case is too sensitive to
 | 
				
			||||||
 | 
					    # changes to Sublime and its plugins.  When I tried to run it just now, it left things
 | 
				
			||||||
 | 
					    # broken.  Instead I have manually installed the following for use in CSE 320:
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #    Package Control
 | 
				
			||||||
 | 
					    #    SublimeLinter
 | 
				
			||||||
 | 
					    #    SublimeLinter-gcc
 | 
				
			||||||
 | 
					    #    TrailingSpaces
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # The only really important thing is to copy SublimeLinter.sublime-settings to
 | 
				
			||||||
 | 
					    # ~/.config/sublime-text-3/Packages/User  as in the last commented line below, so that
 | 
				
			||||||
 | 
					    # the linter works correctly with our project setup.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    # The rest of this stuff I have commented out for now.
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #touch "$HOME/.config/sublime-text-3/Packages/User/Package Control.sublime-settings"
 | 
				
			||||||
 | 
					    #touch "$HOME/.config/sublime-text-3/Installed Packages/Package Control.sublime-package"
 | 
				
			||||||
 | 
					    #wget -qO - https://packagecontrol.io/Package%20Control.sublime-package > "$HOME/.config/sublime-text-3/Installed Packages/Package Control.sublime-package"
 | 
				
			||||||
 | 
					    #
 | 
				
			||||||
 | 
					    #echo "{\"bootstrapped\":true,\"installed_packages\":[\"Package Control\",\"TrailingSpaces\",\"SublimeLinter\",\"SublimeLinter-contrib-gcc\"]}" > "$HOME/.config/sublime-text-3/Packages/User/Package Control.sublime-settings"
 | 
				
			||||||
 | 
					    #echo "{\"trailing_spaces_trim_on_save\": true}" > "$HOME/.config/sublime-text-3/Packages/User/trailing_spaces.sublime-settings"
 | 
				
			||||||
 | 
					    #echo "{\"ignored_packages\":[\"Vintage\"],\"hot_exit\":false,\"save_on_focus_lost\":true,\"translate_tabs_to_spaces\":true}" > "$HOME/.config/sublime-text-3/Packages/User/Preferences.sublime-settings"
 | 
				
			||||||
 | 
					    cp -p SublimeLinter.sublime-settings ~/.config/sublime-text-3/Packages/User
 | 
				
			||||||
 | 
					fi
 | 
				
			||||||
 | 
					echo "-----------------------------"
 | 
				
			||||||
 | 
					echo "!ATTN!" | figlet
 | 
				
			||||||
 | 
					echo "-----------------------------"
 | 
				
			||||||
 | 
					echo -e "If you \e[31;1mcannot\e[0m execute git submit add the following to your ~/.bashrc or other relevant terminal config"
 | 
				
			||||||
 | 
					echo "export PATH=\$PATH:$HOME/.local/bin"
 | 
				
			||||||
							
								
								
									
										754
									
								
								hw0-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										754
									
								
								hw0-doc/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,754 @@
 | 
				
			||||||
 | 
					# CSE320 Spring 2022
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this course you will be using Linux as your primary development
 | 
				
			||||||
 | 
					environment. In addition, we will be providing you with a git
 | 
				
			||||||
 | 
					repository hosted on a department GitLab server. This document will
 | 
				
			||||||
 | 
					briefly explain the course tools and outline the required setup for
 | 
				
			||||||
 | 
					this course.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Setting up your CSE320 Git repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Git is an open-source distributed version control system. We will use
 | 
				
			||||||
 | 
					git repositories to manage your homework submissions. In addition, the
 | 
				
			||||||
 | 
					use of git allows the Professor and TAs to access and view your your
 | 
				
			||||||
 | 
					code remotely in order to assist you. While some students may be
 | 
				
			||||||
 | 
					familiar with version control and git, we ask that everyone complete
 | 
				
			||||||
 | 
					the following tutorial and instructions. This will ensure that
 | 
				
			||||||
 | 
					everyone in the course has the same background knowledge and can
 | 
				
			||||||
 | 
					submit their homeworks.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We are using a CSE department supported git web interface, called
 | 
				
			||||||
 | 
					gitlab. This is similar to github, bitbucket, etc. It is an interface
 | 
				
			||||||
 | 
					to help manage git repositories. These services are INTERFACES to git,
 | 
				
			||||||
 | 
					not git itself.  You *may not* use external repositories as we will
 | 
				
			||||||
 | 
					use the repo provided to you to grade your submitted work and share
 | 
				
			||||||
 | 
					gradesheets with you.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To setup your repository:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Navigate to
 | 
				
			||||||
 | 
					[https://gitlab02.cs.stonybrook.edu](https://gitlab02.cs.stonybrook.edu/)
 | 
				
			||||||
 | 
					and log into it with your CS email account (user name only, do not
 | 
				
			||||||
 | 
					include the `@cs.stonybrook.edu`). If you forgot your CS email
 | 
				
			||||||
 | 
					password you can reset it by following the instructions
 | 
				
			||||||
 | 
					[here](https://auth01.cs.stonybrook.edu:10443/). If those
 | 
				
			||||||
 | 
					instructions fail, please email `rt@cs.stonybrook.edu` requesting a
 | 
				
			||||||
 | 
					password reset. A response may take up to 24-48 hours.
 | 
				
			||||||
 | 
					2. Once you have logged in the creation of your repo will be triggered.
 | 
				
			||||||
 | 
					Normally this will occur within a few minutes.  If not, then send an
 | 
				
			||||||
 | 
					email to `cse320@cs.stonybrook.edu` and we will look into it.
 | 
				
			||||||
 | 
					Sometimes the 'bot responsible for creating the repos has to be reset.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Setting up Linux Environment
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Since C is a systems level language, frequently the behavior from one
 | 
				
			||||||
 | 
					person’s computer to another can vary. In the past, we have provided a
 | 
				
			||||||
 | 
					common server for students to use, but this presented a few
 | 
				
			||||||
 | 
					problems. When you wanted to compile your assignment, you would have
 | 
				
			||||||
 | 
					to continuously transfer the file to the server and then compile
 | 
				
			||||||
 | 
					it. If you had any mistakes, you would have to either edit it on the
 | 
				
			||||||
 | 
					server or make the change locally and upload it again. This became
 | 
				
			||||||
 | 
					very tedious which often led to students compiling and testing
 | 
				
			||||||
 | 
					locally on their own machines. This was not always a good idea as
 | 
				
			||||||
 | 
					something that seemed to work for you didn’t always work for the
 | 
				
			||||||
 | 
					grader which caused many issues. Also, many tools, which assist in
 | 
				
			||||||
 | 
					locating and fixing errors in C code, do not exist in Windows and OSX
 | 
				
			||||||
 | 
					environments. So students who installed operating systems such as
 | 
				
			||||||
 | 
					[Linux](https://en.wikipedia.org/wiki/Linux) were at an advantage over
 | 
				
			||||||
 | 
					the students who did not.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: This document will also outline the homework management and
 | 
				
			||||||
 | 
					  submission process. In this class, you will be creating increasingly
 | 
				
			||||||
 | 
					  complex C projects which may involve many files. To satisfy these
 | 
				
			||||||
 | 
					  requirements, we will be using git to manage & submit your homework
 | 
				
			||||||
 | 
					  assignments.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: While we will try to provide the basics for what needs to be
 | 
				
			||||||
 | 
					  done, it will ultimately be up to you to learn how to use these
 | 
				
			||||||
 | 
					  tools.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To help alleviate the above issues and to setup a local environment
 | 
				
			||||||
 | 
					with the necessary course tools, you must install your working
 | 
				
			||||||
 | 
					environment using one of these two options:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- Option 1: A Virtual Machine running Linux (Encouraged Option)
 | 
				
			||||||
 | 
					- Option 2: Multi-Boot/Install Linux on your machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Option 1 is encouraged for the following reasons:
 | 
				
			||||||
 | 
					- Quick setup
 | 
				
			||||||
 | 
					- Ease of use in your native OS
 | 
				
			||||||
 | 
					- Easy to reset if errors in VM environment
 | 
				
			||||||
 | 
					- All course tools are pre-installed
 | 
				
			||||||
 | 
					- Simulate multiple cores on a single core system
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We have put a lot of effort into setting up a pre-configured VM.  If
 | 
				
			||||||
 | 
					for some reason you are unable or unwilling to use this, we have
 | 
				
			||||||
 | 
					provided basic instructions for Option 2 with a script to install all
 | 
				
			||||||
 | 
					the course tools.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you choose option 2, you should have some idea what you are doing,
 | 
				
			||||||
 | 
					already be comfortable with Linux, and be aware that we probably won't
 | 
				
			||||||
 | 
					have the resources to debug any issues you might encounter.  If you
 | 
				
			||||||
 | 
					deviate in any other way from these procedures, it is completely at
 | 
				
			||||||
 | 
					your peril.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Option 1: A Virtual Machine running Linux
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Students often use either [VMware](https://www.vmware.com) or
 | 
				
			||||||
 | 
					[VirtualBox](https://www.virtualbox.org/) to run virtual machines.
 | 
				
			||||||
 | 
					We recommend that you use VirtualBox.  It is free, and it runs
 | 
				
			||||||
 | 
					on all of the most popular platforms.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In order to run a virtual machine, your machine must support 64-bit
 | 
				
			||||||
 | 
					hardware virtualization. Most machines built after 2006 should support
 | 
				
			||||||
 | 
					this. However, not all machines have the option enabled. You may need
 | 
				
			||||||
 | 
					to modify your BIOS settings to enable this feature. As each machine
 | 
				
			||||||
 | 
					has a different BIOS, it is up to you to find and enable this feature
 | 
				
			||||||
 | 
					on your own machine.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Download and install the VirtualBox platform package appropriate
 | 
				
			||||||
 | 
					for your computer from [this site](https://www.virtualbox.org/wiki/Downloads).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :exclamation:  Because of recent changes made to the way VirtualBox interfaces
 | 
				
			||||||
 | 
					> with the graphics drivers on various platforms, it is important that you make
 | 
				
			||||||
 | 
					> sure to install VirtualBox version 6.1.27 or greater.  With older versions,
 | 
				
			||||||
 | 
					> the course VM image will probably not be able to access the display properly.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Running the Linux VM
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We will be using Linux Mint 20 "Ulyana" -- Cinnamon as this semester's OS. We
 | 
				
			||||||
 | 
					have taken the time to set up the VM so it simply needs to be opened
 | 
				
			||||||
 | 
					in your virtualization program.  The provided Linux virtual machine
 | 
				
			||||||
 | 
					has all the tools required for various aspects of this course; for
 | 
				
			||||||
 | 
					example, homework submission is pre-installed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To get started, download the VM from here:
 | 
				
			||||||
 | 
					[Google Drive]
 | 
				
			||||||
 | 
					(https://drive.google.com/file/d/1rwUM_rm4sEC-we-i-siOPWDnQEtH6mdC/view?usp=sharing)
 | 
				
			||||||
 | 
					(it's nearly 5 gb so give it some time).
 | 
				
			||||||
 | 
					This should result in your having a file called **CSE320_Spring22.ova**.
 | 
				
			||||||
 | 
					This can be imported directly into VirtualBox by choosing
 | 
				
			||||||
 | 
					"Import Appliance" from the "File" menu and then browsing to select
 | 
				
			||||||
 | 
					the file you downloaded.  Click "Next", review the VM settings,
 | 
				
			||||||
 | 
					and then click on "Import".  Once the import has completed, you should
 | 
				
			||||||
 | 
					have a VM called "CSE 320".  Select this and click on
 | 
				
			||||||
 | 
					"Start" to boot the VM.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Login Info
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Upon booting, you will be automatically logged in as user `student`.
 | 
				
			||||||
 | 
					The login info for your reference is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					|     Username    |   Password   |
 | 
				
			||||||
 | 
					|:----------------|:-------------|
 | 
				
			||||||
 | 
					|    `student`    |   `cse320`   |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You will need the password in order to obtain superuser access via `sudo`
 | 
				
			||||||
 | 
					to install software, and you might need to enter both the user name and
 | 
				
			||||||
 | 
					the password if the screen lock should kick in after you have left the VM
 | 
				
			||||||
 | 
					idle for some time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### VirtualBox Guest Additions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The VirtualBox Guest Additions are software components that are added
 | 
				
			||||||
 | 
					to the guest operating system that runs in your VM, to make the VM more
 | 
				
			||||||
 | 
					convenient to use.  Examples of things in the Guest Additions are accelerated
 | 
				
			||||||
 | 
					video drivers, support for clipboard and drag-and-drop between the VM
 | 
				
			||||||
 | 
					and the host system, ability to resize the VM window, and so on.
 | 
				
			||||||
 | 
					There is a version of the Guest Additions installed in the VM,
 | 
				
			||||||
 | 
					but since the Guest Additions need to match the version of VirtualBox
 | 
				
			||||||
 | 
					that you are using, you should reinstall them.  To do this, you should
 | 
				
			||||||
 | 
					start the VM, then from the "Devices" menu (probably in the titlebar of
 | 
				
			||||||
 | 
					the VM window, or wherever top-level application menus appear on your
 | 
				
			||||||
 | 
					system) select "Insert Guest Additions CD Image".  This might cause
 | 
				
			||||||
 | 
					a CD image to be downloaded over the network.  If the system offers to
 | 
				
			||||||
 | 
					auto-run the CD, allow it to do so.  Otherwise you might have to use
 | 
				
			||||||
 | 
					file manager (under Linux Mint) to open the CD manually.  Once started,
 | 
				
			||||||
 | 
					it can take several minutes for the installation to complete.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### VM Snapshots
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you choose to install additional tools or other programs to your
 | 
				
			||||||
 | 
					environment, you may want to take a snapshot of your VM. This may save
 | 
				
			||||||
 | 
					you the time of installing your additional software again, in the
 | 
				
			||||||
 | 
					unfortunate event of an unusable VM. Refer to the appropriate VirtualBox
 | 
				
			||||||
 | 
					documentation to learn how to take a snapshot of your VM.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Option 2: Multi-Boot/Install Linux on your machine
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Remember, if you choose this option, you should have some idea what
 | 
				
			||||||
 | 
					  you are doing, already be comfortable with Linux, and be aware that
 | 
				
			||||||
 | 
					  we probably won't have the resources to debug any issues you might
 | 
				
			||||||
 | 
					  encounter.  If you deviate in any other way from these procedures,
 | 
				
			||||||
 | 
					  it is completely at your peril.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Install [Linux Mint 20 "Ulyana" - Cinnamon 64-bit](https://linuxmint.com/edition.php?id=281)
 | 
				
			||||||
 | 
					or 20.04 Ubuntu variant (as long as you are using gcc 9.3.0) as a dual-boot or fresh
 | 
				
			||||||
 | 
					install.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Clone the [CSE320 course tools](https://gitlab02.cs.stonybrook.edu/cse320/course_tools)
 | 
				
			||||||
 | 
					(https://gitlab02.cs.stonybrook.edu/cse320/course_tools) repository
 | 
				
			||||||
 | 
					into your Linux environment. You may need to install git first.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Follow the README in the `course_tools` repo.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Note about MacOS with Apple M1 Processor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We are aware that a number of students are now using Macs with an M1 processor.
 | 
				
			||||||
 | 
					The M1 hardware uses the ARM instruction set, which is different than the
 | 
				
			||||||
 | 
					x86-64 instruction set which the course Linux Mint VM uses.  At the time of this
 | 
				
			||||||
 | 
					writing, we do not have any reliable information that would indicate that it would
 | 
				
			||||||
 | 
					be possible to run the Linux Mint VM on an M1.  It might be possible to run
 | 
				
			||||||
 | 
					it using QEMU, which is a full x86-64 emulator that is independent of the
 | 
				
			||||||
 | 
					underlying host system hardware and for which versions exist for Macs running
 | 
				
			||||||
 | 
					on the M1, though to date we do not have any information from anyone who has
 | 
				
			||||||
 | 
					succeeded in running the VM this way (please tell us if you have managed to do it).
 | 
				
			||||||
 | 
					However, even if in fact the VM can be run this way it is likely to be very slow.
 | 
				
			||||||
 | 
					So, our best advice at this time would be to try to identify some x86-64-based
 | 
				
			||||||
 | 
					computer that you can use for the course, rather than supposing that you will
 | 
				
			||||||
 | 
					be able to use an M1-based computer.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Working in Unix
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We understand that many of the students taking this class are new to
 | 
				
			||||||
 | 
					CLI (Command-line interface). You can find a quick crash course in
 | 
				
			||||||
 | 
					[Appendix A of Learn Python the Hard Way](https://learnpythonthehardway.org/book/appendixa.html).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: For more advanced usage refer
 | 
				
			||||||
 | 
					  [here](http://www.ibm.com/developerworks/library/l-lpic1-103-1/). This
 | 
				
			||||||
 | 
					  is a REALLY good resource so we recommend bookmarking it for later
 | 
				
			||||||
 | 
					  reference.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: It is **very** important that you properly shut down the Linux Mint
 | 
				
			||||||
 | 
					  operating system when you are finished using it, rather than just
 | 
				
			||||||
 | 
					  "X-ing out" the VirtualBox VM window.  The latter is equivalent to
 | 
				
			||||||
 | 
					  going and yanking your desktop PC's power plug out of the wall without
 | 
				
			||||||
 | 
					  shutting down Windows, and it can cause data loss and even corruption.
 | 
				
			||||||
 | 
					  Use the shutdown icon from the "Mint" menu in the lower left corner
 | 
				
			||||||
 | 
					  of the desktop to shutdown Linux Mint.  At that point, it will be safe
 | 
				
			||||||
 | 
					  to power off the VM.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: Depending on the host system on which you installed VirtualBox,
 | 
				
			||||||
 | 
					  "keyboard integration" and "mouse integration" might or might not be
 | 
				
			||||||
 | 
					  supported.  If they are supported, then you will be able to fairly
 | 
				
			||||||
 | 
					  seamlessly move your mouse in and out of the VM window and what you
 | 
				
			||||||
 | 
					  type on the keyboard will go to the proper place.  If these features
 | 
				
			||||||
 | 
					  are not supported, then you will need to click on the VM window in
 | 
				
			||||||
 | 
					  order to use it, at which point the mouse and keyboard will be "captured"
 | 
				
			||||||
 | 
					  by the VM.  In order to regain control of the mouse and cursor, you
 | 
				
			||||||
 | 
					  will need to press the "host key", which is identified at the right-hand
 | 
				
			||||||
 | 
					  side of the bottom icon tray of the VirtualBox window.  On some systems,
 | 
				
			||||||
 | 
					  the default host key is "Right Ctrl".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: To open a terminal window, you can click on the terminal
 | 
				
			||||||
 | 
					  icon (which should be fairly evident), or you can press CTRL + ALT + T.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Text Editor
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A _good_ basic text editor is the key for C development.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We have pre-installed Sublime Text with plugins such as a C linter to
 | 
				
			||||||
 | 
					assist with C development on the given VM. A linter displays compiler
 | 
				
			||||||
 | 
					errors on top of your code much like an IDE. If you do install another
 | 
				
			||||||
 | 
					editor we recommend looking into a similar feature described as it
 | 
				
			||||||
 | 
					will aid development.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You may use another text editor if you so desire. Some popular ones
 | 
				
			||||||
 | 
					are Atom, Vim, Emacs and VSCode. Each have their own linters that you
 | 
				
			||||||
 | 
					can look into installing.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**DO NOT** install and use a full IDE (Clion, Netbeans, or Eclipse);
 | 
				
			||||||
 | 
					  there are many parts of the compilation process that are hidden from
 | 
				
			||||||
 | 
					  you. Not only would you miss out on valuable information pertinent
 | 
				
			||||||
 | 
					  to the course but your project is not guaranteed to build in an
 | 
				
			||||||
 | 
					  environment separate from the IDE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Homework Management & Submission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Setting up your CSE320 repository
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once your repository has been created on gitlab, you must clone it in
 | 
				
			||||||
 | 
					your Linux environment. Open a new terminal window
 | 
				
			||||||
 | 
					and type `git clone GIT_URL`. You should replace `GIT_URL` with the
 | 
				
			||||||
 | 
					URL to your repository. You can find it by navigating to your projects
 | 
				
			||||||
 | 
					page on GitLab and selecting the https option.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> Your repo should be cloned into your home directory (`/home/student/` or AKA `~/`)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Alternatively if you add an ssh-key to your gitlab account you can
 | 
				
			||||||
 | 
					  clone, pull, push, etc. using the URL under the SSH option (**highly
 | 
				
			||||||
 | 
					  recommended** An SSH key can be done at any time).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  Reference:
 | 
				
			||||||
 | 
					    - [Generating SSH key](http://docs.gitlab.com/ce/ssh/README.html)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### First Commit to your Repo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Open a terminal and from the home directory enter the following command:
 | 
				
			||||||
 | 
					(replacing REPO_NAME with your repo's name)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ subl REPO_NAME
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The text editor, Sublime, will open and your repo's contents will be
 | 
				
			||||||
 | 
					shown on the sidebar. Open the `README.md` file and add the text with
 | 
				
			||||||
 | 
					the following information relevant to you.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```markdown
 | 
				
			||||||
 | 
					# FIRST_NAME LAST_NAME
 | 
				
			||||||
 | 
					## ID_NUMBER
 | 
				
			||||||
 | 
					:FAVORITE_EMOJI:
 | 
				
			||||||
 | 
					PROFESSOR_NAME - SECTION_NUMBER
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can find your favorite emoji code among these
 | 
				
			||||||
 | 
					[https://gist.github.com/rxaviers/7360908](https://gist.github.com/rxaviers/7360908).
 | 
				
			||||||
 | 
					After that you can save and close the file and return to your terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In your terminal, type the following commands, replacing `EMAIL` with
 | 
				
			||||||
 | 
					your CS email address and `NAME` with your name:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git config --global user.email "EMAIL"
 | 
				
			||||||
 | 
					$ git config --global user.name "FIRST_NAME LAST_NAME"
 | 
				
			||||||
 | 
					$ git config --global push.default simple
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					**NOTE:** This will change your settings for all repos.  If you want to
 | 
				
			||||||
 | 
					  have different settings for other repos on your machine then omit
 | 
				
			||||||
 | 
					  `--global`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Change directories into your repo `cd REPO_NAME`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Then run the following commands:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git status
 | 
				
			||||||
 | 
					$ git add README.md
 | 
				
			||||||
 | 
					$ git commit -m "My First Commit"
 | 
				
			||||||
 | 
					$ git push
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> The `git push` command will prompt for username and password if you used HTTPS.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The output will look **similar** to:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git status
 | 
				
			||||||
 | 
					On branch master
 | 
				
			||||||
 | 
					Your branch is up-to-date with 'origin/master'.
 | 
				
			||||||
 | 
					Changes not staged for commit:
 | 
				
			||||||
 | 
					  (use "git add file..." to update what will be committed)
 | 
				
			||||||
 | 
					  (use "git checkout -- file..." to discard changes in working directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    modified:   README.md
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					no changes added to commit (use "git add" and/or "git commit -a")
 | 
				
			||||||
 | 
					$ git add README.md
 | 
				
			||||||
 | 
					$ git commit -m "My First Commit"
 | 
				
			||||||
 | 
					[master XXXXXXX] My First Commit
 | 
				
			||||||
 | 
					 1 files changed, X insertions(+), X deletions(-)
 | 
				
			||||||
 | 
					$ git push
 | 
				
			||||||
 | 
					Counting objects: 4, done.
 | 
				
			||||||
 | 
					Delta compression using up to 4 threads.
 | 
				
			||||||
 | 
					Compressing objects: 100% (4/4), done.
 | 
				
			||||||
 | 
					Writing objects: 100% (4/4), 980 bytes | 0 bytes/s, done.
 | 
				
			||||||
 | 
					Total 4 (delta 2), reused 0 (delta 0)
 | 
				
			||||||
 | 
					To ssh://git@gitlab02.cs.stonybrook.edu:130/CSE320_Fall20/REPONAME.git
 | 
				
			||||||
 | 
					   XXXXXXX..XXXXXXX  master -> master
 | 
				
			||||||
 | 
					Branch master set up to track remote branch master from origin.
 | 
				
			||||||
 | 
					$
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This is the basic usage of git. We check the `status` of which files
 | 
				
			||||||
 | 
					are tracked/untracked. Then we `add` them and we `commit` them along
 | 
				
			||||||
 | 
					with a message. Lastly and most importantly we `push` them to the
 | 
				
			||||||
 | 
					remote repository on the gitlab server. If the push was successful,
 | 
				
			||||||
 | 
					you can navigate back to the page `https://gitlab02.cs.stonybrook.edu`
 | 
				
			||||||
 | 
					and select your repository. Inside your repository, select the files
 | 
				
			||||||
 | 
					option on the left menu. You should now see the file `README.md` with
 | 
				
			||||||
 | 
					the contents you added to it.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :scream: Once a commit has been made, its contents cannot be changed.
 | 
				
			||||||
 | 
					> In addition, the GitLab server has been configured so that it is not
 | 
				
			||||||
 | 
					> possible to delete any commits that have been pushed to the "master"
 | 
				
			||||||
 | 
					> branch.  This means that any junk you commit to the master branch and
 | 
				
			||||||
 | 
					> push to the server will persist there forever in your repo, as well as
 | 
				
			||||||
 | 
					> in copies that we have to store.  In view of this, it is is important that
 | 
				
			||||||
 | 
					> you take great care not to commit junk files, especially files that are
 | 
				
			||||||
 | 
					> very large or binary files that are generated by the compiler.
 | 
				
			||||||
 | 
					> Each time you commit, you should first use `git status` to carefully review
 | 
				
			||||||
 | 
					> the set of files to be committed.  Use `git reset` to remove any files that
 | 
				
			||||||
 | 
					> are staged for commit but should not be.  We strongly recommend that you
 | 
				
			||||||
 | 
					> *never* use commands such as `git add .` or `git add --all`, as these have
 | 
				
			||||||
 | 
					> the potential to add a lot of junk to your commit.  Instead, `git add` each
 | 
				
			||||||
 | 
					> file individually, after perhaps using `git diff` to remind yourself of the
 | 
				
			||||||
 | 
					> reason for the commit and to see if the changes are as they should be.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Git Tutorial
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					We recommend you complete Codecademy’s git tutorial found
 | 
				
			||||||
 | 
					[here](https://www.codecademy.com/learn/learn-git) if you are
 | 
				
			||||||
 | 
					unfamilar with git.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you’re interested in learning more information about git or
 | 
				
			||||||
 | 
					expanding your knowledge, refer to these references:
 | 
				
			||||||
 | 
					- [git-book](https://git-scm.com/book/en/v2) - Chapter 2 is a MUST
 | 
				
			||||||
 | 
					  read chapter, checkout git aliases!
 | 
				
			||||||
 | 
					- [Learn Git Branching](http://learngitbranching.js.org/) - An
 | 
				
			||||||
 | 
					  interactive tutorial on git branching
 | 
				
			||||||
 | 
					- [git cheat sheet](https://scotch.io/bar-talk/git-cheat-sheet)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Homework 0
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Obtaining Assignment Code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Navigate to your repository directory (`cd ~/REPO_NAME`) in your VM
 | 
				
			||||||
 | 
					(using the terminal).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. An assignment, such as this one, will tell you the code is located
 | 
				
			||||||
 | 
					at a particular address. For `hw0` it is:
 | 
				
			||||||
 | 
					`https://gitlab02.cs.stonybrook.edu/cse320/hw0.git`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Add this remote repository as an additional remote into your
 | 
				
			||||||
 | 
					existing repository. We will name the new remote HW0_CODE.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If you use HTTPS:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    $ git remote add HW0_CODE https://gitlab02.cs.stonybrook.edu/cse320/hw0.git
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    If you use SSH:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    $ git remote add HW0_CODE ssh://git@gitlab02.cs.stonybrook.edu:130/cse320/hw0.git
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					4. Fetch all the refs in this new repository. This command will prompt
 | 
				
			||||||
 | 
					for username and password if you used HTTPS.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    $ git fetch HW0_CODE
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					5. Finally, merge and commit the files from the `HW0_CODE` remote's
 | 
				
			||||||
 | 
					`master` branch into your existing repository’s `master` branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    $ git merge -m "Merging HW0_CODE" HW0_CODE/master
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    > :nerd: If you get an error mentioning 'unrelated histories' try
 | 
				
			||||||
 | 
					      again adding this flag: `--allow-unrelated-histories`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					6. If you type the command `ls` you should now see a directory called `hw0`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					7. Push these base files to your remote repository (gitlab). This
 | 
				
			||||||
 | 
					command will prompt for username and password if you used HTTPS.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					    $ git push
 | 
				
			||||||
 | 
					    ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Your Homework 0 Working Directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The directory structure of your repo will now look **similar** to
 | 
				
			||||||
 | 
					this. Use `ls -a` or `tree -a` to see the hidden files that begin with
 | 
				
			||||||
 | 
					`.`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					YOUR_REPO
 | 
				
			||||||
 | 
					├── .git
 | 
				
			||||||
 | 
					│   ├── ...
 | 
				
			||||||
 | 
					├── .gitignore
 | 
				
			||||||
 | 
					├── .gitlab-ci.yml
 | 
				
			||||||
 | 
					├── hw0
 | 
				
			||||||
 | 
					│   ├── academic_honesty.txt
 | 
				
			||||||
 | 
					│   ├── include
 | 
				
			||||||
 | 
					│   │   └── hi.h
 | 
				
			||||||
 | 
					│   ├── Makefile
 | 
				
			||||||
 | 
					│   ├── README.md
 | 
				
			||||||
 | 
					│   ├── src
 | 
				
			||||||
 | 
					│   │   ├── hi.c
 | 
				
			||||||
 | 
					│   │   └── main.c
 | 
				
			||||||
 | 
					│   └── tests
 | 
				
			||||||
 | 
					│       └── test.c
 | 
				
			||||||
 | 
					└── README.md
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Information about each file is explained below.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: Enter `subl REPO_NAME` (or `subl .` if you are in your repo
 | 
				
			||||||
 | 
					  already) as you did before to easily follow along and look inside
 | 
				
			||||||
 | 
					  each file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- `.gitignore` - This is a file that tells git to ignore certain
 | 
				
			||||||
 | 
					  directories or files that you don't want committed. For example, the
 | 
				
			||||||
 | 
					  `bin` and `build` directories are ignored.
 | 
				
			||||||
 | 
					  This is because we don't want executables and other generated binary files
 | 
				
			||||||
 | 
					  pushed to your remote repository, only source code.
 | 
				
			||||||
 | 
					- `.gitlab-ci.yml` This is gitlab's own continuous integration
 | 
				
			||||||
 | 
					  configuration file, explained in a later section.
 | 
				
			||||||
 | 
					- `hw0/` - This is your first homework directory, throughout the
 | 
				
			||||||
 | 
					  semester we'll be adding each homework directory in this fashion
 | 
				
			||||||
 | 
					  'hw#' where # is the homework number. Inside the `hw0/` directory,
 | 
				
			||||||
 | 
					  you will find:
 | 
				
			||||||
 | 
					    - `README.md` - This is a file where you can detail notes about the project.
 | 
				
			||||||
 | 
					    - `Makefile` - This is your ultimate compilation automation
 | 
				
			||||||
 | 
					      tool. The program `make` will use this file to properly compile
 | 
				
			||||||
 | 
					      your assignment.
 | 
				
			||||||
 | 
					    - `include/` - This is where we keep our `.h` headers. Unlike
 | 
				
			||||||
 | 
					      Java, C is a one pass compilation language, which keeps the
 | 
				
			||||||
 | 
					      overhead of creating symbol tables and structures low. Since all
 | 
				
			||||||
 | 
					      functions must be defined before use, we utilize a header file
 | 
				
			||||||
 | 
					      to make the symbols available across multiple files.
 | 
				
			||||||
 | 
					        - `hi.h` - This is our header file for `hw0`. **Examine the
 | 
				
			||||||
 | 
					          contents of this file.**
 | 
				
			||||||
 | 
					    - `src/` - This is where we keep our `.c` source files. These
 | 
				
			||||||
 | 
					      files contain the actual definitions of the functions declared
 | 
				
			||||||
 | 
					      in our headers.
 | 
				
			||||||
 | 
					        - `main.c` - This file contains the C main function, in this
 | 
				
			||||||
 | 
					          course you will **ALWAYS** need to keep your main function
 | 
				
			||||||
 | 
					          in its own C file isolated from the rest of your functions
 | 
				
			||||||
 | 
					          that you implement.
 | 
				
			||||||
 | 
					        - `hi.c` - The helper function, `hi`, is defined (implemented)
 | 
				
			||||||
 | 
					          here. Each function **does not** need its own file, only
 | 
				
			||||||
 | 
					          `main()` needs to be in its own file.
 | 
				
			||||||
 | 
					    - `tests/` - This is where we keep our unit tests. There is an
 | 
				
			||||||
 | 
					      EXCELLENT unit testing framework called
 | 
				
			||||||
 | 
					      [criterion](http://criterion.readthedocs.io/en/master/intro.html)
 | 
				
			||||||
 | 
					      that we will be using in the course.
 | 
				
			||||||
 | 
					        - `test.c` - This file contains the implementation of our
 | 
				
			||||||
 | 
					          testing framework. The Makefile will compile these files
 | 
				
			||||||
 | 
					          with all of the non-`main.c` files. This gives the testing
 | 
				
			||||||
 | 
					          framework access to your helper functions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> **Do not** modify or alter `.gitlab-ci.yml`, the `Makefile` or the
 | 
				
			||||||
 | 
					    `README.md` for any assignment unless otherwise instructed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Academic Honesty Statement
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this course we take Academic Honesty EXTREMELY seriously. Read the
 | 
				
			||||||
 | 
					statement in `academic_honesty.txt` using your favorite text editor or
 | 
				
			||||||
 | 
					using the following command (type `man cat` for more information on
 | 
				
			||||||
 | 
					this tool).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From your repository's root directory type:
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ cat hw0/academic_honesty.txt
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Next, we will append the Academic Honesty Statement into your
 | 
				
			||||||
 | 
					repository's README along with the date and your "signature"
 | 
				
			||||||
 | 
					confirming that you have read the statement and agree with the policy
 | 
				
			||||||
 | 
					and commit it to your repo.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From your repository's root directory type the following commands into
 | 
				
			||||||
 | 
					your terminal, filling in `YOUR_NAME` with the appropriate information
 | 
				
			||||||
 | 
					in the second command.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: The second "crazy" command is an example of redirection which
 | 
				
			||||||
 | 
					  can be done between programs on the command-line. We will learn more
 | 
				
			||||||
 | 
					  about redirection and how it works later in the semester.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ cd hw0
 | 
				
			||||||
 | 
					$ cat academic_honesty.txt <(echo "$(date -u) - YOUR_NAME") >> ../README.md
 | 
				
			||||||
 | 
					$ git add --all
 | 
				
			||||||
 | 
					$ git commit -m "Academic Honesty statement"
 | 
				
			||||||
 | 
					$ git push
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### CI File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This semester we want to ensure that students don't get caught by
 | 
				
			||||||
 | 
					silly mistakes or overlook anything while working on their
 | 
				
			||||||
 | 
					assignments. We will use GitLab's [_Continuous
 | 
				
			||||||
 | 
					Integration_](https://en.wikipedia.org/wiki/Continuous_integration)
 | 
				
			||||||
 | 
					feature to minimize such incidents. It is an automated tool that will
 | 
				
			||||||
 | 
					make sure your work compiles and passes basic tests.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					There is a `.gitlab-ci.yml` file in the base code. This file is used
 | 
				
			||||||
 | 
					to set up a clean vm, compile your code, run your unit tests, and
 | 
				
			||||||
 | 
					lastly run your program on the gitlab server. When looking on gitlab
 | 
				
			||||||
 | 
					you will notice a red :x: or green :heavy_check_mark:. Each represents
 | 
				
			||||||
 | 
					the result of a 'CI pipeline'. Go to the Pipelines tab to view the
 | 
				
			||||||
 | 
					results of your run. We will provide this file with each homework. The
 | 
				
			||||||
 | 
					CI runs when gitlab "gets around" to doing it so don't be alarmed if
 | 
				
			||||||
 | 
					you don't see your result right away.  Also, note that sometimes
 | 
				
			||||||
 | 
					a "Runner System Failure" might occur due to problems on the server.
 | 
				
			||||||
 | 
					A failure reported by CI system does *not* mean that "your commit failed"
 | 
				
			||||||
 | 
					in the sense that what you committed and pushed failed to make it to the
 | 
				
			||||||
 | 
					gitlab server; it means that an error occurred while the system was trying
 | 
				
			||||||
 | 
					to compile and run what you committed.  You can always use the `Repository`
 | 
				
			||||||
 | 
					tab of the gitlab web interface to see what commits you have pushed to the
 | 
				
			||||||
 | 
					server.  If a commit is shown there, then it is safely on the server.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### Hello, World!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the terminal, navigate into the `hw0` folder of your repository
 | 
				
			||||||
 | 
					(ie. `~/REPO_NAME/hw0/`). Open the file `include/hi.h` and examine its
 | 
				
			||||||
 | 
					contents, read the comments, and follow the directions in the
 | 
				
			||||||
 | 
					files. These directions step you through the base files in the HW to
 | 
				
			||||||
 | 
					familiarize you with basic files structure and the included code
 | 
				
			||||||
 | 
					complements.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the terminal, type `make` to build the `hw0` base code. This will
 | 
				
			||||||
 | 
					compile your c code into executables.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ make
 | 
				
			||||||
 | 
					mkdir -p bin build
 | 
				
			||||||
 | 
					gcc build/hi.o build/main.o -o bin/hi
 | 
				
			||||||
 | 
					gcc -Wall -Werror -std=gnu11 -g -DDEBUG -I include build/hi.o tests/test.c -lcriterion -o bin/hi_tests
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					An executable named `hi` and `hi_tests` will be created in the `bin`
 | 
				
			||||||
 | 
					folder of the `hw0` directory.  You can execute either program by
 | 
				
			||||||
 | 
					typing `bin/hi` or `bin/hi_tests` from the `hw0` directory into the
 | 
				
			||||||
 | 
					terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Running `bin/hi` will print "Hello, World!" before exiting.  Running
 | 
				
			||||||
 | 
					`bin/hi_tests` will fail a unit test and print the warning `"Assertion
 | 
				
			||||||
 | 
					failed: say_hi() function did not say 'Hi'"`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ bin/hi
 | 
				
			||||||
 | 
					Hello, World!
 | 
				
			||||||
 | 
					$ bin/hi_tests
 | 
				
			||||||
 | 
					[----] tests/test.c:15: Assertion failed: say_hi() function did not say 'Hi'
 | 
				
			||||||
 | 
					[FAIL] CSE320_Suite::test_it_really_does_say_hi: (0.00s)
 | 
				
			||||||
 | 
					[====] Synthesis: Tested: 1 | Passing: 0 | Failing: 1 | Crashing: 0
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To do this assignment, modify the `say_hi()` function in `src/hi.c` to
 | 
				
			||||||
 | 
					satisfy the unit test (i.e. `return "Hi"`). This is will now make the
 | 
				
			||||||
 | 
					program do what the unit test expects and as a result pass the unit
 | 
				
			||||||
 | 
					test.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Rebuild the hw0 executables by typing in ‘make’ to your terminal. Run
 | 
				
			||||||
 | 
					the program again to make sure it satisfies requirements
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ make
 | 
				
			||||||
 | 
					mkdir -p bin build
 | 
				
			||||||
 | 
					gcc -Wall -Werror -std=gnu11 -g -DDEBUG -I include -c -o build/hi.o src/hi.c
 | 
				
			||||||
 | 
					gcc build/hi.o build/main.o -o bin/hi
 | 
				
			||||||
 | 
					gcc -Wall -Werror -std=gnu11 -g -DDEBUG -I include build/hi.o tests/test.c -lcriterion -o bin/hi_tests
 | 
				
			||||||
 | 
					$ bin/hi
 | 
				
			||||||
 | 
					Hi, World!
 | 
				
			||||||
 | 
					$ bin/hi_tests
 | 
				
			||||||
 | 
					[====] Synthesis: Tested: 1 | Passing: 1 | Failing: 0 | Crashing: 0
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To save your code changes, `add` them to the staging area of
 | 
				
			||||||
 | 
					git. `Commit` the changes to a local commit on your VM. Then `push`
 | 
				
			||||||
 | 
					the commits to the remote server (gitlab).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You can be sure that everything compiles correctly if at some point a
 | 
				
			||||||
 | 
					check appears next to your repo on gitlab.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git status
 | 
				
			||||||
 | 
					On branch master
 | 
				
			||||||
 | 
					Your branch is up-to-date with 'origin/master'.
 | 
				
			||||||
 | 
					Changes not staged for commit:
 | 
				
			||||||
 | 
					  (use "git add file..." to update what will be committed)
 | 
				
			||||||
 | 
					  (use "git checkout -- file..." to discard changes in working directory)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						modified:   src/hi.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					no changes added to commit (use "git add" and/or "git commit -a")
 | 
				
			||||||
 | 
					$ git add src/hi.c
 | 
				
			||||||
 | 
					$ git commit -m "Hi Fix"
 | 
				
			||||||
 | 
					[master XXXXXXX] updated hi.c
 | 
				
			||||||
 | 
					 1 file changed, 1 insertion(+), 1 deletion(-)
 | 
				
			||||||
 | 
					$ git push
 | 
				
			||||||
 | 
					Username for 'https://gitlab02.cs.stonybrook.edu': REPO_NAME
 | 
				
			||||||
 | 
					Password for 'https://REPO_NAME@gitlab02.cs.stonybrook.edu':
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## How to submit with `git submit`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This semester you will be submitting all assignments using our custom
 | 
				
			||||||
 | 
					git command: `git submit`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The usage for `git submit` is:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git submit [-c COMMIT_HASH] TAG
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The **TAG** is which assignment you are tagging, for example: `hw0` or
 | 
				
			||||||
 | 
					`hw1` or `hw2`. This is the format for all tags (with a few
 | 
				
			||||||
 | 
					exceptions) that we will use this semester `hw#` where `#` is the
 | 
				
			||||||
 | 
					assignment number.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `-c` flag is optional. **COMMIT** is the SHA of the commit you
 | 
				
			||||||
 | 
					wish to submit. In case you wanted to submit a different commit than
 | 
				
			||||||
 | 
					your most current one you would just provide the SHA for the commit to
 | 
				
			||||||
 | 
					be submitted. You can view your commit SHAs using the following
 | 
				
			||||||
 | 
					command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> The SHA is the alphanumeric string before the first hyphen.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git log --pretty=format:"%h - %s - %ar"
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					With `git submit`, you may:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Submit your assignment **only** from the master branch.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* The commits that you are submitting must be on the master branch or
 | 
				
			||||||
 | 
					  merged into master (commit hash is on master).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* You may use other branches if you wish, but you cannot use
 | 
				
			||||||
 | 
					  git-submit from these branches.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git submit hw0
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This will submit your latest pushed commit for `hw0`. You can submit
 | 
				
			||||||
 | 
					as many times as you wish prior to any deadline.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#### How to check your submission
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					It creates a special branch in your repo called 'submit'. The only
 | 
				
			||||||
 | 
					reason it is special is that only instructors have permission to push
 | 
				
			||||||
 | 
					to it, hence why you need a special tool to submit your assignment. So
 | 
				
			||||||
 | 
					the submit tool tags the commit that you want to submit and merges
 | 
				
			||||||
 | 
					that commit into the submit branch under an authorized user.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Also, you should see a submission commit on the 'submit' branch. The
 | 
				
			||||||
 | 
					submission commit is a commit with a commit message formatted as
 | 
				
			||||||
 | 
					"<tag-name> submission commit". This you can see by navigating to
 | 
				
			||||||
 | 
					Repository > Commits and selecting the 'submit' branch from the
 | 
				
			||||||
 | 
					dropdown.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you see both of these things, you have successfully submitted the
 | 
				
			||||||
 | 
					assignment. A successfully submitted homework assignment will have a
 | 
				
			||||||
 | 
					tag for that particular homework which you can see if you go to your
 | 
				
			||||||
 | 
					project in Gitlab and navigate to Repository > Tags.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					---------------------------------------------
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					These are the tools and the dev environment you will be working with
 | 
				
			||||||
 | 
					for the rest of the semester. We have provided you with these tools to
 | 
				
			||||||
 | 
					ease the protocols of this course and prevent mishaps from
 | 
				
			||||||
 | 
					occurring.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					So that you do not delay your ability to start on `hw1`, you should make
 | 
				
			||||||
 | 
					every effort to complete the steps above by **February 4, 2022**, 11:59PM.
 | 
				
			||||||
 | 
					After that date it will no longer be possible to `git submit hw0`,
 | 
				
			||||||
 | 
					however you should still make the commits to your repository described
 | 
				
			||||||
 | 
					above prior to submitting `hw1`.
 | 
				
			||||||
 | 
					Although `hw0` will not be formally scored and weighted into the final grade
 | 
				
			||||||
 | 
					calculations, you will not receive credit for any other assignments
 | 
				
			||||||
 | 
					in this course unless the signed Academic Honesty statement has previously
 | 
				
			||||||
 | 
					been committed to your repository and thereby incorporated into the
 | 
				
			||||||
 | 
					submissions for those assignments.
 | 
				
			||||||
							
								
								
									
										
											BIN
										
									
								
								hw1-doc/ECMA-404_2nd_edition_december_2017.pdf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								hw1-doc/ECMA-404_2nd_edition_december_2017.pdf
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							
							
								
								
									
										1196
									
								
								hw1-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1196
									
								
								hw1-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										1168
									
								
								hw2-doc/DebuggingRef.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1168
									
								
								hw2-doc/DebuggingRef.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										420
									
								
								hw2-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										420
									
								
								hw2-doc/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,420 @@
 | 
				
			||||||
 | 
					# Homework 2 Debugging and Fixing - CSE 320 - Spring 2022
 | 
				
			||||||
 | 
					#### Professor Eugene Stark
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### **Due Date: Friday 3/4/2022 @ 11:59pm**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Introduction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In this assignment you are tasked with updating an old piece of
 | 
				
			||||||
 | 
					software, making sure it compiles, and that it works properly
 | 
				
			||||||
 | 
					in your VM environment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Maintaining old code is a chore and an often hated part of software
 | 
				
			||||||
 | 
					engineering. It is definitely one of the aspects which are seldom
 | 
				
			||||||
 | 
					discussed or thought about by aspiring computer science students.
 | 
				
			||||||
 | 
					However, it is prevalent throughout industry and a worthwhile skill to
 | 
				
			||||||
 | 
					learn.  Of course, this homework will not give you a remotely
 | 
				
			||||||
 | 
					realistic experience in maintaining legacy code or code left behind by
 | 
				
			||||||
 | 
					previous engineers but it still provides a small taste of what the
 | 
				
			||||||
 | 
					experience may be like.  You are to take on the role of an engineer
 | 
				
			||||||
 | 
					whose supervisor has asked you to correct all the errors in the
 | 
				
			||||||
 | 
					program, plus add additional functionality.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					By completing this homework you should become more familiar
 | 
				
			||||||
 | 
					with the C programming language and develop an understanding of:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					- How to use tools such as `gdb` and `valgrind` for debugging C code.
 | 
				
			||||||
 | 
					- Modifying existing C code.
 | 
				
			||||||
 | 
					- C memory management and pointers.
 | 
				
			||||||
 | 
					- Working with files and the C standard I/O library.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## The Existing Program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Your goal will be to debug and extend an old program called `par`,
 | 
				
			||||||
 | 
					which was written by Adam M. Costello and posted to Usenet in 1993.
 | 
				
			||||||
 | 
					I have rearranged the original source code and re-written the `Makefile`
 | 
				
			||||||
 | 
					to conform to the format we are using for the assignments in this course.
 | 
				
			||||||
 | 
					Besides a bug that was present in the original version, I have introduced
 | 
				
			||||||
 | 
					a few additional bugs here and there to make things more interesting
 | 
				
			||||||
 | 
					and educational for you :wink:.
 | 
				
			||||||
 | 
					Although you will need to correct these bugs in order to make the program
 | 
				
			||||||
 | 
					function, they do not otherwise change the program behavior from what
 | 
				
			||||||
 | 
					the author intended.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `par` program is a simple paragraph reformatter.  It is basically
 | 
				
			||||||
 | 
					designed to read text from the standard input, parse the text into
 | 
				
			||||||
 | 
					paragraphs, which are delimited by empty lines, chop each paragraph up
 | 
				
			||||||
 | 
					into a sequence of words (forgetting about the original line breaks),
 | 
				
			||||||
 | 
					choose new line breaks to optimize some criteria that are designed to
 | 
				
			||||||
 | 
					produce a pleasing result, and the finally output the paragraph with
 | 
				
			||||||
 | 
					the new line breaks.  There are several parameters that can be set
 | 
				
			||||||
 | 
					which affect the result:  the width of the output text, the length of
 | 
				
			||||||
 | 
					a "prefix" and a "suffix" to be prepended and appended to each output line,
 | 
				
			||||||
 | 
					a parameter "hang", which affects the default value of "prefix", and
 | 
				
			||||||
 | 
					a boolean parameter "last", which affects the way the last line of a
 | 
				
			||||||
 | 
					paragraph is treated.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					What you have to do is to first get the program to compile (for the most part,
 | 
				
			||||||
 | 
					I did not modify the original code, which requires some changes for it
 | 
				
			||||||
 | 
					to compile cleanly with the compiler and settings we are using).
 | 
				
			||||||
 | 
					Then, you need to test the program and find and fix the bugs that prevent it
 | 
				
			||||||
 | 
					from functioning properly.  Some of the bugs existed in the original version and
 | 
				
			||||||
 | 
					some I introduced for the purposes of this assignment.
 | 
				
			||||||
 | 
					Finally, you will make some modifications to the program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					As you work on the program, limit the changes you make to the minimum necessary
 | 
				
			||||||
 | 
					to achieve the specified objectives.  Don't rewrite the program;
 | 
				
			||||||
 | 
					assume that it is essentially correct and just fix a few compilation errors and
 | 
				
			||||||
 | 
					bugs as described below.  You will likely find it helpful to use `git` for this (I did).
 | 
				
			||||||
 | 
					Make exploratory changes first on a side branch (*i.e.* not the master branch),
 | 
				
			||||||
 | 
					then when you think you have understood the proper changes that need to be made,
 | 
				
			||||||
 | 
					go back and apply those changes to the master branch.  Using `git` will help you
 | 
				
			||||||
 | 
					to back up if you make changes that mess something up.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Getting Started - Obtain the Base Code
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Fetch base code for `hw2` as you did for the previous assignments.
 | 
				
			||||||
 | 
					You can find it at this link:
 | 
				
			||||||
 | 
					[https://gitlab02.cs.stonybrook.edu/cse320/hw2](https://gitlab02.cs.stonybrook.edu/cse320/hw2).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Once again, to avoid a merge conflict with respect to the file `.gitlab-ci.yml`,
 | 
				
			||||||
 | 
					use the following command to merge the commits:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					  git merge -m "Merging HW2_CODE" HW2_CODE/master --strategy-option=theirs
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :nerd: I hope that by now you would have read some `git` documentation to find
 | 
				
			||||||
 | 
					  > out what the `--strategy-option=theirs` does, but in case you didn't :angry:
 | 
				
			||||||
 | 
					  > I will say that merging in `git` applies a "strategy" (the default strategy
 | 
				
			||||||
 | 
					  > is called "recursive", I believe) and `--strategy-option` allows an option
 | 
				
			||||||
 | 
					  > to be passed to the strategy to modify its behavior.  In this case, `theirs`
 | 
				
			||||||
 | 
					  > means that whenever a conflict is found, the version of the file from
 | 
				
			||||||
 | 
					  > the branch being merged (in this case `HW2_CODE/master`) is to be used in place
 | 
				
			||||||
 | 
					  > of the version from the currently checked-out branch.  An alternative to
 | 
				
			||||||
 | 
					  > `theirs` is `ours`, which makes the opposite choice.  If you don't specify
 | 
				
			||||||
 | 
					  > one of these options, `git` will leave conflict indications in the file itself
 | 
				
			||||||
 | 
					  > and it will be necessary for you to edit the file and choose the code you want
 | 
				
			||||||
 | 
					  > to use for each of the indicated conflicts.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is the structure of the base code:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					.
 | 
				
			||||||
 | 
					├── .gitlab-ci.yml
 | 
				
			||||||
 | 
					└── hw2
 | 
				
			||||||
 | 
					    ├── doc
 | 
				
			||||||
 | 
					    │   ├── par.1
 | 
				
			||||||
 | 
					    │   ├── par.doc
 | 
				
			||||||
 | 
					    │   └── protoMakefile
 | 
				
			||||||
 | 
					    ├── hw2.sublime-project
 | 
				
			||||||
 | 
					    ├── include
 | 
				
			||||||
 | 
					    │   ├── buffer.h
 | 
				
			||||||
 | 
					    │   ├── debug.h
 | 
				
			||||||
 | 
					    │   ├── errmsg.h
 | 
				
			||||||
 | 
					    │   └── reformat.h
 | 
				
			||||||
 | 
					    ├── Makefile
 | 
				
			||||||
 | 
					    ├── rsrc
 | 
				
			||||||
 | 
					    │   ├── banner.txt
 | 
				
			||||||
 | 
					    │   ├── gettysburg.txt
 | 
				
			||||||
 | 
					    │   └── loremipsum.txt
 | 
				
			||||||
 | 
					    ├── src
 | 
				
			||||||
 | 
					    │   ├── buffer.c
 | 
				
			||||||
 | 
					    │   ├── errmsg.c
 | 
				
			||||||
 | 
					    │   ├── main.c
 | 
				
			||||||
 | 
					    │   ├── par.c
 | 
				
			||||||
 | 
					    │   └── reformat.c
 | 
				
			||||||
 | 
					    ├── test_output
 | 
				
			||||||
 | 
					    │   └── .git-keep
 | 
				
			||||||
 | 
					    └── tests
 | 
				
			||||||
 | 
					        ├── basecode_tests.c
 | 
				
			||||||
 | 
					        ├── rsrc
 | 
				
			||||||
 | 
					        │   ├── banner.txt
 | 
				
			||||||
 | 
					        │   ├── basic.in -> gettysburg.txt
 | 
				
			||||||
 | 
					        │   ├── basic.out
 | 
				
			||||||
 | 
					        │   ├── blank_lines.txt
 | 
				
			||||||
 | 
					        │   ├── EOF.in
 | 
				
			||||||
 | 
					        │   ├── EOF.out
 | 
				
			||||||
 | 
					        │   ├── gettysburg.txt
 | 
				
			||||||
 | 
					        │   ├── loremipsum.txt
 | 
				
			||||||
 | 
					        │   ├── prefix_suffix.in -> banner.txt
 | 
				
			||||||
 | 
					        │   ├── prefix_suffix.out
 | 
				
			||||||
 | 
					        │   ├── valgrind_leak.in -> gettysburg.txt
 | 
				
			||||||
 | 
					        │   ├── valgrind_leak.out
 | 
				
			||||||
 | 
					        │   ├── valgrind_uninitialized.err
 | 
				
			||||||
 | 
					        │   ├── valgrind_uninitialized.in -> loremipsum.txt
 | 
				
			||||||
 | 
					        │   └── valgrind_uninitialized.out
 | 
				
			||||||
 | 
					        ├── test_common.c
 | 
				
			||||||
 | 
					        └── test_common.h
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `src` directory contains C source code files `buffer.c`. `par.c`, `reformat.c`,
 | 
				
			||||||
 | 
					and `errmsg.c`, which were part of the original code.  In addition, I have added
 | 
				
			||||||
 | 
					a new file `main.c`, with a single `main()` function that simply calls
 | 
				
			||||||
 | 
					`original_main()` in `par.c`.  This is to satisfy our requirement (for Criterion)
 | 
				
			||||||
 | 
					that `main()` is the only function in `main.c`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `include` directory contains C header files `buffer.h`, `reformat.h`, and
 | 
				
			||||||
 | 
					`errmsg.h`, which were part of the original source code.  I have also added our
 | 
				
			||||||
 | 
					`debug.h` header file which may be of use to you.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `doc` directory contains documentation files that were part of the original
 | 
				
			||||||
 | 
					distribution of `par`.  The file `par.1` is in the format traditionally used
 | 
				
			||||||
 | 
					for Unix manual pages.  This file `par.` is intended to be processed with the
 | 
				
			||||||
 | 
					the formatting program `nroff` with argument `-man`; for example:
 | 
				
			||||||
 | 
					`nroff -man doc/par.1 | less` could be used to format and view its contents.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `tests` directory contains C source code (in file `basecode_tests.c`) for some Criterion
 | 
				
			||||||
 | 
					tests that can help guide you toward bugs in the program.  These are not guaranteed
 | 
				
			||||||
 | 
					to be complete or exhaustive.  The `test_common.c` and `test_common.h` contain auxiliary code
 | 
				
			||||||
 | 
					used by the tests.  The subdirectory `tests/rsrc` contains input files and reference output files
 | 
				
			||||||
 | 
					that are used by the tests.
 | 
				
			||||||
 | 
					The `par` program was not designed to be particularly conducive to unit testing,
 | 
				
			||||||
 | 
					so all the tests we will make (including the tests used in grading) will be so-called
 | 
				
			||||||
 | 
					"black box" tests, which test the input-output behavior of the program running as a
 | 
				
			||||||
 | 
					separate process from the test driver.
 | 
				
			||||||
 | 
					The `test_common.c` file contains helper functions for launching an instance of `par`
 | 
				
			||||||
 | 
					as a separate process, redirecting `stdin` from an input file, collecting the
 | 
				
			||||||
 | 
					output produced on `stdout` and `stderr`, checking the exit status of the program,
 | 
				
			||||||
 | 
					and comparing the output against reference output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `test_output` directory is a "dummy" directory which is used to hold the output
 | 
				
			||||||
 | 
					produced when you run the Criterion tests.  Look there if you want to understand,
 | 
				
			||||||
 | 
					for example, why the tests reported that the output produced by your program was
 | 
				
			||||||
 | 
					not as expected.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Before you begin work on this assignment, you should read the rest of this
 | 
				
			||||||
 | 
					document.  In addition, we additionally advise you to read the
 | 
				
			||||||
 | 
					[Debugging Document](DebuggingRef.md).  One of the main goals of this assignment
 | 
				
			||||||
 | 
					is to get you to learn how to use the `gdb` debugger, so you should right away
 | 
				
			||||||
 | 
					be looking into how to use this while working on the tasks in the following sections.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Part 1: Debugging and Fixing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You are to complete the following steps:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					1. Clean up the code; fixing any compilation issues, so that it compiles
 | 
				
			||||||
 | 
					   without error using the compiler options that have been set for you in
 | 
				
			||||||
 | 
					   the `Makefile`.
 | 
				
			||||||
 | 
					   Use `git` to keep track of the changes you make and the reasons for them, so that you can
 | 
				
			||||||
 | 
					   later review what you have done and also so that you can revert any changes you made that
 | 
				
			||||||
 | 
					   don't turn out to be a good idea in the end.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					2. Fix bugs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Run the program, exercising the various options, and look for cases in which the program
 | 
				
			||||||
 | 
					    crashes or otherwise misbehaves in an obvious way.  We are only interested in obvious
 | 
				
			||||||
 | 
					    misbehavior here; don't agonize over program behavior that might just have been the choice
 | 
				
			||||||
 | 
					    of the original author.  You should use the provided Criterion tests to help point the way,
 | 
				
			||||||
 | 
						though they are not guaranteed to be exhaustive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					3. Use `valgrind` to identify any memory leaks or other memory access errors.
 | 
				
			||||||
 | 
					   Fix any errors you find.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Run `valgrind` using a command of the following form:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    <pre>
 | 
				
			||||||
 | 
					      $ valgrind --leak-check=full --show-leak-kinds=all --undef-value-errors=yes [PAR PROGRAM AND ARGS]
 | 
				
			||||||
 | 
					    </pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    Note that the bugs that are present will all manifest themselves in some way
 | 
				
			||||||
 | 
					    either as incorrect output, program crashes or as memory errors that can be
 | 
				
			||||||
 | 
						detected by `valgrind`.  It is not necessary to go hunting for obscure issues
 | 
				
			||||||
 | 
						with the program output.
 | 
				
			||||||
 | 
					    Also, do not make gratuitous changes to the program output, as this will
 | 
				
			||||||
 | 
					    interfere with our ability to test your code.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   > :scream:  The author of this program was pretty fastidious about freeing memory before
 | 
				
			||||||
 | 
					   > exiting the program.  Once you have fixed the bugs, the program should exit without
 | 
				
			||||||
 | 
					   > any type of memory leak reported by `valgrind`, including memory that is "still reachable"
 | 
				
			||||||
 | 
					   > at the time of exit.  "Still reachable" memory corresponds to memory that is in use
 | 
				
			||||||
 | 
					   > when the program exits and can still be reached by following pointers from variables
 | 
				
			||||||
 | 
					   > in the program.  Although some people consider it to be untidy for a program
 | 
				
			||||||
 | 
					   > to exit with "still reachable" memory, it doesn't cause any particular problem.
 | 
				
			||||||
 | 
					   > For the present program, however, there should not be any "still reachable" memory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   > :scream: You are **NOT** allowed to share or post on PIAZZA
 | 
				
			||||||
 | 
					   > solutions to the bugs in this program, as this defeats the point of
 | 
				
			||||||
 | 
					   > the assignment. You may provide small hints in the right direction,
 | 
				
			||||||
 | 
					   > but nothing more.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Part 2: Changes to the Program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Rewrite/Extend Options Processing
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The basecode version of `par` performs its own *ad hoc* processing of command-line options.
 | 
				
			||||||
 | 
					This is likely due to the fact that there did not exist a commonly accepted library
 | 
				
			||||||
 | 
					package for performing this function at the time the program was written.
 | 
				
			||||||
 | 
					However, as options processing is a common function that is performed by most programs,
 | 
				
			||||||
 | 
					and it is desirable for programs on the same system to be consistent in how they interpret
 | 
				
			||||||
 | 
					their arguments, there have been more elaborate standardized libraries that have been written
 | 
				
			||||||
 | 
					for this purpose.  In particular, the POSIX standard specifies a `getopt()` function,
 | 
				
			||||||
 | 
					which you can read about by typing `man 3 getopt`.  A significant advantage to using a
 | 
				
			||||||
 | 
					standard library function like `getopt()` for processing command-line arguments,
 | 
				
			||||||
 | 
					rather than implementing *ad hoc* code to do it, is that all programs that use
 | 
				
			||||||
 | 
					the standard function will perform argument processing in the same way
 | 
				
			||||||
 | 
					rather than having each program implement its own quirks that the user has to remember.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For this part of the assignment, you are to replace the original argument-processing
 | 
				
			||||||
 | 
					code in `main()` by code that uses the GNU `getopt` library package.
 | 
				
			||||||
 | 
					In addition to the POSIX standard `getopt()` function, the GNU `getopt` package
 | 
				
			||||||
 | 
					provides a function `getopt_long()` that understands "long forms" of option
 | 
				
			||||||
 | 
					arguments in addition to the traditional single-letter options.
 | 
				
			||||||
 | 
					In your revised program, `main()` should use `getopt_long()` to traverse the
 | 
				
			||||||
 | 
					command-line arguments, and it should support the following option syntax
 | 
				
			||||||
 | 
					(in place of what was originally used by the program):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `--version` (long form only):
 | 
				
			||||||
 | 
					    Print the version number of the program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-w WIDTH` (short form) or `--width WIDTH` (long form):
 | 
				
			||||||
 | 
					    Set the output paragraph width to `WIDTH`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-p PREFIX` (short form) or `--prefix PREFIX` (long form):
 | 
				
			||||||
 | 
					    Set the value of the "prefix" parameter to `PREFIX`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-s SUFFIX` (short form) or `--suffix SUFFIX` (long form):
 | 
				
			||||||
 | 
					    Set the value of the "suffix" parameter to `SUFFIX`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-h HANG` (short form) or `--hang HANG` (long form):
 | 
				
			||||||
 | 
					    Set the value of the "hang" parameter to `HANG`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-l LAST` (short form) or either `--last` or
 | 
				
			||||||
 | 
					    `--no-last` (long form):
 | 
				
			||||||
 | 
					    Set the value of the boolean "last" parameter.
 | 
				
			||||||
 | 
					   For the short form, the values allowed for `LAST` should be either
 | 
				
			||||||
 | 
					   `0` or `1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  - `-m MIN` (short form) or either `--min` or `--no-min` (long form).
 | 
				
			||||||
 | 
					   Set the value of the boolean "min" parameter.
 | 
				
			||||||
 | 
					   For the short form, the values allowed for `MIN` should be either
 | 
				
			||||||
 | 
					   `0` or `1`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					You will probably need to read the Linux "man page" on the `getopt` package.
 | 
				
			||||||
 | 
					This can be accessed via the command `man 3 getopt`.  If you need further information,
 | 
				
			||||||
 | 
					search for "GNU getopt documentation" on the Web.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :scream: You MUST use the `getopt_long()` function to process the command line
 | 
				
			||||||
 | 
					> arguments passed to the program.  Your program should be able to handle cases where
 | 
				
			||||||
 | 
					> the (non-positional) flags are passed IN ANY order.  Make sure that you test the
 | 
				
			||||||
 | 
					> program with prefixes of the long option names, as well as the full names.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Revise the Error Message Scheme
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The original program uses a very *ad hoc* scheme for error-message reporting:
 | 
				
			||||||
 | 
					if an error occurs, a string describing the error is stored into a global
 | 
				
			||||||
 | 
					character array `errmsg` with a hard-coded maximum size.  (This hard-coded
 | 
				
			||||||
 | 
					size has an occurrence in the `fprintf()` format string in `par.c`,
 | 
				
			||||||
 | 
					which creates undesirable implicit coupling between `par.c` and `errmsg.c`.)
 | 
				
			||||||
 | 
					At various points in the program, the existence of an error condition is checked
 | 
				
			||||||
 | 
					by looking to see if the first character of the error message string is a null
 | 
				
			||||||
 | 
					character `'\0'`.  Before the program terminates, if an error message exists,
 | 
				
			||||||
 | 
					then it is printed and the program exits with an error status, otherwise it exits
 | 
				
			||||||
 | 
					with a success indication.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Your job is to revise the error message scheme to make it somewhat more general
 | 
				
			||||||
 | 
					and to eliminate the hard-coded limitation on the length of an error message.
 | 
				
			||||||
 | 
					In particular, you should replace the interface defined in `errmsg.h` by the
 | 
				
			||||||
 | 
					following function prototypes (exactly as shown):
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```c
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Set an error indication, with a specified error message.
 | 
				
			||||||
 | 
					 * @param msg Pointer to the error message.  The string passed by the caller
 | 
				
			||||||
 | 
					 * will be copied.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void set_error(char *msg);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Test whether there is currently an error indication.
 | 
				
			||||||
 | 
					 * @return 1 if an error indication currently exists, 0 otherwise.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int is_error();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * @brief  Issue any existing error message to the specified output stream.
 | 
				
			||||||
 | 
					 * @param file  Stream to which the error message is to be issued.  
 | 
				
			||||||
 | 
					 * @return 0 if either there was no existing error message, or else there
 | 
				
			||||||
 | 
					 * was an existing error message and it was successfully output.
 | 
				
			||||||
 | 
					 * Return non-zero if the attempt to output an existing error message
 | 
				
			||||||
 | 
					 * failed.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					int report_error(FILE *file);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * Clear any existing error indication and free storage occupied by
 | 
				
			||||||
 | 
					 * any existing error message.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					void clear_error();
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The global array `errmsg` should be removed from `errmsg.h` and replaced
 | 
				
			||||||
 | 
					by a pointer variable declared as `static char *` in `errmsg.c`.
 | 
				
			||||||
 | 
					The functions whose prototypes are given above should be implemented so
 | 
				
			||||||
 | 
					that there is no fixed maximum imposed on the length of an error message.
 | 
				
			||||||
 | 
					This means that error messages should be dynamically allocated on the
 | 
				
			||||||
 | 
					heap (for example, using `strdup()`).  The implementation should take care
 | 
				
			||||||
 | 
					not to leak any memory used for error messages; for example if a new error
 | 
				
			||||||
 | 
					message is set when one already exists.  Before exiting, the program should
 | 
				
			||||||
 | 
					call `clear_error()` to cause any existing error message to be freed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Part 3: Testing the Program
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					For this assignment, you have been provided with a basic set of
 | 
				
			||||||
 | 
					Criterion tests to help you debug the program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					In the `tests/basecode_tests.c` file, there are five test examples.
 | 
				
			||||||
 | 
					You can run these with the following command:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					    $ bin/par_tests
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To obtain more information about each test run, you can supply the
 | 
				
			||||||
 | 
					additional option `--verbose=1`.
 | 
				
			||||||
 | 
					You can also specify the option `-j1` to cause the tests to be run sequentially,
 | 
				
			||||||
 | 
					rather than in parallel using multiple processes, as is the default.
 | 
				
			||||||
 | 
					The `-j1` flag is necessary if the tests could interfere with each other in
 | 
				
			||||||
 | 
					some way if they are run in parallel (such as writing the same output file).
 | 
				
			||||||
 | 
					You will probably find it useful to know this; however the basecode tests have
 | 
				
			||||||
 | 
					been written so that they each use output files named after the test and
 | 
				
			||||||
 | 
					(hopefully) will not interfere with each other.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The tests have been constructed so that they will point you at most of the
 | 
				
			||||||
 | 
					problems with the program.
 | 
				
			||||||
 | 
					Each test has one or more assertions to make sure that the code functions
 | 
				
			||||||
 | 
					properly.  If there was a problem before an assertion, such as a "segfault",
 | 
				
			||||||
 | 
					the test will print the error to the screen and continue to run the
 | 
				
			||||||
 | 
					rest of the tests.
 | 
				
			||||||
 | 
					The basecode test cases check the program operation by reading input from
 | 
				
			||||||
 | 
					a pre-defined input file, redirecting `stdout` and `stderr` to output files,
 | 
				
			||||||
 | 
					and comparing the output produced against pre-defined reference files.
 | 
				
			||||||
 | 
					Some of the tests use `valgrind` to verify that no memory errors are found.
 | 
				
			||||||
 | 
					If errors are found, then you can look at the log file that is left behind
 | 
				
			||||||
 | 
					(in the `test_output` directory) by the test code.
 | 
				
			||||||
 | 
					Alternatively, you can better control the information that `valgrind` provides
 | 
				
			||||||
 | 
					if you run it manually.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The tests included in the base code are not true "unit tests", because they all
 | 
				
			||||||
 | 
					run the program as a black box using `system()`.
 | 
				
			||||||
 | 
					You should be able to follow the pattern to construct some additional tests of
 | 
				
			||||||
 | 
					your own, and you might find this helpful while working on the program.
 | 
				
			||||||
 | 
					You are encouraged to try to write some of these tests so that you learn how
 | 
				
			||||||
 | 
					to do it.  Note that in the next homework assignment unit tests will likely
 | 
				
			||||||
 | 
					be very helpful to you and you will be required to write some of your own.
 | 
				
			||||||
 | 
					Criterion documentation for writing your own tests can be found
 | 
				
			||||||
 | 
					[here](http://criterion.readthedocs.io/en/master/).
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream: Be sure that you test non-default program options to make sure that
 | 
				
			||||||
 | 
					  > the program does not crash or otherwise misbehave when they are used.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Hand-in Instructions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Ensure that all files you expect to be on your remote repository are committed
 | 
				
			||||||
 | 
					and pushed prior to submission.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This homework's tag is: `hw2`
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					$ git submit hw2
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
							
								
								
									
										1079
									
								
								hw3-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1079
									
								
								hw3-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										621
									
								
								hw4-doc/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										621
									
								
								hw4-doc/README.md
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,621 @@
 | 
				
			||||||
 | 
					# Homework 4 Scripting Language - CSE 320 - Spring 2022
 | 
				
			||||||
 | 
					#### Professor Eugene Stark
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### **Due Date: Friday 4/15/2022 @ 11:59pm**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Introduction
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The goal of this assignment is to become familiar with low-level Unix/POSIX system
 | 
				
			||||||
 | 
					calls related to processes, signal handling, files, and I/O redirection.
 | 
				
			||||||
 | 
					You will implement an interpreter, called `mush`, for a simple scripting language
 | 
				
			||||||
 | 
					that is capable of managing multiple concurrently executing "jobs".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Takeaways
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					After completing this assignment, you should:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* Understand process execution: forking, executing, and reaping.
 | 
				
			||||||
 | 
					* Understand signal handling.
 | 
				
			||||||
 | 
					* Understand the use of "dup" to perform I/O redirection.
 | 
				
			||||||
 | 
					* Have a more advanced understanding of Unix commands and the command line.
 | 
				
			||||||
 | 
					* Have gained experience with C libraries and system calls.
 | 
				
			||||||
 | 
					* Have enhanced your C programming abilities.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Hints and Tips
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					* We **strongly recommend** that you check the return codes of **all** system calls
 | 
				
			||||||
 | 
					  and library functions.  This will help you catch errors.
 | 
				
			||||||
 | 
					* **BEAT UP YOUR OWN CODE!** Use a "monkey at a typewriter" approach to testing it
 | 
				
			||||||
 | 
					  and make sure that no sequence of operations, no matter how ridiculous it may
 | 
				
			||||||
 | 
					  seem, can crash the program.
 | 
				
			||||||
 | 
					* Your code should **NEVER** crash, and we will deduct points every time your
 | 
				
			||||||
 | 
					  program crashes during grading.  Especially make sure that you have avoided
 | 
				
			||||||
 | 
					  race conditions involving process termination and reaping that might result
 | 
				
			||||||
 | 
					  in "flaky" behavior.  If you notice odd behavior you don't understand:
 | 
				
			||||||
 | 
					  **INVESTIGATE**.
 | 
				
			||||||
 | 
					* You should use the `debug` macro provided to you in the base code.
 | 
				
			||||||
 | 
					  That way, when your program is compiled without `-DDEBUG`, all of your debugging
 | 
				
			||||||
 | 
					  output will vanish, preventing you from losing points due to superfluous output.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: When writing your program, try to comment as much as possible and stay
 | 
				
			||||||
 | 
					> consistent with code formatting.  Keep your code organized, and don't be afraid
 | 
				
			||||||
 | 
					> to introduce new source files if/when appropriate.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Reading Man Pages
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					This assignment will involve the use of many system calls and library functions
 | 
				
			||||||
 | 
					that you probably haven't used before.
 | 
				
			||||||
 | 
					As such, it is imperative that you become comfortable looking up function
 | 
				
			||||||
 | 
					specifications using the `man` command.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `man` command stands for "manual" and takes the name of a function or command
 | 
				
			||||||
 | 
					(programs) as an argument.
 | 
				
			||||||
 | 
					For example, if I didn't know how the `fork(2)` system call worked, I would type
 | 
				
			||||||
 | 
					`man fork` into my terminal.
 | 
				
			||||||
 | 
					This would bring up the manual for the `fork(2)` system call.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :nerd: Navigating through a man page once it is open can be weird if you're not
 | 
				
			||||||
 | 
					> familiar with these types of applications.
 | 
				
			||||||
 | 
					> To scroll up and down, you simply use the **up arrow key** and **down arrow key**
 | 
				
			||||||
 | 
					> or **j** and **k**, respectively.
 | 
				
			||||||
 | 
					> To exit the page, simply type **q**.
 | 
				
			||||||
 | 
					> That having been said, long `man` pages may look like a wall of text.
 | 
				
			||||||
 | 
					> So it's useful to be able to search through a page.
 | 
				
			||||||
 | 
					> This can be done by typing the **/** key, followed by your search phrase,
 | 
				
			||||||
 | 
					> and then hitting **enter**.
 | 
				
			||||||
 | 
					> Note that man pages are displayed with a program known as `less`.
 | 
				
			||||||
 | 
					> For more information about navigating the `man` pages with `less`,
 | 
				
			||||||
 | 
					> run `man less` in your terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Now, you may have noticed the `2` in `fork(2)`.
 | 
				
			||||||
 | 
					This indicates the section in which the `man` page for `fork(2)` resides.
 | 
				
			||||||
 | 
					Here is a list of the `man` page sections and what they are for.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					| Section          | Contents                                |
 | 
				
			||||||
 | 
					| ----------------:|:--------------------------------------- |
 | 
				
			||||||
 | 
					| 1                | User Commands (Programs)                |
 | 
				
			||||||
 | 
					| 2                | System Calls                            |
 | 
				
			||||||
 | 
					| 3                | C Library Functions                     |
 | 
				
			||||||
 | 
					| 4                | Devices and Special Files               |
 | 
				
			||||||
 | 
					| 5                | File Formats and Conventions            |
 | 
				
			||||||
 | 
					| 6                | Games, et al                            |
 | 
				
			||||||
 | 
					| 7                | Miscellanea                             |
 | 
				
			||||||
 | 
					| 8                | System Administration Tools and Daemons |
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					From the table above, we can see that `fork(2)` belongs to the system call section
 | 
				
			||||||
 | 
					of the `man` pages.
 | 
				
			||||||
 | 
					This is important because there are functions like `printf` which have multiple
 | 
				
			||||||
 | 
					entries in different sections of the `man` pages.
 | 
				
			||||||
 | 
					If you type `man printf` into your terminal, the `man` program will start looking
 | 
				
			||||||
 | 
					for that name starting from section 1.
 | 
				
			||||||
 | 
					If it can't find it, it'll go to section 2, then section 3 and so on.
 | 
				
			||||||
 | 
					However, there is actually a Bash user command called `printf`, so instead of getting
 | 
				
			||||||
 | 
					the `man` page for the `printf(3)` function which is located in `stdio.h`,
 | 
				
			||||||
 | 
					we get the `man` page for the Bash user command `printf(1)`.
 | 
				
			||||||
 | 
					If you specifically wanted the function from section 3 of the `man` pages,
 | 
				
			||||||
 | 
					you would enter `man 3 printf` into your terminal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					> :scream: Remember this: **`man` pages are your bread and butter**.
 | 
				
			||||||
 | 
					> Without them, you will have a very difficult time with this assignment.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Getting Started
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Fetch and merge the base code for `hw4` as described in `hw1`.
 | 
				
			||||||
 | 
					You can find it at this link: https://gitlab02.cs.stonybrook.edu/cse320/hw4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is the structure of the base code:
 | 
				
			||||||
 | 
					<pre>
 | 
				
			||||||
 | 
					.
 | 
				
			||||||
 | 
					├── .gitlab-ci.yml
 | 
				
			||||||
 | 
					└── hw4
 | 
				
			||||||
 | 
					    ├── demo
 | 
				
			||||||
 | 
					    │   └── mush
 | 
				
			||||||
 | 
					    ├── include
 | 
				
			||||||
 | 
					    │   ├── debug.h
 | 
				
			||||||
 | 
					    │   ├── mush.h
 | 
				
			||||||
 | 
					    │   ├── mush.tab.h
 | 
				
			||||||
 | 
					    │   └── syntax.h
 | 
				
			||||||
 | 
					    ├── Makefile
 | 
				
			||||||
 | 
					    ├── rsrc
 | 
				
			||||||
 | 
					    │   ├── bg_test.mush
 | 
				
			||||||
 | 
					    │   ├── cancel_test.mush
 | 
				
			||||||
 | 
					    │   ├── delete_test.mush
 | 
				
			||||||
 | 
					    │   ├── fg_test.mush
 | 
				
			||||||
 | 
					    │   ├── goto_test.mush
 | 
				
			||||||
 | 
					    │   ├── list_test.mush
 | 
				
			||||||
 | 
					    │   ├── loop1.mush
 | 
				
			||||||
 | 
					    │   ├── loop2.mush
 | 
				
			||||||
 | 
					    │   ├── pause_test.mush
 | 
				
			||||||
 | 
					    │   ├── pipeline_test.mush
 | 
				
			||||||
 | 
					    │   ├── run_test.mush
 | 
				
			||||||
 | 
					    │   ├── stop_test.mush
 | 
				
			||||||
 | 
					    │   └── wait_test.mush
 | 
				
			||||||
 | 
					    ├── src
 | 
				
			||||||
 | 
					    │   ├── execution.c
 | 
				
			||||||
 | 
					    │   ├── jobs.c
 | 
				
			||||||
 | 
					    │   ├── main.c
 | 
				
			||||||
 | 
					    │   ├── mush.lex.c
 | 
				
			||||||
 | 
					    │   ├── mush.tab.c
 | 
				
			||||||
 | 
					    │   ├── program.c
 | 
				
			||||||
 | 
					    │   ├── store.c
 | 
				
			||||||
 | 
					    │   └── syntax.c
 | 
				
			||||||
 | 
					    └── tests
 | 
				
			||||||
 | 
					        └── base_tests.c
 | 
				
			||||||
 | 
					</pre>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					If you run `make`, the code should compile correctly, resulting in an
 | 
				
			||||||
 | 
					executable `bin/mush`.  If you run this program, it doesn't do very
 | 
				
			||||||
 | 
					much, because there are a number of pieces that you have to fill in.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## `Mush`: Overview
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mush` language is a simple programming language which was roughly
 | 
				
			||||||
 | 
					inspired by the classic programming language BASIC.
 | 
				
			||||||
 | 
					A `mush` program consists of a set of *statements*, with one statement
 | 
				
			||||||
 | 
					per line of program text.
 | 
				
			||||||
 | 
					The syntax of statements is given by the following context-free grammar:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					<statement>       ::= list
 | 
				
			||||||
 | 
					                    | delete <lineno> , <lineno>
 | 
				
			||||||
 | 
					                    | run
 | 
				
			||||||
 | 
					                    | cont
 | 
				
			||||||
 | 
					                    | <lineno> stop
 | 
				
			||||||
 | 
					                    | <optional_lineno> set <name> = <expr>
 | 
				
			||||||
 | 
					                    | <optional_lineno> unset <name>
 | 
				
			||||||
 | 
					                    | <optional_lineno> goto <lineno>
 | 
				
			||||||
 | 
					                    | <optional_lineno> if <expr> goto <lineno>
 | 
				
			||||||
 | 
					                    | <optional_lineno> source <file>
 | 
				
			||||||
 | 
					                    | <optional_lineno> <pipeline>
 | 
				
			||||||
 | 
					                    | <optional_lineno> <pipeline> &
 | 
				
			||||||
 | 
					                    | <optional_lineno> wait <expr>
 | 
				
			||||||
 | 
					                    | <optional_lineno> poll <expr>
 | 
				
			||||||
 | 
					                    | <optional_lineno> cancel <expr>
 | 
				
			||||||
 | 
					                    | <optional_lineno> pause
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Some kinds of statements have required *line numbers*, other kinds of
 | 
				
			||||||
 | 
					statements have no line numbers, and for some statements the line numbers
 | 
				
			||||||
 | 
					are optional.  In general, when the `mush` interpreter reads a statement
 | 
				
			||||||
 | 
					without a line number, it is executed immediately, whereas when it reads
 | 
				
			||||||
 | 
					a statement with a line number it is not immediately executed, but instead
 | 
				
			||||||
 | 
					is saved in the *program store*.
 | 
				
			||||||
 | 
					The program store maintains a set of statements, each of which has a
 | 
				
			||||||
 | 
					line number.  In addition, the program store maintains a *program counter*,
 | 
				
			||||||
 | 
					which keeps track of the next statement to be executed when `mush` is
 | 
				
			||||||
 | 
					in "run mode".
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `list`, `delete`, `run`, and `cont` statements have no line numbers,
 | 
				
			||||||
 | 
					and so can only be executed immediately.  The `list` statement causes
 | 
				
			||||||
 | 
					`mush` to list the contents of the program store.  The `delete` statement
 | 
				
			||||||
 | 
					deletes statements from the program store whose line numbers lie within
 | 
				
			||||||
 | 
					a specified range.  The `run` statement causes `mush` to reset the program
 | 
				
			||||||
 | 
					counter to the lowest-numbered statement in the program store and to begin
 | 
				
			||||||
 | 
					running automatically.  The `cont` statement causes `mush` to continue
 | 
				
			||||||
 | 
					automatic execution that has been stopped by the execution of a `stop` statement.
 | 
				
			||||||
 | 
					Since a `stop` statement has a required line number, such a statement
 | 
				
			||||||
 | 
					can never be executed immediately, but rather only from the program store
 | 
				
			||||||
 | 
					during automatic execution.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The remaining statements have optional line numbers, and so can be executed
 | 
				
			||||||
 | 
					either immediately or from the program store.
 | 
				
			||||||
 | 
					The `set` statement is used to set the value of a variable to be the result
 | 
				
			||||||
 | 
					of evaluating an expression.
 | 
				
			||||||
 | 
					The `unset` statement is used to un-set the value of a variable, leaving it
 | 
				
			||||||
 | 
					with no value.
 | 
				
			||||||
 | 
					The `goto` statement resets the program counter so that the next statement to
 | 
				
			||||||
 | 
					be executed is the one with the specified line number.
 | 
				
			||||||
 | 
					The `if` statement causes control to be transferred conditionally to the
 | 
				
			||||||
 | 
					statement with the specified line number, if the specified expression evaluates
 | 
				
			||||||
 | 
					to a non-zero number.
 | 
				
			||||||
 | 
					The `source` statement causes `mush` to interpret the statements in the specified
 | 
				
			||||||
 | 
					file before continuing on with the current program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A statement can also consist of a *pipeline*, to be executed either in the
 | 
				
			||||||
 | 
					"foreground" or in the "background".  A pipeline consists of a sequence of
 | 
				
			||||||
 | 
					*commands*, separated by vertical bars (`|`), with possible
 | 
				
			||||||
 | 
					*input redirection*, specified using `<` followed by a filename,
 | 
				
			||||||
 | 
					*output redirection*, specified using `>` followed by a filename,
 | 
				
			||||||
 | 
					or *output capturing*, specified using `>@`.
 | 
				
			||||||
 | 
					A pipeline is executed by `mush` in much the same fashion as it would be
 | 
				
			||||||
 | 
					executed by a shell such as `bash`: a group of processes is created to run
 | 
				
			||||||
 | 
					the commands concurrently, with the output of each command in the pipeline
 | 
				
			||||||
 | 
					redirected to become the input of the next command in the pipeline.
 | 
				
			||||||
 | 
					If input redirection is specified, then the first command in the pipeline
 | 
				
			||||||
 | 
					has its input redirected from the specified file.
 | 
				
			||||||
 | 
					If output redirection is specified, then the last command in the pipeline
 | 
				
			||||||
 | 
					has its output redirected to the specified file.
 | 
				
			||||||
 | 
					If output capturing is specified, then the output of the last command in the
 | 
				
			||||||
 | 
					pipeline is read by the `mush` interpreter itself, which makes it available
 | 
				
			||||||
 | 
					as the value of a variable that can be referenced by the execution of
 | 
				
			||||||
 | 
					subsequent statements in the program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Each command in a pipeline consists of a nonempty sequence of *args*,
 | 
				
			||||||
 | 
					where the first arg in the command specifies the name of a program to be run
 | 
				
			||||||
 | 
					and the remaining args are supplied to the program as part of its argument
 | 
				
			||||||
 | 
					vector.  In `mush`, an arg takes the form of an *atomic expression*,
 | 
				
			||||||
 | 
					which can be either a *string variable*, a *numeric variable*,
 | 
				
			||||||
 | 
					a *string literal*, or an arbitrary expression enclosed in parentheses.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The syntax of pipelines, commands, and args is given by the following grammar:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					<pipeline>        ::= <command_list>
 | 
				
			||||||
 | 
					                    | <pipeline>  <  <file>
 | 
				
			||||||
 | 
					                    | <pipeline>  >  <file>
 | 
				
			||||||
 | 
					                    | <pipeline>  >@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<command_list>    ::= <command>
 | 
				
			||||||
 | 
					                    | <command>  |  <command_list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<command>         ::= <arg_list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<arg_list>        ::= <arg>
 | 
				
			||||||
 | 
					                    | <arg> <arg_list>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<arg>             ::= <atomic_expr>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					<atomic_expr>     ::= <literal_string>
 | 
				
			||||||
 | 
					                    | <numeric_var>
 | 
				
			||||||
 | 
					                    | <string_var>
 | 
				
			||||||
 | 
					                    | ( <expr> )
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					`Mush` supports *expressions* built up from *string variables*,
 | 
				
			||||||
 | 
					*numeric variables*, and *literal strings*, using various unary
 | 
				
			||||||
 | 
					and binary operators, as given by the following grammar:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					<expr>            ::= <atomic_expr>
 | 
				
			||||||
 | 
					                    | <expr>  ==  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  <  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  >  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  <=  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  >=  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  &&  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  ||  <expr>
 | 
				
			||||||
 | 
					                    |  !  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  +  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  -  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  *  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  /  <expr>
 | 
				
			||||||
 | 
					                    | <expr>  %  <expr>
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					A *string variable* consists of a `$` symbol followed by a *name*,
 | 
				
			||||||
 | 
					which is a sequence of alphanumeric characters and underscores,
 | 
				
			||||||
 | 
					beginning with an alphabetic character or an underscore.
 | 
				
			||||||
 | 
					A *numeric variable* is similar, except it uses a `#` symbol in place
 | 
				
			||||||
 | 
					of the `$`.
 | 
				
			||||||
 | 
					A *literal string* is either a *number*, which consists of digits,
 | 
				
			||||||
 | 
					a *word*, which consists of non-whitespace characters which do not otherwise
 | 
				
			||||||
 | 
					have some special meaning to `mush`, or a *quoted string*, which is enclosed
 | 
				
			||||||
 | 
					in double quotes and which may contain special characters.
 | 
				
			||||||
 | 
					A *filename* that appears in the input or output redirection part of a
 | 
				
			||||||
 | 
					pipeline is permitted to be either a word or a quoted string.
 | 
				
			||||||
 | 
					This allows simple filenames without special characters to be specified
 | 
				
			||||||
 | 
					without quotes.  Filenames that contain special characters (including `/`)
 | 
				
			||||||
 | 
					must be specified as quoted strings.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Here is a simple example of a `mush` program:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					10 echo "Let's start!"
 | 
				
			||||||
 | 
					20 set x = 0
 | 
				
			||||||
 | 
					30 date >@
 | 
				
			||||||
 | 
					40 set d = $OUTPUT
 | 
				
			||||||
 | 
					50 echo The date and time is: $d
 | 
				
			||||||
 | 
					60 sleep 1
 | 
				
			||||||
 | 
					70 set x = #x + 1
 | 
				
			||||||
 | 
					80 if #x <= 10 goto 30
 | 
				
			||||||
 | 
					90 stop
 | 
				
			||||||
 | 
					```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The remaining types of statements that `mush` understands have to do with
 | 
				
			||||||
 | 
					the manipulation of concurrently executing *jobs*.
 | 
				
			||||||
 | 
					Each time `mush` executes a pipeline statement, a new job is created.
 | 
				
			||||||
 | 
					`Mush` keeps track of the existing jobs in a *jobs table*.
 | 
				
			||||||
 | 
					Each job in the jobs table has an associated *job ID*, which is a nonnegative
 | 
				
			||||||
 | 
					integer that uniquely identifies the job.
 | 
				
			||||||
 | 
					After starting a job, `mush` sets the value of the `JOB` variable to be
 | 
				
			||||||
 | 
					the job ID of the job that was started.
 | 
				
			||||||
 | 
					For a foreground job, `mush` waits for the job to complete and then sets the
 | 
				
			||||||
 | 
					value of the `STATUS` variable to be the exit status of the job.
 | 
				
			||||||
 | 
					`Mush` then *expunges* the job from the jobs table.
 | 
				
			||||||
 | 
					For a background job, `mush` does not wait for the job to complete, but instead
 | 
				
			||||||
 | 
					continues execution.  At a later time, a `wait` statement can be executed
 | 
				
			||||||
 | 
					in order to wait for the background job to complete, to collect its
 | 
				
			||||||
 | 
					exit status, and to expunge the job.  Alternatively, a `poll` statement can
 | 
				
			||||||
 | 
					be executed to check whether the job has terminated without waiting if it
 | 
				
			||||||
 | 
					has not.  If the job has terminated, then the exit status is collected and
 | 
				
			||||||
 | 
					the job is expunged with a `poll` statement, similarly to a `wait` statement.
 | 
				
			||||||
 | 
					Execution of a `cancel` statement makes an attempt to cancel a specified
 | 
				
			||||||
 | 
					background job.  A `SIGKILL` signal is sent to the process group to which the
 | 
				
			||||||
 | 
					processes in the jobs belong.  If the processes have not already terminated,
 | 
				
			||||||
 | 
					then they will terminate upon receiving the `SIGKILL` signal.
 | 
				
			||||||
 | 
					A `wait` statement may be used to wait for this termination to occur and
 | 
				
			||||||
 | 
					to expunge the canceled job from the jobs table.
 | 
				
			||||||
 | 
					Note that the `wait`, `poll`, and `cancel` statements all permit the use of an
 | 
				
			||||||
 | 
					arbitrary expression to specify the job ID.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The final kind of statement that `mush` supports is the `pause` statement.
 | 
				
			||||||
 | 
					This statement causes execution to be suspended pending the receipt of a signal
 | 
				
			||||||
 | 
					that might indicate a change in the status of jobs in the jobs table.
 | 
				
			||||||
 | 
					When such a signal is received, execution continues.
 | 
				
			||||||
 | 
					This way, `mush` can wait for a change in job status without consuming an
 | 
				
			||||||
 | 
					excessive amount of CPU time.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### Demonstration version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					To help you understand how `mush` is intended to behave, I have provided a
 | 
				
			||||||
 | 
					demonstration version as a binary with the assignment basecode.
 | 
				
			||||||
 | 
					This can be found as the executable `demo/mush`.
 | 
				
			||||||
 | 
					This demonstration version is intended as an aid to understanding only;
 | 
				
			||||||
 | 
					it should not be regarded as a specification of what you are to do.
 | 
				
			||||||
 | 
					It is likely that the demonstration version has some bugs or that its
 | 
				
			||||||
 | 
					behavior does not conform in some respects to what is stated here and in
 | 
				
			||||||
 | 
					the specifications in the basecode.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Tasks to be Completed
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Included in the basecode for this assignment is an implementation of a
 | 
				
			||||||
 | 
					parser for `mush` statements and the basic control structure of the
 | 
				
			||||||
 | 
					`mush` interpreter.  A number of modules have been left for you to
 | 
				
			||||||
 | 
					implement.  These are:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * A *program store* module, which is used to hold a `mush` program
 | 
				
			||||||
 | 
					   and manage the program counter.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * A *data store* module, which is used to keep track of the current values
 | 
				
			||||||
 | 
					   of the variables used in a `mush` program.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * A *jobs* module, which keeps track of the currently executing jobs using
 | 
				
			||||||
 | 
					   a jobs table, and implements job manipulation functions used to execute
 | 
				
			||||||
 | 
					   and wait for pipelines, collect exit status, perform input and output
 | 
				
			||||||
 | 
					   redirection, and implement the output capture feature of `mush`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The Program Store Module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Specifications and stubs for the functions that make up the program store module
 | 
				
			||||||
 | 
					of `mush` are given in the source file `src/program.c`.
 | 
				
			||||||
 | 
					Implementation of these functions from the specifications should be relatively
 | 
				
			||||||
 | 
					straightforward, so I will not spend additional space on them here.
 | 
				
			||||||
 | 
					The choice of data structure used to represent the program store has been left
 | 
				
			||||||
 | 
					to you.
 | 
				
			||||||
 | 
					Pay close attention to what the specifications say about who has the responsibility
 | 
				
			||||||
 | 
					for freeing the memory associated with statements in the store.
 | 
				
			||||||
 | 
					A correct implementation should not leak memory associated with program statements,
 | 
				
			||||||
 | 
					and of course it should not suffer from double free bugs and the like.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The Data Store Module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Specifications and stubs for the functions that make up the data store module
 | 
				
			||||||
 | 
					of `mush` are given in the source file `src/store.c`.
 | 
				
			||||||
 | 
					Once again, I expect that implementation of these functions should be relatively
 | 
				
			||||||
 | 
					straightforward.  As for the program store, the choice of data structure used
 | 
				
			||||||
 | 
					to implement the data store is for you to make and you should pay attention to
 | 
				
			||||||
 | 
					what the specifications say about who is responsible for freeing memory.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The Jobs Module
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Specifications and stubs for the functions that make up the jobs module
 | 
				
			||||||
 | 
					of `mush` are given in the source file `src/jobs.c`.
 | 
				
			||||||
 | 
					It is this module that is likely to be unfamiliar and to present some challenges
 | 
				
			||||||
 | 
					to you, so I am providing some additional guidance here.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * You will need to implement some form of "jobs table" in this module,
 | 
				
			||||||
 | 
					   to keep track of the jobs that have been created but not yet expunged.
 | 
				
			||||||
 | 
					   The data structure you use is up to you.  If you find it convenient,
 | 
				
			||||||
 | 
					   you may assume that at most `JOBS_MAX` jobs can exist at one time,
 | 
				
			||||||
 | 
					   where `JOBS_MAX` is a C preprocessor symbol defined in `mush.h`.
 | 
				
			||||||
 | 
					   Write your code so that it does not depend on a particular value for
 | 
				
			||||||
 | 
					   `JOBS_MAX`; do not hard-code the value into your implementation.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Your jobs module will need to make use of handlers for two types of signals.
 | 
				
			||||||
 | 
					   The first is the `SIGCHLD` signal used to obtain notifications when a child
 | 
				
			||||||
 | 
					   process terminates.  This has been discussed in class and can also be found
 | 
				
			||||||
 | 
					   in the textbook.
 | 
				
			||||||
 | 
					   The second type of signal you will need to handle is the `SIGIO` signal used
 | 
				
			||||||
 | 
					   to obtain notifications when a file descriptor is ready for reading.
 | 
				
			||||||
 | 
					   This will be important to enable your program to capture output from
 | 
				
			||||||
 | 
					   concurrently executing background jobs without the need to commit to waiting
 | 
				
			||||||
 | 
					   for data from any one of them at any particular time.  This is discussed
 | 
				
			||||||
 | 
					   further below.
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					 * For correct operation, your implementation will likely have to make use of
 | 
				
			||||||
 | 
					   the `sigprocmask()` function to mask signals during times when a signal handler
 | 
				
			||||||
 | 
					   should be prevented from running.  You will likely also need to use the
 | 
				
			||||||
 | 
					   `sigsuspend()` function under certain circumstances to await the arrival of a
 | 
				
			||||||
 | 
					   signal.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * When executing a pipeline consisting of N commands, a total of N+1 processes
 | 
				
			||||||
 | 
					   should be used.  One of these processes, which we will call the pipeline
 | 
				
			||||||
 | 
					   *leader*, should be the direct child of the main `mush` process.
 | 
				
			||||||
 | 
					   The remaining `N` processes will be children of the leader process, and will
 | 
				
			||||||
 | 
					   each execute one of the commands in the pipeline.
 | 
				
			||||||
 | 
					   The leader process should set itself into a new process group using its own
 | 
				
			||||||
 | 
					   process ID as the process group ID, and its `N` child processes should belong
 | 
				
			||||||
 | 
					   to this process group.  This is so that job cancellation can be performed by
 | 
				
			||||||
 | 
					   sending just one `SIGKILL`, directed at the process group for the job.
 | 
				
			||||||
 | 
					   The leader process should wait for and reap its `N` children before terminating.
 | 
				
			||||||
 | 
					   The main `mush` process should use its `SIGCHLD` handler to receive notifications
 | 
				
			||||||
 | 
					   about the termination of pipeline leader processes and to collect their
 | 
				
			||||||
 | 
					   exit status.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Besides the `fork()` system call used to create the processes, the creation of the pipeline
 | 
				
			||||||
 | 
					   will involve the use of the `open()`, `pipe()`, and `dup2()` system calls to set up the pipes
 | 
				
			||||||
 | 
					   and redirections, and the `execvp()` system call must be used to execute the individual
 | 
				
			||||||
 | 
					   commands.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > **Important:**  You **must** create the processes in a pipeline using calls to
 | 
				
			||||||
 | 
					  > `fork()` and `execvp()`.  You **must not** use the `system()` function, nor use any
 | 
				
			||||||
 | 
					  > form of shell in order to create the pipeline, as the purpose of the assignment is
 | 
				
			||||||
 | 
					  > to give you experience with using the system calls involved in doing this.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * Once having set up the pipeline, the pipeline leader will use `wait()` or `waitpid()`
 | 
				
			||||||
 | 
					   to await the completion of the processes in the pipeline.
 | 
				
			||||||
 | 
					   The leader process should wait for all of its children to terminate before
 | 
				
			||||||
 | 
					   terminating itself.  The leader should return the exit status of the process
 | 
				
			||||||
 | 
					   running the last command in the pipeline as its own exit status, if that
 | 
				
			||||||
 | 
					   process terminated normally.  If the last process terminated with a signal,
 | 
				
			||||||
 | 
					   then the leader should terminate via SIGABRT.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * The `pipe()` and `dup2()` system calls should be used to perform the input
 | 
				
			||||||
 | 
					   and output redirection associated with a pipeline, as discussed in class and
 | 
				
			||||||
 | 
					   in the textbook.  Files used for input and output redirection should be opened
 | 
				
			||||||
 | 
					   using the `open()` system call.  For correct operation of a pipeline, care
 | 
				
			||||||
 | 
					   should be taken while setting up the pipeline that each process makes sure to
 | 
				
			||||||
 | 
					   `close()` pipe file descriptors that it does not use.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 * The capturing of output from a pipeline by the main `mush` process is to be
 | 
				
			||||||
 | 
					   accomplished as follows.  Before forking the pipeline leader, a pipe should
 | 
				
			||||||
 | 
					   be created to provide a way to redirect output from the last process in the
 | 
				
			||||||
 | 
					   pipeline back to the main `mush` process.  The redirection will be accomplished
 | 
				
			||||||
 | 
					   using `dup2()` as usual.  The main `mush` process will need to save the file
 | 
				
			||||||
 | 
					   descriptor for the read side of the pipe in the jobs table along with other
 | 
				
			||||||
 | 
					   state information from that job.  Output from the pipeline will be collected
 | 
				
			||||||
 | 
					   by the main `mush` process by reading from the read side of the pipe and
 | 
				
			||||||
 | 
					   saving what is read in memory.  Automatic dynamic allocation of however much
 | 
				
			||||||
 | 
					   memory is required to hold the output can be accomplished by using the
 | 
				
			||||||
 | 
					   `open_memstream()` function to obtain a `FILE` object to which the data can
 | 
				
			||||||
 | 
					   be written.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The main technical issue involved in output capturing is how to arrange for
 | 
				
			||||||
 | 
					   the main `mush` process to collect the output produced from multiple
 | 
				
			||||||
 | 
					   concurrently executing pipelines, without having to block waiting for any one
 | 
				
			||||||
 | 
					   of them to produce output at any given time.  This can be done using so-called
 | 
				
			||||||
 | 
					   *asynchronous I/O*.  When the main `mush` process creates the pipe from which
 | 
				
			||||||
 | 
					   it will read the captured data, it should perform the following system calls
 | 
				
			||||||
 | 
					   (`readfd` is the file descriptor for the read side of the pipe):
 | 
				
			||||||
 | 
					   
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					      fcntl(readfd, F_SETFL, O_NONBLOCK);
 | 
				
			||||||
 | 
					      fcntl(readfd, F_SETFL, O_ASYNC);
 | 
				
			||||||
 | 
					      fcntl(readfd, F_SETOWN, getpid());
 | 
				
			||||||
 | 
					   ```
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   The first of these calls enables *non-blocking I/O* on the file descriptor.
 | 
				
			||||||
 | 
					   This means that an attempt to `read()` the file descriptor when no data is
 | 
				
			||||||
 | 
					   available will not cause the main `mush` process to block (*i.e.* wait for
 | 
				
			||||||
 | 
					   data to arrive); rather the `read()` will return immediately with an error
 | 
				
			||||||
 | 
					   and `errno` set to `EWOULDBLK`.
 | 
				
			||||||
 | 
					   The second call sets *asynchronous mode* on the file descriptor.
 | 
				
			||||||
 | 
					   When this is set, the operating system kernel will send a `SIGIO` signal
 | 
				
			||||||
 | 
					   whenever there has been a change in status of the file descriptor; for example,
 | 
				
			||||||
 | 
					   whenever data becomes available for reading.
 | 
				
			||||||
 | 
					   The third call is necessary to set the "ownership" of the file descriptor
 | 
				
			||||||
 | 
					   to the main `mush` process, so that the kernel knows to which process
 | 
				
			||||||
 | 
					   the `SIGIO` signals should be directed.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   Once you have done this, then the main `mush` process can use a handler for
 | 
				
			||||||
 | 
					   `SIGIO` signals to become notified when there is output that needs to be
 | 
				
			||||||
 | 
					   captured.  It can then poll each of the file descriptors from which output
 | 
				
			||||||
 | 
					   is supposed to be captured, using `read()` to read input from each of them
 | 
				
			||||||
 | 
					   and save it in memory, until `EWOULDBLK` indicates that there is no more data
 | 
				
			||||||
 | 
					   currently available.  This way, it can collect the captured output in a timely
 | 
				
			||||||
 | 
					   fashion without getting "stuck" waiting for output that might take an
 | 
				
			||||||
 | 
					   indefinite amount of time to arrive.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					   For more information, you will have to look at the man pages for the various
 | 
				
			||||||
 | 
					   system calls involved, including `pipe()`, `dup2()`, `fcntl()`, `open()`, `read()`,
 | 
				
			||||||
 | 
					   `signal()` (or `sigaction()`), `sigprocmask()`, and `sigsuspend()`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Using `gdb` to Debug Multi-process Programs
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Although it gets harder to debug using `gdb` once multiple processes are involved,
 | 
				
			||||||
 | 
					there is some support for it.  The `gdb` command `set follow-fork-mode parent`
 | 
				
			||||||
 | 
					causes `gdb` to follow the parent process after a `fork()` (this is the default).
 | 
				
			||||||
 | 
					Similarly, the command `set follow-fork-mode child` causes `gdb` to follow the child
 | 
				
			||||||
 | 
					process instead.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Provided Components
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `mush.h` Header File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `mush.h` header file that we have provided gives function prototypes for
 | 
				
			||||||
 | 
					the functions that you are to implement, and contains a few other related
 | 
				
			||||||
 | 
					definitions.  The actual specifications for the functions will be found
 | 
				
			||||||
 | 
					as comments attached to stubs for these functions in the various C source files.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream: **Do not make any changes to `mush.h`.  It will be replaced
 | 
				
			||||||
 | 
					  > during grading, and if you change it, you will get a zero!**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `syntax.h` Header File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `syntax.h` header file that we have provided defines the data structures
 | 
				
			||||||
 | 
					used to represent parsed `mush` statements.  Mostly, you don't have to know
 | 
				
			||||||
 | 
					much about the details of these data structures, except, for example,
 | 
				
			||||||
 | 
					that you will need to be able to extract some information from them,
 | 
				
			||||||
 | 
					such as the pipeline from a foreground or background pipeline statement.
 | 
				
			||||||
 | 
					To avoid memory leaks, you will need to use the various `free_xxx()`
 | 
				
			||||||
 | 
					functions provided to free syntactic objects when they are no longer being used.
 | 
				
			||||||
 | 
					You will also need to use the function provided to make a copy of a pipeline
 | 
				
			||||||
 | 
					object in a certain situation -- see the specification for `jobs_run()` for
 | 
				
			||||||
 | 
					more information.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream: **Do not make any changes to `syntax.h`.  It will be replaced
 | 
				
			||||||
 | 
					  > during grading, and if you change it, you will get a zero!**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `syntax.c` Source File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `syntax.c` source file that we have provided contains the implementations
 | 
				
			||||||
 | 
					of the various functions for which prototypes are given in `syntax.h`.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream: **Do not make any changes to `syntax.c`.  It will be replaced
 | 
				
			||||||
 | 
					  > during grading, and if you change it, you will get a zero!**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `mush.lex.c`, `mush.tab.c`, and `mush.tab.h` Files
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The basecode provides a parser for the `mush` language.  This parser is
 | 
				
			||||||
 | 
					implemented using the GNU `bison` parser generator. and the GNU `flex`
 | 
				
			||||||
 | 
					lexical analyzer generator.  The `mush.lex.c`, `mush.tab.c`, and `mush.tab.h`
 | 
				
			||||||
 | 
					files are auto-generated files produced by the `bison` and `flex` programs.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream: **None of these files should be changed or edited.
 | 
				
			||||||
 | 
					  > Do *not* do the sloppy things that lots of people seem to do,
 | 
				
			||||||
 | 
					  > namely, editing these files, reformatting them or otherwise mutating them,
 | 
				
			||||||
 | 
					  > and then committing the changed results to `git`.  You will regret it
 | 
				
			||||||
 | 
					  > if you do this, and you have been duly warned!**
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `demo/mush` Executable
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The file `demo/mush` is an executable program that behaves more or less like
 | 
				
			||||||
 | 
					how your program should behave when it is finished.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  > :scream:  The behavior of the demo program should be regarded as an example
 | 
				
			||||||
 | 
					  > implementation only, not a specification.  If there should be any discrepancy
 | 
				
			||||||
 | 
					  > between the behavior of the demo program and what it says either in this document
 | 
				
			||||||
 | 
					  > or in the specifications in the header files, the latter should be regarded
 | 
				
			||||||
 | 
					  > as authoritative.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `rsrc` Directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `rsrc` directory contains some sample `mush` scripts which I used while
 | 
				
			||||||
 | 
					writing the demo version.  They were mostly designed very quickly to exercise
 | 
				
			||||||
 | 
					the basic features of `mush`, to verify that they worked to a first cut.
 | 
				
			||||||
 | 
					One way to run them is to type *e.g.* `source rsrc/xxx_test.mush` to the
 | 
				
			||||||
 | 
					`mush` prompt, to get it to read and execute the test.
 | 
				
			||||||
 | 
					If you have run one test and you want to run another, you should use the
 | 
				
			||||||
 | 
					`delete` command to clear any statements from the program store that might
 | 
				
			||||||
 | 
					have been left by the first test, otherwise they might interfere with the
 | 
				
			||||||
 | 
					new test.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					### The `tests` Directory
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					The `tests` directory contains just one file, `base_tests.c`, which contains one
 | 
				
			||||||
 | 
					Criterion test that isn't very interesting.  This file is basically just a
 | 
				
			||||||
 | 
					placeholder where you can put tests you might think of yourself.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					## Hand-in instructions
 | 
				
			||||||
 | 
					As usual, make sure your homework compiles before submitting.
 | 
				
			||||||
 | 
					Test it carefully to be sure that doesn't crash or exhibit "flaky" behavior
 | 
				
			||||||
 | 
					due to race conditions.
 | 
				
			||||||
 | 
					Use `valgrind` to check for memory errors and leaks.
 | 
				
			||||||
 | 
					Besides `--leak-check=full`, also use the option `--track-fds=yes`
 | 
				
			||||||
 | 
					to check whether your program is leaking file descriptors because
 | 
				
			||||||
 | 
					they haven't been properly closed.
 | 
				
			||||||
 | 
					You might also want to look into the `valgrind` `--trace-children` and related
 | 
				
			||||||
 | 
					options.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Submit your work using `git submit` as usual.
 | 
				
			||||||
 | 
					This homework's tag is: `hw4`.
 | 
				
			||||||
							
								
								
									
										1280
									
								
								reference_doc/CSE320_ReferenceDoc.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1280
									
								
								reference_doc/CSE320_ReferenceDoc.md
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user