This commit is contained in:
bronku 2025-10-21 18:50:21 +02:00
parent 7c888a3dd0
commit 5d9fc7d18d
11 changed files with 247 additions and 297 deletions

21
README.md Normal file
View file

@ -0,0 +1,21 @@
```
// Generates a random.txt file with parameters specified, and exits
// parameters besides N, are only used internally to specify how big are the chunks written
<main> -g -N 100000 -b 10 -n 101 -o <filename>
// Sort the input file, using the temporary dir, and the parameters specified, save to the output file
<main> -i <input-file> -o <output-file> -d <tmp dir> -N 100000 -b 10 -n 101
// If no option is specified, system will prompt for parameters, and use the input data from stdin
<main>
```
- option `-i` implies the program is supposed to sort something, and thus is incompatible with `-g`
- when a parameter is not specified the default values are used:
- i = "1.in"
- o = "1.out"
- d = "tmp"
- g isn't set (false)
- N = 100000
- b = 10
- n = 101

43
buffer.c Normal file
View file

@ -0,0 +1,43 @@
#include "buffer.h"
#include "record.h"
#include "status_codes.h"
buffer create_buffer(int capacity)
{
buffer out;
out.length = 0;
out.capacity = capacity;
out.location = malloc(sizeof(record) * capacity);
return out;
}
int read_buffer(buffer* buff, FILE* in)
{
int status;
record* current = buff->location;
buff->length = 0;
for (int i = 0; i < buff->capacity; i++) {
status = read_record(in, current);
if (status != SUCCESS) {
return status;
}
buff->length++;
current++;
}
return SUCCESS;
}
int write_buffer(buffer* buff, FILE* out)
{
int status;
record* current = buff->location;
for (int i = 0; i < buff->length; i++) {
status = print_record(out, current);
if (status < 0) {
return status;
}
fprintf(out, "\n");
current++;
}
return SUCCESS;
}

12
buffer.h Normal file
View file

@ -0,0 +1,12 @@
#pragma once
#include "record.h"
typedef struct {
record* location;
int length;
int capacity;
} buffer;
buffer create_buffer(int capacity);
int read_buffer(buffer* buff, FILE* in);
int write_buffer(buffer* buff, FILE* in);

52
config.c Normal file
View file

@ -0,0 +1,52 @@
#include "config.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
int process_args(int argc, char** argv, Configuration* opts)
{
opts->input_file = DEFAULT_IN;
opts->output_file = DEFAULT_OUT;
opts->directory = DEFAULT_DIR;
opts->generate_data = false;
opts->N = DEFAULT_NN;
opts->n = DEFAULT_N;
opts->b = DEFAULT_B;
int opt;
bool input_set = false;
while ((opt = getopt(argc, argv, "i:o:d:gN:n:b:")) != -1) {
switch (opt) {
case 'i':
opts->input_file = optarg;
input_set = true;
break;
case 'o':
opts->output_file = optarg;
break;
case 'd':
opts->directory = optarg;
break;
case 'g':
opts->generate_data = true;
break;
case 'N':
opts->N = atoi(optarg);
break;
case 'n':
opts->n = atoi(optarg);
break;
case 'b':
opts->b = atoi(optarg);
break;
case '?':
printf("wrong argument\n");
return ERROR;
}
}
if (opts->generate_data && input_set) {
printf("incompatible arguments\n");
return ERROR;
}
return SUCCESS;
}

23
config.h Normal file
View file

@ -0,0 +1,23 @@
#pragma once
#include "status_codes.h"
#include <stdbool.h>
#define DEFAULT_IN "1.in"
#define DEFAULT_OUT "1.in"
#define DEFAULT_DIR "tmp"
#define DEFAULT_NN 100000
#define DEFAULT_N 101
#define DEFAULT_B 10
typedef struct
{
const char* input_file;
const char* output_file;
const char* directory;
bool generate_data;
int N; // number of records in a file
int b; // blocking factor
int n; // number of buffers
} Configuration;
int process_args(int argc, char** argv, Configuration* opts);

219
main.c
View file

@ -1,167 +1,62 @@
#include "buffer.h"
#include "config.h"
#include "record.h"
#include "tape.h"
#include <stdbool.h>
#include <stdio.h>
#include <stdlib.h>
#include "status_codes.h"
#include <sys/stat.h>
#include <sys/types.h>
#include <time.h>
#include <unistd.h>
#define DEFAULT_FILE "tests/1.in"
#define DEFAULT_DIR "tmp"
#define DEFAULT_NN 100000
#define DEFAULT_N 101
#define DEFAULT_B 10
#define END_PROGRAM -1
#define SUCCESS 0
#define ERROR -2
void print_usage()
int generate_file(int N, const char* filename)
{
printf("Options:\n");
printf(" -f [filename]\tRead/Generate records from [filename], default %s\n", DEFAULT_FILE);
printf(" -d [dirname]\tSet the directory used for temporary files, default %s\n", DEFAULT_DIR);
printf(" -N [count]\tSet total number of records, default %d\n", DEFAULT_NN);
printf(" -n [count]\tSet blocking factor, default %d\n", DEFAULT_N);
printf(" -b [count]\tSet number of buffers, default %d\n", DEFAULT_B);
printf(" -r\t randomly generate N records\n");
printf(" -h\tShow this help message\n");
}
srand(time(0));
FILE* f = fopen(filename, "w");
record rec;
typedef struct
{
FILE* input;
char* filename;
char* dirname;
bool generate_data;
bool manual_input;
int N; // number of records in a file
int b; // blocking factor
int n; // number of buffers
} options;
// reads args into opts
int process_args(int argc, char** argv, options* opts)
{
if (opts == NULL) {
return ERROR;
}
opts->input = stdin;
opts->filename = DEFAULT_FILE;
opts->dirname = DEFAULT_DIR;
opts->generate_data = false;
opts->manual_input = false;
opts->N = DEFAULT_NN;
opts->n = DEFAULT_N;
opts->b = DEFAULT_B;
int opt;
while ((opt = getopt(argc, argv, "f:d:N:n:b:rhm")) != -1) {
switch (opt) {
case 'f':
opts->filename = optarg;
break;
case 'd':
opts->dirname = optarg;
break;
case 'r':
opts->generate_data = true;
break;
case 'N':
opts->N = atoi(optarg);
break;
case 'n':
opts->n = atoi(optarg);
break;
case 'b':
opts->b = atoi(optarg);
break;
case 'm':
opts->manual_input = true;
break;
case 'h':
print_usage();
return END_PROGRAM;
case '?':
fprintf(stderr, "invalid option, terminating\n");
return ERROR;
}
}
if (opts->manual_input == true && opts->generate_data == true) {
fprintf(stderr, "Incompatible arguments: mr, aborting\n");
return ERROR;
}
opts->input = fopen(opts->filename, "r+");
if (!opts->input) {
opts->input = fopen(opts->filename, "w+");
}
if (!opts->input) {
fprintf(stderr, "Error: Cannot open file '%s'\n", opts->filename);
return ERROR;
}
struct stat st = { 0 };
if (stat(opts->dirname, &st) == -1) {
mkdir(opts->dirname, 0777);
for (int i = 0; i < N; i++) {
random_record(&rec);
print_record(f, &rec);
fprintf(f, "\n");
}
return SUCCESS;
}
void generate_file(options* opts)
int sort_file(Configuration* opts)
{
srand(time(0));
record rec;
for (int i = 0; i < opts->N; i++) {
random_record(&rec);
print_record(opts->input, &rec);
fprintf(opts->input, "\n");
}
fseek(opts->input, 0, SEEK_SET);
}
// create buffer
buffer buff = create_buffer(opts->b * opts->n);
// open file
FILE* in = fopen(opts->input_file, "r");
// <stage 1>
// while !eof:
for (int i = 0; true; i++) {
// read buffer
int status = read_buffer(&buff, in);
printf("buffer i:%d, status: %d\n", i, status);
// sort buffer
void write_file(options* opts)
{
// write run
write_buffer(&buff, stdout);
if (status != SUCCESS) {
break;
}
int sort_block(tape* t, buffer* buff)
{
static int counter = 0;
int status = read_buffer(buff, t);
if (status != SUCCESS && status != EOF) {
fprintf(stderr, "Error reading file: %d\n", status);
return status;
}
sort_buffer(buff);
printf("sorted the buffer %d, the results:\n", counter);
print_buffer(buff);
counter++;
return status;
}
int sort_file(options* opts)
{
tape a = { 0, 0, opts->input };
buffer buff;
buff.capacity = opts->b * opts->n;
buff.location = malloc(sizeof(record) * buff.capacity);
int status = 0;
while (status == SUCCESS) {
status = sort_block(&a, &buff);
}
if (status != EOF) {
// <stage 2>
// while tmp:
// merge b-1 runs
//
// close file
// free buffer
fclose(in);
free(buff.location);
fclose(a.file);
return status;
}
free(buff.location);
fclose(a.file);
return SUCCESS;
}
int main(int argc, char** argv)
{
options opts;
Configuration opts;
if (argc <= 1) {
// #todo: stdin input
fprintf(stderr, "please specify input args\n");
return ERROR;
}
@ -170,12 +65,42 @@ int main(int argc, char** argv)
return result;
}
if (opts.generate_data) {
generate_file(&opts);
return SUCCESS;
}
if (opts.manual_input) {
write_file(&opts);
return generate_file(opts.N, opts.output_file);
}
sort_file(&opts);
fclose(opts.input);
}
// int sort_block(tape* t, buffer* buff)
// {
// static int counter = 0;
// int status = read_buffer(buff, t);
// if (status != SUCCESS && status != EOF) {
// fprintf(stderr, "Error reading file: %d\n", status);
// return status;
// }
// sort_buffer(buff);
// printf("sorted the buffer %d, the results:\n", counter);
// print_buffer(buff);
// counter++;
// return status;
// }
// int sort_file(options* opts)
// {
// tape a = { 0, 0, opts->input };
// buffer buff;
// buff.capacity = opts->b * opts->n;
// buff.location = malloc(sizeof(record) * buff.capacity);
// int status = 0;
// while (status == SUCCESS) {
// status = sort_block(&a, &buff);
// }
// if (status != EOF) {
// free(buff.location);
// fclose(a.file);
// return status;
// }
// free(buff.location);
// fclose(a.file);
// return SUCCESS;
// }

View file

@ -1,30 +1,33 @@
CFLAGS = -g
build/main: build/main.o build/tape.o build
clang $(CFLAGS) build/main.o build/tape.o -o build/main
build/main: build/main.o build/config.o build/buffer.o
clang $(CFLAGS) build/main.o build/config.o build/buffer.o -o build/main
build/main.o: main.c build
clang $(CFLAGS) -c main.c -o build/main.o
build/tape.o: tape.c build
clang $(CFLAGS) -c tape.c -o build/tape.o
build/config.o: config.c build
clang $(CFLAGS) -c config.c -o build/config.o
build/buffer.o: buffer.c build
clang $(CFLAGS) -c buffer.c -o build/buffer.o
build:
mkdir -p build
tests:
mkdir -p tests
build/run: build
mkdir -p build/run
clean:
rm -rf build tests tmp
rm -rf build
run: build/main tests/1.in
build/main -f tests/1.in | less
build/run/1.in: build/run build/main
build/main -g -o build/run/1.in
run: build/main build/run/1.in
build/main -i build/run/1.in | less
debug: build/main tests/1.in
lldb -- build/main -f tests/1.in
tests/1.in: build/main tests
build/main -f tests/1.in -r
lldb -- build/main
.PHONY: clean run debug

View file

@ -28,9 +28,9 @@ static inline int compare_records(const void* a, const void* b)
return result;
}
static inline void print_record(FILE* stream, const record* out)
static inline int print_record(FILE* stream, const record* out)
{
fprintf(stream, "%d %d %d %d %d %d",
return fprintf(stream, "%d %d %d %d %d %d",
out->a[0], out->a[1], out->a[2], out->a[3], out->a[4], out->x);
}

5
status_codes.h Normal file
View file

@ -0,0 +1,5 @@
#pragma once
#define END_PROGRAM -1
#define SUCCESS 0
#define ERROR -2

108
tape.c
View file

@ -1,108 +0,0 @@
#include "record.h"
#include "tape.h"
int partition(record* arr, int start, int end)
{
int i = start;
record* pivot = arr;
pivot += end;
for (int j = start; j < end; j++) {
record* current = arr;
current += j;
if (compare_records(current, pivot) > 0) {
continue;
}
record* i_rec = arr;
i_rec += i;
record tmp = *i_rec;
*i_rec = *current;
*current = tmp;
i++;
}
record* i_rec = arr;
i_rec += i;
record tmp = *i_rec;
*i_rec = *pivot;
*pivot = tmp;
return i;
}
void quicksort(record* arr, int start, int end, int depth)
{
if (start >= end || start < 0) {
return;
}
int p = partition(arr, start, end);
quicksort(arr, start, p - 1, depth + 1);
quicksort(arr, p + 1, end, depth + 1);
}
void sort_buffer(buffer* buff)
{
quicksort(buff->location, 0, buff->length - 1, 0);
}
int read_buffer(buffer* buff, tape* tape)
{
int status;
record* destination = buff->location;
buff->length = 0;
while (buff->capacity > buff->length) {
status = read_record(tape->file, destination);
if (status != 0) {
return status;
}
destination++;
buff->length++;
tape->reads++;
}
return 0;
}
void print_full_buffer(buffer* buff)
{
for (int i = 0; i < buff->length; i++) {
record* current = buff->location;
current += i;
printf("i: %d\tg: %d\t", i, g(current));
print_record(stdout, current);
printf("\n");
}
}
void print_buffer(buffer* buff)
{
if (buff->length <= 10) {
print_full_buffer(buff);
return;
}
for (int i = 0; i < 5; i++) {
record* current = buff->location;
current += i;
printf("i: %d\tg: %d\t", i, g(current));
print_record(stdout, current);
printf("\n");
}
for (int i = buff->length - 5; i < buff->length; i++) {
record* current = buff->location;
current += i;
printf("i: %d\tg: %d\t", i, g(current));
print_record(stdout, current);
printf("\n");
}
}
int write_buffer(buffer* buff, tape* tape)
{
record* current = buff->location;
record* last = current;
last += buff->length;
while (current < last) {
print_record(tape->file, current);
fprintf(tape->file, "\n");
current++;
tape->reads++;
}
return 0;
}

26
tape.h
View file

@ -1,26 +0,0 @@
#pragma once
#include <stdio.h>
typedef struct {
int reads;
int writes;
FILE* file;
} tape;
typedef struct {
void* location;
int length;
int capacity;
} buffer;
// sorts the entire buffer
void sort_buffer(buffer* buff);
// reads [capacity] records
int read_buffer(buffer* buff, tape* tape);
// writes everything
int write_buffer(buffer* buff, tape* tape);
// for debugging
void print_buffer(buffer* buff);
void clear_tape(tape* tape);