All pastes #790256 Raw Edit

Unnamed

public text v1 · immutable
·published 2007-11-20 06:21 UTC
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;
}