/*
detab_v6.c FINAL 01.03.2018.
Skida beline (space karaktere i tabulatore) sa kraja redova
i preostale tabulatore zamenjuje space karakterima.
Obraca se paznja na tab stopove.
Verzija sa fgets() i fputs() i funkcijama
trim_string_end()
detab_string()
detab_file().
Dodata je funkcija trim_string_end() koja uklanja beline
(space i tabulatore) sa kraja stringa s,
i njeni brojaci
br_skinutih_space,
br_skinutih_tabulatora,
br_skinutih_belina.
U main() se obradjuju argumenti programa (ImeFajla.ekstenzija i t)
a funkciji detab_file() se prosledjuju imena ulaznog i izlaznog fajla, t
i pointeri na brojace karaktera, redova i tabulatora.
Tabulator pomera kurzor od trenutne pozicije do sledeceg tab stopa.
t je razmak izmedju dva susedna tab stopa izrazen brojem space karaktera.
Najcesce je t=4, a moze biti 2, 4, 6, 8 ili bilo koja druga pozitivna vrednost.
Ako se tabulator nalazi na i-tom indeksu reda,
zamenjuje se odgovarajucim brojem space karaktera:
nb = t-(i%t) ( ZAPAMTI FORMULU ! )
do sledeceg tab stopa.
Ako t=4, tab stopovi su na indeksima reda:
1 2 3 4 5 6 7 8
012345678901234567890123456789012345678901234567890123456789012345678901234567890
4 8 12 16 20 24 28 32 36 40 44 48 52 56 60 64 68 72 76 80 ... indeksu.
Celobrojno deljenje:
x%y = x , ako je x<y
x%y = 0 , ako je x=y
x%y = celobrojni ostatak pri delenju x sa y, ako je x>y
Tabulator na indeksu i se menja sa nb = t-(i%t) space karakterom ( ZAPAMTI FORMULU ! )
da bi se stiglo do sledeceg tab stopa:
indeks nb tab stop
0, menja se sa t-(i%t) = 4-( 0%4) = 4-0 = 4 space da bi se stiglo do 4. indeksa
1, menja se sa t-(i%t) = 4-( 1%4) = 4-1 = 3 space da bi se stiglo do 4. indeksa
2, menja se sa t-(i%t) = 4-( 2%4) = 4-2 = 2 space da bi se stiglo do 4. indeksa
3, menja se sa t-(i%t) = 4-( 3%4) = 4-3 = 1 space da bi se stiglo do 4. indeksa
4, menja se sa t-(i%t) = 4-( 4%4) = 4-0 = 4 space da bi se stiglo do 8. indeksa
5, menja se sa t-(i%t) = 4-( 5%4) = 4-1 = 3 space da bi se stiglo do 8. indeksa
6, menja se sa t-(i%t) = 4-( 6%4) = 4-2 = 2 space da bi se stiglo do 8. indeksa
7, menja se sa t-(i%t) = 4-( 7%4) = 4-3 = 1 space da bi se stiglo do 8. indeksa
8, menja se sa t-(i%t) = 4-( 8%4) = 4-0 = 4 space da bi se stiglo do 12. indeksa
9, menja se sa t-(i%t) = 4-( 9%4) = 4-1 = 3 space da bi se stiglo do 12. indeksa
10, menja se sa t-(i%t) = 4-(10%4) = 4-2 = 2 space da bi se stiglo do 12. indeksa
11, menja se sa t-(i%t) = 4-(11%4) = 4-3 = 1 space da bi se stiglo do 12. indeksa
12, menja se sa t-(i%t) = 4-(12%4) = 4-0 = 4 space da bi se stiglo do 16. indeksa
13, menja se sa t-(i%t) = 4-(13%4) = 4-1 = 3 space da bi se stiglo do 16. indeksa
14, menja se sa t-(i%t) = 4-(14%4) = 4-2 = 2 space da bi se stiglo do 16. indeksa
15, menja se sa t-(i%t) = 4-(15%4) = 4-3 = 1 space da bi se stiglo do 16. indeksa
...
Primer poziva programa: detab ImeFajla 4
U tekst fajlu ImeFajla
tabulatore zamenjuje space karakterima
i rezultat snima u tekst fajl ImeFajla.txt
Ako t nije navedeno ili je t=0, ne zamenjuje tabulatore.
*/
#include <stdio.h>
#include <stdlib.h> // zbog exit()
#include <string.h> // zbog strcpy()
#define MAX_DUZINA_STRINGA 1024 // maksimalna duzina jednog reda u fajlu
// Uklanja beline (space i tabulatore) sa kraja stringa s.
// U stringu s moze biti samo jedan znak za novi red '\n' i to samo na kraju stringa s,
// i tada taj znak za novi red ostaje i na kraju trimovanog stringa.
void trim_string_end( char s[],
int *br_skinutih_space,
int *br_skinutih_tabulatora,
int *br_skinutih_belina){
int znak_za_novi_red_je_na_kraju=0; // flag kojim pamtimo da je '\n' bio na kraju stringa s
int n = strlen(s); // n je duzina stringa s (ne broji se zavrsni karakter '\0')
// n je redni broj poslednjeg karaktera u stringu, ciji je indeks n-1
if (s[n-1]=='\n'){ // ako je poslednji karakter u stringu znak za novi red '\n'
znak_za_novi_red_je_na_kraju=1; // pamtimo ga u flagu
n--; // i preskacemo, ponovo cemo ga dodati na kraju funkcije
}
while(n > 0){ // od kraja stringa prema pocetku, ulevo
if (s[n-1]==' '){ // ako je poslednji karakter space
(*br_skinutih_space)++;
(*br_skinutih_belina)++;
s[n-1]='\0'; // brisemo ga
}else if (s[n-1]=='\t'){ // ako je poslednji karakter tabulator
(*br_skinutih_tabulatora)++;
(*br_skinutih_belina)++;
s[n-1]='\0'; // brisemo ga
}else // ako nije space ili tabulator
break; // prekini while petlju
n--; // prelazimo na sledeci karakter ulevo
}
if (znak_za_novi_red_je_na_kraju==1){ // ako je na kraju stringa s bio znak za novi red
n = strlen(s); // n je nova duzina stringa s na koju
s[n]='\n'; // ponovo dodajemo karakter za novi red '\n' i
s[n+1]='\0'; // zavrsavamo string s
}
} // trim_string_end()
// detab_string() u stringu s, tabulatore zamenjuje odgovarajucim brojem space znakova.
// Vraca broj zamenjenih tabulatora br_tab.
// t je razmak izmedju tab stopova izrazen brojem space znakova.
int detab_string(char s[], int t){
char sp[MAX_DUZINA_STRINGA]; // pomocni string
int br_tab = 0; // brojac za tabulatore
int len = strlen(s); // duzina stringa s (broj karaktera u stringu s)
int nb = 0; // broj space karaktera kojima menjamo konkretni tabulator na mestu indeksa i
int i = 0; // i je index za glavni string s
int j = 0; // j je index za pomocni string sp
int k; // brojac for petlje
// Kopiramo s u sp, dalje citamo iz sp i pisemo u s,
// zato sto ce duzina stringa s kada tabulatore zamenimo space karakterima biti veca od pocetne
// Bezbedno je kopirati s u sp jer su oba deklarisana sa MAX_DUZINA_STRINGA.
strcpy(sp,s);
while(sp[j]!='\0'){ // citamo sp od pocetka do kraja
if( sp[j] == '\t') { // ako ch ocitan iz sp tabulator
br_tab++; // brojimo tabulatore
// racunamo koliko space karaktera treba od trenutne pozicije (i) do sledeceg tab stopa
nb = t-(i%t); // ( ZAPAMTI FORMULU ! )
for(k=0;k<nb;k++) // u s menjamo ch sa nb space karaktera
s[i++]=' '; // za svaki space karakter, uvecavamo indeks i od s
j++; // prelazimo na sledeci ch u sp
}else // sve ostale ch iz sp koji nisu tabulator,
s[i++]=sp[j++]; // nepromenjene stavljamo u s
}
s[i]='\0'; // zavrsavamo string s
return br_tab; // vraca broj tabulatora u stringu sp
} // int detab_string()
// detab_file() otvara ulazni i izlazni fajl, vrsi obradu i zatvara oba fajla.
// U ulaznom fajlu uklanja beline (space karaktere i tabulatore) sa kraja redova,
// preostale tabulatore zamenjuje odgovarajucim brojem space karaktera
// i rezultat snima u novi izlazni fajl.
// Poziva funkcije trim() i detab_string().
void detab_file(char ime_ulaznog_fajla[],
char ime_izlaznog_fajla[],
int t,
int *br_karaktera,
int *br_redova,
int *br_tabulatora,
int *br_skinutih_space,
int *br_skinutih_tabulatora,
int *br_skinutih_belina ){
FILE* pointer_na_ulazni_fajl;
FILE* pointer_na_izlazni_fajl;
char red[MAX_DUZINA_STRINGA]; // jedan red teksta
// Otvaramo ulazni tekst fajl za citanje
if( (pointer_na_ulazni_fajl = fopen(ime_ulaznog_fajla, "r")) == NULL ) {
fprintf(stderr, "\n\n Greska pri otvaranju ulaznog fajla %s ! \n\n", ime_ulaznog_fajla );
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// Otvaramo izlazni tekst fajl za pisanje
if( (pointer_na_izlazni_fajl = fopen(ime_izlaznog_fajla, "w")) == NULL ) {
fprintf(stderr, "\n\n Greska pri otvaranju izlaznog fajla %s ! \n\n", ime_izlaznog_fajla );
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// ucitava jedan po jedan red iz ulaznog fajla i vrsi njihovu obradu
while( (fgets(red,MAX_DUZINA_STRINGA,pointer_na_ulazni_fajl)) != NULL ) {
// skidamo beline sa kraja stringa red
trim_string_end( red,
br_skinutih_space,
br_skinutih_tabulatora,
br_skinutih_belina);
// provera maksimalne duzine reda iz fajla
if (strlen(red)>MAX_DUZINA_STRINGA){
fprintf(stderr, "\n\n %8d. red je duzi od %d karaktera ! \n\n",
(*br_redova)+1,MAX_DUZINA_STRINGA);
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
(*br_karaktera)+=strlen(red); // ucitali smo 1 red i povecavamo ukupan broj karaktera
// fgets() ucitava i broji i karakter \n na kraju reda
(*br_redova)++; // ucitali smo 1 red i povecavamo ukupan broj redova
(*br_tabulatora) += detab_string(red,t); // racuna ukupan broj tabulatora
fputs(red,pointer_na_izlazni_fajl); // upisuje obradjeni red u izlazni fajl
}
// Zatvaranje ulaznog fajla
if( ( fclose(pointer_na_ulazni_fajl) ) == EOF ) { // Zatvaramo ulazni fajl
fprintf(stderr, "\n\n Greska pri zatvaranju ulaznog fajla %s ! \n\n", ime_ulaznog_fajla);
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// else
// printf("\n\n Fajl \"%s\" je uspesno zatvoren. \n\n", ime_ulaznog_fajla );
// Zatvaranje izlaznog fajla
if( ( fclose(pointer_na_izlazni_fajl) ) == EOF ) { // Zatvaramo izlazni fajl
fprintf(stderr, "\n\n Greska pri zatvaranju izlaznog fajla %s ! \n\n", ime_izlaznog_fajla);
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// else
// printf("\n\n Fajl \"%s\" je uspesno zatvoren. \n\n", ime_izlaznog_fajla );
} // void detab_file()
int main(int argc, char *argv[]) {
char ime_ulaznog_fajla[MAX_DUZINA_STRINGA];
char ime_izlaznog_fajla[MAX_DUZINA_STRINGA];
char red[MAX_DUZINA_STRINGA]; // jedan red teksta
int ch; // Ascii kod jednog karaktera
int br_karaktera = 0; // Ukupan broj karaktera u fajlu
int br_redova = 0; // Ukupan broj redova u fajlu
int br_tabulatora = 0; // Ukupan broj tabulatora u fajlu
int br_skinutih_space = 0; // Ukupan broj skinutih space sa krajeva redova fajla
int br_skinutih_tabulatora = 0; // Ukupan broj skinutih tabulatora sa krajeva redova fajla
int br_skinutih_belina = 0; // Ukupan broj skinutih belina sa krajeva redova fajla
int t=0; // razmak izmedju tab stopova (izrazen brojem space karaktera)
// broj argumenata komandne linije pri pozivu programa
// detab , argc = 1, to je ime samog programa
// detab fajl.txt , argc = 2, to je ime samog programa i ime ulaznog fajla
// detab fajl.txt 4 , argc = 3, to je ime samog programa, ime ulaznog fajla i t
// Zamena tabulatora space karakterima vrsi se samo ako je argc=3 i t>0
// inace se samo ispisuje opis programa.
// printf("\n argc = %d \n ", argc);
// argv[0] je ime samog programa, (detab.exe)
// argv[1] je ime ulaznog fajla, (fajl.txt)
// argv[2] je t, (4)
if( argc == 3 ) { // ako su navedeni svi argumenti
t = atoi(argv[2]); // pretvaranjem stringa argv[2] u integer dobijamo t
if (t<=0) { // provera da li je t pozitivan broj
fprintf(stderr, "\n GRESKA: t = %d nije pozitivan broj ! \n\n",t);
system("PAUSE");
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// provera da li funkcija strcpy() ima dovoljno mesta u memoriji
if (strlen(argv[1]) > MAX_DUZINA_STRINGA-5) { // -5 zbog .txt i \0 za ime_izlaznog_fajla
fprintf(stderr, "\n GRESKA: Ime ulaznog fajla \"%s\" je duze od %d karaktera ! \n\n",
argv[1], MAX_DUZINA_STRINGA-5);
system("PAUSE"); // pauziramo zatvaranje ekrana
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// formiramo imena ulaznog i izlaznog fajla
strcpy(ime_ulaznog_fajla,argv[1]); // od argv[1] pravimo ime ulaznog fajla
strcpy(ime_izlaznog_fajla,ime_ulaznog_fajla); // ime izlaznog fajla je kao ime ulaznog
strcat(ime_izlaznog_fajla,".txt"); // sa dodatkom .txt
}
if( argc != 3 || t<=0 ) { // ispis opisa programa, ako nisu ispravno navedeni svi argumenti ImeFajla i t
printf("\n DETAB ImeFajla 4 \n"
"\n u tekst fajlu ImeFajla tabulatore zamenjuje odgovarajucim \n"
"\n brojem space karaktera i rezultat snima u ImeFajla.txt \n\n");
system("PAUSE"); // pauziramo zatvaranje ekrana
exit(EXIT_FAILURE); // prekidamo izvrsavanje programa
}
// poziv funkcije sa njenim argumentima
detab_file( ime_ulaznog_fajla,
ime_izlaznog_fajla,
t,
&br_karaktera,
&br_redova,
&br_tabulatora,
&br_skinutih_space,
&br_skinutih_tabulatora,
&br_skinutih_belina);
// Prikaz rezultata obrade ulaznog fajla:
printf("\n U ulaznom fajlu \"%s\" ima: \n\n", ime_ulaznog_fajla );
printf("%8d karaktera \n\n", br_karaktera); // Ukupan broj karaktera u ulaznom fajlu
printf("%8d redova \n\n", br_redova); // Ukupan broj redova u ulaznom fajlu
printf("%8d tabulatora koji su zamenjeni sa space\n\n", br_tabulatora);
printf("%8d skinutih space sa krajeva redova \n\n", br_skinutih_space);
printf("%8d skinutih tabulatora sa krajeva redova \n\n", br_skinutih_tabulatora);
printf("%8d skinutih belina (space karaktera i tabulatora) sa krajeva redova \n\n", br_skinutih_belina);
printf(" Izlazni fajl je: \"%s\" \n\n",ime_izlaznog_fajla);
system("PAUSE"); // pauziramo zatvaranje ekrana
return 0; // vracamo 0, program je uspesno zavrsen
} // int main()