Biblioteka za logičke vektore

Napraviti malu biblioteku za rad sa logičkim vektorima predstavljenim nizom bitova (0/1). Vektor se cuva kao dinamicki niz bitova sa najmanje značajnim bitom na indeksu 0. Biblioteka treba da omogući elementarne logičke operacije, poređenje i čitanje/pisanje u fajl.

Zadatak se reševa u fajlovima logic.h, logic.c i main.c.

Biblioteka obezbeđuje:

Ulaz

Sa standardnog ulaza se učitavaju komande do kraja ulaza. Dostupne su:

Izlaz

Za svaku komandu ispisati trazeni rezultat u posebnoj liniji (0/1 string za vektore ili 0/1 za eq).

U slučaju nepoznate komande, nekompletnog ulaza ili neuspešnog otvaranja/upisa u fajl, program prijavljuje grešku na standardni izlaz za greške i završava se neuspešno.

Primer

stdin

and 1010 1100
or 1010 1100
xor 1010 1100
not 0011
eq 0101 101

stdout

1000
1110
110
1100
1

Primer

a.txt

101010

b.txt

001100

stdin

andf a.txt b.txt
xorf a.txt b.txt
eqf a.txt a.txt
notf b.txt
write 101 out.txt

stdout

1000
100110
1
110011
101

out.txt

101

Rešenje

logic.h

#ifndef LOGIC_H
#define LOGIC_H

#include <stddef.h>
#include <stdio.h>

typedef struct {
	size_t len;   /* number of bits */
	int *bits;    /* least significant bit first */
} LogicVec;

LogicVec logic_from_string(const char *s);
LogicVec logic_from_file(FILE *f);
void logic_free(LogicVec *v);

LogicVec logic_not(const LogicVec *a);
LogicVec logic_and(const LogicVec *a, const LogicVec *b);
LogicVec logic_or(const LogicVec *a, const LogicVec *b);
LogicVec logic_xor(const LogicVec *a, const LogicVec *b);
int logic_equal(const LogicVec *a, const LogicVec *b);

int logic_fprint(FILE *f, const LogicVec *v);
void logic_print(const LogicVec *v);

#endif

main.c

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

static int read_two_inline(LogicVec *a, LogicVec *b)
{
	char buf_a[4096], buf_b[4096];
	if (scanf("%4095s %4095s", buf_a, buf_b) != 2) {
		return 0;
	}

	*a = logic_from_string(buf_a);
	*b = logic_from_string(buf_b);

	return 1;
}

static int read_one_inline(LogicVec *a)
{
	char buf[4096];
	if (scanf("%4095s", buf) != 1) {
		return 0;
	}

	*a = logic_from_string(buf);

	return 1;
}

static int read_two_files(const char *pa, const char *pb, LogicVec *a, LogicVec *b)
{
	FILE *fa = fopen(pa, "r");
	if (!fa) {
		fprintf(stderr, "Error: Could not open file %s\n", pa);
		return 0;
	}

	FILE *fb = fopen(pb, "r");
	if (!fb) {
		fprintf(stderr, "Error: Could not open file %s\n", pb);
		fclose(fa);
		return 0;
	}

	*a = logic_from_file(fa);
	*b = logic_from_file(fb);

	fclose(fa);
	fclose(fb);

	return 1;
}

static int read_one_file(const char *path, LogicVec *a)
{
	FILE *f = fopen(path, "r");
	if (!f) {
		fprintf(stderr, "Error: Could not open file %s\n", path);
		return 0;
	}

	*a = logic_from_file(f);

	fclose(f);

	return 1;
}

static void handle_binary(LogicVec (*op)(const LogicVec *, const LogicVec *), int is_eq)
{
	LogicVec a, b;
	if (!read_two_inline(&a, &b)) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	if (is_eq) {
		printf("%d\n", logic_equal(&a, &b));
	} else {
		LogicVec r = op(&a, &b);
		logic_print(&r);
		logic_free(&r);
	}

	logic_free(&a);
	logic_free(&b);
}

static void handle_binary_file(LogicVec (*op)(const LogicVec *, const LogicVec *), int is_eq)
{
	char pa[512], pb[512];
	if (scanf("%511s %511s", pa, pb) != 2) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	LogicVec a, b;
	if (!read_two_files(pa, pb, &a, &b)) {
		exit(EXIT_FAILURE);
	}

	if (is_eq) {
		printf("%d\n", logic_equal(&a, &b));
	} else {
		LogicVec r = op(&a, &b);
		logic_print(&r);
		logic_free(&r);
	}

	logic_free(&a);
	logic_free(&b);
}

static void handle_unary(LogicVec (*op)(const LogicVec *))
{
	LogicVec v;
	if (!read_one_inline(&v)) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	LogicVec r = op(&v);

	logic_print(&r);

	logic_free(&v);
	logic_free(&r);
}

static void handle_unary_file(LogicVec (*op)(const LogicVec *))
{
	char path[512];
	if (scanf("%511s", path) != 1) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	LogicVec v;
	if (!read_one_file(path, &v)) {
		exit(EXIT_FAILURE);
	}

	LogicVec r = op(&v);

	logic_print(&r);

	logic_free(&v);
	logic_free(&r);
}

static void handle_read()
{
	char path[512];
	if (scanf("%511s", path) != 1) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	LogicVec v;
	if (!read_one_file(path, &v)) {
		exit(EXIT_FAILURE);
	}

	logic_print(&v);

	logic_free(&v);
}

static void handle_write()
{
	char bits[4096];
	char path[512];
	if (scanf("%4095s %511s", bits, path) != 2) {
		fprintf(stderr, "Error: Invalid input format.\n");
		exit(EXIT_FAILURE);
	}

	LogicVec v = logic_from_string(bits);

	FILE *out = fopen(path, "w");
	if (!out) {
		fprintf(stderr, "Error: Could not open file %s\n", path);
		logic_free(&v);
		exit(EXIT_FAILURE);
	}

	if (!logic_fprint(out, &v)) {
		fprintf(stderr, "Error: Could not write file %s\n", path);
		fclose(out);
		logic_free(&v);
		exit(EXIT_FAILURE);
	}

	logic_print(&v);

	fclose(out);

	logic_free(&v);
}

int main(void)
{
	char op[16];

	while (scanf("%15s", op) == 1) {
		if (strcmp(op, "and") == 0) {
			handle_binary(logic_and, 0);
		} else if (strcmp(op, "or") == 0) {
			handle_binary(logic_or, 0);
		} else if (strcmp(op, "xor") == 0) {
			handle_binary(logic_xor, 0);
		} else if (strcmp(op, "eq") == 0) {
			handle_binary(logic_and, 1);
		} else if (strcmp(op, "not") == 0) {
			handle_unary(logic_not);
		} else if (strcmp(op, "andf") == 0) {
			handle_binary_file(logic_and, 0);
		} else if (strcmp(op, "orf") == 0) {
			handle_binary_file(logic_or, 0);
		} else if (strcmp(op, "xorf") == 0) {
			handle_binary_file(logic_xor, 0);
		} else if (strcmp(op, "eqf") == 0) {
			handle_binary_file(logic_and, 1);
		} else if (strcmp(op, "notf") == 0) {
			handle_unary_file(logic_not);
		} else if (strcmp(op, "read") == 0) {
			handle_read();
		} else if (strcmp(op, "write") == 0) {
			handle_write();
		} else {
			fprintf(stderr, "Error: Unknown operation %s\n", op);
			exit(EXIT_FAILURE);
		}
	}

	exit(EXIT_SUCCESS);
}

logic.c

#include "logic.h"
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static LogicVec logic_zero(void)
{
	LogicVec v;
	v.len = 1;
	v.bits = calloc(1, sizeof (int));
	if (v.bits) {
		v.bits[0] = 0;
	} else {
		v.len = 0;
	}
	return v;
}

static void logic_strip(LogicVec *v)
{
	while (v->len > 1 && v->bits[v->len - 1] == 0) {
		v->len--;
	}
}

LogicVec logic_from_string(const char *s)
{
	if (s == NULL) {
		return logic_zero();
	}

	size_t raw_len = strlen(s);
	if (raw_len == 0) {
		return logic_zero();
	}

	LogicVec v;
	v.len = raw_len;
	v.bits = calloc(raw_len, sizeof (int));
	if (v.bits == NULL) {
		return logic_zero();
	}

	for (size_t i = 0; i < raw_len; i++) {
		char c = s[raw_len - 1 - i];
		if (c != '0' && c != '1') {
			logic_free(&v);
			return logic_zero();
		}
		v.bits[i] = c - '0';
	}

	return v;
}

LogicVec logic_from_file(FILE *f)
{
	if (f == NULL) {
		return logic_zero();
	}

	size_t cap = 128;
	size_t len = 0;
	char *buf = malloc(cap);
	if (buf == NULL) {
		return logic_zero();
	}

	int c;
	/* skip whitespace */
	do {
		c = fgetc(f);
		if (c == EOF) {
			free(buf);
			return logic_zero();
		}
	} while (isspace(c));

	while (c != EOF && !isspace(c)) {
		if (len + 1 >= cap) {
			cap *= 2;
			char *tmp = realloc(buf, cap);
			if (!tmp) {
				free(buf);
				return logic_zero();
			}
			buf = tmp;
		}
		buf[len++] = (char)c;
		c = fgetc(f);
	}
	buf[len] = '\0';

	LogicVec v = logic_from_string(buf);

	free(buf);

	return v;
}

void logic_free(LogicVec *v)
{
	if (v && v->bits) {
		free(v->bits);
		v->bits = NULL;
		v->len = 0;
	}
}

LogicVec logic_not(const LogicVec *a)
{
	LogicVec res;
	res.len = a->len;
	res.bits = calloc(res.len, sizeof (int));
	if (res.bits == NULL) {
		return logic_zero();
	}

	for (size_t i = 0; i < res.len; i++) {
		res.bits[i] = a->bits[i] ? 0 : 1;
	}

	logic_strip(&res);

	return res;
}

static LogicVec logic_binary_op(const LogicVec *a, const LogicVec *b, int (*comb)(int, int))
{
	size_t max_len = (a->len > b->len) ? a->len : b->len;
	LogicVec res;
	res.len = max_len;
	res.bits = calloc(max_len, sizeof (int));
	if (res.bits == NULL) {
		return logic_zero();
	}

	for (size_t i = 0; i < max_len; i++) {
		int va = (i < a->len) ? a->bits[i] : 0;
		int vb = (i < b->len) ? b->bits[i] : 0;
		res.bits[i] = comb(va, vb);
	}

	logic_strip(&res);

	return res;
}

static int comb_and(int a, int b) { return a && b; }
static int comb_or(int a, int b) { return a || b; }
static int comb_xor(int a, int b) { return a ^ b; }

LogicVec logic_and(const LogicVec *a, const LogicVec *b)
{
	return logic_binary_op(a, b, comb_and);
}

LogicVec logic_or(const LogicVec *a, const LogicVec *b)
{
	return logic_binary_op(a, b, comb_or);
}

LogicVec logic_xor(const LogicVec *a, const LogicVec *b)
{
	return logic_binary_op(a, b, comb_xor);
}

int logic_equal(const LogicVec *a, const LogicVec *b)
{
	size_t len_a = a->len;
	size_t len_b = b->len;

	while (len_a > 1 && a->bits[len_a - 1] == 0) {
		len_a--;
	}

	while (len_b > 1 && b->bits[len_b - 1] == 0){
		len_b--;
	}

	if (len_a != len_b) {
		return 0;
	}

	for (size_t i = 0; i < a->len; i++) {
		if (a->bits[i] != b->bits[i]) {
			return 0;
		}
	}

	return 1;
}

int logic_fprint(FILE *f, const LogicVec *v)
{
	if (f == NULL || v == NULL || v->bits == NULL) {
		return 0;
	}

	for (size_t i = 0; i < v->len; i++) {
		fputc(v->bits[v->len - 1 - i] ? '1' : '0', f);
	}

	fputc('\n', f);

	return 1;
}

void logic_print(const LogicVec *v)
{
	logic_fprint(stdout, v);
}