Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- /* Author: Dawid Mocek */
- #include <stdlib.h>
- #include <stdio.h>
- #include <string.h>
- #include <errno.h>
- /**
- * Funkcja sprawdza czy string jest pusty
- * @param str tekst do przetestowania
- * @return 1 jesli tekst jest pusty, 0 jesli linia zawiera chociaz jeden znak (nawet bialy jak np spacja czy tabulator (\t))
- */
- int strIsEmpty(const char *str)
- {
- if (str && str[0]) {
- return 0;
- }
- return 1;
- }
- /**
- * Funkcja czyta linia po lini z pliku
- *
- * @param fh uchwyt do czytanego pliku
- * @return NULL jesli linia zostala przeczytana lub nie ma nic wiecej do czytania
- */
- char * getLine(FILE *fh) {
- // Macro BUFSIZ zdefiniowane jest w pliku naglowkowy <stdio.h>
- // Mozemy podejrzec ile dokladnie wynosi dla naszego systemu: printf("BUFSIZ = %d\n", BUFSIZ);
- // Dla testów zamiast BUFSIZ możemy dac mniejszy chunk jaki będzie czytany "na raz" z lini (np: buffer[16], buffer[32] ... buffer[128]). Wazne, zeby byl potęgą dwójki.
- // Mozna także zdefiniowac buffer[1] co jest rowne czytaniem 1 znak po 1 znaku (tj jeden char po 1 char'ze lub jeszcze inaczej: 1 bajt za 1 bajtem bo sizeof(char) == 1 bajt na wiekszosci popularnych systemów)
- // z danej lini - nawet jak bedziemy posiadac najszybszy dysk na swiecie to przeczytanie pliku parumegabajtwoego
- // moze zajac godzine dwie... z buferem równym 1
- char buffer[BUFSIZ] = { 0 };
- // Przyczytana linia która zostanie zwrocona z tej funkcji
- char *line = NULL;
- // Flaga oznaczajaca ze nie ma nic wiecej do czytania w danej linii
- int success = 0;
- // Dlugosc stringu
- size_t length = 0;
- // Potrzebne dla realloc - tymczasowna zmienna do przepinania pamięci.
- char *tmp = NULL;
- // Sprawdzamy czy plik został otwarty - jesli nie tj fh == NULL to zwracamy NULL jako brak przeczytanej lini
- if (fh == NULL)
- {
- return NULL;
- }
- // Algorytm składa sie z dwoch przypadkow - fgets przczytal od razu cała linie i fgets przez to ze moze czytac tylko do bufforu o stalej dlugosc tj BUFSIZ nie przeczyta calej lini tylko jej czesc wiec
- // musimy realkowac koljne chunki pamieci (wszystkie dokladnie o wielkosc BUFSIZ)
- // Czytamy linie za pomoca fgets.
- if (fgets(buffer, sizeof(buffer), fh) != NULL)
- {
- length = strlen(buffer);
- // 1 Przypadek - tutaj sprawdzamy czy linia rzeczywiscie ma swoj koniec (\n) czyli liczba znakow przeczytanych miescie sie w liczbie BUFSIZ lub
- // czy musimy zaalokowac nastepny chunk pamieci i czytac dalej....
- if (buffer[length - 1] == '\n')
- {
- // Musimy zamknąć stringa null`em
- buffer[length - 1] = '\0';
- // Alokujemy pamiec dla tej linii:
- line = (char *)malloc(length);
- // Sprawdzamy czy pamiec sie zaalkowała
- if (line == NULL)
- {
- fclose(fh);
- printf("Memory allocation error\n");
- exit(-1);
- }
- // kopiujemy linie z tymczaswoego bufora
- strcpy(line, buffer);
- // jesli linia ma rzeczywiscie swoj koniec to zwracamy ją natychmiast jesli nie to czas na zabawe z reaalkoacja
- return line;
- }
- // Dotarlismy tu wiec nie mamy calej lini przeczytanej (powyzszy 'return line' sie nei wykonał).
- // Oznacza to tyle ze musimy wyczysci nasz buffer zeby przeczytac nastepną porcję lini. Porcja jak wyzej pisalem jest okreslona jako BUFSIZ.
- // Alokujemy miejsce na nowa pamiec + znak konca stringu (\0);
- line = (char *)malloc(strlen(buffer) + 1);
- // Kopiujemy do 'line' buffor juz z przeczytany fgetsem
- strcpy(line, buffer);
- // Teraz czytamy tak dlugo az przeczytamy cala linie realokujac pamieci co BUFSIZ
- success = 0;
- while (!success && fgets(buffer, sizeof(buffer), fh) != NULL)
- {
- length = strlen(buffer);
- // Sprawdzamy czy mamy koniec linii
- // jesli tak to...
- if (buffer[length - 1] == '\n')
- {
- // zamykamy ta linie null terminatorem
- buffer[length - 1] = '\0';
- // i ustawiamy flage ze nie ma potrzeby dalszego czytania danej linii
- success = 1;
- }
- // poniewaz flaga jest jeszcze nue ustawiona musimy realkowac pamiec i czytac dalej
- // portzebujemy wiecej pamieci weic realkujemy `line` o wielkosci sumy: jej dlugosci + przczytanej wczesniej dlugosci + znak null terminatora
- tmp = (char *)realloc(line, strlen(line) + length + 1);
- // Sprawdzamy czy realkoacja sie udała
- if (tmp == NULL)
- {
- // jesli nie to:
- // czysciemy pamiec
- free(line);
- // musimy zamknac pliku
- fclose(fh);
- printf("Could not reallocate memory!\n");
- // i uciec z programu
- exit(-1);
- }
- // Ustawiamy wskaznik zeby wskazywal na nowa realokowana pamiec
- line = tmp;
- // Dokljemy zawartosc buffora do lini
- strcat(line, buffer);
- }
- }
- // Zwracamu linie zawiarjaca tekst jesli jest koniec pliku lub nie ma nic wiecej do czytania to line w tym punkcie jest równe NULL
- return line;
- }
- /**
- * Funkcja zastepuje wyrazy w tekscie.
- * @param line orginalna linia czy tez tekst
- * @param from czego szukamy
- * @param to czym zastepujemy
- * @return linia z zastapionymi wyrazami
- */
- char *replace(const char *line, const char *from, const char *to)
- {
- // Caly problem tego algo. polega na tym ze dlugosc slowa szukanego moze byc inna niz slowa nowego ktorym zastepujemy
- // dlatego musimy policzyc sobie jak wielka pamiec zaalokowac.
- // Pointerna nowa linie oraz pomocniczy pointer
- char *newLine, *pt;
- // Trzyma sume bajtów o jakie przeskoczymy
- size_t i = 0;
- // Ile wyrazow znalezismy
- size_t count = 0;
- size_t toLength = strlen(to);
- size_t fromLength = strlen(from);
- // Spradzamy czy dlugosc wyrazu szukanego jest rozna od nowego wyrazu
- if (toLength != fromLength)
- {
- // Iterujemy po tekscie (lini) dopoki nie napotkamy znaku konca lini
- for (i = 0; line[i] != '\0';)
- {
- // porownujemy (MEMoryCoMPare()) czy nowy wyraz zostal znaleziony na danym indesie 'i'
- if (memcmp(&line[i], from, fromLength) == 0)
- {
- // Zostal znaleziony zwiekszamy counter
- count++;
- // Przesuwamy sie o 'i'+ dlugosc nowego slowa w tekscie(lini)
- i += fromLength;
- }
- else
- {
- // jesli wyraz nie zostal znaleziony w bufforze 'line' skaczemy na nastepy indeks tablicy
- i++;
- }
- }
- }
- else
- {
- // Jesli wyraz szukany i nowy sa takie same to 'i' jest po porstu dlugoscia lini/tekstu orginalnego
- i = strlen(line);
- }
- // Rezerowujemy miejsce na nowa linie
- newLine = (char *)malloc(i + 1 + count * (toLength - fromLength));
- if (newLine == NULL)
- {
- printf("Memory allocation error!");
- exit(-1);
- }
- // Wskazuje nowa linie na pomocniczy pointer - maja ten sam adres, wiec modyfkujemy ten sam obrzare pamiec w while`u ponizej
- pt = newLine;
- // printf("Wskaznik pt = %p <=> newLine = %p", pt, newLine);
- // Cała zabawa
- // While`ujemy dopoki *line nie jest nullem
- while (*line)
- {
- // Porownujemy nowy wyraz z aktualna pozycja wyrazu w `line`
- if (memcmp(line, from, fromLength) == 0)
- {
- // jesli sa rowne to kopiujemy nowy wyraz do pomocniczego pointera
- memcpy(pt, to, toLength);
- // Przesuwamy pointer pt o dlugosc nowego wyrazu
- pt += toLength;
- // Przesuwamy pointer line p dlugosc szukanego wyrazu
- line += fromLength;
- }
- // jesli nowy wyraz nie jest na pozycji przesuwamy sie o jeden offset(indeks) w tablicy 'line' do porzdu i przypisujemy ten adres do nastpenego w pt
- else
- {
- *pt++ = *line++;
- }
- }
- // Zamykamy null terminamtorem
- *pt = '\0';
- return newLine;
- }
- /**
- * Drukuje informacje przczytane z lini komend
- * @param from wyraz szukany
- * @param to tekst ktorym zamieniamy
- * @param inFilename pliku wejsciowy
- * @param outFilename plik wyjsciowy
- * @return void
- */
- void info(const char *from, const char *to, const char *inFilename, const char *outFilename)
- {
- printf("INFO\n");
- printf("from: \"%s\"\n", from);
- printf("to: \"%s\"\n", to);
- printf("input file: \"%s\"\n", inFilename);
- printf("output file: \"%s\"\n", outFilename);
- }
- /**
- * Drukuje pomoc programu
- * @param programName nazwa programu
- */
- void help(const char* programName)
- {
- printf("Usage: %s -f<from> -t<to> -i<inFilename> -o<outFilename>\n", programName);
- printf("\t%s -h - program help", programName);
- printf("Usage example: change \"and\" words to \"[or]\" word: %s -fand -t[or] -iD:\\in.txt -oD:\\out.txt\n", programName);
- exit(1);
- }
- int main(int argc, char **argv) {
- // Czytane z linii komend. Tekst ktorego szukamy do zamiany
- char *from = NULL;
- // Czytane z linii komend. Tekst ktorym zastepujemy
- char *to = NULL;
- // Czytane z linii komend. Sciezka do pliku wejsciowego
- char *inFilename = NULL;
- // Czytane z linii komend. Sciezka do pliku wyjscowiego
- char *outFilename = NULL;
- // Uchwyt pliku wejsciowego
- FILE *inFh = NULL;
- // Uchwyt pliku wyjsciwoego
- FILE *outFh = NULL;
- // Buffor zawierajcy przeczytana linie przez funkcje getLine();
- char *line = NULL;
- char *rep = NULL;
- // Przetwarznie lini komend
- while ((argc > 1) && (argv[1][0] == '-'))
- {
- switch (argv[1][1])
- {
- case 'f':
- from = &argv[1][2];
- break;
- case 't':
- to = &argv[1][2];
- break;
- case 'i':
- inFilename = &argv[1][2];
- break;
- case 'o':
- outFilename = &argv[1][2];
- break;
- case 'h':
- help(argv[0]);
- break;
- default:
- help(argv[0]);
- }
- ++argv;
- --argc;
- }
- // Sprwadzamy user input - wartosc przekazne przez usera z lini komend
- if(strIsEmpty(inFilename) == 1) {
- printf("\"inFilename\" is empty!\n");
- help(argv[0]);
- }
- if(strIsEmpty(outFilename) == 1) {
- printf("\"outFilename\" is empty!\n");
- help(argv[0]);
- }
- if(strIsEmpty(from) == 1) {
- printf("\"from\" is empty!\n");
- help(argv[0]);
- }
- if(strIsEmpty(to) == 1) {
- printf("\"to\" is empty!\n");
- help(argv[0]);
- }
- // Sprawdzamy czy da sie otworzyc pliki
- inFh = fopen(inFilename, "r");
- if(inFh == NULL)
- {
- printf("Cannot open file: %s", inFilename);
- help(argv[0]);
- }
- outFh = fopen(outFilename, "w+");
- if(inFh == NULL)
- {
- printf("Cannot open file: %s", outFilename);
- help(argv[0]);
- }
- info(from, to, inFilename, outFilename);
- // Czytamy linia po lini z pliku
- while ((line = getLine(inFh)) != NULL)
- {
- // Zamieniamy i zapisujemy od razu
- rep = replace(line, from, to);
- fprintf(outFh, "%s\n", rep);
- // Poniewaz w funkcji getLine rezerwowalimsy pamiec to muismy ja zwolnic:
- free(line);
- free(rep);
- // To musiy tu byc dla bezpieczenstwa:
- rep = NULL;
- line = NULL;
- }
- // Zamykamy uchwyty pliku
- fclose(inFh);
- fclose(outFh);
- inFh = NULL;
- outFh = NULL;
- return 0;
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement