Linux程式設計之三(轉)
Linux程式設計之三(轉)[@more@]Linux程式設計-12.目錄操作 (2001-05-26 10:08:00)Linux下的目錄是依照標準來實作的,因此,您可以毫無問題地移殖到任何其它UNIX平臺。--------------------------------------------------------------------------------getcwd/getwd : 取得目前所在目錄--------------------------------------------------------------------------------#includechar * getcwd(char *buf,size_t size);buf將會返回目前路徑名稱。任何的錯誤發生,將會返回NULL。如果路徑長度超過size,errno為ERANGE。getcwd返回的值永遠是沒有symbol link的。--------------------------------------------------------------------------------#includechar *getwd(char *buf);getwd是個危險的函式,一般都會強烈建議不要用,因為您無法確定最長的目錄長度為多少。PATH_MAX定義了最長的路徑長度。在Linux下所以提供這個函式主要是因為「傳統」。--------------------------------------------------------------------------------chdir/fchdir/chroot : 改變目前所在目錄--------------------------------------------------------------------------------#includeint chdir(const char * pathname);int fchdir(int fd);chdir根據pathname變更目前的所在目錄,它只改變該程式的所在目錄。fchdir根據已開啟的fd(file descriptor)目錄來變更。--------------------------------------------------------------------------------#includeint chroot(const char * path);chroot改變該程式的根目錄所在。例如chroot("/home/ftp")會將根目錄換到/home/ftp下,而所有檔案操作都不會超出這個圍內。為保障安全性,當chdir("/..")時,將會僅切換到chdir("/"),如此便不會有檔案安全問題。--------------------------------------------------------------------------------mkdir/rmdir : 造/移除目錄--------------------------------------------------------------------------------#include#includeint mkdir(const char * dirname,mode_t mode);mkdir會造一個新目錄出來,例如mkdir("/home/foxman",0755);。如果該目錄或檔案已經存在,則操作失敗。--------------------------------------------------------------------------------#includeint rmdir(char * pathname);這個函式移除pathname目錄。--------------------------------------------------------------------------------opendir/readdir/closedir/rewinddir : 讀取目錄資訊--------------------------------------------------------------------------------#includeDIR * opendir(const char * pathname);int closedir(DIR *dir);struct dirent * readdir(DIR *dir);int rewinddir(DIR *dir);struct dirent {long d_ino; /* inode number */off_t d_off; /* offset to this dirent */unsigned short d_reclen; /* length of this d_name */char d_name [NAME_MAX+1]; /* file name (null-terminated) */};opendir開啟一個目錄操作DIR,closedir關閉之。readdir則循序讀取目錄中的資訊,rewinddir則可重新讀取目錄資訊。以下是個標準例。--------------------------------------------------------------------------------#include#includechar ** dirGetInfo(const char *pathname){char ** filenames;DIR * dir;struct dirent * ent;int n = 0;filenames = (char **)malloc(sizeof(char*));filenames[0]=NULL;dir = opendir(pathname);if (!dir) return filenames;while ((ent = readdir(dir))) {filenames = (char**)realloc(filenames,sizeof(char*)*(n+1));filenames[n] = strdup(ent->d_name);n++;}closedir(dir);filenames = (char **)realloc(filenames,sizeof(char*)*(n+1));filenames[n] = NULL;return filenames;}Linux程式設計-13.記憶體對映mmap (2001-05-26 11:00:00)Linux允許將檔案對映到記憶體空間中。如此可以產生一個在檔案資料及記憶體資料一對一的對映,例如字型檔的存取。使用記憶體對映有許多好處:高速檔案存取。一般的I/O機制通常需要將資料先到緩區中。記憶體對映免去了中間這一層,加速檔案存取速度。可執行檔可對映到記憶體空間中,使程式動態載入。Linux Dynamic Loading便是如此實作出來的。新的記憶體可以透過利用/dev/zero來產生全零的檔案。新的記憶體可以用於執行目的,這對解譯式編譯器非常有用。可把檔案當成記憶體來用,直接使用指標來操作。對映的記憶體可當成行程間共享記憶體,該記憶體內容存在檔案中,因此與行程無關。--------------------------------------------------------------------------------頁對齊「Page Alignment」#includesize_t getpagesize(void);系統記憶體通常被分割成頁的單位。在Intel及SPARC上,每頁為4096 Bytes(4K),在Alpha上則為8192 Bytes(8K)。getpagesize返回該系統的頁大小。--------------------------------------------------------------------------------#include#includevoid * mmap(void *start, size_t length, int prot , int flags, int fd, off_t offset);int munmap(void *start, size_t length);mmap開啟記憶體對映。start指定記憶體位置,通常都是用NULL。offset指定檔案要在那裡開始對映,通常都是用0。protectionsPROT_READPROT_WRITEPROT_EXECPROT_NONEflagsMAP_FIXEDMAP_PRIVATEMAP_SHAREDMAP_ANONYMOUSMAP_DENYWRITEMAP_GROWSDOWNMAP_LOCKEDmunmap關閉記憶體對映。--------------------------------------------------------------------------------int msync(const void *start, size_t length, int flags);如果開啟記憶體對映是希望寫入檔案中,那麼修改過的記憶體會在一段時間內與檔案稍稍有點不同。如果您希望立即將資料寫入檔案中,可使用msync。start為記憶體開始位置,length為長度。flags則有三個:MS_ASYNC : 請Kernel快將資料寫入。MS_SYNC : 在msync結束返回前,將資料寫入。MS_INVALIDATE : 讓核心自行決定是否寫入,僅在特殊狀況下使用。--------------------------------------------------------------------------------int mlock(const void *addr, size_t len);int munlock(const void *addr, size_t len);鎖住記憶體,僅root有許可權這樣做。--------------------------------------------------------------------------------int mlockall(int flags);鎖住所有記憶體空間。MCL_CURRENT : 所有的記憶頁都會被鎖住。MCL_FUTURE : 所有的新增的記憶頁都會被鎖住。int munlockall(void);Linux程式設計-14.動態函式庫 (2001-05-26 12:10:00)--------------------------------------------------------------------------------本節說明Linux下動態函式庫的使用及設計。大多數大型的UNIX軟體都會將許多個別的部份拆開來設計,通常這些部份被稱為「plugins」或「modules」。它們會用許多方式來結合,如「pipe」、「IPC」或「shared objects」。Linux下的Dynamic Linking Loader介面標準來自於Solaris。在Dynamic Linking的操作方式下,所有的函式及資料變數都被稱為「symbol」,要使用時,需要透過dlsym來找出其實際位址。--------------------------------------------------------------------------------所有動態函式載入的函式均宣告在中,共有四個函式。void *dlopen (const char *filename, int flag);const char *dlerror(void);void *dlsym(void *handle, char *symbol);int dlclose (void *handle);--------------------------------------------------------------------------------dlopen()的作用為尋找函式庫檔案,開啟它、並做一些初始化的動作。filename如果以"/"符號開始,dlopen()將不會搜尋該函式庫的路徑,否則它將會透過以下方式搜尋檔案:透過LD_LIBRARY_PATH所指定的路徑搜尋/etc/ld.so.cache所指定的路徑。該檔案是由ldconfig所產生,其設定位於/etc/ld.so.conf。找尋/usr/lib及/lib兩個內定目錄。flag有三個:RTLD_GLOBAL : 在函式庫中的變數內定是不輸出的。指定RTLD_GLOBAL可輸出這些變數。RTLD_LAZY : 當函式被執行時,才找出所使用的變數對照表。RTLD_NOW : 當函式被載入時,立刻找出所使用的變數對照表。RTLD_GLOBAL可與RTLD_LAZY或RTLD_NOW結合,RTLD_LAZY及RTLD_NOW不可同時使用。--------------------------------------------------------------------------------dlerror()返回最近發生的錯誤訊息,如果沒有錯誤發生,那麼將會返回NULL。--------------------------------------------------------------------------------dlsym()載入所指定的函式。--------------------------------------------------------------------------------dlclose()關閉開啟的函式庫。它會檢查一個對照計數,將開啟的函式庫次數數量減一,如果為零,則關閉該函式庫。--------------------------------------------------------------------------------hellodl--------------------------------------------------------------------------------hello.so的設計Linux程式設計-15.同步I/O多重處理 (2001-05-26 13:04:00)同步I/O多重處理(Synchronous I/O Multiplexing)--------------------------------------------------------------------------------當我們在同時間需要處理許多I/O時,例如網路伺服器socket,有時候一個一個處理,程式非常難寫,這時候可以利用select來達成。--------------------------------------------------------------------------------#include#include#includeint select(int n, fd_set *readfds, fd_set *writefds,fd_set *exceptfds, struct timeval *timeout);FD_CLR(int fd, fd_set *set);FD_ISSET(int fd, fd_set *set);FD_SET(int fd, fd_set *set);FD_ZERO(fd_set *set);FD_ZERO清除所有fd_set。FD_SET將fd加入fd_set中。FD_CLR將fd從fd_set中移除。FD_ISSET檢查fd是否屬於該fd_set。struct timeval {int tv_sec;int tv_usec;};Linux程式設計-16.TarBall (2001-05-26 14:08:00)我寫了一個targz的函式庫,專門處理檔案安裝的事宜,這個函式庫在我寫的X Corona Package Installer中使用到。它與zlib一起使用。targz.htargz.c--------------------------------------------------------------------------------typedef struct {char name[100];char mode[8];char uid[8];char gid[8];char size[12];char mtime[12];char chksum[8];char typeflag;char linkname[100];char magic[6];char version[2];char uname[32];char gname[32];char devmajor[8];char devminor[8];char prefix[155];} TarEntry;GNU Tar檔案格式--------------------------------------------------------------------------------typedef struct {char * Package;char * FileName;char * path;gzFile fp;int size;int totalsize;int expanding;int mode;int result;TarEntry ** NAME;} TarBall;--------------------------------------------------------------------------------TarBall * tgzOpen(char * Filename,char * mode);開啟一個tarball檔,檔名為Filename。mode"r":為讀取模式。"w":為寫入模式。--------------------------------------------------------------------------------int tgzLookup(TarBall * tgz);擷取tarball內檔案資訊。--------------------------------------------------------------------------------int tgzClose(TarBall * tgz);關閉tarball檔。--------------------------------------------------------------------------------int tgzExpand(TarBall * tgz);解開檔案。--------------------------------------------------------------------------------int tgzSkip(TarBall * tgz);跳過下一個檔案,不安裝。--------------------------------------------------------------------------------int tgzAppend(TarBall * tgz,char *FileName);新增檔案到tarball中,必須要是Write ModeLinux程式設計-17.SVGALIB (2001-05-26 15:00:00)SvgaLib 是Linux Console下的VGA驅動函式庫。雖然它的品質還是有點低,支援的螢幕卡種類不算太多,但是有許多的遊戲及程式都是用它來做開發,可以算是非官方的標準了。如果您準備要在Console下撰寫圖形功能的程式,目前來說SVGALIB是您唯一的選擇。目前使用SVGALIB的程式有許多,中文終端機使用 SVGALIB的就有a4c.tty/yact/bcs16。這裡我只講一些簡單的使用方法,如啟動vga及mouse的使用。要有效地、高階的運用,技巧雜很多,例如a4c.tty就另外往上架一層Star Window Manager,來管理一個小型視窗系統。--------------------------------------------------------------------------------vgavgamouse--------------------------------------------------------------------------------int vga_setmode(int mode);int vga_hasmode(int mode);int vga_setpalette(int index, int red, int green, int blue);int vga_getpalette(int index, int *red, int *green, int *blue);int vga_setcolor(int color);int vga_drawpixel(int x, int y);int vga_drawline(int x1, int y1, int x2, int y2);int vga_getpixel(int x, int y);vga_modeinfo *vga_getmodeinfo(int mode);unsigned char *graph_mem;unsigned char *vga_getgraphmem(void);void vga_setpage(int p);void vga_setreadpage(int p);void vga_setreadpage(int p);void vga_setwritepage(int p);void vga_setdisplaystart(int a);void vga_waitretrace(void);int vga_init(void);int vga_setrgbcolor(int r, int g, int b);--------------------------------------------------------------------------------#define TEXT 0 /* Compatible with VGAlib v1.2 */#define G320x200x16 1#define G640x200x16 2#define G640x350x16 3#define G640x480x16 4#define G320x200x256 5#define G320x240x256 6#define G320x400x256 7#define G360x480x256 8#define G640x480x2 9#define G640x480x256 10#define G800x600x256 11#define G1024x768x256 12#define G1280x1024x256 13 /* Additional modes. */#define G320x200x32K 14#define G320x200x64K 15#define G320x200x16M 16#define G640x480x32K 17#define G640x480x64K 18#define G640x480x16M 19#define G800x600x32K 20#define G800x600x64K 21#define G800x600x16M 22#define G1024x768x32K 23#define G1024x768x64K 24#define G1024x768x16M 25#define G1280x1024x32K 26#define G1280x1024x64K 27#define G1280x1024x16M 28#define G800x600x16 29#define G1024x768x16 30#define G1280x1024x16 31#define G720x348x2 32 /* Hercules emulation mode */#define G320x200x16M32 33 /* 32-bit per pixel modes. */#define G640x480x16M32 34#define G800x600x16M32 35#define G1024x768x16M32 36#define G1280x1024x16M32 37/* additional resolutions */#define G1152x864x16 38#define G1152x864x256 39#define G1152x864x32K 40#define G1152x864x64K 41#define G1152x864x16M 42#define G1152x864x16M32 43#define G1600x1200x16 44#define G1600x1200x256 45#define G1600x1200x32K 46#define G1600x1200x64K 47#define G1600x1200x16M 48#define G1600x1200x16M32 49typedef struct {int width;int height;int bytesperpixel;int colors;int linewidth; /* scanline width in bytes */int maxlogicalwidth; /* maximum logical scanline width */int startaddressrange; /* changeable bits set */int maxpixels; /* video memory / bytesperpixel */int haveblit; /* mask of blit functions available */int flags; /* other flags *//* Extended fields: */int chiptype; /* Chiptype detected */int memory; /* videomemory in KB */int linewidth_unit; /* Use only a multiple of this as parameter for set_displaystart */char *linear_aperture; /* points to mmap secondary mem aperture of carint aperture_size; /* size of aperture in KB if size>=videomemory.void (*set_aperture_page) (int page);/* if aperture_size void *extensions; /* points to copy of eeprom for mach32 *//* depends from actual driver/chiptype.. etc. */} vga_modeinfo;Linux程式設計-18.Dialog (1)前言 (2001-05-26 17:04:00)dialog 是個shell scripts用的,事實上當您下載Linux Kernel時,裡面有個scripts/lxdialog目錄,其實那就是dialog原始碼,只是Linux kernel為了避免與原有dialog相突,將名字修改為lxdialog。當您使用"make menuconfig"時,便是在用dialog這套工具。另外,Slackware的安裝程式,事實上也是用dialog這套工具來做介面的。您可以利用shell script來呼叫dialog,也可以利用perl來呼叫它,用以提供較友善的使用者介面。利用dialog這個工具,您可以在不需要寫"艱深"的ncurses的程式的狀況下,使用Shell Script,完成很雜的操作介面,大大減少產品開發時間。Linux程式設計-19.gpm (2001-05-27 12:10:00)gpm是Linux console下的滑鼠驅動程式,它主要提供文字模式下的滑鼠事件處理。Linux下文字介面的滑鼠幾乎都是用gpm來處理。gpm的檔案在gpm原始碼的doc目錄中,詳細的說明可參考該目錄中的檔案gpm programming guide,此處只提供給您KickStart的一些技巧及一些參考說明。特別注意到以下的例,需在console下執行,不可在X Window的 Terminal下執行。--------------------------------------------------------------------------------例 : gpm_mouse.cgpm原始碼中有一個mev.c的程式,主要用來測試滑鼠狀態。事實上,mev.c是個很好的例,本例便是取自mev.c,經過簡化修改而來。#include#include#include#includevoid main(int argc,char **argv){fd_set readset;Gpm_Event event;Gpm_Connect conn;conn.eventMask = ~0;conn.defaultMask = ~GPM_HARD;conn.maxMod = 0;conn.minMod = 0;if (Gpm_Open(&conn,0)==-1) {printf("Can not open mouse connection ");exit(1);}while (1) {FD_ZERO(&readset);FD_SET(gpm_fd,&readset);select(gpm_fd+1,&readset,0,0,0);if (FD_ISSET(gpm_fd,&readset)) {if (Gpm_GetEvent(&event)>0) {printf("mouse: event 0x%02X, at %2i %2i (delta %2i %2i),""button %i, modifiers 0x%02X ",event.type,event.x,event.y,event.dx,event.dy,event.buttons,event.modifiers);}}}while (Gpm_Close());}編譯gcc -o gpm_mouse gpm_mouse.c -lgpm檢驗結果mouse: event 0x01, at 15 1 (delta -2 -1),button 0, modifiers 0x00mouse: event 0x01, at 14 1 (delta -1 0),button 0, modifiers 0x00mouse: event 0x01, at 13 1 (delta -1 0),button 0, modifiers 0x00--------------------------------------------------------------------------------資料結構typedef struct Gpm_Connect {unsigned short eventMask, defaultMask;unsigned short minMod, maxMod;int pid;int vc;} Gpm_Connect;enum Gpm_Etype {GPM_MOVE=1,GPM_DRAG=2, /* exactly one of the bare ones is active at a time */GPM_DOWN=4,GPM_UP= 8,GPM_SINGLE=16, /* at most one in three is set */GPM_DOUBLE=32,GPM_TRIPLE=64, /* WARNING: I depend on the values */GPM_MFLAG=128, /* motion during click? */GPM_HARD=256, /* if set in the defaultMask, force an already used event to pass over to another handler */GPM_ENTER=512, /* enter event, user in Roi's */GPM_LEAVE=1024 /* leave event, used in Roi's */};typedef struct Gpm_Event {unsigned char buttons, modifiers; /* try to be a multiple of 4 */unsigned short vc;short dx, dy, x, y;enum Gpm_Etype type;int clicks;enum Gpm_Margin margin;} Gpm_Event;typedef int Gpm_Handler(Gpm_Event *event, void *clientdata);函式宣告int Gpm_Open(Gpm_Connect * CONN, int FLAGS);int Gpm_Close(void);int Gpm_GetEvent(Gpm_Event * EVENT);int Gpm_Getc(FILE * fp);#define Gpm_Getchar() Gpm_Getc(stdin)int Gpm_Wgetch();#define Gpm_Getch() (Gpm_Wgetch(NULL))int Gpm_Repeat (int millisecs);int Gpm_DrawPointer (int X, int Y, int FD);int GPM_DRAWPOINTER (Gpm_Event *EPTR;)int Gpm_FitValuesM (int *X, int *Y, int MARGIN);int Gpm_FitValues (X,Y);Gpm_FitEvent (EPTR);char *Gpm_GetLibVersion (int *where);char *Gpm_GetServerVersion (int *where);int Gpm_GetSnapshot (Gpm_Event *ePtr);Linux程式設計-20.getopt (2001-05-27 13:04:00)getopt在UNIX下的命令列程式特別好用,特別是在你有許多引數要加入時。一般來說,你可以透過「man 3 getopt」來獲得其說明。--------------------------------------------------------------------------------int getopt(int argc, char * const argv[],const char *optstring);extern char *optarg;extern int optind, opterr, optopt;--------------------------------------------------------------------------------例:這個例是從manpage抄出來的,蠻不清處的。我會再找時間寫一系列例。#includeintmain (argc, argv)int argc;char **argv;{int c;int digit_optind = 0;while (1){int this_option_optind = optind ? optind : 1;int option_index = 0;static struct option long_options[] ={{"add", 1, 0, 0},{"append", 0, 0, 0},{"delete", 1, 0, 0},{"verbose", 0, 0, 0},{"create", 1, 0, 'c'},{"file", 1, 0, 0},{0, 0, 0, 0}};c = getopt_long (argc, argv, "abc:d:012",long_options, &option_index);if (c == -1)break;switch (c){case 0:printf ("option %s", long_options[option_index].name);if (optarg)printf (" with arg %s", optarg);printf (" ");break;case '0':case '1':case '2':if (digit_optind != 0 && digit_optind != this_option_optind)printf ("digits occur in two different argv-elements. ");digit_optind = this_option_optind;printf ("option %c ", c);break;case 'a':printf ("option a ");break;case 'b':printf ("option b ");break;case 'c':printf ("option c with value `%s' ", optarg);break;case 'd':printf ("option d with value `%s' ", optarg);break;case '?':break;default:printf ("?? getopt returned character code 0%o ?? ", c);}}if (optind < argc){printf ("non-option ARGV-elements: ");while (optind < argc)printf ("%s ", argv[optind++]);printf (" ");}exit (0);} (linux知識寶庫
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/8225414/viewspace-944737/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- C++程式設計思想筆記之三 (轉)C++程式設計筆記
- Linux 程式設計之Shell程式設計(轉)Linux程式設計
- Linux核心程式設計(阻塞程式)(轉)Linux程式設計
- linux驅動程式設計(轉)Linux程式設計
- Linux程式設計之一(轉)Linux程式設計
- Linux程式設計之四(轉)Linux程式設計
- Linux防火牆程式設計(轉)Linux防火牆程式設計
- Linux Unicode 程式設計(轉)LinuxUnicode程式設計
- IOS高階程式設計之三:IOS 多執行緒程式設計iOS程式設計執行緒
- Linux核心模組程式設計--阻塞程式(轉)Linux程式設計
- Java高效程式設計之三【類和介面】Java程式設計
- C#程式設計利器之三:介面(Interface)C#程式設計
- Linux核心模組程式設計指南(轉)Linux程式設計
- Linux程式設計入門-crypt(轉)Linux程式設計
- Linux的shell程式設計(一)(轉)Linux程式設計
- Linux的shell程式設計(二)(轉)Linux程式設計
- Linux的shell程式設計(三)(轉)Linux程式設計
- Linux的shell程式設計(四)(轉)Linux程式設計
- Linux下的OpenGL程式設計(轉)Linux程式設計
- Linux核心程式設計(結論)(轉)Linux程式設計
- Linux程式設計入門-gpm(轉)Linux程式設計
- Linux程式設計入門 - crypt(轉)Linux程式設計
- 玩轉Linux – shell 程式設計基礎Linux程式設計
- Linux下面程式設計工具介紹(轉)Linux程式設計
- Linux下C語言程式設計(轉)LinuxC語言程式設計
- Linux核心模組程式設計指南(一)(轉)Linux程式設計
- Linux核心模組的程式設計方法(轉)Linux程式設計
- Linux程式設計入門 - Dialog(轉)Linux程式設計
- Linux程式設計入門 - SVGALIB(轉)Linux程式設計SVG
- Linux_FAQ:程式設計問題(轉)Linux程式設計
- Linux系統共享庫程式設計(轉)Linux程式設計
- linux系統程式設計影片教程(轉)Linux程式設計
- Linux守護程式的程式設計實現(轉)Linux程式設計
- 微信小程式入門教程之三:指令碼程式設計微信小程式指令碼程式設計
- ES6 非同步程式設計之三:Generator續非同步程式設計
- 設計模式(Design Patterns)筆記之三:Bridge (轉)設計模式筆記
- Linux核心模組程式設計--中斷處理程式(轉)Linux程式設計
- Linux網路程式設計入門 (轉載)Linux程式設計