2011. 10. 14. 09:05

/**
 * strcpy - Copy a %NUL-terminated string
 * @dest:   Where to copy the string to
 * @src:    Where to copy the string from
 */
char *strcpy ( char *dest, const char *src ) {
    char *tmp = dest;

    while ( ( *dest++ = *src ) != '\0' )
        /* nothing */;
    return tmp;
}

/**
 * strncpy - Copy a length-limited, %NUL-terminated string
 * @dest:   Where to copy the string to
 * @src:    Where to copy the string from
 * @count:  The maximum number of bytes to copy
 *
 * The result is not %NUL-terminated if the source exceeds
 * @count bytes.
 *
 * In the case where the length of @src is less than that of
 * count, the remainder of @dest will be padded with %NUL.
 */
char *strncpy ( char *dest, const char *src, size_t count ) {
    char *tmp = dest;

    while ( count ) {
        if ( ( *dest = *src ) != 0 )
            src++;
        dest++;
        count--;
    }
    return tmp;
}

/**
 * strcat - Append one %NUL-terminated string to another
 * @dest:   The string to be appended to
 * $src:    The string to append to it
 */
char *strcat ( char *dest, const char *src ) {
    char *tmp = dest;

    while ( *dest )
        dest++;
    while ( ( *dest++ = *src++ ) != '\0' )
        /* nothing */;
    return tmp;
}

/**
 * strcat - Append a length-limited, %NUL-terminated string to another
 * @dest:   The string to be appended to
 * @src:    The string to append to it
 * @count:  The maximum numbers of bytes to copy
 *
 * Note that in contrast to strncpy(), strncat() ensures the result is
 * terminated.
 */
char *strncat ( char *dest, const char *src, size_t count ) {
    char *tmp = dest;

    if ( count ) {
        while ( *dest )
            dest++;
        while ( ( *dest++ = *src++ ) != '\0' ) {
            if ( --count == 0 ) {
                *dest = '\0';
                break;
            }
        }
    }
    return tmp;
}

/**
 * strcmp - Compare two strings
 * @cs:	One string
 * @ct:	Another string
 */
int strcmp ( const char *cs, const char *ct ) {
    unsigned char c1, c2;

    do {
        c1 = *cs++;
        c2 = *ct++;
        if ( c1 != c2 )
            return c1 < c2 ? -1 : 1;
    } while ( c1 );
    return 0;
}

/**
 * strncmp - Compare two length-limited strings
 * @cs:	One string
 * @ct:	Another string
 * @count: The maximum number of bytes to Compare
 */
int strncmp ( const char *cs, const char *ct, size_t count ) {
    unsigned int c1, c2;
    while ( count-- ) {
        c1 = *cs++;
        c2 = *ct++;
        if ( c1 != c2 )
            return c1 < c2 ? -1 : 1;
        if ( !c1 )
            break;
    }
    return 0;
}

/**
 * strlen - Find the length of a string
 * @s:	The string to be sized
 */
size_t strlen ( const char *s ) {
    const char *sc;

    for ( sc = s; *sc != '\0'; ++sc )
        /* nothing */;
    return  sc - s;
}
Posted by devanix
2011. 9. 3. 22:35

재시작 라이브러리(restart library)는 순간적인 사건으로 요청한 작업을 완료하지 못했을 경우

스스로 재시작할 수 있는 함수들의 집합이다.

 

재시작 라이브러리는 시그널에 의한 중단과 불완전한 I/O 두 부분에 중점을 두고 있다.

예를 들어 read, write와 같은 라이브러리 함수들은 I/O 명령을 완전히 실행하기 전에

시그널에 의해 중단될 때 -1을 리턴하고, errno를 EINTR로 설정한다.

 

이러한 중단은 실제로 에러 상황이 아닌 프로그램이 블로킹 I/O를 사용할 때 시그널의 처리를 위한 자연스러운

사건이다. 함수가 -1을 리턴하고, errno가 EINTR로 설정된 경우 재시작 함수는 재시작 과정을 수행한다.

 

[ restart.c ]

/data/workspace/b-example/usp/appendixB/restart.c.html
#include <errno.h>
#include <fcntl.h>
#include <limits.h>
#include <string.h>
#include <sys/select.h>
#include <sys/time.h>
#include <sys/wait.h>
#include "restart.h"
#define BLKSIZE PIPE_BUF
#define MILLION 1000000L
#define D_MILLION 1000000.0

/* Private functions */

static int gettimeout(struct timeval end,
                               struct timeval *timeoutp) {
   gettimeofday(timeoutp, NULL);
   timeoutp->tv_sec = end.tv_sec - timeoutp->tv_sec;
   timeoutp->tv_usec = end.tv_usec - timeoutp->tv_usec;
   if (timeoutp->tv_usec >= MILLION) {
      timeoutp->tv_sec++;
      timeoutp->tv_usec -= MILLION;
   }
   if (timeoutp->tv_usec < 0) {
      timeoutp->tv_sec--;
      timeoutp->tv_usec += MILLION;
   }
   if ((timeoutp->tv_sec < 0) ||
       ((timeoutp->tv_sec == 0) && (timeoutp->tv_usec == 0))) {
      errno = ETIME;
      return -1;
   }
   return 0;
}

/* Restart versions of traditional functions */

int r_close(int fildes) {
   int retval;
   while (retval = close(fildes), retval == -1 && errno == EINTR) ;
   return retval;
}

int r_dup2(int fildes, int fildes2) {
   int retval;
   while (retval = dup2(fildes, fildes2), retval == -1 && errno == EINTR) ;
   return retval;
}


int r_open2(const char *path, int oflag) {
   int retval;
   while (retval = open(path, oflag), retval == -1 && errno == EINTR) ;
   return retval;
}

int r_open3(const char *path, int oflag, mode_t mode) {
   int retval;
   while (retval = open(path, oflag, mode), retval == -1 && errno == EINTR) ;
   return retval;
}

ssize_t r_read(int fd, void *buf, size_t size) {
   ssize_t retval;
   while (retval = read(fd, buf, size), retval == -1 && errno == EINTR) ;
   return retval;
}

pid_t r_wait(int *stat_loc) {
   pid_t retval;
   while (((retval = wait(stat_loc)) == -1) && (errno == EINTR)) ;
   return retval;
}

pid_t r_waitpid(pid_t pid, int *stat_loc, int options) {
   pid_t retval;
   while (((retval = waitpid(pid, stat_loc, options)) == -1) &&
           (errno == EINTR)) ;
   return retval;
}

ssize_t r_write(int fd, void *buf, size_t size) {
   char *bufp;
   size_t bytestowrite;
   ssize_t byteswritten;
   size_t totalbytes;

   for (bufp = buf, bytestowrite = size, totalbytes = 0;
        bytestowrite > 0;
        bufp += byteswritten, bytestowrite -= byteswritten) {
      byteswritten = write(fd, bufp, bytestowrite);
      if ((byteswritten == -1) && (errno != EINTR))
         return -1;
      if (byteswritten == -1)
         byteswritten = 0;
      totalbytes += byteswritten;
   }
   return totalbytes;
}

/* Utility functions */

struct timeval add2currenttime(double seconds) {
   struct timeval newtime;

   gettimeofday(&newtime, NULL);
   newtime.tv_sec += (int)seconds;
   newtime.tv_usec += (int)((seconds - (int)seconds)*D_MILLION + 0.5);
   if (newtime.tv_usec >= MILLION) {
      newtime.tv_sec++;
      newtime.tv_usec -= MILLION;
   }
   return newtime;
}

int copyfile(int fromfd, int tofd) {
   int bytesread;
   int totalbytes = 0;

   while ((bytesread = readwrite(fromfd, tofd)) > 0)
      totalbytes += bytesread;
   return totalbytes;
}

ssize_t readblock(int fd, void *buf, size_t size) {
   char *bufp;
   ssize_t bytesread;
   size_t bytestoread;
   size_t totalbytes;

   for (bufp = buf, bytestoread = size, totalbytes = 0;
        bytestoread > 0;
        bufp += bytesread, bytestoread -= bytesread) {
      bytesread = read(fd, bufp, bytestoread);
      if ((bytesread == 0) && (totalbytes == 0))
         return 0;
      if (bytesread == 0) {
         errno = EINVAL;
         return -1;
      }
      if ((bytesread) == -1 && (errno != EINTR))
         return -1;
      if (bytesread == -1)
         bytesread = 0;
      totalbytes += bytesread;
   }
   return totalbytes;
}

int readline(int fd, char *buf, int nbytes) {
   int numread = 0;
   int returnval;

   while (numread < nbytes - 1) {
      returnval = read(fd, buf + numread, 1);
      if ((returnval == -1) && (errno == EINTR))
         continue;
      if ((returnval == 0) && (numread == 0))
         return 0;
      if (returnval == 0)
         break;
      if (returnval == -1)
         return -1;
      numread++;
      if (buf[numread-1] == '\n') {
         buf[numread] = '\0';
         return numread;
      }
   }
   errno = EINVAL;
   return -1;
}

ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds) {
   struct timeval timedone;

   timedone = add2currenttime(seconds);
   if (waitfdtimed(fd, timedone) == -1)
      return (ssize_t)(-1);
   return r_read(fd, buf, nbyte);
}

int readwrite(int fromfd, int tofd) {
   char buf[BLKSIZE];
   int bytesread;

   if ((bytesread = r_read(fromfd, buf, BLKSIZE)) < 0)
      return -1;
   if (bytesread == 0)
      return 0;
   if (r_write(tofd, buf, bytesread) < 0)
      return -1;
   return bytesread;
}

int readwriteblock(int fromfd, int tofd, char *buf, int size) {
   int bytesread;

   bytesread = readblock(fromfd, buf, size);
   if (bytesread != size)         /* can only be 0 or -1 */
      return bytesread;
   return r_write(tofd, buf, size);
}

int waitfdtimed(int fd, struct timeval end) {
   fd_set readset;
   int retval;
   struct timeval timeout;

   if ((fd < 0) || (fd >= FD_SETSIZE)) {
      errno = EINVAL;
      return -1;
   }
   FD_ZERO(&readset);
   FD_SET(fd, &readset);
   if (gettimeout(end, &timeout) == -1)
      return -1;
   while (((retval = select(fd+1, &readset, NULL, NULL, &timeout)) == -1)
           && (errno == EINTR)) {
      if (gettimeout(end, &timeout) == -1)
         return -1;
      FD_ZERO(&readset);
      FD_SET(fd, &readset);
   }
   if (retval == 0) {
      errno = ETIME;
      return -1;
   }
   if (retval == -1)
      return -1;
   return 0;
}

 

[ restart.h ]

/data/workspace/b-example/usp/appendixB/restart.h.html
#ifndef __RESTART_H_
#define __RESTART_H_

#include <fcntl.h>
#include <unistd.h>
#include <sys/time.h>
#include <sys/types.h>

#ifndef ETIME
#define ETIME ETIMEDOUT
#endif

struct timeval add2currenttime(double seconds);
int copyfile(int fromfd, int tofd);
int r_close(int fildes);
int r_dup2(int fildes, int fildes2);
int r_open2(const char *path, int oflag);
int r_open3(const char *path, int oflag, mode_t mode);
ssize_t r_read(int fd, void *buf, size_t size);
pid_t r_wait(int *stat_loc);
pid_t r_waitpid(pid_t pid, int *stat_loc, int options);
ssize_t r_write(int fd, void *buf, size_t size);
ssize_t readblock(int fd, void *buf, size_t size);
int readline(int fd, char *buf, int nbytes);
ssize_t readtimed(int fd, void *buf, size_t nbyte, double seconds);
int readwrite(int fromfd, int tofd);
int readwriteblock(int fromfd, int tofd, char *buf, int size);
int waitfdtimed(int fd, struct timeval end);

#endif /* __RESTART_H_ */

 

Posted by devanix
2011. 9. 3. 02:32

Catexit 함수는 사용자가 정의한 종료 핸들러를 등록한다.

종료 핸들러는 프로그램이 main 함수로부터 리턴 하거나 exit 함수를 호출하였을 때

마지막에 등록된 핸들러가 먼저 실행되는 순서로 실행. (여러 번 호출하여 핸들러 등록 가능)

 

 

showtimes 예제는 showtimes 함수를 exit 핸들러로 등록하여

프로그램과 그 자식들이 사용한 시간에 대한 통계를 표준 에러로 출력한다.

 

[ 예제 코드 : showtimes.c ]

#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <sys/times.h>
#include <sys/wait.h>

int wastetime(int maxus);

static void showtimes(void) {
   double ticks;
   struct tms tinfo;

   if ((ticks = (double) sysconf(_SC_CLK_TCK)) == -1)
      perror("Failed to determine clock ticks per second");
   else if (times(&tinfo) == (clock_t)-1)
      perror("Failed to get times information");
   else {
      fprintf(stderr, "User time:              %8.3f seconds\n",
         tinfo.tms_utime/ticks);
      fprintf(stderr, "System time:            %8.3f seconds\n",
         tinfo.tms_stime/ticks);
      fprintf(stderr, "Children's user time:   %8.3f seconds\n",
         tinfo.tms_cutime/ticks);
      fprintf(stderr, "Children's system time: %8.3f seconds\n",
         tinfo.tms_cstime/ticks);
   }
}
 
int main(void) {
   if (atexit(showtimes))  {
      fprintf(stderr, "Failed to install showtimes exit handler\n");
      return 1; 
   }
   if (fork())
      wastetime(2900000);
   else
      wastetime(5400000);
   if (wait(NULL) > 0)
      fprintf(stderr, "\nChild has exited, parent stats follow:\n");
   return 0;
}

times 함수는 시간 틱(tick) 수의 시간 정보를 나타낸다.

 

 

[ 예제 코드 : wastetime.c ]

#include <stdio.h>
#include <sys/time.h>
#define MILLION 1000000L

/* waste maxus microseconds of time */
int wastetime(int maxus) {
   long timedif;
   struct timeval tp1, tp2;

   if (gettimeofday(&tp1, NULL)) {
      fprintf(stderr, "Failed to get initial time\n");
      return 1;
   }
   timedif = 0;
   while (timedif < maxus) {
      if (gettimeofday(&tp2, NULL)) {
         fprintf(stderr, "Failed to get check time\n");
         return 1;
      }
      timedif = MILLION*(tp2.tv_sec - tp1.tv_sec) +
                   tp2.tv_usec - tp1.tv_usec;
      if (timedif < 0)
         break;
   }
   return 0;
}

 

▶ 사용 예:

$ ./showtimes

User time:                         1.270 seconds

System time:                    2.660 seconds

Children's user time:      0.000 seconds

Children's system time: 0.000 seconds

 

Child has exited, parent stats follow:

User time:                        0.460 seconds

System time:                    0.970 seconds

Children's user time:      1.270 seconds

Children's system time: 2.660 seconds

 

Posted by devanix
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