Advertisement
m4ly

C FUN

Jun 20th, 2015
172
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C 13.36 KB | None | 0 0
  1. /* Author: Dawid Mocek */
  2.  
  3. #include <stdlib.h>
  4. #include <stdio.h>
  5. #include <string.h>
  6. #include <errno.h>
  7.  
  8.  
  9. /**
  10.  * Funkcja sprawdza czy string jest pusty
  11.  * @param str tekst do przetestowania
  12.  * @return 1 jesli tekst  jest pusty, 0 jesli linia zawiera chociaz jeden znak (nawet bialy jak np spacja czy tabulator (\t))
  13.  */
  14. int strIsEmpty(const char *str)
  15. {
  16.     if (str && str[0]) {
  17.         return 0;
  18.         }
  19.         return 1;
  20. }
  21.  
  22. /**
  23.  * Funkcja czyta linia po lini z pliku
  24.  *
  25.  * @param fh uchwyt do czytanego pliku
  26.  * @return NULL jesli linia zostala przeczytana lub nie ma nic wiecej do czytania
  27.  */
  28. char * getLine(FILE *fh) {
  29.  
  30.         // Macro BUFSIZ zdefiniowane jest w pliku naglowkowy <stdio.h>
  31.         // Mozemy podejrzec ile dokladnie wynosi dla naszego systemu: printf("BUFSIZ = %d\n", BUFSIZ);
  32.         // 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.
  33.         // 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)
  34.         // z danej lini - nawet jak bedziemy posiadac najszybszy dysk na swiecie to przeczytanie pliku parumegabajtwoego
  35.         // moze zajac godzine dwie... z buferem równym 1
  36.         char buffer[BUFSIZ] = { 0 };
  37.  
  38.         // Przyczytana linia która zostanie zwrocona z tej funkcji
  39.         char *line = NULL;
  40.  
  41.         // Flaga oznaczajaca ze nie ma nic wiecej do czytania w danej linii
  42.         int success = 0;
  43.  
  44.         // Dlugosc stringu
  45.         size_t length = 0;
  46.  
  47.         // Potrzebne dla realloc - tymczasowna zmienna do przepinania pamięci.
  48.         char *tmp = NULL;
  49.  
  50.         // Sprawdzamy czy plik został otwarty - jesli nie tj fh == NULL to zwracamy NULL jako brak przeczytanej lini
  51.         if (fh == NULL)
  52.         {
  53.                 return NULL;
  54.         }
  55.  
  56.  
  57.         // 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
  58.         // musimy realkowac koljne chunki pamieci (wszystkie dokladnie o wielkosc BUFSIZ)
  59.  
  60.         // Czytamy linie za pomoca fgets.
  61.         if (fgets(buffer, sizeof(buffer), fh) != NULL)
  62.         {
  63.  
  64.                 length = strlen(buffer);
  65.  
  66.                 // 1 Przypadek - tutaj sprawdzamy czy linia rzeczywiscie ma swoj koniec (\n) czyli liczba znakow przeczytanych miescie sie w liczbie BUFSIZ lub
  67.                 // czy musimy zaalokowac nastepny chunk pamieci i czytac dalej....
  68.                 if (buffer[length - 1] == '\n')
  69.                 {
  70.                         // Musimy zamknąć stringa null`em
  71.                         buffer[length - 1] = '\0';
  72.  
  73.                         // Alokujemy pamiec dla tej linii:
  74.                         line = (char *)malloc(length);
  75.  
  76.                         // Sprawdzamy czy pamiec sie zaalkowała
  77.                         if (line == NULL)
  78.                         {
  79.  
  80.                                 fclose(fh);
  81.                                 printf("Memory allocation error\n");
  82.                                 exit(-1);
  83.                         }
  84.  
  85.                         // kopiujemy linie z tymczaswoego bufora
  86.                         strcpy(line, buffer);
  87.  
  88.                         // jesli linia ma rzeczywiscie swoj koniec to zwracamy ją natychmiast jesli nie to czas na zabawe z reaalkoacja
  89.                         return line;
  90.                 }
  91.  
  92.  
  93.                 // Dotarlismy tu wiec nie mamy calej lini przeczytanej (powyzszy 'return line' sie nei wykonał).
  94.                 // Oznacza to tyle ze musimy wyczysci nasz buffer zeby przeczytac nastepną porcję lini. Porcja jak wyzej pisalem jest okreslona jako BUFSIZ.
  95.  
  96.                 // Alokujemy miejsce na nowa pamiec + znak konca stringu (\0);
  97.                 line = (char *)malloc(strlen(buffer) + 1);
  98.  
  99.                 // Kopiujemy do 'line'  buffor  juz z przeczytany fgetsem
  100.                 strcpy(line, buffer);
  101.  
  102.  
  103.                 // Teraz czytamy tak dlugo az przeczytamy cala linie realokujac pamieci co BUFSIZ
  104.                 success = 0;
  105.                 while (!success && fgets(buffer, sizeof(buffer), fh) != NULL)
  106.                 {
  107.  
  108.                         length = strlen(buffer);
  109.                         // Sprawdzamy czy mamy koniec linii
  110.                         // jesli tak to...
  111.                         if (buffer[length - 1] == '\n')
  112.                         {
  113.                                 // zamykamy ta linie null terminatorem
  114.                                 buffer[length - 1] = '\0';
  115.  
  116.                                 // i ustawiamy flage ze nie ma potrzeby dalszego czytania danej linii
  117.                                 success = 1;
  118.                         }
  119.  
  120.                         // poniewaz flaga jest jeszcze nue ustawiona musimy realkowac pamiec i czytac dalej
  121.  
  122.                         // portzebujemy wiecej pamieci weic realkujemy `line` o wielkosci sumy:  jej dlugosci + przczytanej wczesniej dlugosci + znak null terminatora
  123.                         tmp = (char *)realloc(line, strlen(line) + length + 1);
  124.  
  125.                         // Sprawdzamy czy realkoacja sie udała
  126.                         if (tmp == NULL)
  127.                         {
  128.                                 // jesli nie to:
  129.                                 // czysciemy pamiec
  130.                                 free(line);
  131.  
  132.                                 // musimy zamknac pliku
  133.                                 fclose(fh);
  134.                                 printf("Could not reallocate memory!\n");
  135.                                 // i uciec z programu
  136.                                 exit(-1);
  137.                         }
  138.  
  139.                         // Ustawiamy wskaznik zeby wskazywal na nowa realokowana pamiec
  140.                         line = tmp;
  141.  
  142.                         // Dokljemy zawartosc buffora do lini
  143.                         strcat(line, buffer);
  144.                 }
  145.         }
  146.  
  147.         // Zwracamu linie zawiarjaca tekst jesli jest koniec pliku lub nie ma nic wiecej do czytania to line w tym punkcie jest równe NULL
  148.         return line;
  149. }
  150.  
  151. /**
  152.  * Funkcja zastepuje  wyrazy w tekscie.
  153.  * @param line orginalna linia czy tez tekst
  154.  * @param from czego szukamy
  155.  * @param to czym zastepujemy
  156.  * @return linia z zastapionymi wyrazami
  157.  */
  158. char *replace(const char *line, const char *from, const char *to)
  159. {
  160.  
  161.     // Caly problem tego algo. polega na tym ze dlugosc slowa szukanego moze byc inna niz slowa nowego ktorym zastepujemy
  162.     // dlatego musimy policzyc sobie jak wielka pamiec zaalokowac.
  163.  
  164.     // Pointerna nowa linie oraz pomocniczy pointer
  165.     char *newLine, *pt;
  166.  
  167.     // Trzyma sume bajtów o jakie przeskoczymy
  168.     size_t i = 0;
  169.  
  170.     // Ile wyrazow znalezismy
  171.     size_t count = 0;
  172.  
  173.     size_t toLength = strlen(to);
  174.     size_t fromLength = strlen(from);
  175.  
  176.     // Spradzamy czy dlugosc wyrazu szukanego jest rozna od nowego wyrazu
  177.     if (toLength != fromLength)
  178.     {
  179.         // Iterujemy po tekscie (lini)  dopoki nie napotkamy znaku konca lini
  180.         for (i = 0; line[i] != '\0';)
  181.         {
  182.             // porownujemy (MEMoryCoMPare())  czy nowy wyraz zostal znaleziony na danym indesie 'i'
  183.             if (memcmp(&line[i], from, fromLength) == 0)
  184.             {
  185.                 // Zostal znaleziony zwiekszamy counter
  186.                 count++;
  187.  
  188.                 // Przesuwamy sie o 'i'+ dlugosc nowego slowa w tekscie(lini)
  189.                 i += fromLength;
  190.             }
  191.             else
  192.             {
  193.                 // jesli wyraz nie zostal znaleziony w bufforze 'line' skaczemy na nastepy  indeks tablicy
  194.                 i++;
  195.             }
  196.         }
  197.     }
  198.     else
  199.     {
  200.         // Jesli wyraz szukany i nowy sa takie same to 'i' jest po porstu dlugoscia lini/tekstu orginalnego
  201.         i = strlen(line);
  202.     }
  203.  
  204.     // Rezerowujemy miejsce na nowa linie
  205.     newLine = (char *)malloc(i + 1 + count * (toLength - fromLength));
  206.     if (newLine == NULL)
  207.     {
  208.             printf("Memory allocation error!");
  209.             exit(-1);
  210.     }
  211.    
  212.     // Wskazuje nowa linie na pomocniczy pointer - maja ten sam adres, wiec modyfkujemy ten sam obrzare pamiec w while`u ponizej
  213.     pt = newLine;
  214.     // printf("Wskaznik pt = %p <=> newLine = %p", pt, newLine);
  215.  
  216.     // Cała zabawa
  217.     // While`ujemy dopoki *line nie jest nullem
  218.     while (*line)
  219.     {
  220.         // Porownujemy nowy wyraz z aktualna pozycja wyrazu w `line`
  221.         if (memcmp(line, from, fromLength) == 0)
  222.         {
  223.             // jesli sa rowne to kopiujemy nowy wyraz do pomocniczego pointera
  224.  
  225.             memcpy(pt, to, toLength);
  226.             // Przesuwamy pointer pt o dlugosc nowego wyrazu
  227.             pt += toLength;
  228.             // Przesuwamy pointer line p dlugosc szukanego wyrazu
  229.            line += fromLength;
  230.         }
  231.         // 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
  232.          else
  233.          {
  234.         *pt++ = *line++;
  235.         }
  236.     }
  237.  
  238.     // Zamykamy null terminamtorem
  239.     *pt = '\0';
  240.  
  241.     return newLine;
  242. }
  243.  
  244.  
  245. /**
  246.  * Drukuje informacje przczytane z lini komend
  247.  * @param from wyraz szukany
  248.  * @param to tekst ktorym zamieniamy
  249.  * @param inFilename  pliku wejsciowy
  250.  * @param outFilename plik wyjsciowy
  251.  * @return void
  252.  */
  253. void info(const char *from, const char *to, const char *inFilename, const char *outFilename)
  254. {
  255.         printf("INFO\n");
  256.         printf("from: \"%s\"\n", from);
  257.         printf("to: \"%s\"\n", to);
  258.         printf("input file: \"%s\"\n", inFilename);
  259.         printf("output file: \"%s\"\n", outFilename);
  260. }
  261.  
  262.  
  263. /**
  264.  * Drukuje pomoc programu
  265.  * @param programName nazwa programu
  266.  */
  267. void help(const char* programName)
  268. {
  269.         printf("Usage: %s -f<from> -t<to> -i<inFilename> -o<outFilename>\n", programName);
  270.         printf("\t%s -h - program help", programName);
  271.         printf("Usage example: change \"and\" words to \"[or]\" word: %s -fand -t[or] -iD:\\in.txt -oD:\\out.txt\n", programName);
  272.         exit(1);
  273. }
  274.  
  275. int main(int argc, char **argv) {
  276.  
  277.         // Czytane z linii komend. Tekst  ktorego szukamy do zamiany
  278.         char *from = NULL;
  279.  
  280.         // Czytane z linii komend. Tekst ktorym zastepujemy
  281.         char *to = NULL;
  282.  
  283.         // Czytane z linii komend.  Sciezka do pliku wejsciowego
  284.         char *inFilename = NULL;
  285.  
  286.         // Czytane z linii komend.  Sciezka do pliku wyjscowiego
  287.         char *outFilename = NULL;
  288.  
  289.         // Uchwyt pliku wejsciowego
  290.         FILE *inFh  = NULL;
  291.  
  292.         // Uchwyt pliku wyjsciwoego
  293.         FILE *outFh = NULL;
  294.  
  295.         // Buffor zawierajcy przeczytana linie przez funkcje getLine();
  296.         char *line = NULL;
  297.  
  298.         char *rep = NULL;
  299.  
  300.         // Przetwarznie lini komend
  301.  
  302.         while ((argc > 1) && (argv[1][0] == '-'))
  303.         {
  304.                 switch (argv[1][1])
  305.                 {
  306.                         case 'f':
  307.                                 from = &argv[1][2];
  308.                                 break;
  309.  
  310.                         case 't':
  311.                                 to = &argv[1][2];
  312.                                 break;
  313.  
  314.                         case 'i':
  315.                                 inFilename = &argv[1][2];
  316.                                 break;
  317.                         case 'o':
  318.                                 outFilename =  &argv[1][2];
  319.                                 break;
  320.                         case 'h':
  321.                                 help(argv[0]);
  322.                                 break;
  323.                         default:
  324.  
  325.                                 help(argv[0]);
  326.                 }
  327.  
  328.                 ++argv;
  329.                 --argc;
  330.         }
  331.  
  332.         // Sprwadzamy user input - wartosc przekazne przez usera z lini komend
  333.         if(strIsEmpty(inFilename) == 1) {
  334.                 printf("\"inFilename\" is empty!\n");
  335.                 help(argv[0]);
  336.         }
  337.  
  338.         if(strIsEmpty(outFilename) == 1) {
  339.                 printf("\"outFilename\" is empty!\n");
  340.                 help(argv[0]);
  341.         }
  342.  
  343.         if(strIsEmpty(from) == 1) {
  344.                 printf("\"from\" is empty!\n");
  345.                 help(argv[0]);
  346.         }
  347.  
  348.         if(strIsEmpty(to) == 1) {
  349.                 printf("\"to\" is empty!\n");
  350.                 help(argv[0]);
  351.         }
  352.  
  353.  
  354.         // Sprawdzamy czy da sie otworzyc pliki
  355.         inFh = fopen(inFilename, "r");
  356.         if(inFh == NULL)
  357.         {
  358.                 printf("Cannot open file: %s",  inFilename);
  359.                 help(argv[0]);
  360.         }
  361.  
  362.         outFh = fopen(outFilename, "w+");
  363.         if(inFh == NULL)
  364.         {
  365.                 printf("Cannot open file: %s",  outFilename);
  366.                 help(argv[0]);
  367.         }
  368.  
  369.         info(from, to, inFilename, outFilename);
  370.  
  371.         // Czytamy linia po lini z pliku
  372.         while ((line = getLine(inFh)) != NULL)
  373.         {
  374.                 // Zamieniamy i zapisujemy od razu
  375.                 rep = replace(line, from, to);
  376.                 fprintf(outFh, "%s\n",  rep);
  377.  
  378.                 // Poniewaz w funkcji getLine rezerwowalimsy pamiec to muismy ja zwolnic:
  379.                 free(line);
  380.                 free(rep);
  381.  
  382.                 // To musiy tu byc dla bezpieczenstwa:
  383.                 rep = NULL;
  384.                 line = NULL;
  385.         }
  386.  
  387.         // Zamykamy uchwyty pliku
  388.         fclose(inFh);
  389.         fclose(outFh);
  390.  
  391.         inFh = NULL;
  392.         outFh = NULL;
  393.  
  394.         return 0;
  395.  
  396. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement