COMP1521 24T3 W09A tutorial code

Here you'll find all the code I've written in the W09A tutorials, as well as some possibly useful information:

Week #9

print_diary.c

// Write a C program, print_diary.c, which prints the contents
// of the file $HOME/.diary to stdout 

#include <stdio.h>
#include <stdlib.h>
#include <string.h>

// path = <whatever the HOME env variable is>/.diary


int main(void) {
    char *home = getenv("HOME");
    printf("home = \"%s\"\n", home);

    char *diary_suffix = "/.diary";

    int path_size = strlen(home) + strlen(diary_suffix) + 1;
    char *path = malloc(path_size);
    if (path == NULL) {
        perror("malloc");
        return 1;
    }

    snprintf(path, path_size, "%s%s", home, diary_suffix);

    printf("path = \"%s\"\n", path);

    FILE *stream = fopen(path, "r");

    int byte;
    while ((byte = fgetc(stream)) != EOF) {
        putchar(byte);
    }

    fclose(stream);
    free(path);
}

chmod_if_public_write.c

#include <sys/types.h>
#include <sys/stat.h>
#include <stdio.h>

// ./chmod_if_public_write print_diary.c file code.txt

void chmod_if_public_write(char *path);

int main(int argc, char *argv[]) {
    for (int i = 1; i < argc; i++) {
        chmod_if_public_write(argv[i]);
    }
}

void chmod_if_public_write(char *path) {
    struct stat statbuf;
    if (stat(path, &statbuf) != 0) {
        perror(path);
        return;
    }

    if ((statbuf.st_mode & S_IWOTH) == 0) {
        printf("public write bit not set for %s\n", path);
        return;
    }

    printf("public write bit set for %s... chmoding!\n", path);

    // ~S_IWOTH  = 111111101

    mode_t new_permission = statbuf.st_mode & ~S_IWOTH;

    if (chmod(path, new_permission) != 0) {
        perror(path);
    }
}

Week #8

first_line.c

// Write a C program, first_line.c, which is given one command-line argument,
// the name of a file, and which prints the first line of that file to stdout.
// If given an incorrect number of arguments, or if there was an error opening
// the file, it should print a suitable error message.

#include <stdio.h>
#include <stdlib.h>

// $ ./first_line lines.txt
//      argc = 2
//      argv[0] = "./first_line"
//      argv[1] = "lines.txt"

int main(int argc, char *argv[]) {
    if (argc != 2) {
        fprintf(stderr, "Usage: ./first_line <file>\n");
        exit(1);
    }

    char *path = argv[1];

    FILE *stream = fopen(path, "r");
    if (stream == NULL) {
        perror(path);
        exit(1);
    }

    //  functions to read from a file: fgetc, fread, fscanf, fgets
    // functions to write from a file: fputc, fwrite, fprintf, fputs

    int byte;
    while ((byte = fgetc(stream)) != EOF) {
        putchar(byte);

        if (byte == '\n') {
            break;
        }
    }

    fclose(stream);
}

Week #7

Here's the presentation

float_weird.c

#include <stdio.h>

int main(void) {
    float a = 0.1;
    float b = 0.2;
    float sum = a + b;

    printf("a = %.9g, b = %.9g and sum = %.9g\n", a, b, sum);
    printf("And sum == 0.3 is: %d\n", sum == 0.3);
}

get_bit_groups.c

#include <stdint.h>
#include <stdio.h>

typedef struct six_bit_groups {
    uint8_t middle_bits;
    uint8_t lower_bits;
} six_bit_groups_t;

/*
Example:

    01100010   10101101   11001100   10010011
                    ^^^   ^^^          ^^^^^^
                      middle            lower
                       = 46             = 19


    01100010   10101101   11001100   10010011 <-- value
    00000000   00000000   0000000    00111111 <-- mask
    00000000   00000000   0000000    01000000 <-- 1 << 6
    -----------------------------------------
    00000000   00000000   0000000    00010011 <-- value & mask

    00000000   00000000   0000000    00111111 <-- mask
    00000000   00000111   1110000    00000000 <-- mask << 13
    00000000   00000101   1100000    00000000 <-- value & mask
    00000000   00000101   1100000    00000000 <-- (value & mask) >> 13
*/


six_bit_groups_t get_bit_groups(uint32_t value) {
    // uint32_t mask = 0b111111;
    uint32_t mask = 0x3f;
    // uint32_t mask = 077;
    // uint32_t mask = 63;
    // uint32_t mask = (1 << n) - 1;

    // uint32_t lower_bits = mask & value;
    // // uint32_t middle_bits = ((mask << 13) & value) >> 13;
    // uint32_t middle_bits = (value >> 13) & mask;

    int a = 30000;
    int b = 30000;
    int result = a + b;

    six_bit_groups_t result;
    result.lower_bits = lower_bits;
    result.middle_bits = middle_bits;
    return result;
}

Week #5

reverse_bits.c

#include <assert.h>
#include <stdio.h>
#include <stdint.h>


// Reverse a 32 bit value
uint32_t reverse_bits(uint32_t value) {
    uint32_t answer = 0;

    for (int i = 0; i < 32; i++) {
        // 1. first check if bit `i` in `value` is a 1?
        uint32_t mask = 1;
        mask = mask << i;

        if ((value & mask) != 0) {
            // 2.   => if so, set opposite bit to `i` in answer
            int opposite_bit_index = 31 - i;

            mask = 1;
            mask <<= opposite_bit_index;

            answer = answer | mask;
        }
    }

    return answer;
}

int main(void) {
    assert(reverse_bits(0xFFFFFFFF) == 0xFFFFFFFF);
    assert(reverse_bits(0x00000000) == 0x00000000);
    assert(reverse_bits(0x1) == 0x80000000);
    assert(reverse_bits(0x2) == 0x40000000);
    assert(reverse_bits(0x01234567) == 0xE6A2C480);
    printf("All tests passed!\n");
    return 0;
}

examples.txt

  uint16_t a = 0x5566, b = 0xAAAA, c = 0x0001;

   a) a | b
   b) a & b
   c) a ^ b
   d) a & ~b
   e) c << 6
   f) a >> 4
   g) a & (b << 1)
   h) b | c
   i) a & ~c

Week #4

No code yet! If the tutorial is over, please remind Xavier to run the upload script :)

Week #3

Here's the spreadsheet I used

print_array.c

// A simple program that will print 10 numbers from an array

#define N_SIZE 10

#include <stdio.h>

// int -> word
// char -> byte
// short -> half

int numbers[N_SIZE] = {
    3, 1, 4, 1, 5, 9, 2, 6, 5, 3
};

int main(void) {
    for (int i = 0; i < N_SIZE; i++) {
        int num = numbers[i];
        printf("%d\n", num);
    }
}

print_array.s

	MY_FAVOURITE_NUMBER = 10

main:
	# Locals:
	#   i: $t0
	#   num: $t1

loop_init:
	# int i = 0;
	li	$t0, 0

loop_cond:
	bge	$t0, MY_FAVOURITE_NUMBER, loop_end

loop_body:
	# int num = numbers[i];

	# 1. get the address of the object
	#    we're accessing into a register

	# &numbers[i] = &numbers + sizeof(element) * i
	la	$t2, numbers			# &numbers
	mul	$t3, 4, $t0			# i * 4
	add	$t2, numbers, $t3		# &numbers + i * 4
						#   == &numbers[i]

	# 2. figure out if we're doing a load
	#    or a store

	#  it's a load!

	# 3. figure out if we're loading/storing
	#    a byte, half or word

	#  we're loading a word

	lw	$t1, ($t2)

	# printf("%d\n", num);
	li	$v0, 1
	move	$a0, $t1
	syscall

	li	$v0, 11
	li	$a0, '\n'
	syscall

loop_step:
	addi	$t0, $t0, 1
	b	loop_cond

loop_end:
	li	$v0, 0
	jr	$ra


	.data
numbers:
	.word	3, 1, 4, 1, 5, 9, 2, 6, 5, 3

read_array.c

// A simple program that will read 10 numbers into an array

#define N_SIZE 5

#include <stdio.h>

int numbers[N_SIZE];

int main(void) {
    int i;

    i = 0;
    while (i < N_SIZE) {
        scanf("%d", &numbers[i]);
        i++;
    }

    i = 0;
    while (i < N_SIZE) {
        int num = numbers[i];
        printf("%d\n", num);
        i++;
    }
}

read_array.s

	N_SIZE = 5
	SIZEOF_INT = 4

main:
	# Locals:
	#   i: $t0
	#   num: $t1

read_loop_init:
	li	$t0, 0
read_loop_cond:
	bge	$t0, N_SIZE, read_loop_end

read_loop_body:
	# scanf("%d", &numbers[i]);
	# numbers[i] = read_int()
	li	$v0, 5
	syscall

	# 1. get address
	la	$t2, numbers			# &numbers
	mul	$t3, 4, $t0			# i * 4
	add	$t2, numbers, $t3		# &numbers + i * 4
						#   == &numbers[i]

	# 2. it's a store!
	# 3. word

	sw	$v0, ($t2)

read_loop_step:
	addi	$t0, $t0, 1
	b	read_loop_cond

read_loop_end:

print_loop_init:
	# int i = 0;
	li	$t0, 0

print_loop_cond:
	bge	$t0, N_SIZE, print_loop_end

print_loop_body:
	# int num = numbers[i];

	# 1. get the address of the object
	#    we're accessing into a register

	# &numbers[i] = &numbers + sizeof(element) * i
	la	$t2, numbers			# &numbers
	mul	$t3, 4, $t0			# i * 4
	add	$t2, numbers, $t3		# &numbers + i * 4
						#   == &numbers[i]

	# 2. figure out if we're doing a load
	#    or a store

	#  it's a load!

	# 3. figure out if we're loading/storing
	#    a byte, half or word

	#  we're loading a word

	lw	$t1, ($t2)

	# printf("%d\n", num);
	li	$v0, 1
	move	$a0, $t1
	syscall

	li	$v0, 11
	li	$a0, '\n'
	syscall

print_loop_step:
	addi	$t0, $t0, 1
	b	print_loop_cond

print_loop_end:
	li	$v0, 0
	jr	$ra


	.data

	.align	2
numbers:
	.space	SIZEOF_INT*N_SIZE

	# .word	0:N_SIZE
	# .word	3, 1, 4, 1, 5, 9, 2, 6, 5, 3

Week #2

hello.s

# Write a MIPS assembly program that prints "Hello, world!"

	.text

main:
	li	$v0, 4			# $v0 = 4
	la	$a0, hello_world_str
	syscall				# printf("Hello, world!")

	li	$v0, 0
	jr	$ra			# return 0;

	.data
hello_world_str:
	.asciiz	"Hello, world!\n"

square.c

// Prints the square of a number

#include <stdio.h>

int main(void) {
    int x, y;

    printf("Enter a number: ");
    scanf("%d", &x);

    // printf("%d\n", x * x);
    y = x * x;
    printf("%d", y);
    putchar('\n');
}

square.s

main:
	# Locals:
	#   x: $t0
	#   y: $t1

	# int x;

	# printf("Enter a number: ");
	li	$v0, 4
	la	$a0, enter_a_number_str
	syscall

	# scanf("%d", &x);
	li	$v0, 5
	syscall
	move	$t0, $v0		# $t0 = $v0

	# y = x * x;
	mul	$t1, $t0, $t0

	# printf("%d", y);
	li	$v0, 1
	move	$a0, $t1
	syscall

	# putchar('\n');
	li	$v0, 11
	li	$a0, '\n'
	syscall

	# return 0;
	li	$v0, 0
	jr	$ra


	.data
enter_a_number_str:
	.asciiz	"Enter a number: "

bounded_square.c

// Squares a number, unless its square is too big for a 32-bit integer.
// If it is too big, prints an error message instead.

#include <stdio.h>

#define SQUARE_MAX 46340

int main(void) {
    int x, y;

    printf("Enter a number: ");
    scanf("%d", &x);

    // if (x > SQUARE_MAX) {
    // if (x <= SQUARE_MAX) { goto print_square; }
    if (x > SQUARE_MAX) { goto square_too_big; }
    goto print_square;

square_too_big:
    printf("square too big for 32 bits\n");
    goto epilogue;

    // } else {

print_square:
    y = x * x;
    printf("%d\n", y);

    // }

epilogue:
    return 0;
}

bounded_square.s

	SQUARE_MAX = 46340


main:
	# Locals:
	#   x: $t0
	#   y: $t1

	# int x;

	# printf("Enter a number: ");
	li	$v0, 4
	la	$a0, enter_a_number_str
	syscall

	# scanf("%d", &x);
	li	$v0, 5
	syscall
	move	$t0, $v0		# $t0 = $v0

	ble	$t0, SQUARE_MAX, print_square

	# printf("square too big for 32 bits\n");
	li	$v0, 4
	la	$a0, square_too_big_str
	syscall

	b	epilogue

print_square:
	# y = x * x;
	mul	$t1, $t0, $t0

	# printf("%d", y);
	li	$v0, 1
	move	$a0, $t1
	syscall

	# putchar('\n');
	li	$v0, 11
	li	$a0, '\n'
	syscall

epilogue:
	# return 0;
	li	$v0, 0
	jr	$ra


	.data
enter_a_number_str:
	.asciiz	"Enter a number: "
square_too_big_str:
	.asciiz	"square too big for 32 bits\n"

for.c

// Print every third number from 24 to 42.
#include <stdio.h>

int main(void) {
    // for (int x = 24; x < 42; x += 3) {
        // printf("%d\n", x);
    // }

    int x = 24;

loop_cond:
    if (x >= 42) { goto loop_end; }

    printf("%d\n", x);
    x += 3;

    goto loop_cond;

loop_end:;

}

Week #1

No code yet! If the tutorial is over, please remind Xavier to run the upload script :)