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