mirror of
https://github.com/peter-tanner/Systems-programming-labs.git
synced 2024-11-30 10:50:19 +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
|
||||
.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