mirror of
https://github.com/peter-tanner/Systems-programming-labs.git
synced 2024-11-30 09:00:30 +08:00
listints and part of mywc done
This commit is contained in:
parent
0f05a2c1a5
commit
deeb3836ad
4
.gitignore
vendored
4
.gitignore
vendored
|
@ -4,5 +4,7 @@
|
||||||
|
|
||||||
*.out
|
*.out
|
||||||
.vscode/
|
.vscode/
|
||||||
|
.gdb_history
|
||||||
|
|
||||||
concordance/
|
concordance/
|
||||||
|
etc/
|
150
Week 9/1_listints/s1_listints.c
Normal file
150
Week 9/1_listints/s1_listints.c
Normal file
|
@ -0,0 +1,150 @@
|
||||||
|
|
||||||
|
// SOLUTION 1 - DYNAMIC MEMORY WITH realloc()
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. Write a C program, named listints, which will print the integers requested
|
||||||
|
via a single command-line argument. The list of integers is to appear in
|
||||||
|
strictly increasing order, with each requested integer appearing once and only
|
||||||
|
once (even if duplicated in the request).
|
||||||
|
* Simple examples of its use are:
|
||||||
|
prompt> listints 8
|
||||||
|
will print: 8
|
||||||
|
|
||||||
|
prompt> listints 3,5,9
|
||||||
|
will print: 3 5 9
|
||||||
|
|
||||||
|
prompt> listints 1-10
|
||||||
|
will print: 1 2 3 4 5 6 7 8 9 10
|
||||||
|
|
||||||
|
prompt> listints 1-10,6
|
||||||
|
will print: 1 2 3 4 5 6 7 8 9 10
|
||||||
|
* 🌶 🌶 And some much more difficult examples:
|
||||||
|
prompt> listints 2000-2020,40-50
|
||||||
|
prompt> listints 1-10,2010-2020,3000000-3000010
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define RANGE_SEP '-'
|
||||||
|
#define LIST_SEP ','
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long start;
|
||||||
|
long end;
|
||||||
|
} RANGE;
|
||||||
|
|
||||||
|
int sort_range(const void *v1, const void *v2)
|
||||||
|
{
|
||||||
|
RANGE* range_1 = (RANGE*)v1;
|
||||||
|
RANGE* range_2 = (RANGE*)v2;
|
||||||
|
return (range_1->start - range_2->start);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *substr(char *str, char *end)
|
||||||
|
{
|
||||||
|
size_t length = end - str;
|
||||||
|
char *substring = malloc(length + 1);
|
||||||
|
strncpy(substring,str,length);
|
||||||
|
*(substring+length) = '\0';
|
||||||
|
return substring;
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGE convert_to_range(char *range_str)
|
||||||
|
{
|
||||||
|
char *sep = strchr(range_str, RANGE_SEP);
|
||||||
|
RANGE range;
|
||||||
|
if (sep != NULL) {
|
||||||
|
sep++;
|
||||||
|
range.start = atol(substr(range_str,sep-1));
|
||||||
|
range.end = atol(sep);
|
||||||
|
} else {
|
||||||
|
range.start = atol(range_str);
|
||||||
|
range.end = range.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.end < range.start) {
|
||||||
|
fprintf(stderr, "ERROR: End range must be before start range.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGE *split_ranges(char *list, size_t *list_size)
|
||||||
|
{
|
||||||
|
size_t range_list_max = 1;
|
||||||
|
RANGE *range_list = malloc(sizeof(RANGE));
|
||||||
|
if (range_list == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: Couldn't allocate memory.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
RANGE *range = range_list;
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
while ( (end = strchr(list, LIST_SEP)) != NULL ) {
|
||||||
|
// EXTRACT ONE RANGE.
|
||||||
|
char *element = substr(list, end);
|
||||||
|
|
||||||
|
// EXPAND MEMORY
|
||||||
|
if (*list_size >= range_list_max) {
|
||||||
|
range_list_max *= 2;
|
||||||
|
range_list = realloc(range_list, range_list_max * sizeof(RANGE));
|
||||||
|
if (range_list == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: Couldn't allocate memory.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
range = range_list + *list_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
*range = convert_to_range(element);
|
||||||
|
range++;
|
||||||
|
|
||||||
|
*list_size = (size_t)(range - range_list);
|
||||||
|
list = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(range_list, *list_size, sizeof(RANGE), sort_range);
|
||||||
|
return range_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
long max(long v1, long v2)
|
||||||
|
{
|
||||||
|
if (v1 < v2) {
|
||||||
|
return v2;
|
||||||
|
}
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_ranges(RANGE *range_list, size_t list_size)
|
||||||
|
{
|
||||||
|
long max_number = 0;
|
||||||
|
for (size_t i = 0; i < list_size; i++) {
|
||||||
|
RANGE *range = range_list + i;
|
||||||
|
for (size_t n = max(range->start, max_number); n <= range->end; n++)
|
||||||
|
{
|
||||||
|
max_number = n+1;
|
||||||
|
printf("%lu ",n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: listints [INTEGER RANGE]\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STRING WITH A ',' APPENDED TO MAKE THE SPLIT WORK.
|
||||||
|
char *ext_str = malloc(strlen(argv[1]) + 1);
|
||||||
|
strcpy(ext_str,argv[1]);
|
||||||
|
strcat(ext_str,",");
|
||||||
|
|
||||||
|
size_t list_size = 0;
|
||||||
|
RANGE *range_list = split_ranges(ext_str, &list_size);
|
||||||
|
print_ranges(range_list, list_size);
|
||||||
|
return 0;
|
||||||
|
}
|
145
Week 9/1_listints/s2_listints.c
Normal file
145
Week 9/1_listints/s2_listints.c
Normal file
|
@ -0,0 +1,145 @@
|
||||||
|
|
||||||
|
// SOLUTION 1 - NO DYNAMIC MEMORY ALLOCATION
|
||||||
|
|
||||||
|
/*
|
||||||
|
* 1. Write a C program, named listints, which will print the integers requested
|
||||||
|
via a single command-line argument. The list of integers is to appear in
|
||||||
|
strictly increasing order, with each requested integer appearing once and only
|
||||||
|
once (even if duplicated in the request).
|
||||||
|
* Simple examples of its use are:
|
||||||
|
prompt> listints 8
|
||||||
|
will print: 8
|
||||||
|
|
||||||
|
prompt> listints 3,5,9
|
||||||
|
will print: 3 5 9
|
||||||
|
|
||||||
|
prompt> listints 1-10
|
||||||
|
will print: 1 2 3 4 5 6 7 8 9 10
|
||||||
|
|
||||||
|
prompt> listints 1-10,6
|
||||||
|
will print: 1 2 3 4 5 6 7 8 9 10
|
||||||
|
* 🌶 🌶 And some much more difficult examples:
|
||||||
|
prompt> listints 2000-2020,40-50
|
||||||
|
prompt> listints 1-10,2010-2020,3000000-3000010
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#define RANGE_SEP '-'
|
||||||
|
#define LIST_SEP ','
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
long start;
|
||||||
|
long end;
|
||||||
|
} RANGE;
|
||||||
|
|
||||||
|
int sort_range(const void *v1, const void *v2)
|
||||||
|
{
|
||||||
|
RANGE* range_1 = (RANGE*)v1;
|
||||||
|
RANGE* range_2 = (RANGE*)v2;
|
||||||
|
return (range_1->start - range_2->start);
|
||||||
|
}
|
||||||
|
|
||||||
|
char *substr(char *str, char *end)
|
||||||
|
{
|
||||||
|
size_t length = end - str;
|
||||||
|
char *substring = malloc(length + 1);
|
||||||
|
strncpy(substring,str,length);
|
||||||
|
*(substring+length) = '\0';
|
||||||
|
return substring;
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGE convert_to_range(char *range_str)
|
||||||
|
{
|
||||||
|
char *sep = strchr(range_str, RANGE_SEP);
|
||||||
|
RANGE range;
|
||||||
|
if (sep != NULL) {
|
||||||
|
sep++;
|
||||||
|
range.start = atol(substr(range_str,sep-1));
|
||||||
|
range.end = atol(sep);
|
||||||
|
} else {
|
||||||
|
range.start = atol(range_str);
|
||||||
|
range.end = range.start;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (range.end < range.start) {
|
||||||
|
fprintf(stderr, "ERROR: End range must be before start range.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
return range;
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGE *split_ranges(char *list, size_t list_size)
|
||||||
|
{
|
||||||
|
RANGE *range_list = malloc(list_size * sizeof(RANGE));
|
||||||
|
if (range_list == NULL) {
|
||||||
|
fprintf(stderr, "ERROR: Couldn't allocate memory.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
RANGE *range = range_list;
|
||||||
|
|
||||||
|
char *end;
|
||||||
|
while ( (end = strchr(list, LIST_SEP)) != NULL ) {
|
||||||
|
// EXTRACT ONE RANGE.
|
||||||
|
char *element = substr(list, end);
|
||||||
|
*range = convert_to_range(element);
|
||||||
|
range++;
|
||||||
|
list = end + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
qsort(range_list, list_size, sizeof(RANGE), sort_range);
|
||||||
|
return range_list;
|
||||||
|
}
|
||||||
|
|
||||||
|
long max(long v1, long v2)
|
||||||
|
{
|
||||||
|
if (v1 < v2) {
|
||||||
|
return v2;
|
||||||
|
}
|
||||||
|
return v1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_ranges(RANGE *range_list, size_t list_size)
|
||||||
|
{
|
||||||
|
long max_number = 0;
|
||||||
|
for (size_t i = 0; i < list_size; i++) {
|
||||||
|
RANGE *range = range_list + i;
|
||||||
|
for (size_t n = max(range->start, max_number); n <= range->end; n++)
|
||||||
|
{
|
||||||
|
max_number = n+1;
|
||||||
|
printf("%lu ",n);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
putchar('\n');
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
if (argc != 2)
|
||||||
|
{
|
||||||
|
fprintf(stderr, "Usage: listints [INTEGER RANGE]\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
// STRING WITH A ',' APPENDED TO MAKE THE SPLIT WORK.
|
||||||
|
char *ext_str = malloc(strlen(argv[1]) + 1);
|
||||||
|
strcpy(ext_str,argv[1]);
|
||||||
|
strcat(ext_str,",");
|
||||||
|
|
||||||
|
// COUNT RANGES REQUIRED.
|
||||||
|
size_t ranges = 0;
|
||||||
|
size_t i = 0;
|
||||||
|
char c;
|
||||||
|
while ((c = ext_str[i]) != '\0') {
|
||||||
|
i++;
|
||||||
|
if (c == ',') {
|
||||||
|
ranges++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
RANGE *range_list = split_ranges(ext_str, ranges);
|
||||||
|
print_ranges(range_list, ranges);
|
||||||
|
return 0;
|
||||||
|
}
|
110
Week 9/3_mywc/mywc.c
Normal file
110
Week 9/3_mywc/mywc.c
Normal file
|
@ -0,0 +1,110 @@
|
||||||
|
/*
|
||||||
|
* 3. Both Linux and macOS provide a standard command named wc (an abbreviation for
|
||||||
|
wordcount!) which determines the number of lines, words, and characters in a
|
||||||
|
named file. You can read about this command using the online documentation:
|
||||||
|
(man wc).
|
||||||
|
* For this task, you will develop your own version of the wc program named mywc.
|
||||||
|
|
||||||
|
* a. Firstly, write a function named counter() that calculates and prints out
|
||||||
|
the number of lines contained within a file. Your counter() function should
|
||||||
|
take one argument, a character array that provides a filename.
|
||||||
|
* b. Next, modify your mywc program and the counter() function to either count
|
||||||
|
the lines of a file, named on the command-line, or to count the input
|
||||||
|
"arriving" via the stdin stream. We often described such a program as a
|
||||||
|
filter.
|
||||||
|
* c. Next, extend your counter() function so that it now also counts, and
|
||||||
|
prints, the number of characters and words found in the file. Be careful with
|
||||||
|
the meaning of a "word" - it's just a sequence of any characters surrounded by
|
||||||
|
whitespace characters. Check your printed results against those of the
|
||||||
|
standard wc program.
|
||||||
|
* d. Next, observe that our counter() function is printing its three
|
||||||
|
results - as we can only return a single result. Modify the counter() function
|
||||||
|
so that its three calculated results are now "given" back to the calling
|
||||||
|
function through pointers passed as parameters. Now, the calling function will
|
||||||
|
have the results placed in its own local variables, and be able to print
|
||||||
|
(or use) the results itself.
|
||||||
|
|
||||||
|
* 4. 🌶 Now, using the standard getopt() function introduced in Lecture 17, add
|
||||||
|
support for command-line options to your mywc utility from Task-3.
|
||||||
|
* Add command-line options to request:
|
||||||
|
|
||||||
|
-c to report the number of characters,
|
||||||
|
-l to report the number of lines,
|
||||||
|
-L to report the maximum line length (as supported on Linux, but not macOS),
|
||||||
|
and
|
||||||
|
-w to report the number of words.
|
||||||
|
|
||||||
|
* Ensure that your program still works with meaningful defaults if no options
|
||||||
|
are provided on the command-line.
|
||||||
|
* Ensure that your program checks that the provided command-line arguments are
|
||||||
|
sensible - if they are not, issue an appropriate error message to stderr after
|
||||||
|
all options have been processed.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <ctype.h>
|
||||||
|
|
||||||
|
void counter_stats(FILE *file, int *lines, int *words, int *characters)
|
||||||
|
{
|
||||||
|
char buffer[BUFSIZ];
|
||||||
|
// PROCESS IN CHUNKS
|
||||||
|
bool word = false;
|
||||||
|
while ( fgets(buffer, BUFSIZ, file) != NULL ) {
|
||||||
|
char *c = &buffer[0];
|
||||||
|
while ( *c != '\0' ) {
|
||||||
|
// COUNT WORDS
|
||||||
|
if (word && isspace(*c)) {
|
||||||
|
(*words)++;
|
||||||
|
word = false;
|
||||||
|
} else if (!word) {
|
||||||
|
word = true;
|
||||||
|
}
|
||||||
|
// COUNT CHARACTERS
|
||||||
|
(*characters)++;
|
||||||
|
// COUNT NEWLINES
|
||||||
|
if ( *c == '\n' ) {
|
||||||
|
(*lines)++;
|
||||||
|
}
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// NUMBER OF LINES IN A FILE.
|
||||||
|
void counter(char *path, int *lines, int *words, int *characters)
|
||||||
|
{
|
||||||
|
FILE *file;
|
||||||
|
if (path == NULL) {
|
||||||
|
file = stdin;
|
||||||
|
} else {
|
||||||
|
file = fopen(path, "r");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (file != NULL) {
|
||||||
|
counter_stats(file, lines, words, characters);
|
||||||
|
} else {
|
||||||
|
fprintf(stderr, "Error reading file.\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char *file = argv[1];
|
||||||
|
// CHECK IF WE ARE ACCEPTING INPUT FROM A PIPE.
|
||||||
|
if (argc > 2) {
|
||||||
|
fprintf(stderr, "Usage: mywc [FILE]\n");
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
|
||||||
|
int lines;
|
||||||
|
int words;
|
||||||
|
int characters;
|
||||||
|
counter(argv[1], &lines, &words, &characters);
|
||||||
|
printf( "LINES %d, WORDS %d, CHARACTERS %d\n",
|
||||||
|
lines, words, characters );
|
||||||
|
return 0;
|
||||||
|
}
|
30
Week 9/3_mywc/unix-1969-1971.txt
Normal file
30
Week 9/3_mywc/unix-1969-1971.txt
Normal file
|
@ -0,0 +1,30 @@
|
||||||
|
Unix was born in 1969 out of the mind of a computer scientist at Bell
|
||||||
|
Laboratories, Ken Thompson. Thompson had been a researcher on the Multics
|
||||||
|
project, an experience which spoiled him for the primitive batch computing
|
||||||
|
that was the rule almost everywhere else. But the concept of timesharing
|
||||||
|
was still a novel one in the late 1960s; the first speculations on it had
|
||||||
|
been uttered barely ten years earlier by computer scientist John McCarthy
|
||||||
|
(also the inventor of the Lisp language), the first actual deployment had
|
||||||
|
been in 1962, seven years earlier, and timesharing operating systems were
|
||||||
|
still experimental and temperamental beasts.
|
||||||
|
|
||||||
|
Computer hardware was at that time more primitive than even people who
|
||||||
|
were there to see it can now easily recall. The most powerful machines
|
||||||
|
of the day had less computing power and internal memory than a typical
|
||||||
|
cellphone of today. Video display terminals were in their infancy
|
||||||
|
and would not be widely deployed for another six years. The standard
|
||||||
|
interactive device on the earliest timesharing systems was the ASR-33
|
||||||
|
teletype - a slow, noisy device that printed upper-case-only on big
|
||||||
|
rolls of yellow paper. The ASR-33 was the natural parent of the Unix
|
||||||
|
tradition of terse commands and sparse responses.
|
||||||
|
|
||||||
|
When Bell Labs withdrew from the Multics research consortium, Ken
|
||||||
|
Thompson was left with some Multics-inspired ideas about how to build a
|
||||||
|
file system. He was also left without a machine on which to play a game
|
||||||
|
he had written called Space Travel, a science-fiction simulation that
|
||||||
|
involved navigating a rocket through the solar system. Unix began its
|
||||||
|
life on a scavenged PDP-7 minicomputer, as a platform for the Space Travel
|
||||||
|
game and a testbed for Thompson's ideas about operating system design.
|
||||||
|
|
||||||
|
[adapted from https://www.catb.org/esr/writings/taoup/html/ch02s01.html]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user