/** * Soubor: proj4.c * Datum: 28.11.2008 * Autor: Vojtěch Kalčík, xkalci01@stud.fit.vutbr.cz * Projekt: České řazení, projekt č. 4 pro předmět IZP * Popis: Program řadí údaje ze souboru csv podle zadaného klíče */ #include #include #include #include #define POCET_SLOUPCU 5 #define POCET_SLOUPCU_ZNAK '5' #define POCET_PLATNYCH_ZNAKU 20 #define OD -1 #define POCET_ALOKOVANI 30 const int POCET_DVOJZNAKU = 1; const char POVOLENE_ZNAKY[] = "áčďéěíňóřšťúůýžÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ .-\0"; // kromně A-Z a 0-9 //ZNAKY jsou procházeny pouze jednou ve funkci vytvor_tabulky, kde se vytvoří pole priority znaků. const char ZNAKY[] = " aábcčdďeěéfghiíjklmnňoópqrřsštťuúůvwxyýzž0123456789.-\0"; const char VELKE[] = "ÁČĎÉĚÍŇÓŘŠŤÚŮÝŽ\0"; const char MALE[] = "áčďéěíňóřšťúůýž\0"; const char PRED[] = "áďéěíňóťúůý\0"; const char PO[] = "adeeinotuuy\0"; /** * Hlasky programu, ktere se vazi ke stavum programu. */ const char *STAVY[] = { "Vse v poradku.", "Autor: Vojtěch Kalčík, xkalci01@stud.fit.vutbr.cz\n" "Projekt: České řazení, projekt č. 4 pro předmět IZP\n" "Popis: Program řadí údaje ze souboru csv podle zadaného klíče" "\n" "Parametry:\n" " -h : Vypíše napovedu.\n" " +key=klic soubor1 soubor2 : Seřadí záznamy vzestupně.\n" " -key=klic soubor1 soubor2 : Seřadí záznamy sestupně.\n" "\n" "Příklad:\n" " +key=154 vstup.csv vystup.csv\n" "\n" "klic: se skládá z číslic 1,2,3,4,5 a káždá tam může být nanejvýš jednou. Číslice udává sloupec." "Pořadí číslic udává prioritu sloupce při řazení.\n" "soubor1 : vstupní soubor, kde na každém řádku je zapsaná jedna osoba ve formátu\n" " příjmení,jméno,pohlaví(M/Ž),město,rodné číslo(pouze číslice)\n" "soubor2 : výstupní soubor, kam se uloží seřazené záznamy.\n", "Chyba v parametrech. Parametrem -h zobrazite napovedu.", "Nepodařilo se otevřít první soubor.", "Nepodařilo se otevřít druhý soubor.", "Nepodařilo se alokovat pole.", "Ve vstupní souboru je chyba. Parametrem -h zobrazite napovedu.", "Nepodařil se otevřít soubor se znakama.", "V souboru se znakam je chyba. Parametrem -h zobrazite napovedu.", "Nepodařilo se alokovat pole pro dvojznaky.", }; /** * Vycet stavu programu. */ enum e_stav { ST_OK = 0, // Vse v poradku ST_NAPOVEDA, // Napoveda ST_SP_PARAMETRY, // Chyba v parametrech ST_SP_SOUB1, // 1. soubor se nepodařilo otevřít ST_SP_SOUB2, // 2. soubor se nepodařilo otevřít ST_SP_ALOK, // Nepodařilo se alokovat pole ST_SP_VSTUP, // Chyba ve vstupním souboru ST_SP_ALOK_DVOJ, // Nepodařilo se alokovat pole pro dvojznaky }; /** * Výčet sloupců */ enum e_sloupce { PRIJMENI = 0, // příjmení JMENO, // jméno POHLAVI, // pohlaví MESTO, // město ROD_CISLO, // rodné číslo }; /** * Struktura, kterou navrací funkce zpracuj_parametry. */ typedef struct parametry { int stav; bool vzestupne; char *klic; FILE *soubor1; FILE *soubor2; }Tparametry; /** * Struktura pro jednotlive osoby */ typedef struct osoba { char jmeno[POCET_PLATNYCH_ZNAKU+1]; char prijmeni[POCET_PLATNYCH_ZNAKU+1]; char mesto[POCET_PLATNYCH_ZNAKU+1]; char pohlavi[2]; long long rod_cislo; }Tosoba; /** * Struktura pro dvojznaky a víceznaky */ typedef struct dvoj_znak { char znak[2]; int poradi; }Tdvojznak; /** * Zjistí, jestli je klíč korektní */ bool klic_ok(char *text, int delka) { bool navrat = true; if ((delka > POCET_SLOUPCU)||(delka < 1)) { navrat = false; } for(int i=0;(iPOCET_SLOUPCU_ZNAK)) { navrat = false; } } int pole[POCET_SLOUPCU] = {0}; for(int i=0;(i 1) { navrat = false; } } return navrat; } /** * Vrátí podřetězec od počátku do delky. Funkce vrací také délku podřetězce. */ int substr(char *text, int pocatek, int delka) { int delka_text = strlen(text); if(delka == 0) { delka = delka_text - pocatek; } int j = 0; for(int i=pocatek;i 10)) { navrat = false; } for(int i=0;(i'9')) { navrat = false; } } return navrat; } /** * Vypíše záznamy do souboru */ void vypis_do_souboru(FILE *soubor, Tosoba *pole,int pocet, bool vzestupne) { int i = 0; if(!vzestupne) { i = pocet - 1; } while((i>=0)&&(i= '0')&&(znak <= '9')) { navrat = true; } else if((znak >= 'A')&&(znak <= 'Z')) { navrat = true; } else if((znak >= 'a')&&(znak <= 'z')) { navrat = true; } int i = 0; while((POVOLENE_ZNAKY[i] != '\0')&&(!navrat)) { if(znak == POVOLENE_ZNAKY[i]) { navrat = true; } i++; } return navrat; } /** * Načte soubor */ int nacti_soubor(FILE *soubor, Tosoba *pole, int *pocet_osob) { int navrat = ST_OK; int osob_naalokovano = POCET_ALOKOVANI; int osob_nacteno = 0; int sloupec = PRIJMENI; int i = 0; signed char znak; char nacitano[POCET_PLATNYCH_ZNAKU+1]; bool zapsat_konec = true; Tosoba *pole_realok; while(((znak = fgetc(soubor))!=EOF)&&(navrat == ST_OK)) { // alokace a realokace pole if((osob_naalokovano <= osob_nacteno)&&(navrat == ST_OK)) { pole_realok = realloc(pole, (osob_naalokovano+POCET_ALOKOVANI)*sizeof(Tosoba)); // kontrola alokace if(pole_realok == NULL) { navrat = ST_SP_ALOK; } else { pole = pole_realok; } osob_naalokovano += POCET_ALOKOVANI; } if(navrat == ST_OK) { if(znak == '\n') { if(sloupec == ROD_CISLO) { nacitano[i] = '\0'; i = 0; if(rod_cislo_ok(nacitano)) { pole[osob_nacteno].rod_cislo = atoll(nacitano); osob_nacteno++; } else { navrat = ST_SP_VSTUP; } } else if(sloupec != PRIJMENI) { navrat = ST_SP_VSTUP; } sloupec = PRIJMENI; } else if(znak == ',') { if(zapsat_konec) { nacitano[i] = '\0'; } else { zapsat_konec = true; } i = 0; if(sloupec == PRIJMENI) { strcpy(pole[osob_nacteno].prijmeni, nacitano); } else if(sloupec == JMENO) { strcpy(pole[osob_nacteno].jmeno, nacitano); } else if(sloupec == POHLAVI) { if((strcmp(nacitano,"M")==0)||(strcmp(nacitano,"Ž")==0)) { strcpy(pole[osob_nacteno].pohlavi, nacitano); } else { navrat = ST_SP_VSTUP; } } else if(sloupec == MESTO) { strcpy(pole[osob_nacteno].mesto, nacitano); } sloupec++; } else { bool cti = (i= 'A')&&(znak <= 'Z')) { znak = znak - 'A' + 'a'; } else if(znak < 0) { int i = 0; while((VELKE[i]!='\0')&&(pokracuj_velke)) { if(znak == VELKE[i]) { znak = MALE[i]; pokracuj_velke = false; } i++; } } if(pruchod1) { int i = 0; while((PRED[i]!='\0')&&(pokracuj_pruchod)) { if(znak == PRED[i]) { znak = PO[i]; pokracuj_pruchod = false; } i++; } } return znak; } /** * Načte znaky pro řazení */ void vytvor_tabulky(int *znaky_poradi, Tdvojznak *dvojznaky) { int i = 0; int dvojznak_poradi = 0; int dvojznak_znak = 0; bool je_dvojznak = false; while(ZNAKY[i] != '\0') { if(ZNAKY[i] == '<') { je_dvojznak = true; } else if(ZNAKY[i] == '>') { dvojznaky[dvojznak_poradi].poradi = i; dvojznak_znak = 0; dvojznak_poradi++; je_dvojznak = false; } else if(je_dvojznak) { dvojznaky[dvojznak_poradi].znak[dvojznak_znak] = ZNAKY[i]; dvojznak_znak++; } else { znaky_poradi[(unsigned char)ZNAKY[i]] = i; } i++; } } /** * Zjistí hodnotu priority znaku */ int priorita_znaku(int *znaky_poradi, Tdvojznak *dvojznak, int index, char *text, bool pruchod1, int *posun) { int hodnota = -1; for(int i = 0; (i < POCET_DVOJZNAKU)&&(hodnota == -1); i++) { if((dvojznak[i].znak[0] == uprav_znak(text[index], pruchod1))&&(dvojznak[i].znak[1] == uprav_znak(text[index+1], pruchod1))) { hodnota = dvojznak[i].poradi; *posun = 1; } } if(hodnota == -1) { hodnota = znaky_poradi[(unsigned char)uprav_znak(text[index], pruchod1)]; } return hodnota; } /** * Porovná dva texty */ int porovnej(int *znaky_poradi, Tdvojznak *dvojznak, char *text1, char *text2) { int navrat = 0; bool pokracuj = true; int pruchod1 = 0; int pruchod2 = 0; int i1 = 0; int i2 = 0; int posun1 = 0; int posun2 = 0; while(pokracuj) { if((text1[i1] == '\0')&&(text2[i2] == '\0')) { pruchod1 = 0; pokracuj = false; } else if(text1[i1] == '\0') { pruchod1 = -1; pokracuj = false; } else if(text2[i2] == '\0') { pruchod1 = 1; pokracuj = false; } else { int znak1 = priorita_znaku(znaky_poradi, dvojznak, i1, text1, true, &posun1); int znak2 = priorita_znaku(znaky_poradi, dvojznak, i2, text2, true, &posun2); if(znak1 < znak2) { pruchod1 = -1; pokracuj = false; } else if(znak1 > znak2) { pruchod1 = 1; pokracuj = false; } else if(znak1 == znak2) { znak1 = priorita_znaku(znaky_poradi, dvojznak, i1, text1, false, &posun1); znak2 = priorita_znaku(znaky_poradi, dvojznak, i2, text2, false, &posun2); if(pruchod2 == 0) { if(znak1 < znak2) { pruchod2 = -1; } else if(znak1 > znak2) { pruchod2 = 1; } } } } i1++; i2++; i1 += posun1; i2 += posun2; posun1 = 0; posun2 = 0; } if(pruchod1 != 0) { navrat = pruchod1; } else { navrat = pruchod2; } return navrat; } /** * Porovná dvě osoby */ int porovnej_osoby(int *znaky_poradi, Tdvojznak *dvojznak, Tosoba *osoba1, Tosoba *osoba2, char *klic) { int i = 0; int navrat = 0; while((klic[i]!='\0')&&(navrat == 0)) { if(klic[i] - '1' == PRIJMENI) { navrat = porovnej(znaky_poradi, dvojznak, osoba1->prijmeni, osoba2->prijmeni); } else if(klic[i] - '1' == JMENO) { navrat = porovnej(znaky_poradi, dvojznak, osoba1->jmeno, osoba2->jmeno); } else if(klic[i] - '1' == POHLAVI) { navrat = porovnej(znaky_poradi, dvojznak, osoba1->pohlavi, osoba2->pohlavi); } else if(klic[i] - '1' == MESTO) { navrat = porovnej(znaky_poradi, dvojznak, osoba1->mesto, osoba2->mesto); } else if(klic[i] - '1' == ROD_CISLO) { if(osoba1->rod_cislo > osoba2->rod_cislo) { navrat = 1; } else { navrat = -1; } } i++; } return navrat; } /** * Postaví haldu */ void postav_haldu(Tosoba *pole, int *znaky_poradi, Tdvojznak *dvojznaky, char *klic, int pocet_zaznamu) { for(int velikost_haldy = 1; velikost_haldy <= pocet_zaznamu; velikost_haldy++) { int i = velikost_haldy; while((i > 1)&&(porovnej_osoby(znaky_poradi, dvojznaky, &pole[i OD], &pole[i/2 OD], klic)>0)) { Tosoba pomocna; pomocna = pole[i OD]; pole[i OD] = pole[i/2 OD]; pole[i/2 OD] = pomocna; i = i/2; } } } /** * Rozebere haldu haldu */ void rozeber_haldu(Tosoba *pole, int *znaky_poradi, Tdvojznak *dvojznaky, char *klic, int pocet_zaznamu) { for(int velikost_haldy = pocet_zaznamu-1; velikost_haldy > 0; velikost_haldy--) { Tosoba pomocna; pomocna = pole[0]; pole[0] = pole[velikost_haldy]; pole[velikost_haldy] = pomocna; int i = 1; bool pokracuj = true; do { if((2*i+1>velikost_haldy)||(porovnej_osoby(znaky_poradi, dvojznaky, &pole[2*i OD], &pole[2*i+1 OD], klic)>0)) { if((2*i<=velikost_haldy)&&(porovnej_osoby(znaky_poradi, dvojznaky, &pole[i OD], &pole[2*i OD], klic)<0)) { pomocna = pole[i OD]; pole[i OD] = pole[2*i OD]; pole[2*i OD] = pomocna; i = 2*i; } else { pokracuj = false; } } else { if(porovnej_osoby(znaky_poradi, dvojznaky, &pole[i OD], &pole[2*i+1 OD], klic)<0) { pomocna = pole[i OD]; pole[i OD] = pole[2*i+1 OD]; pole[2*i+1 OD] = pomocna; i = 2*i+1; } else { pokracuj = false; } } if(2*i>velikost_haldy) { pokracuj = false; } } while(pokracuj); } } /** * Porovná záznamy podle zadaného klíče */ int setrid_zaznamy(Tosoba *pole, int pocet_zaznamu, char *klic) { int navrat = ST_OK; int znaky_poradi[256]; Tdvojznak *dvojznaky; dvojznaky = malloc(POCET_DVOJZNAKU * sizeof(Tdvojznak)); if((dvojznaky == NULL)&&(POCET_DVOJZNAKU != 0)) { navrat = ST_SP_ALOK_DVOJ; } if(navrat == ST_OK) { vytvor_tabulky(znaky_poradi, dvojznaky); postav_haldu(pole, znaky_poradi, dvojznaky, klic, pocet_zaznamu); rozeber_haldu(pole, znaky_poradi, dvojznaky, klic, pocet_zaznamu); free(dvojznaky); } return navrat; } /** * Z této funkce se volají další funkce pro zpracování souboru */ void pracuj(Tparametry *parametry) { Tosoba *pole; pole = malloc(POCET_ALOKOVANI*sizeof(Tosoba)); int pocet = 0; if(pole != NULL) { parametry->stav = nacti_soubor(parametry->soubor1, pole, &pocet); if(parametry->stav == ST_OK) { setrid_zaznamy(pole, pocet, parametry->klic); vypis_do_souboru(parametry->soubor2, pole, pocet, parametry->vzestupne); } free(pole); } else { parametry->stav = ST_SP_ALOK; } } /** * Vypsani chybove hlasky nebo napovedy. */ void vypis_hlasku(int stav) { FILE *vystup = stdout; if(stav > ST_NAPOVEDA) { vystup = stderr; } fprintf(vystup, "%s\n", STAVY[stav]); } /** * Zpracovani parametru */ Tparametry zpracuj_parametry(int argc, char *argv[]) { Tparametry navrat = { .stav = ST_OK, .vzestupne = true, .klic = NULL, .soubor1 = NULL, .soubor2 = NULL, }; if(argc == 2) { if(strcmp(argv[1], "-h") == 0) { navrat.stav = ST_NAPOVEDA; } else { navrat.stav = ST_SP_PARAMETRY; } } else if(argc == 4) { if((strncmp(argv[1], "+key=", 5) == 0)||(strncmp(argv[1], "-key=", 5) == 0)) { navrat.vzestupne = (strncmp(argv[1], "+key", 4) == 0); navrat.klic = argv[1]; int delka_text = substr(navrat.klic,5,0); if(!klic_ok(navrat.klic, delka_text)) { navrat.stav = ST_SP_PARAMETRY; } //ukazatele na soubor if(navrat.stav == ST_OK) { navrat.soubor1 = fopen(argv[2],"r"); if(navrat.soubor1 == NULL) { navrat.stav = ST_SP_SOUB1; } navrat.soubor2 = fopen(argv[3],"w"); if(navrat.soubor2 == NULL) { navrat.stav = ST_SP_SOUB2; } } } else { navrat.stav = ST_SP_PARAMETRY; } } else { navrat.stav = ST_SP_PARAMETRY; } return navrat; } /** *Hlavni program */ int main(int argc, char *argv[]) { int navrat = EXIT_SUCCESS; Tparametry parametry = zpracuj_parametry(argc, argv); if(parametry.stav == ST_OK) { pracuj(¶metry); if(parametry.stav != ST_OK) { vypis_hlasku(parametry.stav); navrat = EXIT_FAILURE; } } else { vypis_hlasku(parametry.stav); if(parametry.stav == ST_NAPOVEDA) { navrat = EXIT_SUCCESS; } else { navrat = EXIT_FAILURE; } } if(parametry.soubor1 != NULL) { fclose(parametry.soubor1); } if(parametry.soubor2 != NULL) { fclose(parametry.soubor2); } return navrat; }