= Skeleton Filter Program in C = ÀÌ ±ÛÀº C ¾ð¾î¸¦ ½á¼­ DevelFilterSkeleon¿¡¼­ ´Ù·é ÇÊÅÍ ÇÁ·Î±×·¥ÀÇ »©´ë¸¦ ¸¸µå´Â ¹æ¹ýÀ» ¼Ò°³ÇÕ´Ï´Ù. [[TableOfContents]] == Output Messages == ÇÊÅÍ ÇÁ·Î±×·¥Àº ¾î¶² »óȲÀÌ ¹ß»ýÇßÀ» ¶§, »ç¿ëÀÚ¿¡°Ô º¸°íÇϰųª, ¿¡·¯¸¦ Ãâ·ÂÇÒ ¶§°¡ Á¾Á¾ ¹ß»ýÇϱ⠶§¹®¿¡, °æ°í ¶Ç´Â ¿¡·¯ ¸Þ½ÃÁö¸¦ ³» º¸³»´Â °æ¿ì°¡ ÀÖ½À´Ï´Ù. ÇÊÅÍ ÇÁ·Î±×·¥Àº ±âº»ÀûÀ¸·Î ó¸®ÇÑ µ¥ÀÌÅ͸¦ Ç¥ÁØ Ãâ·ÂÀ» ÅëÇØ ³» º¸³»¹Ç·Î, ÀÌ·± ¸Þ½ÃÁöµéÀ» Ç¥ÁØ ÀÔ·ÂÀ¸·Î º¸³½´Ù¸é, µ¥ÀÌÅÍ¿Í ¼¯ÀÏ °æ¿ì°¡ Àֱ⠶§¹®¿¡ ´ëºÎºÐ Ç¥ÁØ Ãâ·ÂÀ» ½á¼­ ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÕ´Ï´Ù. ´ë°³ ÇÊÅÍ ÇÁ·Î±×·¥ÀÌ µû·Î Ãâ·ÂÇÏ´Â ¸Þ½ÃÁö´Â ÁÖ·Î °æ°í¼ºÀ̳ª, ¿¡·¯°¡ ¹ß»ýÇÑ °æ¿ì°¡ ´ëºÎºÐÀÔ´Ï´Ù. ¸¸¾à ½Ã½ºÅÛ ÇÔ¼ö¸¦ È£ÃâÇؼ­ ¿¡·¯°¡ ¹ß»ýÇÑ °æ¿ì¿¡´Â Àü¿ª º¯¼ö errno¿¡ ¿¡·¯ ¿øÀÎÀÌ ÀúÀåµÇ°Ô µÇ´Âµ¥ (¸ðµç ½Ã½ºÅÛ ÇÔ¼öµéÀÌ errno¸¦ ¾²´Â °ÍÀº ¾Æ´Õ´Ï´Ù.), ÀÌ °æ¿ì strerror(3)¸¦ ½á¼­, ¿øÇÏ´Â ¿¡·¯ ¸Þ½ÃÁö¸¦ ¾òÀ» ¼ö ÀÖ½À´Ï´Ù. ¿¡·¯¸¦ ½±°Ô ó¸®Çϱâ À§ÇØ ¿ì¸®´Â GNU È®Àå ÇÔ¼öÀÎ error(3)¸¦ ¾µ °ÍÀÔ´Ï´Ù. {{{#!vim c #include void error(int STATUS, int ERRNUM, const char *FORMAT, ...); }}} »ç¿ë¹ýÀº °£´ÜÇÕ´Ï´Ù. ¸ÕÀú, FORMAT°ú ±× ´ÙÀ½¿¡ µé¾î¿À´Â printf(3) ½ºÅ¸ÀÏ ÀÎÀÚ¸¦ ó¸®Çؼ­ Ç¥ÁØ ¿¡·¯·Î Ãâ·ÂÇÕ´Ï´Ù. ±×¸®°í ERRNUMÀÌ 0ÀÌ ¾Æ´Ñ °æ¿ì, error(3)´Â strerror(ERRNUM)À» ºÒ·¯¼­ ¸Þ½ÃÁö¸¦ Ç¥ÁØ ¿¡·¯·Î Ãâ·ÂÇÕ´Ï´Ù. ±× ´ÙÀ½, STATUS°¡ 0ÀÌ ¾Æ´Ñ °æ¿ì exit(STATUS)¸¦ È£ÃâÇØ ÁÝ´Ï´Ù. ¿¹¸¦ µé¾î Á¦ÀÛÇÒ ÇÊÅÍ ÇÁ·Î±×·¥ÀÌ ÁöÁ¤ÇÑ ¼³Á¤ ÆÄÀÏ¿¡¼­ ¿øÇÏ´Â ¼³Á¤À» ÀоîµéÀÎ´Ù°í °¡Á¤ÇØ º¾½Ã´Ù. ÀÌ ¼³Á¤ ÆÄÀÏ À̸§Àº INIT_FILEÀ̶õ ¸ÅÅ©·Î¿¡ ÀúÀåÀÌ µÇ¾î ÀÖ°í, À̸¦ fopen(3)À¸·Î ¿­ ¶§, ¿¡·¯°¡ ¹ß»ýÇß´Ù°í °¡Á¤ÇսôÙ. ¶Ç, ÀÌ ÇÊÅÍ ÇÁ·Î±×·¥Àº ÁöÁ¤ÇÑ ¼³Á¤ ÆÄÀÏÀÌ Á¸ÀçÇÏÁö ¾Ê´Â °æ¿ì, °æ°í ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÏ°í, ±âº» °ªÀ» ½á¼­ µ¿ÀÛÇÑ´Ù°í °¡Á¤ÇսôÙ. ÀÌ °æ¿ì ¿ì¸®´Â ´ÙÀ½°ú °°Àº Äڵ带 ¸¸µé¾î¾ß ÇÕ´Ï´Ù: {{{#!vim c FILE *fp; fp = fopen(INIT_FILE, "r"); if (!fp) { error(0, errno, "cannot open %s", INIT_FILE); } }}} ±×·¯¸é ³ªÁß¿¡ ÀÌ ÇÁ·Î±×·¥À» ½ÇÇàÇÒ ¶§ (ÇÁ·Î±×·¥ À̸§Àº "foo"¶ó°í °¡Á¤ÇսôÙ), INIT_FILEÀÌ ¾ø´Â °æ¿ì, ´ÙÀ½°ú °°ÀÌ °æ°í ¸Þ½ÃÁö°¡ Ãâ·ÂµÇ´Â °ÍÀ» ¾Ë ¼ö ÀÖ½À´Ï´Ù: {{{#!vim sh $ foo foo: cannot open /etc/foorc: No such file or directory $ _ }}} == Option Processing == °¡Àå ¸ÕÀú ó¸®ÇØ¾ß ÇÒ °ÍÀº command-line argument¸¦ ¹Þ¾Æ¼­ ó¸®ÇÏ´Â °ÍÀÔ´Ï´Ù. ÀÌ´Â main() ÇÔ¼ö¸¦, µÎ °³ÀÇ ÆĶó¸ÞÅ͸¦ ¹Þ¾Æ¼­ ó¸®ÇÏ°Ô ÇÒ ¼ö ÀÖ½À´Ï´Ù: {{{#!vim c #include int main(int argc, char *argv[]) { int i; for (int i = 0; i < argc; i++) printf("argv[%d]: %s\n", i, argv[i]); return 0; } }}} À§ ¼Ò½º¸¦ ÄÄÆÄÀÏÇÏ°í ½ÇÇàÇØ º¸¸é argc¿Í argv°¡ ¾î¶°ÇÑ ¿ªÇÒÀ» ÇÏ´ÂÁö ½±°Ô ¾Ë ¼ö ÀÖ½À´Ï´Ù: {{{#!vim sh $ cc -Wall arg.c $ ./a.out # argc == 1 argv[0]: ./a.out $ ./a.out hello world # argc == 3 argv[0]: ./a.out argv[1]: hello argv[2]: world $ ls *.c arg.c hello.c $ ./a.out *.c # argc == # of .c files plus 1. argv[0]: ./a.out argv[1]: arg.c argv[2]: hello.c $ _ }}} ¿É¼ÇÀ» ó¸®Çϱâ À§Çؼ­ getopt(3)À̳ª getopt_long(3) ÇÔ¼ö¸¦ ¾²´Â °ÍÀÌ Æí¸®ÇÕ´Ï´Ù. ¸ÕÀú °¡Àå ÈçÇÑ '-h'¿Í '-v' (µµ¿ò¸»°ú ¹öÀü Ãâ·Â) ¿É¼ÇÀ» ¸¸µé¾î º¾½Ã´Ù. getopt(3)¿Í getopt_long(3)Àº ¿É¼Ç 󸮸¦ ¸Å¿ì °£´ÜÇÏ°Ô ÇØ ÁÝ´Ï´Ù. ¸ÕÀú ´ëºÎºÐ UNIX ½Ã½ºÅÛÀº POSIX.2¿¡ ÁØÇÏ´Â getopt(3)¸¦ Á¦°øÇϸç, GNU ½Ã½ºÅÛ¿¡¼­´Â È®Àå ÇÔ¼öÀÎ getopt_long(3)À» ¾µ ¼ö ÀÖ½À´Ï´Ù. getopt(3)°¡ ÇÑ ±ÛÀÚ ¿É¼Ç¸¸À» ó¸®ÇÒ ¼ö ÀÖ´Â ¹Ý¸é, getopt_long(3)Àº ÇÑ ±ÛÀÚ ¿É¼Ç »Ó¸¸ ¾Æ´Ï¶ó ±ä ¿É¼Çµµ ó¸® °¡´ÉÇÕ´Ï´Ù: {{{#!vim c #include int getopt(int ARGC, char * const ARGV[], const char *OPTSTRING); extern char *optarg; extern int optind, opterr, optopt; #include int getopt_long(int ARGC, char * const ARGV[], const char *OPTSTRING, const struct option *LONGOPTS, int *LONGINDEX); }}} ¸ÕÀú µÎ ÇÔ¼öÀÇ ¼¼¹ø° ÆĶó¸ÞÅÍÀÎ OPTSTRING¿¡ ´ëÇØ ¾Ë¾Æ º¾½Ã´Ù. ÀÌ ÆĶó¸ÞÅÍ¿¡´Â, ÀÌ ÇÁ·Î±×·¥ÀÌ Ã³¸®ÇÒ ¼ö ÀÖ´Â ÇÑ ±ÛÀÚ ¿É¼ÇµéÀÇ ¸ñ·ÏÀ» ½á ÁÝ´Ï´Ù. ¸¸¾à ¿É¼ÇÀÌ ÀÎÀÚ¸¦ ¹Þ´Â´Ù¸é ¿É¼Ç ±ÛÀÚ µÚ¿¡ ':'µµ ½á ÁÝ´Ï´Ù. ¸¸¾à ¿É¼Ç¿¡ ´ëÇÑ ÀÎÀÚ¸¦ »ý·«ÇÒ ¼ö ÀÖ´Â °æ¿ì¿¡´Â ':'¸¦ µÎ°³ ½á ÁÝ´Ï´Ù. ¿¹¸¦ µé¾î ÇÁ·Î±×·¥ÀÌ Ã³¸®ÇÏ´Â ¿É¼ÇÀÌ '-h', '-v', '-q', '-o FILE' ÀÌ ³×°³¶ó°í Çϸé, OPTSTRINGÀº "hvqo:"°¡ µË´Ï´Ù. ÀÌÁ¦ getopt(3)ÀÇ ¸®ÅÏ °ª¿¡ ´ëÇØ ¾Ë¾Æº¾½Ã´Ù. getopt(3)Àº ÇÁ·Î±×·¥¿¡ Àü´ÞµÈ ÀÎÀÚ¸¦ Çϳª¾¿ ó¸®ÇÕ´Ï´Ù. Áï, °³¹ßÀÚ´Â getopt(3)À» ÇÊ¿äÇÑ ¸¸Å­ ºÒ·¯¼­, ÇÁ·Î±×·¥¿¡ Àü´ÞµÈ ¿É¼ÇÀ» ¸ðµÎ ó¸®ÇØ ÁÖ¾î¾ß ÇÕ´Ï´Ù. ´õ ÀÌ»ó ó¸®ÇÒ ¿É¼ÇÀÌ ¾ø´Â °æ¿ì, getopt(3)´Â -1À» ¸®ÅÏÇÕ´Ï´Ù. µû¶ó¼­ ¿ì¸®´Â ´ÙÀ½°ú °°Àº Äڵ带 »ý°¢ÇÒ ¼ö ÀÖ½À´Ï´Ù: {{{#!vim c int main(int argc, char *argv[]) { int ch; while ((ch = getopt(argc, argv, "hvqo:")) != -1) { ... } ... } }}} getopt(3)´Â ÀÚ½ÅÀÌ Ã³¸®ÇÑ ¿É¼Ç ±ÛÀÚ¸¦ ¸®ÅÏÇØ ÁÝ´Ï´Ù. µû¶ó¼­ getopt(3)°¡ '-h'¸¦ ó¸®Çß´Ù¸é 'h'¸¦ ¸®ÅÏÇÕ´Ï´Ù. µû¶ó¼­ ¿ì¸®´Â getopt(3)ÀÇ °á°ú¸¦ switch ¹®ÀåÀ» ½á¼­ ¿øÇÏ´Â ÀÛ¾÷À» ó¸®ÇØÁÖ¸é µË´Ï´Ù. ¸¸¾à ÇÁ·Î±×·¥ »ç¿ëÀÚ°¡ ¾Ë ¼ö ¾ø´Â ¿É¼ÇÀ» ½è´Ù¸é getopt(3)´Â '?'¸¦ ¸®ÅÏÇÕ´Ï´Ù. µû¶ó¼­ À§ ¿¹Á¦ÀÇ while ¹®Àå ¾ÈÀº ´ÙÀ½°ú °°ÀÌ ¾µ ¼ö ÀÖ½À´Ï´Ù: {{{#!vim c switch (ch) { case 'h': /* show help message and exit */ case 'v': /* show version information and exit */ case 'q': /* set quiet mode */ break; case 'o': /* set the output file name */ break; case '?': /* unknown option. ignored. */ break; default: /* getopt(3) returns unrecognized value. */ abort(); } }}} ¸ÕÀú getopt(3)°¡ '?'¸¦ ¸®ÅÏÇß´Ù¸é, ÇÁ·Î±×·¥ »ç¿ëÀÚ°¡ ¾Ë ¼ö ¾ø´Â ¿É¼ÇÀ» ÁöÁ¤ÇÑ °ÍÀ» ¶æÇÕ´Ï´Ù. ÀÌ °æ¿ì getopt(3)´Â ÀÚµ¿À¸·Î ¾Ë ¼ö ¾ø´Â ¿É¼ÇÀÌ µé¾î¿Ô´Ù´Â ¿¡·¯ ¸Þ½ÃÁö¸¦ Ãâ·ÂÇÕ´Ï´Ù¸¸, ÀÌ °ÍÀ¸·Î ÃæºÐÇÏÁö ¾Ê½À´Ï´Ù. ¿ì¸®´Â ÀÌ °æ¿ì '-h'¸¦ ¾²¸é µµ¿ò¸»À» º¼ ¼ö ÀÖ´Ù´Â °Í±îÁö Ãâ·ÂÇØ ÁÙ °ÍÀÔ´Ï´Ù: {{{#!vim c case '?': /* getopt(3) prints "unknown option" message automatically. */ fprintf(stderr, "Try `opt -h' for more information.\n"); break; }}} ´ÙÀ½À¸·Î, ÀÎÀÚ¸¦ ¹Þ´Â ¿É¼ÇÀÎ '-o FILE'¿¡ ´ëÇØ ´õ ¾Ë¾Æº¾½Ã´Ù. getopt(3)´Â ÀÎÀÚ¸¦ ¹Þ´Â ¿É¼ÇÀÌ µé¾î¿Ã °æ¿ì, Àü¿ª º¯¼ö optarg¿¡, ±× ¿É¼Ç ÀÎÀÚ¸¦ °¡¸®Å°´Â Æ÷ÀÎÅÍ °ªÀ» ÀúÀåÇØ µÓ´Ï´Ù. µû¶ó¼­ ¿ì¸®´Â ÀÌ optarg¿¡¼­ ¿øÇÏ´Â ÀÎÀÚ¸¦ ¾òÀ» ¼ö ÀÖ½À´Ï´Ù. ÇÑ°¡Áö ´õ, optarg´Â getopt(3)¸¦ ºÎ¸¦ ¶§ ´Ù¸¥ °ªÀ¸·Î µ¤¾î ½á Áú ¼ö ÀÖÀ¸¹Ç·Î, ´ÙÀ½°ú °°Àº ÄÚµå´Â À§ÇèÇÒ ¼ö ÀÖ½À´Ï´Ù: {{{#!vim c const char *filename; ... filename = optarg; }}} °¡Àå ¼Õ½¬¿î ¹æ¹ýÀº strdup(3) ÇÔ¼ö¸¦ ½á¼­ ¸Þ¸ð¸®¸¦ ÇÒ´çÇÑ ´ÙÀ½, optarg°¡ °¡¸®Å°´Â ¹®ÀÚ¿­À» º¹»çÇÏ´Â °ÍÀÔ´Ï´Ù: {{{#!vim c const char *filename; ... filename = strdup(optarg); }}} ¸¶Áö¸·À¸·Î, getopt(3)¸¦ ½á¼­ ¿É¼Ç 󸮸¦ ´Ù ³¡³Â´Ù¸é, ÀÌÁ¦ ÇÁ·Î±×·¥¿¡ Àü´ÞµÈ (¿É¼ÇÀÌ ¾Æ´Ñ) ÀÎÀÚµéÀ» ó¸®ÇØ¾ß ÇÕ´Ï´Ù. ÀÌ ¶§, ¿ì¸®´Â Àü¿ª º¯¼ö optind¿¡ ´ã±ä °ªÀ» ¾¹´Ï´Ù. optind¿¡´Â getopt°¡ argv[]¿¡ ÀÖ´Â ¿É¼ÇµéÀ» ó¸®ÇÏ°í ³­ ¸¶Áö¸· ÀÎÀÚ¿¡ ´ëÇÑ index °ªÀÌ µé¾î ÀÖ½À´Ï´Ù. µû¶ó¼­ ¿ì¸®´Â argv{{{[optind]}}}ºÎÅÍ argv{{{[argc - 1]}}}±îÁö ó¸®ÇÏ¸é µË´Ï´Ù. ¸¸¾à ÇÁ·Î±×·¥¿¡ Àü´ÞµÈ ÀÎÀÚµéÀÌ ¾ø´Â °æ¿ì¸¦ µû·Î ó¸®ÇÏ°í ½Í´Ù¸é, optind°¡ argc°¡ °°Àº °æ¿ì¸¦ ó¸®ÇÏ¸é µË´Ï´Ù. ¿¹¸¦ µé¾î À§ getopt¸¦ ¾´ while ¹®Àå ´ÙÀ½¿¡ ¾Æ·¡¿Í °°Àº Äڵ带 Ãß°¡ÇÏ¸é µË´Ï´Ù. {{{#!vim c if (optind == argc) { /* there is no argument in the command-line. */ ... } else { int i; for (i = optind; i < argc; i++) { /* process each argv[i] here */ ... } } }}} == Skelton Template #1 == {{{#!vim c #include #include #include #include #include #include const char *program_name = "opt"; const char *version_string = "0.1"; int verbose_mode = 1; const char *output_filename; static void help_and_exit(void); static void version_and_exit(void); int main(int argc, char *argv[]) { int c; while (1) { c = getopt(argc, argv, "hvo:q"); if (c < 0) break; switch (c) { case 'h': help_and_exit(); break; case 'v': version_and_exit(); break; case 'q': verbose_mode = 0; break; case 'o': output_filename = strdup(optarg); break; case '?': error(0, 0, "Try `%s -h' for more information.\n", program_name); break; default: abort(); } } if (optind == argc) { /* There is no more argument in the command-line */ /* TODO: insert code for no argument */ } else { int i; for (i = optind; i < argc; i++) { /* Process each argv[i] here */ printf("processing %s\n", argv[i]); } } return 0; } static void help_and_exit(void) { static const char *msgs[] = { "usage: opt [OPTION...] [FILES...]", "", " -h display this help and exit", " -v output version information and exit", " -q quite mode", " -o FILE send output to file FILE. If FILE is `-', ", " send output to stdout.", "", "Report bugs to ", }; int i; for (i = 0; i < sizeof(msgs) / sizeof(const char *); i++) puts(msgs[i]); exit(EXIT_SUCCESS); } static void version_and_exit(void) { printf("opt version %s\n", version_string); exit(EXIT_SUCCESS); } }}} ---- ±Û¾´ÀÌ´Â Ç×»ó ÀÌ »À´ë Äڵ带 ÃÖ½ÅÀ¸·Î ¸¸µé·Á°í ÇÏ°í ÀÖ½À´Ï´Ù. ÃֽŠÄÚµå´Â ±Û¾´ÀÌÀÇ [http://www.cinsk.org/viewcvs/snippets/filter-skel.c CVS]¿¡¼­ ¹Ù·Î º¼ ¼ö ÀÖ½À´Ï´Ù. ³¡ -- [http://www.cinsk.org/ ½Å¼º±¹] ---- CategoryDevelFilter CategoryDevelopment