rendered paste body#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
#include "helpers.h"
#include "tree.h"
#define BUFFER_SIZE 12
#define MIN_WORD_LENGTH 2
int ignore_case = 0; /* Jos true, niin kaikki kirjaimet muutetaan pieniksi */
char *input_filename = NULL; /* Mahdollisen syötetiedoston nimi */
char *output_filename = NULL; /* Mahdollisen tulostiedoston nimi */
FILE *source = NULL; /* Syötevirta, jota luetaan */
FILE *destination = NULL; /* Tulostevirta, jonne kirjoitetaan */
char *word_buffer = NULL; /* read_word() funktion käyttämä puskuri */
TreeNode *root = NULL; /* Sanabinääripuun juurisolmu */
/*
Puun lehtien tulostusfunktio. Välitetään tree_inorder()-funktiolle.
Ks. node_handler_func tree.h:sta.
*/
void print_node(TreeNode *node) {
if (*node->word == '\0') {
/* Juurisolmua ei tulosteta. */
return;
}
fprintf(destination, "%d\t%s\n", node->frequency, node->word);
}
/*
Tulostaa ohjelman käyttö-ohjeet stdiniin.
*/
void print_help() {
printf("Sanalaskuri\n");
printf("===========\n");
printf("Sanalaskuri lukee annetusta syötteestä sanojen esiintymistiheyden. \n");
printf("Käyttö: sanalaskuri -hc [syötetiedosto [tulostetiedosto]]\n\n");
printf("Mikäli syöte- tai tulostetiedostoa ei määritellä, käytetään standardisyöttö- ja tulostusvirtaa.\n\n");
printf("Parametrit:\n");
printf("\t-h : tämä ohje\n");
printf("\t-c : samaista isot ja pienet kirjaimet\n");
printf("\t[syötetiedosto] : lue syöte tästä tiedostosta\n");
printf("\t[tulostetiedosto] : tulosta tiedot tähän tiedostoon\n\n");
#ifndef NDEBUG
printf("\nOhjelma on käännetty debug-tilassa.\n\n");
#endif
}
/*
Lukee komentoriviparametrit ja säätää ohjelman toiminnan vastaamaan näitä.
sanalaskuri -hc [syötetiedosto [tulostetiedosto]]
*/
void parse_parameters(int argc, char **argv) {
int i;
if (argc == 1) {
print_help();
return;
}
for(i = 1; i<argc; i++) {
if (*argv[i] == '-') {
/* Kyseessä on vipuparametri eli -h tai -c. */
char param = argv[i][1];
if (param == 'h') {
print_help();
exit(0); /* Lopetetaan ohjelman suoritus. */
} else if (param == 'c') {
ignore_case = 1;
}
} else {
/* Kyseessä tiedostonimi */
if (input_filename == NULL) {
input_filename = argv[i];
debug_print("input_filename: %s", input_filename);
} else if (output_filename == NULL) {
output_filename = argv[i];
debug_print("output_filename: %s", output_filename);
}
}
}
if (ignore_case) {
printf("Isot ja pienet merkit samaistetaan.\n");
}
}
/*
Asettaa source ja destination tiedostokahvat.
*/
void setup_io() {
/*
Mikäli input-tiedostoa ei ole määriteltyä, luetaan syöte standardisyöttövirrasta.
Jos määritelty, yritetään avata tiedosto.
*/
if (input_filename == NULL) {
source = stdin;
printf("Luetaan sanoja standardisyöttövirrasta.\n");
} else {
if ( (source = fopen(input_filename, "r")) != NULL) {
printf("Luetaan sanoja tiedostosta nimeltä %s\n", input_filename);
} else {
printf("Syötetiedostoa '%s' ei voitu avata.\n", input_filename);
exit(0);
}
}
/* Sama kuin edellä, mutta tulostetiedostoille. */
if (output_filename == NULL) {
destination = stdout;
printf("Tulostetaan standarditulostevirtaan.\n");
} else {
if ( (destination = fopen(output_filename, "w")) != NULL) {
printf("Tulostetaan tiedostoon %s\n", output_filename);
} else {
printf("Tulostetiedostoa '%s' ei voitu avata.\n", output_filename);
exit(0);
}
}
}
/* Sulkee käytetyt tiedostot */
void close_io() {
if (source != NULL) {
fclose(source);
source = NULL;
}
if (destination != NULL) {
fclose(destination);
destination = NULL;
}
}
/*
Lukee seuraavan sanan annetusta tiedostosta. Alussa olevat tyhjät merkit ohitetaan.
Kirjoittaa globaaliin word_buffer luetun sanan tai NULL, jos mitään ei saatu luettua
tai muistinvaraus epäonnistuu.
*/
void read_word(FILE *source) {
int c = 0; /* merkki, joka luetaan */
int len = 0; /* puskuriin luettujen merkkien lkm */
int reallocs = 0; /* puskurin kasvatusten lukumäärä */
while ( (c = fgetc(source)) != EOF) {
if (isspace(c)) {
if (len == 0) {
/* puskurissa ei ole merkkejä, joten syödään whitespacet pois */
continue;
} else {
/* puskuriin on luettu tavaraa, joten jokin sana päättyi nyt */
break;
}
} else {
if (len >= (BUFFER_SIZE * reallocs)) {
/* kasvatetaan puskurin kokoa */
reallocs++;
word_buffer = realloc(word_buffer, sizeof(char) * (BUFFER_SIZE * reallocs) + 1);
debug_print("word_bufferille varattiin lisää muistia. Uusi koko: %d\n", BUFFER_SIZE*reallocs +1); ;
}
if (word_buffer != NULL) {
word_buffer[len] = (char)c;
len++;
}
}
}
debug_print("read_word luki %d merkkiä eli sanan %s", len, word_buffer);
/* Lisätään sanan loppuun terminaattori */
word_buffer[len] = '\0';
}
/* Pääohjelma */
int main(int argc, char **argv) {
int done = 0;
parse_parameters(argc, argv);
setup_io();
/* Luodaan puun juurisolmu */
root = create_node("\0");
while ( !done ) {
read_word(source);
if (word_buffer == NULL) {
done = 1;
break;
}
if (strlen(word_buffer) == 1) {
done = 1;
break;
}
if (strlen(word_buffer) >= MIN_WORD_LENGTH) {
if (ignore_case) {
convert_lowercase(word_buffer);
}
insert_word(root, word_buffer);
}
}
/* Tulostetaan puu. Käydään lehdet sisäkkäisläpikäynnillä läpi */
tree_inorder(root, &print_node);
delete_tree(root);
close_io();
free(word_buffer);
return 0;
}