From b372fafd93bfc257396220fd50d0a4d12e8b6d9b Mon Sep 17 00:00:00 2001 From: Peter Date: Mon, 9 Aug 2021 17:20:19 +0800 Subject: [PATCH] Workshop solution week 2 --- Week 2-workshop/README.md | 22 ++++++ Week 2-workshop/cal.c | 110 +++++++++++++++++++++++++++ Week 2-workshop/first_day_of_month.c | 28 +++++++ Week 2-workshop/year_utils.c | 33 ++++++++ 4 files changed, 193 insertions(+) create mode 100644 Week 2-workshop/README.md create mode 100644 Week 2-workshop/cal.c create mode 100644 Week 2-workshop/first_day_of_month.c create mode 100644 Week 2-workshop/year_utils.c diff --git a/Week 2-workshop/README.md b/Week 2-workshop/README.md new file mode 100644 index 0000000..3828f1b --- /dev/null +++ b/Week 2-workshop/README.md @@ -0,0 +1,22 @@ + +## Workshop 1 content +Workshop content: https://web.archive.org/web/20210809074913/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/workshop2.php\ +`first_day_of_month.c`: https://web.archive.org/web/20210809075040/https://teaching.csse.uwa.edu.au/units/CITS2002/workshops/first_day_of_month.c + +EXTRA WORK +* There's some required information that we haven't yet covered in lectures (information we can get from our computer's operating system). Try to identify that extra information. +* Consider the file first_day_of_month.c whose function determines the first day (Sun, Mon, ...) of a requested month. Identify the functions that are used to determine this information, and read their documentation for your system. +* We know that Linux utility programs can receive optional command-line arguments to specify actions beyond their default actions. In the case of the cal utility, if two (optional) arguments are provided, we are specifying the required month and year to be printed. +* Assuming we receive the additional two command-line arguments, which the C program receives as character strings, we can 'convert' their string representations of integers to integer values using the standard atoi() function. +* Extend your program to detect optional command-line arguments, and to print the requested calendar. +* 🌶 And how could we support left-handers? +* 🌶 🌶 Wow! What happened in September 1752? (which you don't have to deal with!) : +``` +prompt> cal 9 1752 + + September 1752 +Su Mo Tu We Th Fr Sa + 1 2 14 15 16 +17 18 19 20 21 22 23 +24 25 26 27 28 29 30 +``` \ No newline at end of file diff --git a/Week 2-workshop/cal.c b/Week 2-workshop/cal.c new file mode 100644 index 0000000..4a420c0 --- /dev/null +++ b/Week 2-workshop/cal.c @@ -0,0 +1,110 @@ + +#include +#include +#include +#include + +#include "first_day_of_month.c" +#include "year_utils.c" + +#define WEEK_LENGTH 7 + +// Adds padding so it's centered. +void printHeader(int month, int year) { + int len = strlen(MONTH_NAME[month-1]) + 5; // Let's assume the year length is 4. + int lPad = (3*WEEK_LENGTH - len)/2; + printf("%*s %d\n", 12, MONTH_NAME[month-1], year); +} + +static bool LEFT_HAND = false; + +int leftIdx(int i) { + switch (LEFT_HAND) + { + case true: + return 6-i; + default: + return i; + } +} + +void printCal(int month, int year) { + printHeader(month, year); + for (int i = 0; i < WEEK_LENGTH; i++) + { + printf("%s ", DAY_NAME[leftIdx(i)]); + } + printf("\n"); + + // Original solution just printed but easier to use + // 2d array for left hand mode. + int limit = monthLimit(month, year); + int week[WEEK_LENGTH] = {0}; + int idx = first_day_of_month(month, year); + int day_ = 1; + for (int i = 1; i < 6; i++) + { + while (idx < WEEK_LENGTH) + { + if (day_ > limit) { + break; + } + week[idx] = day_; + day_++; + idx++; + } + + // print row + idx = 0; + for (int j = 0; j < WEEK_LENGTH; j++) + { + int d = week[leftIdx(j)]; + switch (d) + { + case 0: + printf(" "); + break; + default: + printf("%-3d", d); + break; + } + } + memset(week, 0, sizeof week); // clear int array + printf("\n"); + } + printf("\n"); +} + + +int main(int argc, char const *argv[]) +{ + int year = 1; + int month = 1; + switch (argc) + { + case 0: + case 1: + { + struct tm tm = getCurrentTime(); + year = tm.tm_year+1900; + month = tm.tm_mon+1; + } + break; + case 4: + LEFT_HAND = (strcmp(argv[3], "true") == 0); + case 3: + year = atoi(argv[1]); + month = atoi(argv[2]); + if (month >= 1 && month <= 12 && year >= 1) { + break; + } + default: + printf("Incorrect arguments - expected no arguments or two arguments\ncal year month\ncal year month lefthanded_mode(true|false)\n"); + exit(EXIT_FAILURE); + break; + } + + printCal(month, year); + exit(EXIT_SUCCESS); + return 0; +} \ No newline at end of file diff --git a/Week 2-workshop/first_day_of_month.c b/Week 2-workshop/first_day_of_month.c new file mode 100644 index 0000000..8e473eb --- /dev/null +++ b/Week 2-workshop/first_day_of_month.c @@ -0,0 +1,28 @@ +#include +#include + +// written by Chris.McDonald@uwa.edu.au + +// PROVIDED WITHOUT MUCH EXPLANATION YET! + +// RETURNS 0=Sun, 1=Mon, ..... +// +int first_day_of_month(int month, int year) +{ + struct tm tm; + +// SET ALL FIELDS OF tm TO ZERO TO MAKE SOME FIELDS 'UNKNOWN' + memset(&tm, 0, sizeof(tm)); + +// INITIALIZE THE FILEDS THAT WE ALREADY KNOW + tm.tm_mday = 1; + tm.tm_mon = month-1; // 0=Jan, 1=Feb, .... + tm.tm_year = year-1900; + +// ASK THE POSIX FUNCTION mktime TO DETERMINE THE 'UNKNOWN' FIELDS +// See: http://pubs.opengroup.org/onlinepubs/9699919799/ + mktime(&tm); + +// RETURN THE INTEGER MONTH VALUE + return tm.tm_wday; // 0=Sun, 1=Mon, ..... +} diff --git a/Week 2-workshop/year_utils.c b/Week 2-workshop/year_utils.c new file mode 100644 index 0000000..cf27473 --- /dev/null +++ b/Week 2-workshop/year_utils.c @@ -0,0 +1,33 @@ + +#include +#include + +static char *DAY_NAME[] = {"Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"}; +static char *MONTH_NAME[] = { + "January", "February", "March", "April", + "May", "June", "July", "August", "September", + "October", "November", "December" + }; + + +bool isLeapYear(int year) { + return year % 4 == 0 && (year % 100 != 0 || year % 400 == 0); +} + +int monthLimit(int month, int year) +{ + bool leapYear = isLeapYear(year); + switch (month) + { + case 2: + return 28 + leapYear; + default: + return 31 - (month - 1) % 7 % 2; + } +} + +struct tm getCurrentTime() { + time_t t = time(NULL); + struct tm tm = *localtime(&t); + return tm; +} \ No newline at end of file