2007年8月31日 星期五

C Function - split

ANSI C 中缺少類似 PHP 中的 split 處理函式,在字串處理中卻又常使用,以下是簡單範例

str:欲被 split 的字串

delim:用來分隔的字串

num:設定分隔出來的子字串最大的數目,如果 <1則不限制

傳回值為一儲存分割結果的字串陣列,當陣列中的值為 NULL表示結束。

char** split(char* str, const char* delim, int num){
char** tab=NULL;
int flag;
unsigned int pos_num=0, pos_num2=0;
unsigned long int i, j, k, str_leng, delim_leng, *pos;

str_leng = strlen(str);
delim_leng = strlen(delim);

pos = (unsigned long int*)malloc(sizeof(unsigned long int)*(int)(str_leng/delim_leng+1));

i = 0;

while(i<=(str_leng - delim_leng)) {
flag = 0;
for(j=0; j<delim_leng; j++) {
if(str[i+j]!=delim[j]) { flag=-1; break; }
flag = 1;
}
if(flag == 1) {
i = i + delim_leng;
pos[pos_num++] = i - delim_leng;
if(num<1) continue;
else if(num==pos_num) break;
} else i++;
}

if(pos_num==0) {
tab = (char **)malloc(sizeof(char*)*2);
tab[0] = (char *)malloc(sizeof(char)*(str_leng+1));
strcpy(tab[0], str);
tab[1] = NULL;
return tab;
}

tab = (char **)malloc(sizeof(char*)*pos_num);

if(pos[0]!=0) {
tab[pos_num2] = (char *)malloc(sizeof(char)*pos[0]);
for(i=0, j=0; i<pos[0]; i++, j++) tab[pos_num2][j] = str[i];
tab[pos_num2][j] = '\0';
pos_num2++;
}

for(i=1; i<pos_num; i++) {
if(pos[i] - (pos[i-1] + delim_leng) >0) {
tab[pos_num2] = (char *)malloc(sizeof(char)*(pos[i] - (pos[i-1] + delim_leng)) + 1 + 1);
for(j=pos[i-1] + delim_leng, k=0; j<pos[i]; j++, k++) tab[pos_num2][k] = str[j];
tab[pos_num2][k] = '\0';
pos_num2++;
}
}

if((pos[pos_num-1] + delim_leng - 1) < str_leng - 1) {
tab[pos_num2] = (char *)malloc(sizeof(char)*(pos[pos_num-1] + delim_leng - 1) + 1 + 1);
for(j=pos[pos_num - 1] + delim_leng, i=0; j<str_leng; j++, i++) tab[pos_num2][i] = str[j];
tab[pos_num2][i] = '\0';
pos_num2++;
}

tab[pos_num2] = NULL;
return tab;
}

使用範例

char **tab;
int i;

tab = split("1,2,3,4,5,6,7,8,9,0", ",", -1);
i = 0;
while(tab[i]!=NULL) printf("%d = %s =\n", i, tab[i++]);

C Function - fgetc、fgets讀取整個檔案內容

fgetc:傳回所讀到的字元,傳回值如果是 EOF,可能是有錯誤發生或是檔案終止(end-of-file),所以應該利用 feof 或是 ferror 來判定錯誤發生或是檔案終止。

fgets: 傳回所讀到的字串,傳回值如果是 NULL,可能是有錯誤發生或是檔案終止(end-of-file),所以應該利用 feof 或是 ferror 來判定錯誤發生或是檔案終止。

使用 fgetc 讀取整個檔案 

#include "stdio.h"
main()
{
FILE *fp;
ch ch;

if((fp=fopen("test", "r"))==NULL)
{
printf("file cannot be opened\n");
exit(1);
}

while((ch=fgetc(fp))!=EOF) fputc(ch,stdout);
fclose(fp);
}

使用 fgets 讀取整個檔案
#include "stdio.h"
main()
{
FILE *fp;
char str[128];

if((fp=fopen("test", "r"))==NULL)
{
printf("cannot open file\n");
exit(1);
}

while(!feof(fp))
if(fgets(str,128,fp)!=NULL) printf("%s",str);

fclose(fp);
}

2007年8月30日 星期四

C Function - trim

不少程式語言都有提供 trim 這個字串處理函式,但標準的 C 函式庫並沒有,以下是一個簡單的範例


void trim(char *s){
int i=0, j, k, l=0;

while((s[i]==' ')||(s[i]=='\t')||(s[i]=='\n'))
i++;

j = strlen(s)-1;
while((s[j]==' ')||(s[j]=='\t')||(s[j]=='\n'))
j--;

if(i==0 && j==strlen(s)-1) { }
else if(i==0) s[j+1] = '\0';
else {
for(k=i; k<=j; k++) s[l++] = s[k];
s[l] = '\0';
}
}

2007年8月15日 星期三

無磁碟 Linux 工作站安裝筆記

無磁碟 Linux工作站具有維護容易,新增設備簡便的優點,因此有不少的 Cluster,或是電腦教室採用這個方式建置。

建置和安裝方式有很多種,以下使用 DHCP Server + TFTP Server + NFSROOT + PXELinux 方式建置。

環境說明

OS:SUSE Linux Enterprise 9.0

Master-Server及Node1有相同的硬體規格,提供網路PXE的開機功能,唯一的差異是Node1上沒有任何的硬碟。

Master-Server:提供Node1開機及所需的任何資源,已安裝 SUSE Linux 9 Enterprise 所有軟體。

Node1:透過網路開機的設備,網卡MAC為 00:0C:29:7D:A2:CD

安裝步驟

1.設定 NFS Server 及準備 Node1 所需檔案

mkdir /remote

mkdir /remote/node1

cp -rpi /bin/ /remote/node1/

cp -rpi /dev/ /remote/node1/

cp -rpi /etc/ /remote/node1/

cp -rpi /lib/ /remote/node1/

cp -rpi /sbin/ /remote/node1/

cp -rpi /var/ /remote/node1/

cp -rpi /root/ /remote/node1/

mkdir /remote/node1/proc

mkdir /remote/node1/sys

mkdir /remote/node1/tmp

chmod a+rwx /remote/node1/tmp

mkdir /remote/node1/home

mkdir /remote/node1/usr

編輯 /remote/node1/etc/fstab 檔案 內容如下

192.168.120.128:/remote/node1 / nfs

編輯/etc/exports 檔案 內容如下

/home *(rw,root_squash,sync)
/usr *(ro)
/remote/node1 *(rw,no_root_squash)

重新啟動 nfs /etc/initd./nfs restart

2.安裝設定 tftp server

mkdir /tftpboot

mkdir /tftpboot/pxelinux.cfg

cp /usr/share/syslinux/pxelinux.0 /tftpboot

vi /tftpboot/pxelinux.cfg/01-00-0c-29-7a-a2-cd 內容如下

default linux

label linux
kernel bzImage
append ip=dhcp root=nfs nfsroot=192.168.120.128:/remote/node1

設定 tftp server 相關設定檔:/etc/xinetd.d/tftp 內容如下

# default: off
# description: tftp service is provided primarily for booting or when a
# router need an upgrade. Most sites run this only on machines acting as
# "boot servers".
service tftp
{
socket_type = dgram
protocol = udp
wait = yes
user = root
server = /usr/sbin/in.tftpd
server_args = -s /tftpboot
disable = no
}

重新啟動 /etc/init.d/xinetd restart

3.建立適合 Node1 開機的核心

cd /usr/src/linux

make menuconfig --> 產生 .config 檔案 可直接編輯 .config

核心必須包含的選項

網路卡的驅動程式

# Networking options

# Kernel level IP autoconfiguration
CONFIG_IP_PNP=y
# DHCP support
CONFIG_IP_PNP_DHCP=y

# Network File Systems

# NFS file system support
CONFIG_NFS_FS=y
# Provide NFSv3 client support
CONFIG_NFS_V3=y
# Root file system on NFS
CONFIG_ROOT_NFS=y

make bzImage

cp /usr/src/linux/arch/i386/boot/bzImage /tftpboot

4.設定 DHCP Server

dhcpd相關設定檔 /etc/sysconfig/dhcpd

/etc/dhcpd.conf 內容如下

allow booting;
allow bootp;

option domain-name-servers 168.95.1.1;
option routers 192.168.120.2;
ddns-update-style none;
subnet 192.168.120.0 netmask 255.255.255.0 {
host node1 {
# option root-path "192.168.120.128:/remote/node1,v3,tcp,hard";
hardware ethernet 00:0C:29:7D:A2:CD;
fixed-address 192.168.120.20;
option broadcast-address 192.168.120.255;
filename "pxelinux.0";
}
}

重新啟動 /etc/init.d/dhcpd restart

5.將 Node1 開機設定為網路 PXE 開機,即完成

6.其他

大部份相關的安裝說明文件會提到NIS或是LDAP的安裝,作為帳號管理使用,在此文件就略過了,因為所有安裝過程中最關鍵的部份都在上面了。