> Dizin girişlerinin elde edilmesi: >> Bir dizin girişindeki (directory entries) bilgileri elde etmek için bir takım POSIX fonksiyonları bulundurulmuştur. Burada dikkat etmemiz gereken nokta, dizinlerin "open" ve "openat" fonksiyonları ile açılabildiği fakat pek çok sistemde "read" fonksiyonu ile okumanın yapılamadığıdır. Ek olarak dizin dosyalarının iç formatı, dosya sisteminden dosya sistemine değişebilmektedir. İş bu POSIX fonksiyonların bulunma amacı da budur. >> Linux sistemlerinde bu amaç için "getdents" isimli bir SİSTEM FONKSİYONU BULUNMAKTADIR. >> Dizin girişlerini elde edebilmek için evvela dizinimizi "opendir" isimli POSIX fonksiyonu ile açmamız gerekiyor. Bunu gerçekleştirebilmek için de prosesimizin ilgili dizin üzerinde "r" hakkının olması gerekiyor. >>> "opendir" fonksiyonu, "dirent.h" isimli başlık dosyasında bildirilmiştir. Argüman olarak sadece açılacak dizin'in ismini almaktadır. Geri dönüş değeri ise "DIR" türünden bir yapı nesnesinin adresidir. Fonksiyon başarısızlık durumunda NULL değerini döndürür ve "errno" uygun değerini alır. Yine bu fonksiyonun da "f" li versiyonu vardır ve ismi "fopendir" şeklindedir. >>>> "DIR": Bir tür eş ismidir. İlgili fonksiyonları direkt olarak bu "DIR" türünden argüman almaktadırlar. Bu yapı türü halihazırda tahsis edilmiştir, ilgili bellek alanını geri vermeyeceğiz. >>>> "fopendir" : "open" veya "openat" ile açılan bir dizine dair "DIR" bilgisini elde etmek için bu fonksiyonu çağırabiliriz çünkü bu fonksiyon bir "file descriptor" almaktadır. Aşağıda bu konuya ilişkin bir örnekler verilmiştir: * Örnek 1, "opendir" fonksiyonunun kullanılması: #include #include #include void exit_sys(const char* msg); int main(void) { /* # OUTPUT # Success!... */ DIR* dir; if ( (dir = opendir("/usr/include")) == NULL ) exit_sys("opendir"); printf("Success!...\n"); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, //.. #include #include #include void exit_sys(const char* msg); int main(void) { /* # OUTPUT # opendir: Not a directory */ DIR* dir; if ( (dir = opendir("test.txt")) == NULL ) exit_sys("opendir"); printf("Success!...\n"); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >> Bir dizin girişindekileri okuyabilmek içi öncesinde "opendir" ya da "fopendir" ile açmamız gerekiyor, "readdir" fonksiyonunu kullanmamız gerekmektedir. İş bu fonksiyon da bir POSIX fonksiyonudur. >>> "readdir" fonksiyonu, yine "opendir" gibi, "dirent.h" isimli başlık dosyasında bildirilmiştir. Argüman olarak bir "DIR" yapısının adresini almaktadır. Geri dönüş değeri olarak "dirent" isimli yapının adresini döndürmektedir. İş bu yapı da statik ömürlüdür. İş bu fonksiyon her çağrıldığında bir sonraki dizin girişi geri döndürülür. Dolayısıyla bütün dizin girişlerini okuyabilmek için bir döngü içinde çağrı yapmamız gerekiyor. İş bu fonksiyon, dizin girişinin sonuna geldiğinde bizlere NULL değerini döndürmektedir. İş bu fonksiyon başarısızlık durumunda da NULL değerini döndürmektedir ve ek olarak "errno" değişkenini uygun değere çekmektedir. BİZLER ARTIK HEM NULL HEM DE "errno" KONTROLÜ YAPMAMIZ GEREKİYOR. >>>> "dirent" yapısı, POSIX standartlarına göre en az iki elemana sahip olmalıdır. Bu elemanlar "d_ino" ve "d_name" isimlerine sahiptirler. Bu elemanlar sırasıyla "ino_t" ve "char[]" türlerindendir. İş bu yapı ikiden fazla elemana da sahip olabilir. Linux işletim sisteminde, bu iki elemana ek olarak 3 eleman daha bu yapının içerisindedir. Bu elemanlar "d_off", "d_reclen" ve "d_type" isimli elemanlardır. Bu üç elemandan en önemlisi şüphesiz "d_type" isimli olanıdır çünkü dosyanın tür bilgisini de tutmaktadır. Böylelikle tekrardan "stat" fonksiyonuna çağrı yapmayacağız. FAKAT UNUTULMAMALIDIR Kİ POSIX STANDARTLARINDA SADECE YUKARIDA ZİKREDİLEN İKİ ELEMAN VARDIR. Linux işletim sisteminde ilgili yapı aşağıdaki biçimdedir; struct dirent { ino_t d_ino; /* i-node number */ off_t d_off; /* offset to the next dirent */ unsigned short d_reclen; /* length of this record */ unsigned char d_type; /* type of file; not supported by all file system types */ char d_name[256]; /* filename */ }; Bu elemanlardan; -> "d_ino", dosyaya ait "i-node" numarasını tutmaktadır. -> "d_name", dizin girişinin ismini vermektedir. Bu dizin girişi "regular file" olabileceği gibi bir "directory" de olabilir. -> "d_type", Linux sistemlerinde bitsel düzeyde kodlanmadığından ki bu durumda karşılaştırma için "==" operatörünü kullanmalıyız, aşağıdaki değerlerden birisini tutmaktadır: -> DT_UNKNOWN, The type is unknown. Only some filesystems have full support to return the type of the file, others might always return this value. -> DT_REG, A regular file. -> DT_DIR, A directory. -> DT_FIFO, A named pipe, or FIFO -> DT_SOCK, A local-domain socket. -> DT_CHR, A character device. -> DT_BLK, A block device. -> DT_LNK, A symbolic link. >> Dizin girişlerinin kapatılması "closedir" isimli bir POSIX fonksiyonuyla mümkündür. >>> "closedir" fonksiyonu argüman olarak yine bir "DIR" nesnesinin adresini alırlar. Başarısızlık durumunda "-1" ile başarı durumunda 0 ile geri dönerler. >> "rewinddir" fonksiyonu, "readdir" ile okumanın sil baştan tekrardan yapılmasını sağlamaktadır. Anımsayacağımız üzere her bir "readdir" çağrısı sonrasında bir sonraki dizin girişine dair bilgiler bize döndürülmektedir. En sonunda da bize NULL değeri döndürülüyor. Bu noktadan sonra yapılacak her "readdir" çağrısı bize NULL değerini döndürecektir. İşte böyle bir durumda bir defalık "rewinddir" çağrısı ile arka plandaki dosya göstericisinin konumunu en başa çekebiliriz. Buradaki dosya göstericisi, ilgili dizine ait bir dosya göstericisidir. * Örnek 1, #include #include #include #include void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => . */ /* # OUTPUT # mest.txt main.c test.txt .. . a.out -------- mest.txt main.c test.txt .. . a.out */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } DIR* dir; if( (dir = opendir(argv[1])) == NULL ) exit_sys("opendir"); struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) printf("%s\n", de->d_name); if( errno != 0 ) exit_sys("readdir"); puts("--------"); rewinddir(dir); while( errno = 0, (de = readdir(dir)) != NULL ) printf("%s\n", de->d_name); if( errno != 0 ) exit_sys("readdir"); closedir(dir); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } >> "telldir" fonksiyonu ile o anki konum göstericisinin konum bilgisini öğrenebilir, "seekdir" fonksiyonu ile de elde edilen konum bilgisine yeniden konumlandırma yapabiliriz. Bu iki fonksiyonun kullandığı konum bilgisi "long" TÜRÜNDENDİR. Burada unutmamalıyız ki okuma yaptıktan sonra konum göstericisinin konumunu çektiğimizden ötürü, ilgili dosya göstericisinin konumu hali hazırda bir ileri ötelenmiş olacaktır. İş bu sebepten dolayı, ikinci defa okumaya başladığımızda, yeniden "test.txt" isimli dizin girişini okumamış olduk. * Örnek 1, #include #include #include #include #include void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => . */ /* # OUTPUT # mest.txt main.c test.txt .. . a.out -------- .. . a.out */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } DIR* dir; if( (dir = opendir(argv[1])) == NULL ) exit_sys("opendir"); long loc; struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { printf("%s\n", de->d_name); if(!strcmp(de->d_name, "test.txt")) loc = telldir(dir); } if( errno != 0 ) exit_sys("readdir"); puts("--------"); seekdir(dir, loc); while( errno = 0, (de = readdir(dir)) != NULL ) printf("%s\n", de->d_name); if( errno != 0 ) exit_sys("readdir"); closedir(dir); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } Aşağıda bu konuya ilişkin örnekler verilmiştir: * Örnek 1, dizin girişlerinin ekrana yazdırılması: #include #include #include #include void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* # COMMAND LINE # /usr/include */ /* # OUTPUT # 952460 -> .. 952462 -> . 948136 -> caml 898005 -> caca_types.h 898004 -> caca_conio.h ... */ if( argc != 2 ) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } DIR* dir; if ( (dir = opendir(argv[1])) == NULL ) exit_sys("opendir"); struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { printf("%llu -> %s\n", (unsigned long long)de->d_ino, de->d_name); } if(errno != 0) exit_sys("readdir"); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, argüman olarak geçilen bir dizinin girişindekilerinin yazdırılması: #include #include #include #include #include #include #include #include #include #define BUFFER_SIZE 4096 void my_ls_command(struct stat* file_info, const char* file_name); void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => /usr/include */ /* # OUTPUT # [drwxr-xr-x 1 root root 4096 Jun 8 04:56 ..] [drwxr-xr-x 1 root root 4096 Jun 8 05:42 .] [lrwxrwxrwx 1 root root 19 Jun 8 05:42 caml] [-rw-r--r-- 1 root root 3398 Oct 20 13:39 caca_types.h] [-rw-r--r-- 1 root root 4759 Oct 20 13:39 caca_conio.h] ... */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } DIR* dir; if( (dir = opendir(argv[1])) == NULL) exit_sys("opendir"); char path[BUFFER_SIZE]; struct dirent* de; struct stat info; while(errno = 0, (de = readdir(dir)) != NULL) { /* * "lstat" ile dosya bilgilerini çekmek için, yol ifadesinin ilgili dosya isminin başında bulunması gerekmektedir. * Bu tür durumlarda fonksiyonların "at" li versiyonlarını kullanmak daha uygun olabilir. "dirfd" isimli fonksiyonu burada kullabiliriz. Üçüncü örnekte kullanılmıştır. */ sprintf(path, "%s/%s", argv[1], de->d_name); if(lstat(path, &info) == -1) exit_sys("lstat"); my_ls_command(&info, de->d_name); } if(errno != 0) exit_sys("readdir"); closedir(dir); } void my_ls_command(struct stat* file_info, const char* file_name) { static char buffer[BUFFER_SIZE]; static mode_t modes[] = { S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH }; static mode_t f_types[] = { S_IFBLK, S_IFCHR, S_IFIFO, S_IFREG, S_IFDIR, S_IFLNK, S_IFSOCK }; int index = 0; for(int i = 0; i < 7; ++i) if( (file_info->st_mode & S_IFMT) == f_types[i] ) { buffer[index++] = "bcp-dls"[i]; break; } for(int i = 0; i < 9; ++i) buffer[index++] = modes[i] & file_info->st_mode ? "rwx"[i % 3] : '-'; struct passwd* pw; char uname[BUFFER_SIZE]; if((pw = getpwuid(file_info->st_uid)) == NULL) sprintf(uname, "%llu", (unsigned long long)file_info->st_uid); else strcpy(uname, pw->pw_name); struct group* gr; char gname[BUFFER_SIZE]; if((gr = getgrgid(file_info->st_gid)) == NULL) sprintf(gname, "%llu", (unsigned long long)file_info->st_gid); else strcpy(gname, gr->gr_name); index += sprintf(buffer + index, " %llu", (unsigned long long)file_info->st_nlink); index += sprintf(buffer + index, " %s", uname); index += sprintf(buffer + index, " %s", gname); index += sprintf(buffer + index, " %llu", (unsigned long long)file_info->st_size); struct tm* ptime; ptime = localtime(&file_info->st_mtim.tv_sec); index += strftime(buffer + index, BUFFER_SIZE, " %b %2e %H:%M", ptime); sprintf(buffer + index, " %s", file_name); printf("[%s]\n", buffer); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 3, #include #include #include #include #include #include #include #include #include #include #define BUFFER_SIZE 4096 void my_ls_command(struct stat* file_info, const char* file_name); void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => /usr/include */ /* # OUTPUT # [drwxr-xr-x 1 root root 4096 Jun 8 04:56 ..] [drwxr-xr-x 1 root root 4096 Jun 8 05:42 .] [lrwxrwxrwx 1 root root 19 Jun 8 05:42 caml] [-rw-r--r-- 1 root root 3398 Oct 20 13:39 caca_types.h] [-rw-r--r-- 1 root root 4759 Oct 20 13:39 caca_conio.h] [drwxr-xr-x 3 root root 4096 Jun 8 05:10 alsa] [-rw-r--r-- 1 root root 91325 Mar 5 06:43 slang.h] [drwxr-xr-x 2 root root 4096 Jun 8 05:10 ogg] [-rw-r--r-- 1 root root 39438 Oct 20 13:39 caca.h] ... */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } DIR* dir; if( (dir = opendir(argv[1])) == NULL) exit_sys("opendir"); int fd; if( (fd = dirfd(dir)) == -1 ) exit_sys("dirfd"); struct dirent* de; struct stat info; while(errno = 0, (de = readdir(dir)) != NULL) { /* * Dördüncü parametreye "0" geçilmesi durumunda, "stat" semantiği uygulanacaktır. "AT_SYMLINK_NOFOLLOW" sembolik sabiti "fcntl.h" içerisinde bildirilmiştir. */ if(fstatat(fd, de->d_name, &info, AT_SYMLINK_NOFOLLOW) == -1) exit_sys("lstat"); my_ls_command(&info, de->d_name); } if(errno != 0) exit_sys("readdir"); closedir(dir); } void my_ls_command(struct stat* file_info, const char* file_name) { static char buffer[BUFFER_SIZE]; static mode_t modes[] = { S_IRUSR, S_IWUSR, S_IXUSR, S_IRGRP, S_IWGRP, S_IXGRP, S_IROTH, S_IWOTH, S_IXOTH }; static mode_t f_types[] = { S_IFBLK, S_IFCHR, S_IFIFO, S_IFREG, S_IFDIR, S_IFLNK, S_IFSOCK }; int index = 0; for(int i = 0; i < 7; ++i) if( (file_info->st_mode & S_IFMT) == f_types[i] ) { buffer[index++] = "bcp-dls"[i]; break; } for(int i = 0; i < 9; ++i) buffer[index++] = modes[i] & file_info->st_mode ? "rwx"[i % 3] : '-'; struct passwd* pw; char uname[BUFFER_SIZE]; if((pw = getpwuid(file_info->st_uid)) == NULL) sprintf(uname, "%llu", (unsigned long long)file_info->st_uid); else strcpy(uname, pw->pw_name); struct group* gr; char gname[BUFFER_SIZE]; if((gr = getgrgid(file_info->st_gid)) == NULL) sprintf(gname, "%llu", (unsigned long long)file_info->st_gid); else strcpy(gname, gr->gr_name); index += sprintf(buffer + index, " %llu", (unsigned long long)file_info->st_nlink); index += sprintf(buffer + index, " %s", uname); index += sprintf(buffer + index, " %s", gname); index += sprintf(buffer + index, " %llu", (unsigned long long)file_info->st_size); struct tm* ptime; ptime = localtime(&file_info->st_mtim.tv_sec); index += strftime(buffer + index, BUFFER_SIZE, " %b %2e %H:%M", ptime); sprintf(buffer + index, " %s", file_name); printf("[%s]\n", buffer); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } Şimdi de dizin ağacının özyinelemeli biçimde dolaşımı hususuna değinelim; dizin girişlerinin bir fonksiyonun kendisini çağırmasıyla dolaşma işlemidir. İki farklı yaklaşım ele alınabilir. İlk yaklaşımda ilk dizin komple gezilir. Sonrasında varsa bu dizin içerisindeki diğer dizinler sırasıyla gezilir. Sonrasında varsa bu dizinler içerisindeki diğer dizinler komple gezilir. Buradaki amaç bir dizinin gezilmesini bitirmeden başka bir dizini gezmeye GEÇİLMEMESİDİR. İkinci yaklaşım türünde ise bir dizin taranırken bir dizin ile karşılaşılması durumunda programın akışının iş bu yeni dizini taramaya geçmesidir. Bu yaklaşım türündeki amaç ile görülen ilk dizini taramayı hedeflemektedir. UNUTULMAMALIDIR Kİ DİZİN AĞACI DOLAŞIRKEN "lstat" FONKSİYONUNU KULLANMALIYIZ. ÇÜNKÜ DİZİNLERİ GÖSTEREN SEMBOLİK LİNKLERİ "stat" İLE ÇAĞIRDIĞIMIZ ZAMAN BAĞLANTI LİNKİNİ TAKİP EDECEĞİNDEN, SONSUZ DÖNGÜYE GİREBİLİRİZ. Özyinelemeli çalışım bittikten sonra prosesin çalışma dizini orjinal hale getirilmelidir. * Örnek 1, "Depth-First" dolaşım örneği: #include #include #include #include #include #include #include void walkdir(const char* path); void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => . */ /* # OUTPUT # [mest.txt] [main.c] [test.txt] [..] [.] [a.out] */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } walkdir(argv[1]); return 0; } void walkdir(const char* path) { /* * i. Dizini açtık. Fakat prosesimiz, ilgili dosya üzerinde 'r' hakkına sahip değilse fonksiyon başarısız olacaktır. Bu durumda programı komple sonlandırmak doğru olmaz. */ DIR* dir; if( (dir = opendir(path)) == NULL ) { fprintf(stderr, "cannot read directory: %s\n", path); return; } /* * ii. Prosesimizin 'Current Working Directory' konumunu, o anki dizin olacak şekilde değiştirdik. */ if( (chdir(path)) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } struct stat finfo; struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { /* * iii. Bilgisini aldığımız dizinin bilgilerini işlemeye başladık. */ printf("[%s]\n", de->d_name); /* * iv. Her bir dizin içerisinde bulunan "." ve ".." dizinlerini pas geçmemiz gerekli. Aksi halde sonsuz döngüye gireceğiz. */ if( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ) continue; /* * v. Artık prosesimizin göreli yol ifadesi, yukarıda açtığımız dizin şeklindedir. Dolayısıyla tekrardan 'path' bilgisini değiştirmemize gerek kalmadı. Artık bu noktada bulunan dosyaların bilgisini çekiyoruz. */ if ( lstat(de->d_name, &finfo) == -1 ) { fprintf(stderr, "cannot read directory: %s\n", de->d_name); continue; } /* * vi. Eğer bu gerçekten bir dizin ise, bu dizinin içini aramaya koyuluyoruz. */ if(S_ISDIR(finfo.st_mode)) { walkdir(de->d_name); /* * vii. İçerideki dizinlerin hepsini gezdikten sonra prosesimizin 'current working directory' bilgisini tekrardan bir üst dizine göre ayarlıyoruz. */ if( (chdir("..")) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } } } if( errno != 0 ) fprintf(stderr, "cannot read directory info: [%s]\n", path); EXIT: closedir(dir); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, İlgili dizin ağacını kademeli olarak yazdırılması: #include #include #include #include #include #include #include void walkdir(const char* path, int level); void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => /usr/include */ /* # OUTPUT # ... [ncurses_dll.h] [search.h] [event2] [buffer_compat.h] [event-config.h] [event_struct.h] ... [xcb] [xcb.h] ... [mtd] [mtd-abi.h] ... [librsvg-2.0] [librsvg] ... [..] [.] [krb5.h] [paths.h] [linux] ... [ImageMagick-6] [..] [magick] ... [wand] ... [nl_types.h] [evdns.h] */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } walkdir(argv[1], 0); return 0; } void walkdir(const char* path, int level) { /* * i. Dizini açtık. Fakat prosesimiz, ilgili dosya üzerinde 'r' hakkına sahip değilse fonksiyon başarısız olacaktır. Bu durumda programı komple sonlandırmak doğru olmaz. */ DIR* dir; if( (dir = opendir(path)) == NULL ) { fprintf(stderr, "cannot read directory: %s\n", path); return; } /* * ii. Prosesimizin 'Current Working Directory' konumunu, o anki dizin olacak şekilde değiştirdik. */ if( (chdir(path)) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } struct stat finfo; struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { /* * iii. Bilgisini aldığımız dizinin bilgilerini işlemeye başladık. */ printf("%*s[%s]\n", level * 4, "", de->d_name); /* * iv. Her bir dizin içerisinde bulunan "." ve ".." dizinlerini pas geçmemiz gerekli. Aksi halde sonsuz döngüye gireceğiz. */ if( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ) continue; /* * v. Artık prosesimizin göreli yol ifadesi, yukarıda açtığımız dizin şeklindedir. Dolayısıyla tekrardan 'path' bilgisini değiştirmemize gerek kalmadı. Artık bu noktada ilgili dizin içerisindekilerinin bilgisini çekiyoruz. */ if ( lstat(de->d_name, &finfo) == -1 ) { fprintf(stderr, "cannot read directory: %s\n", de->d_name); continue; } /* * vi. Eğer bu gerçekten bir dizin ise, bu dizinin içini aramaya koyuluyoruz. */ if(S_ISDIR(finfo.st_mode)) { walkdir(de->d_name, level + 1); /* * vii. İçerideki dizinlerin hepsini gezdikten sonra prosesimizin 'current working directory' bilgisini tekrardan bir üst dizine göre ayarlıyoruz. */ if( (chdir("..")) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } } } if( errno != 0 ) fprintf(stderr, "cannot read directory info: [%s]\n", path); EXIT: closedir(dir); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 3, İlgili dizin ağacını kademeli olarak yazdırılması ve prosesin çalışma dizininin korunması: #include #include #include #include #include #include #include void walkdir(const char* path); void walkdir_recur(const char* path, int level); void exit_sys(const char* msg); int main(int argc, char* argv[]) { /* Command Line Arguments => /usr/include */ /* # OUTPUT # ... [ncurses_dll.h] [search.h] [event2] [buffer_compat.h] [event-config.h] [event_struct.h] ... [xcb] [xcb.h] ... [mtd] [mtd-abi.h] ... [librsvg-2.0] [librsvg] ... [..] [.] [krb5.h] [paths.h] [linux] ... [ImageMagick-6] [..] [magick] ... [wand] ... [nl_types.h] [evdns.h] */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } walkdir(argv[1]); return 0; } void walkdir(const char* path) { char cwd[PATH_MAX]; if( getcwd(cwd, PATH_MAX) == NULL ) { perror("getcwd"); return; } walkdir_recur(path, 0); if( chdir(cwd) == -1 ) { perror("chdir"); return; } } void walkdir_recur(const char* path, int level) { /* * i. Dizini açtık. Fakat prosesimiz, ilgili dosya üzerinde 'r' hakkına sahip değilse fonksiyon başarısız olacaktır. Bu durumda programı komple sonlandırmak doğru olmaz. */ DIR* dir; if( (dir = opendir(path)) == NULL ) { fprintf(stderr, "cannot read directory: %s\n", path); return; } /* * ii. Prosesimizin 'Current Working Directory' konumunu, o anki dizin olacak şekilde değiştirdik. */ if( (chdir(path)) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } struct stat finfo; struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { /* * iii. Bilgisini aldığımız dizinin bilgilerini işlemeye başladık. */ printf("%*s[%s]\n", level * 4, "", de->d_name); /* * iv. Her bir dizin içerisinde bulunan "." ve ".." dizinlerini pas geçmemiz gerekli. Aksi halde sonsuz döngüye gireceğiz. */ if( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ) continue; /* * v. Artık prosesimizin göreli yol ifadesi, yukarıda açtığımız dizin şeklindedir. Dolayısıyla tekrardan 'path' bilgisini değiştirmemize gerek kalmadı. Artık bu noktada ilgili dizin içerisindekilerinin bilgisini çekiyoruz. */ if ( lstat(de->d_name, &finfo) == -1 ) { fprintf(stderr, "cannot read directory: %s\n", de->d_name); continue; } /* * vi. Eğer bu gerçekten bir dizin ise, bu dizinin içini aramaya koyuluyoruz. */ if(S_ISDIR(finfo.st_mode)) { walkdir_recur(de->d_name, level + 1); /* * vii. İçerideki dizinlerin hepsini gezdikten sonra prosesimizin 'current working directory' bilgisini tekrardan bir üst dizine göre ayarlıyoruz. */ if( (chdir("..")) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); goto EXIT; } } } if( errno != 0 ) fprintf(stderr, "cannot read directory info: [%s]\n", path); EXIT: closedir(dir); } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 4, #include #include #include #include #include #include #include int disp(const char* fname, const struct stat* finfo, int level); int walkdir(const char* path, int (*proc)(const char* fname, const struct stat* finfo, int level)); int walkdir_recur(const char* path, int level, int (*proc)(const char* fname, const struct stat* finfo, int level)); int main(int argc, char* argv[]) { /* Command Line Arguments => /usr/include */ /* # OUTPUT # ... [re_comp.h] [glib-2.0] [gobject] [gparam.h] [gtypeplugin.h] [genums.h] [gsignal.h] [gobject-autocleanups.h] [gsourceclosure.h] [gtype.h] [gparamspecs.h] [gvaluearray.h] [gmarshal.h] [glib-enumtypes.h] [gvalue.h] [gobjectnotifyqueue.c] [gbinding.h] function terminated prematurely with 1 code!... */ if(argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } int result; if( (result = walkdir(argv[1], disp)) == -1 ) { fprintf(stderr, "function terminates unexpectedly!...\n"); exit(EXIT_FAILURE); } if( result != 0 ) printf("function terminated prematurely with %d code!...\n", result); else printf("function terminated normally!...\n"); return 0; } int disp(const char* fname, const struct stat* finfo, int level) { printf("%*s[%s]\n", level * 4, "", fname); if( !strcmp(fname, "gbinding.h") ) return 1; return 0; } int walkdir(const char* path, int (*proc)(const char* fname, const struct stat* finfo, int level)) { char cwd[PATH_MAX]; if( getcwd(cwd, PATH_MAX) == NULL ) { perror("getcwd"); return -1; } int result; result = walkdir_recur(path, 0, proc); if( chdir(cwd) == -1 ) { perror("chdir"); return -1; } return result; } int walkdir_recur(const char* path, int level, int (*proc)(const char* fname, const struct stat* finfo, int level)) { int result = 0; DIR* dir; if( (dir = opendir(path)) == NULL ) { fprintf(stderr, "cannot read directory: %s\n", path); return -1; } if( (chdir(path)) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); result = -1; goto EXIT; } struct stat finfo; struct dirent* de; while( errno = 0, (de = readdir(dir)) != NULL ) { if( !strcmp(de->d_name, ".") || !strcmp(de->d_name, "..") ) continue; if ( lstat(de->d_name, &finfo) == -1 ) { fprintf(stderr, "cannot read directory: %s\n", de->d_name); continue; } if ( (result = proc(de->d_name, &finfo, level)) != 0) result = -1; goto EXIT; if(S_ISDIR(finfo.st_mode)) { result = walkdir_recur(de->d_name, level + 1, proc); if( (chdir("..")) == -1) { fprintf(stderr, "current working directory cannot change to: [%s]\n", path); result = -1; goto EXIT; } if( result != 0 ) goto EXIT; } } if( errno != 0 ) fprintf(stderr, "cannot read directory info: [%s]\n", path); EXIT: closedir(dir); return result; } Dizin ağacını öz yinelemeli olarak dolaşan "scandir" fonksiyonun ek olarak iki fonksiyon daha mevcuttur. Bu fonksiyonlar "ftw" ve "nftw" isimli fonksiyonlardır. Bu fonksiyonlar POSIX fonksiyonlarıdır. Günümüzde "ftw" isimli fonksiyon "deprecated" hale getirildi. Artık günümüzde "nftw" isimli fonksiyon kullanılmaktadır. Bu fonksiyonu Linux altında, GNU kütüphanesiyle birlikte kullanmak için, "_XOPEN_SOURCE" isimli sembolik sabitini en az "500" rakamı olacak şekilde tanımlamamız gerekiyor. Tanımlandığı nokta, başlık dosyalarının yukarısında olmalıdır. "nftw" isimli fonksiyonun imzası şu şekildedir: #include int nftw( const char *path, int (*fn)(const char * path, const struct stat *finfo, int flag, struct FTW *ftw), int fd_limit, int flags ); Fonksiyonun, -> Fonksiyonun birinci parametresi, öz yinelemeli olarak dolaşılacak dizinin yol ifadesidir. -> İkinci parametre bir "callback" parametresidir. Her dizin girişi bulunduğunda bu "callback" fonksiyona çağrı yapılacaktır. "callback" fonksiyonunun parametreleri de şu şekildedir: -> Birinci parametre, bulunan dizin girişinin yol ifadesi yerleştirilir. Bu yol ifadesinin baş kısmı tamamen bizim "nftw" fonksiyonuna verdiğimiz dizin ifadesinden oluşmaktadır. Eğer "nftw" fonksiyonuna mutlak yol ifadesi geçilmişse, bu "callback" fonksiyonunun birinci parametresi de mutlak bir yol ifadesi olacaktır. Göreli olsaydı, göreli olacaktı. -> İkinci parametre, bulunan dizin girişine ilişkin "stat" yapısının adresini tutmaktadır. -> Üçüncü parametre, bulunan dizin girişinin türünü belirtmektedir. Bu tür şunlardan birine tam eşit ("==" operatörünü kullanmalıyız) olmalıdır. Bu türler; -> FTW_D - Bulunan giriş bir dizine aittir. -> FTW_DNR - Bulunan giriş bir dizine aittir. Ancak bu dizinin içi okunamamıştır. Artık bu dizin öz yineleme sırasında dolaşılamayacaktır. -> FTW_DP - "post-order" biçimindeki dolaşımda bir dizin ile karşılaşıldığında FTW_D bayrağı yerine bu bayrak kullanılacaktır. -> FTW_F - Bulunan dizin girişinin "regular file" a ait belirtmektedir. -> FTW_NS - Bulunan dizin girişi için "stat" çağrısının başarısız olduğunu belirtmektedir. Bu durumda fonksiyona geçilen "stat" yapısının elemanları ANLAMLI DEĞİLDİR. -> FTW_SL - Bulunan giriş bir SEMBOLİK LİNK DOSYASINA İLİŞKİNDİR. -> FTW_SLN - Bulunan giriş bir SEMBOLİK LİNK DOSYASINA İLİŞKİNDİR. Fakat bu sembolik bağlantı dosyası "dangling" konumundadır. Yani hedefteki gerçek dosya MEVCUT DEĞİLDİR. -> Dördüncü parametre, "FTW" türünden bir yapının adresini tutmaktadır. Bu yapı bünyesinde iki elemana sahip olup isimleri "level" ve "base" biçimindedir. Bu elemanlar da "int" türdendir. "level" elemanı derine dalarken kaçıncı derinlikte olduğumuzun bilgisini tutarken, "base" elemanı ise dizin girişinin, birinci parametrede belirtilen yol ifadesinin kaçıncı indeksten başladığını belirtmektedir. Örneğin, "/home/kaan/Study" dizinini dolaşmak istemiş olalım. Fonksiyon da dizin girişi olarak "sample.c" yi bulmuş olsun. Fonksiyon, bize, bu girişi "/home/kaan/Study/sample.c" biçiminde verecektir. İş bu "base" elemanı "17" değerini tutacaktır. Çünkü "sample.c" ismindeki "s" harfi, ilgili yol ifadesindeki 17. karaktere denk gelmektedir. -> Fonksiyonun üçüncü parametresi, kullanılacak maksimum dosya betimleyicisinin adedini belirtmektedir. Dün yazdığmız "walkdir_recur" isimli fonksiyon her çağrıldığında, fonksiyonun gövdesinde çağrılan "opendir" fonksiyonundan dolayı, "File Description Table" bir elemana daha sahip oluyor. İşte bu tabloyu doldurmamak adına, bu üçüncü parametreyi kullanarak, bu fonksiyon ile oluşturulacak maksimum "File Description" adedini belirtmiş oluyoruz. Her ne kadar bir dizini dolaşmayı bitirip tekrar bir üst dizine döndüğümüz zaman ilgili "File Description" yok edilse de, her gördüğümüz ilk dizinin içine girilmektedir. Bu üçüncü parametre ile kaç defa ilk gördüğümüz dizine gireceğimiz sınırlanmış olmaktadır. -> Fonksiyonun dördüncü parametresi ise öz yinelemeli dolaşım sırasında bazı belirlemeler için kullanılmaktadır. Bu parametre çeşitli sembolik sabitlerin "bit-wise OR" işlemine sokulması ile oluşturulmaktadır. Bu dördüncü parametreye hiç bir bayrak geçmek istemez ise "0" değerini geçebilir. İş bu sabitler; -> FTW_CHDIR - Eğer bu bayrak belirtilirse, fonksiyon her dizine geçtiğinde, prosesin çalışma dizinini de o dizin olacak şekilde değiştirmektedir. -> FTW_DEPTH - Normal şartlarda öz yinelemeli dolaşım "pre-order" denilem biçimde yapılmaktadır. Yani önce bütün dizin girişlerinin ele alınması, sonrasında da öz yineleme yapılması demektir. Bu bayrak belirtilirse dolaşım "post-order" biçiminde yapılacaktır. Yani önce öz yineleme yapılması, sonrasında dizin girişlerinin ele alınmasıdır. -> FTW_MOUNT - Unix/Linux sistemlerinde tek bir ağaç vardır, haliyle en altta sadece bir tane "root" dizin mevcuttur. Sisteme "Removable Drive" bağlantısı yapıldığında bir nevi "mount" işlemi yapmış oluyoruz. Fakat bu tip harici bağlantıların dosya sistemleri, bizim işletim sisteminde kullanılan dosya sisteminden farklı olmaktadır. Eğer bu bayrak belirtilirse, öz yineleme sırasında bu tip "mount" edilmiş dizinler MUAF TUTULACAKTIR. -> FTW_PHYS - Bu bayrak belirtilirse, bir sembolik link ile karşılaşıldığında sembolik linki İZLEMEMEKTEDİR. Fakat varsayılan durumlarda sembolik linkler izlenmektedir. Daha önce de belirttiğimiz gibi, bir dizine açılan sembolik linklerin izlenmesi sonsuz döngü meydana getirebilir. -> "nftw" fonksiyonunun geri dönüş değeri ise başarısızlık durumunda "-1", başarı durumunda "0" şeklindedir fakat başarılı olması durumunda "callback" olarak kullanılan fonksiyonun geri dönüş değeri ile geri dönmektedir. Dolayısıyla bu "callback" fonksiyonunu "0" ile geri döndürürsek, öz yinelemeye devam etmek istediğimizi belirtmiş oluruz. Başka bir hata olmaması durumunda "nftw" de "0" ile geri dönecektir. Velev ki bizler "callback" fonksiyonundan sıfırdan başka bir değer ile geri dönersek, "nftw" fonksiyonu öz yinelemeyi kontrollü bir şekilde durdurur ve iş bu sıfırdan başka değer ile geri döner. Aşağıda bu konuya ilişkin bir örnekler verilmiştir: * Örnek 1, #define _XOPEN_SOURCE 500 #include #include #include int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw); void exit_sys(const char* msg); int main(int argc, char** argv) { /* Command Line Argument => "." */ /* # OUTPUT # [.] [./main.c] [./testTESTtest.txt] [./test.txt] [./a.out] result = 0 */ if (argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } int result; if((result = nftw(argv[1], call_back, 100, FTW_PHYS) ) == -1) exit_sys("nftw"); printf("result = %d\n", result); return 0; } int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw) { printf("[%s]\n", path); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, #define _XOPEN_SOURCE 500 #include #include #include int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw); void exit_sys(const char* msg); int main(int argc, char** argv) { /* Command Line Argument => "." */ /* # OUTPUT # [.] [main.c] [testTESTtest.txt] [test.txt] [a.out] result = 0 */ if (argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } int result; if((result = nftw(argv[1], call_back, 100, FTW_PHYS) ) == -1) exit_sys("nftw"); printf("result = %d\n", result); return 0; } int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw) { printf("[%s]\n", path + ftw->base); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 3, #define _XOPEN_SOURCE 500 #include #include #include int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw); void exit_sys(const char* msg); int main(int argc, char** argv) { /* Command Line Argument => "." */ /* # OUTPUT # [.] [main.c] [testTESTtest.txt] [test.txt] [a.out] result = 0 */ if (argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } int result; if((result = nftw(argv[1], call_back, 100, FTW_PHYS) ) == -1) exit_sys("nftw"); printf("result = %d\n", result); return 0; } int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw) { printf("%*s[%s]\n", ftw->level * 4, "", path + ftw->base); return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 4, #define _XOPEN_SOURCE 500 #include #include #include int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw); void exit_sys(const char* msg); int main(int argc, char** argv) { /* Command Line Argument => "/" */ /* # OUTPUT # [driver] - cannot read directory. [fd] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [fd] - cannot read directory. [map_files] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [fd] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [fd] - cannot read directory. [map_files] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [fd] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [fd] - cannot read directory. [map_files] - cannot read directory. [fdinfo] - cannot read directory. [ns] - cannot read directory. [private] - cannot read directory. [localauthority] - cannot read directory. [root] - cannot read directory. [unattended-upgrades] - cannot read directory. [private] - cannot read directory. [ldconfig] - cannot read directory. [partial] - cannot read directory. [private] - cannot read directory. [partial] - cannot read directory. [sessions] - cannot read directory. [polkit-1] - cannot read directory. [private] - cannot read directory. result = 0 */ if (argc != 2) { fprintf(stderr, "wrong number of arguments!...\n"); exit(EXIT_FAILURE); } int result; if((result = nftw(argv[1], call_back, 100, FTW_PHYS) ) == -1) exit_sys("nftw"); printf("result = %d\n", result); return 0; } int call_back(const char * path, const struct stat *finfo, int flag, struct FTW *ftw) { switch(flag) { // default: printf("%*s[%s]\n", ftw->level * 4, "", path + ftw->base); break; case FTW_DNR: printf("%*s[%s] - cannot read directory.\n", ftw->level * 4, "", path + ftw->base); break; case FTW_NS: printf("%*s[%s] - cannot get stat info.\n", ftw->level * 4, "", path + ftw->base); break; } return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } > Hatırlatıcı Notlar: >> "printf" fonksiyonu, varsayılan biçimde, sola dayalı olarak ekrana bastırmaktadır. Format belirleyicisi "%d" nin içerisine rakam yazmamız durumunda, o rakam kadarlık bir yer ayıracak fakat sağa dayalı olarak yazacaktır. Bu rakamın negatifini kullanmamız durumunda ise sola dayalı olarak ekrana basacaktır. * Örnek 1 #include int main() { /* # OUTPUT # 1-Bir 11-Onbir 111-Yuzonbir 1-Bir 11-Onbir 111-Yuzonbir 1 -Bir 11 -Onbir 111 -Yuzonbir */ int a = 1; const char* a_name = "Bir"; int b = 11; const char* b_name = "Onbir"; int c = 111; const char* c_name = "Yuzonbir"; printf("%d-%s\n", a, a_name); printf("%d-%s\n", b, b_name); printf("%d-%s\n", c, c_name); puts(""); printf("%5d-%s\n", a, a_name); printf("%5d-%s\n", b, b_name); printf("%5d-%s\n", c, c_name); puts(""); printf("%-5d-%s\n", a, a_name); printf("%-5d-%s\n", b, b_name); printf("%-5d-%s\n", c, c_name); } >> Bir rakamın kaç basamaklı olduğunu pratik hesaplamak için ilgili sayının on tabanına göre logaritmasını alır ve bir ekleriz. Fakat matematik fonksiyonlarını kullanırken, "-lm" seçeneğini kullanmamız gerekiyor. * Örnek 1, gcc derleyicisinde "-lm" seçeneğiyle birlikte kullanılmıştır. #include #include int main() { /* # OUTPUT # 6 */ int max = 0; int a[] = { 1, 11, 111, 1111, 11111, 111111 }; int n_digit; for(int i = 0; i < sizeof(a) / sizeof(a[0]); ++i) { n_digit = (int)log10(a[i]) + 1; if (max < n_digit) max = n_digit; } printf("%d", max); } >> "printf" fonksiyonunda hizalama yaparken kaç karakterlik hizalama yapılacağı çalışma zamanında belli olacaksa, "%d" format belirleyicisinin içine "*" karakteri yazıyoruz. Sonrasında "," karakterinden sonra bu "*" karakterine karşılık gelecek değişkeni belirtiyoruz. * Örnek 1, #include #include int main() { /* # OUTPUT # 1-Bir 11-Onbir 111-Yuzonbir 1-Bir 11-Onbir 111-Yuzonbir 1 -Bir 11 -Onbir 111 -Yuzonbir 1-Bir 11-Onbir 111-Yuzonbir 1 -Bir 11 -Onbir 111 -Yuzonbir */ int a = 1; const char* a_name = "Bir"; int b = 11; const char* b_name = "Onbir"; int c = 111; const char* c_name = "Yuzonbir"; printf("%d-%s\n", a, a_name); printf("%d-%s\n", b, b_name); printf("%d-%s\n", c, c_name); puts(""); printf("%5d-%s\n", a, a_name); printf("%5d-%s\n", b, b_name); printf("%5d-%s\n", c, c_name); puts(""); printf("%-5d-%s\n", a, a_name); printf("%-5d-%s\n", b, b_name); printf("%-5d-%s\n", c, c_name); puts(""); int n_digit = 5; printf("%*d-%s\n", n_digit, a, a_name); printf("%*d-%s\n", n_digit, b, b_name); printf("%*d-%s\n", n_digit, c, c_name); puts(""); printf("%-*d-%s\n", n_digit,a, a_name); printf("%-*d-%s\n", n_digit,b, b_name); printf("%-*d-%s\n", n_digit,c, c_name); } >> "printf" fonksiyonunda "%s" içerisinde "." atomu ve yanına bir rakam yazmamız, sadece o rakam kadarlık yaz manasındadır. * Örnek 1, #include int main(void) { /* # OUTPUT # >>> xXxxXXxxxXXXxxxxXXXXxxxxxXXXXX <<< >>> xXxxXXxxxX <<< */ char buffer[30] = "xXxxXXxxxXXXxxxxXXXXxxxxxXXXXX"; printf(">>> %s <<<\n", buffer); int n_digit = 10; printf(">>> %.*s <<<\n", n_digit, buffer); } >> "scandir" fonksiyonu, kendi içerisinde "opendir" fonksiyonunu barındırmaktadır. Dolayısıyla daha üst seviye bir fonksiyondur. Prototipi aşağıdaki şekildedir. #include int scandir( const char *dir, struct dirent ***namelist, int (*sel)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **) ); Birinci parametresi bir dizine ait yol ifadesidir. İkinci parametre, bir göstericiyi gösteren göstericinin adresidir. Buradaki gösterici dinamik ömürlü bir bellek alanını göstermektedir ve işimiz bittiğinde bu alanın geri verilmesinden BİZ SORUMLUYUZ. Üçüncü ve dördüncü parametreler ise birer fonksiyon adresleri olup; üçüncü parametre filtreleme yapacak olan fonksiyonun adresini, dördüncü parametre ise sıralama yapacak olan fonksiyonun adresidir. Buradaki amaç, bizim istediğimiz özelliklere haiz bir dizin girişlerini sıralı bir şekilde elde etmektir. Burada, dördüncü parametre için standart bir fonksiyon yazıldığı için bizlerin tekrardan bir fonksiyon yazmasına gerek kalmamıştır. Yazılan bu fonksiyonun adı ise "alphasort".Üçüncü parametreye NULL geçilmesi durumunda ise dizin girişindeki bütün girişler elde edilecektir. * Örnek 1, "/home" dizini içerisindeki dosyalardan başı "t" ya da "T" ile başlayanların sıraya dizilmiş bir şekilde elde edilmesi: #include #include #include #include int my_filter(const struct dirent* de); void exit_sys(const char* msg); int main(void) { /* In the directory: /home */ /* # INPUT # test.txt mest.txt main.c */ /* # OUTPUT # [1] test.txt */ int result; struct dirent** dents; if( (result = scandir("/home", &dents, my_filter, alphasort)) == -1 ) exit_sys("scandir"); for(int i = 0; i < result; ++i) { printf("%s\n", dents[i]->d_name); } for(int i = 0; i < result; ++i) free(dents[i]); free(dents); return 0; } int my_filter(const struct dirent* de) { return de->d_name[0] == 't' || de->d_name[0] == 'T'; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); } * Örnek 2, Dördüncü parametre olarak yeni bir fonksiyon yazılması: #include #include #include #include #include #include int my_filter(const struct dirent* de); int cmp_size(const struct dirent** de1, const struct dirent** de2); void exit_sys(const char* msg); int main(int argc, char** argv) { /* Command Line Argument: /usr/include */ /* # OUTPUT # tar.h term.h term_entry.h termcap.h termio.h termios.h tgmath.h thread_db.h threads.h tic.h time.h ttyent.h */ int result; struct dirent** dents; if( chdir(argv[1]) == -1 ) exit_sys("chdir"); if( (result = scandir(argv[1], &dents, my_filter, cmp_size)) == -1 ) exit_sys("scandir"); for(int i = 0; i < result; ++i) { printf("%s\n", dents[i]->d_name); } for(int i = 0; i < result; ++i) { free(dents[i]); } free(dents); return 0; } int my_filter(const struct dirent* de) { return de->d_name[0] == 't' || de->d_name[0] == 'T'; } int cmp_size(const struct dirent** de1, const struct dirent** de2) { struct stat finfo1, finfo2; if( stat((**de1).d_name, &finfo1) == -1 || stat((**de2).d_name, &finfo2) == -1 ) exit_sys("stat"); if( finfo1.st_size > finfo2.st_size ) return -1; if( finfo1.st_size < finfo2.st_size ) return 1; return 0; } void exit_sys(const char* msg) { perror(msg); exit(EXIT_FAILURE); }