♧ 이 리스트 객체는 프로그램에 의해 실행된 명령어를 기록한다.
요구사항:
- 사용자가 한 번 입력한 자료는 수정하지 못하기 때문에,
원래의 문자열에 대한 포인터 대신 이 문자열의 사본(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"를 읽을 때마다 프로그램은 이제까지 실행한 명령어의 기록을 출력.
'예제 코드 & 코드 조각' 카테고리의 다른 글
[string.c] strcat, strcpy, strcmp, strlen (1) | 2011.10.14 |
---|---|
재시작 라이브러리 (restart library) (0) | 2011.09.03 |
showtimes - exit핸들러 등록하여 프로그램 CPU 사용률 출력 (0) | 2011.09.03 |
wordaverage - 한 줄 평균 단어 구하기 (0) | 2011.09.02 |
makeargv - 인자 배열 만들기 (0) | 2011.09.02 |