2011. 9. 2. 23:52

♧ 이 리스트 객체는 프로그램에 의해 실행된 명령어를 기록한다.

 

요구사항:

- 사용자가 한 번 입력한 자료는 수정하지 못하기 때문에,

원래의 문자열에 대한 포인터 대신 이 문자열의 사본(copy)을 가리키는 포인터를 리스트로 추가.

- 리스트에서 자료를 가져올 때, 구현은 실제 데이터에 대한 포인터를 리턴하지 않고 사본의 포인터를 리턴.

사본(copy)에 대한 포인터를 리턴받은 경우, 호출자는 사본에 대한 메모리 해제.

- 탐색하는 동안, 리스트는 다음요청의 시작점을 알기 위해 현재의 위치를 기억해야만 한다.

자료 탐색 시에 사용되는 키(key) 값을 호출자에게 제공함으로써 리스트 객체는 키를 통해

- 인덱싱되는 리스트 내의원소에 대한 포인터의 배열을 유지하고 있다.

 

[ 예제 코드 : listlib.h ]

#ifndef __LISTLIB_H_
#define __LISTLIB_H_

#include <time.h>

typedef struct data_struct {
    time_t   time;
    char    *string;
} data_t;

int accessdata(void);
int adddata(data_t data);
int getdata(int key, data_t *datap);
int freekey(int key);

#endif /* __LISTLIB_H_ */

☞ adddata() : 내부 리스트 구조에 data의 사본을 가지는 노드를 추가.

☞ accessdata() : 리스트를 탐색하기 위한 키를 리턴.

☞ getdata() : 탐색되는 자료를 사용자가 제공한 data_t 형의 버퍼에 사본을 복사. (호출자가 메모리 해제)

☞ freekey() : 키 값이 더 이상 필요하지 않다면 키를 해제.

 

 

[ 예제 코드 : listlib.c ]

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "listlib.h"

#define TRAV_INIT_SIZE	8

typedef struct list_struct {
    data_t item;
    struct list_struct *next;
} list_t;

static list_t   endlist;
static list_t  *headptr  = NULL;
static list_t  *tailptr  = NULL;
static list_t **travptrs = NULL;
static int travptrs_size = 0;

/* return a nonnegative key if successful */
int accessdata(void) {
    int i;
    list_t **newptrs;

    /* can't access a completely emptry list */
    if (headptr == NULL) {
	errno = EINVAL;
	return -1;	
    }

    if (travptrs_size == 0) { /* first traversal */
	travptrs = (list_t **) calloc(TRAV_INIT_SIZE, sizeof(list_t *));
	if (travptrs == NULL) /* douldn't allocate space or traversal keys */
	    return -1;
	travptrs[0]   = headptr;
	travptrs_size = TRAV_INIT_SIZE;
	return 0;
    }
    
    /* look for an emptr slot for key */
    for (i=0; i<travptrs_size; i++) {
	if (travptrs[i] == NULL) {
	    travptrs[i] = headptr;
	    return i;
	}
    }    

    newptrs = realloc(travptrs, 2 * travptrs_size * sizeof(list_t *));
    if (newptrs == NULL)    /* couldn't expand the array of traversal keys */
	return -1;
    travptrs = newptrs;
    travptrs[travptrs_size] = headptr;
    travptrs_size *= 2;
    return travptrs_size/2;
}

/* allocate node for data and add to end of list */
int adddata(data_t data) {
    list_t *newnode;
    int	    nodesize;

    nodesize = sizeof(list_t) + strlen(data.string) + 1;
    /* couldn't add node */
    if ((newnode = (list_t *) (malloc(nodesize))) == NULL)
	return -1;
    newnode->item.time   = data.time;
    newnode->item.string = (char *)newnode + sizeof(list_t);
    strcpy(newnode->item.string, data.string);
    newnode->next = NULL;

    if (headptr == NULL)
	headptr = newnode;
    else
	tailptr->next = newnode;
    tailptr = newnode;

    return 0;
}

/* copy next item and set datap->string */
int getdata(int key, data_t *datap) {
    list_t *t;

    if( (key < 0) || (key >= travptrs_size) || (travptrs[key] == NULL)) {
	errno = EINVAL;
	return -1;
    }
    
    /* end of list, set datap->string to NULL */
    if (travptrs[key] == &endlist) {
	datap->string = NULL;
	travptrs[key] = NULL;
	return 0;   /* reaching end of list natural condition, not an error */
    }

    t = travptrs[key];
    datap->string = (char *)malloc(strlen(t->item.string) + 1);
    /* couldn't allocate space for returning string */
    if (datap->string == NULL)
	return -1;
    datap->time = t->item.time;
    strcpy(datap->string, t->item.string);

    if (t->next == NULL)
	travptrs[key] = &endlist;
    else
	travptrs[key] = t->next;

    return 0;
}

/* free list entry corresponding to key */
int freekey(int key) {
    /* key out of range */
    if ( (key < 0) || (key >= travptrs_size) ) {
	errno = EINVAL;
	return -1;
    }
    travptrs[key] = NULL;
    return 0;
}

 

 

[ 예제 코드 : keeplog.c ]

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#ifndef MAX_CANON
#define MAX_CANON   8192
#endif

extern int  runproc(char *cmd);
extern void showhistory(FILE *f);

int main(int argc, char *argv[]) {
    char cmd[MAX_CANON];
    int	 history = 1;

    if (argc == 1) {
	history = 0;
    } else if ((argc > 2) || strcmp(argv[1], "history")) {
	fprintf(stderr, "Usage: %s [history]\n", argv[0]);
	return 1;
    }

    while(fgets(cmd, MAX_CANON, stdin) != NULL) {
	if( cmd[strlen(cmd) - 1] == '\n')
	    cmd[strlen(cmd) - 1] = 0;

	if( history && !strcmp(cmd, "history")) {
	    showhistory(stdout);
	} else if (runproc(cmd)) {
	    perror("Failed to execute command");
	    break;
	}
    }
    printf("\n\n>>>>>>The list of commands executed is:\n");
    showhistory(stdout);

    return 0;
}

 

 

[ 예제 코드 : keeploglib.c ]

#include <stdio.h>
#include <stdlib.h>
#include "listlib.h"

/* execute cmd; store cmd and time in history list */
int runproc(char *cmd) {
    data_t execute;

    if (time(&(execute.time)) == (time_t)-1)
	return -1;
    execute.string = cmd;
    /* command could not be executed at all */
    if (system(cmd) == -1)
	return -1;    
    return adddata(execute);
}

/* output the history list of the file f */
void showhistory(FILE *f) {
    data_t  data;
    int	    key;

    key = accessdata();
    if (key == -1) {
	fprintf(f, "No history\n");
	return;
    }

    while (!getdata(key, &data) && (data.string != NULL)) {
	fprintf(f, "Command: %s\nTime: %s\n", data.string, ctime(&(data.time)));
	free(data.string);
    }
}

☞ runproc() : 성공적으로 명령어를 실행하면, adddata()를 호출하여 기록 리스트에 추가.

☞ showhistory() : accessdata() 호출하여 key값을 받아 getdata() 로 데이터 사본을 받아 히스토리 출력.

 

▶ 사용 예:

$ ./keeplog history

ls

Makefile argtest.c keeplog.c listlib.c makeargv.c wordaverage.c

argtest keeplog keeploglib.c listlib.h wordaverage wordaveragetest.c

date

2011. 09. 02. (금) 23:54:27 KST

history

Command: ls

Time: Fri Sep 2 23:54:27 2011

 

Command: date

Time: Fri Sep 2 23:54:27 2011

 

 

>>>>>>The list of commands executed is:

Command: ls

Time: Fri Sep 2 23:54:27 2011

 

Command: date

Time: Fri Sep 2 23:54:27 2011

☞ 프로그램은 "history"라는 커맨드라인 인자를 선택적으로 입력 받는다.

☞ "history"인자가 선택되고 표준 입력에서 "history"를 읽을 때마다 프로그램은 이제까지 실행한 명령어의 기록을 출력.

Posted by devanix
2011. 9. 2. 20:38

♧ strtok_r 함수를 이용해서 한 줄의 평균 단어 수를 구한다.

원형

double wordaverage(char *s);

인수

const char *s : 문자열 버퍼를 가리키는 포인터.

반환

double - 평균 단어 수.

 

strtok함수는 하나의 지역 변수만을 사용하기 때문에 여러 번에 걸쳐 호출하게 된다면

 문자열의 파싱은 서로 방해 받고 말 것이다.

☞ 그래서 멀티스레드 프로그램에서의 안전성을 위하여 strtok대신 strtok_r 함수를 사용.

strtok_r 에서 "_r" 표시는 재진입(reentrant)를 뜻하며,

 함수가 그 전의 호출이 끝나기 전에 재진입(재호출)될 수 있다는 것을 의미.

 

 

[ 예제 코드 : wordaveragetest.c ]

#include <stdio.h>
#include <unistd.h>

#define BUFSIZE	1024

extern double wordaverage(char *s);

int main() {
    char    buf[BUFSIZE];
    int	    size = 0;
    int	    num;
    double  ave;

    while (size < BUFSIZE-1) {
	num = read(0, buf+size, BUFSIZE-size-1);
	if (num == 0) break;
	if (num < 0) {
	    fprintf(stderr, "Error reading from standard input!\n");
	    return 1;
	}
	fprintf(stderr, "%d bytes read\n", num);
	size += num;
    }
    buf[size] = 0;
    fprintf(stderr, "Total number of bytes read = %d\n", size);
    ave = wordaverage(buf);
    fprintf(stderr, "The average number of word is %f\n", ave);

    return 0;
}

 

[ 예제 코드 : wordaverage.c ]

#include <string.h>
#define LINE_DELIMITERS	"\n"
#define WORD_DELIMITERS	" "

static int wordcount(char *s) {
    int   count = 1;
    char *lasts;

    if (strtok_r(s, WORD_DELIMITERS, &lasts) == NULL)
	return 0;
    while (strtok_r(NULL, WORD_DELIMITERS, &lasts) != NULL)
	count++;

    return count;
}

/* return average size of words in s */
double wordaverage(char *s) {
    char *lasts;
    char *nextline;
    int	  words;
    int   linecount = 1;

    nextline = strtok_r(s, LINE_DELIMITERS, &lasts);
    if (nextline == NULL)
	return 0.0;
    words = wordcount(nextline);
    while ((nextline = strtok_r(NULL, LINE_DELIMITERS, &lasts)) != NULL) {
	words += wordcount(nextline);
	linecount++;
    }
    return (double)words/linecount;
}

 

▶ 사용 예:

$ ./wordaverage

word1 word2 word3

18 bytes read

word4 word5

12 bytes read

word6 word7 word8 word9 word10

31 bytes read

Total number of bytes read = 61

The average number of word is 3.333333

 

Posted by devanix
2011. 9. 2. 19:02

▣ 설명 : 하나의 커맨드라인 인자를 가지고 makeargv() 호출하여 인자 배열을 만든다.

원형

int makeargv(const char *s, const char *delimiters, char ***argvp);

인수

const char *s : 문자열

const char *delimiters : 구분자

char ***argvp : 인자 배열을 가리키는 포인터.

반환

성공 : 토큰 수

실패 : -1리턴, errno 설정.

makeargv 함수는 delimiter를 구분자로 가지고, 문자열 s로부터 argvp가 가리키는 곳에 인자 배열을 만든다.

 

[ 예제코드 : argtest.c ]

#include <stdio.h>
#include <stdlib.h>

extern int makeargv(const char *s, const char *delimiters, char ***argvp);
extern void freemakeargv(char **argv);

int main(int argc, char *argv[]) {
    char delim[] = " \t";
    int i;
    char **myargv;
    int numtokens;

    if (argc != 2) {
	fprintf(stderr, "Usage: %s string\n", argv[0]);
	return 1;
    }

    if ((numtokens = makeargv(argv[1], delim, &myargv)) == -1) {
	fprintf(stderr, "Failed to construct an argument array for %s\n",
	    argv[1]);
	return 1;
    }
    fputs("The argument array contains:\n", stdout);
    for (i=0; i<numtokens; i++)
	printf("%d: %s\n", i, myargv[i]);

    freemakeargv(myargv);
    return 0;
}

 

[ 예제코드 : makeargv.c ]

#include <errno.h>
#include <stdlib.h>
#include <string.h>

int makeargv(const char *s, const char *delimiters, char ***argvp) {
    int error;
    int i;
    int numtokens;
    const char *snew;
    char *t;

    if ((s == NULL) || (delimiters == NULL) || (argvp == NULL)) {
	errno = EINVAL;
	return -1;
    }
    *argvp = NULL;

    /* snew is real start of string */
    snew = s + strspn(s, delimiters);	
    if ((t = malloc(strlen(snew) + 1)) == NULL)
	return -1;
    strcpy(t, snew);

    numtokens=0;
    /* count the number of tokens in s */
    if (strtok(t, delimiters) != NULL)
	for (numtokens=1; strtok(NULL, delimiters) != NULL; numtokens++) ;

    /* create argument array for ptrs to the tokens */
    if ((*argvp = malloc((numtokens + 1) * sizeof(char *))) == NULL) {
	error = errno;
	free(t);
	errno = error;
	return -1;
    }

    /* insert pointers to tokens into the argument array */
    if (numtokens == 0) {
	free(t);
    } else {
	strcpy(t, snew);
	**argvp = strtok(t, delimiters);
	for(i=1; i<numtokens; i++)
	    *((*argvp)+i) = strtok(NULL, delimiters);
    }
    /* put in final NULL pointer */
    *((*argvp)+numtokens) = NULL;    
    return numtokens;
}

void freemakeargv(char **argv) {
    if (argv == NULL)
	return;
    if (*argv != NULL)
	free(*argv);
    free(argv);
    argv=NULL;
}

 

▣ 사용 예: 하나의 커맨드라인 인자("큰따옴표"로 묶는다)를 받아 인자 배열로 만듬.

$ ./argtest

Usage: ./argtest string

 

$ ./argtest "mine -c 10 2.0"

The argument array contains:

0: mine

1: -c

2: 10

3: 2.0

 

전반적인 구현 순서 :

1. 문자열 분석을 위한 버퍼 tmalloc로 할당한다.

버퍼 t는 문자열 s와 종료문자 '\0'을 담을 수 있을 만큼 충분한 크기를 가져야 한다.

2. st에 복사 (문자열 : "mine -c 10 2.0")

3. 문자열 t를 매개변수로 strtok 함수를 호출하여 토큰의 수를 계산.

4. 토큰의 수(numtokens)를 이용하여 argv 배열의 크기를 할당.

5. st에 다시 복사.

6. strtok를 사용하여 각각의 토큰에 대한 포인터를 만들고, t를 분석하기 좋은 형태로 수정.

 

Posted by devanix
2011. 9. 2. 17:07

 

[ 책소개 ]

이 책은 이전 판(기존 제목은 "Practical UNIX Programming")을 완전히 새롭게 구성하였으며,

복잡한 소프트웨어를 설계하는 방법을 설명함으로써 UNIX 운영체제의 대부분을 이해할 수 있게 도와 준다.

UNIX Systems Programming은 UNIX 프로그래밍의 필수적인 지식들을 명확하고도 이해하기 쉽게 설명하고 있다.

두 명의 저자들은 독자들의 실력을 넓혀 주기 위해, 독자들이 시스템 콜을 사용하는 방법을 설명하는 짤막한

코드에서부터 시작하여 곧바로 직접 참여할 수 있는 프로젝트를 접해볼 수 있도록 책을 구성하였다.

 

수많은 연습문제와 예제, 프로젝트를 통해 UNIX의 이론을 체험하자!!!

220여 개의 예제, 400여 개의 연습문제, 7개의 대형 프로젝트 수록

 

이 책을 통해 여러분은 Linux, Solaris, MacOS X 등의 POSIX 기반 시스템에서 신뢰성 있는 UNIX 소프트웨어를

설계하고 구현하는 방법을 배울 수 있다.

 

[ 목차 ]

PART 1 기초

Chapter 1 프로그램에 끼친 기술의 영향

Chapter 2 프로그램, 프로세스, 쓰레드

Chapter 3 UNIX의 프로세스

Chapter 4 UNIX I/O

Chapter 5 파일과 디렉토리

Chapter 6 UNIX 특수 파일

Chapter 7 프로젝트 : 토큰 링(Token Ring)

 

PART 2 비동기 이벤트

Chapter 8 시그널

Chapter 9 시간과 타이머

Chapter 10 프로젝트 : 가상 타이머

Chapter 11 프로젝트 : 쉘 만들기

 

PART 3 병행성

Chapter 12 POSIX 쓰레드

Chapter 13 쓰레드 동기화

Chapter 14 크리티컬 섹션과 세마포어

Chapter 15 POSIX IPC

Chapter 16 프로젝트 : 생산자 소비자 동기화

Chapter 17 프로젝트 : NTPVM(Not Too Parallel Virtual Machine)

 

PART 4 통신

Chapter 18 연결 지향 통신

Chapter 19 프로젝트 : WWW 재지향

Chapter 20 비연결형 통신과 멀티캐스트

Chapter 21 프로젝트 : 인터넷 라디오

Chapter 22 프로젝트 : 서버의 성능

 

PART 5 부록

Appendix A UNIX 기초

Appendix B 재시작 라이브러리

Appendix C UICI의 구현

Appendix D 로깅 함수

 

예제 소스 : 


참조사이트 : 
http://usp.cs.utsa.edu/usp/

'컴퓨터 문서 모음 > 시스템 프로그래밍' 카테고리의 다른 글

Advanced Linux Programming  (1) 2011.08.12
Posted by devanix