Contents
prtext
printf埋め込み前のgrep.c(3.1)を使ってprtextを読んでいきます。
変数や関数の名前の意味を推測していきます。
1292 /* Output the lines between BEG and LIM. Deal with context. */ 1293 static void 1294 prtext (char *beg, char *lim)
引数のbeg、limとは何でしょう。
prtextを使用しているソースを確認してみましょう。
1409 char *prbeg = out_invert ? p : b; 1410 char *prend = out_invert ? b : endp; 1411 prtext (prbeg, prend);
使用されている変数名はprbegとprendです。
begin~endってことですね。
つまりbegはbeginの略です。
となると、limは、limitやlimitterといったところでしょう。
続いてこちら。
1296 static bool used; /* Avoid printing SEP_STR_GROUP before any output.
usedとは実に簡単な名前ですが、何がusedなんでしょう。この関数(prtext)がusedなのか。コメントでは、出力の前のSEP_STR_GROUPの表示を中止するとあります。
では、SEP_STR_GROUPとは何なのか。
56行目に定義されています。
54 enum { SEP_CHAR_SELECTED = ':' }; 55 enum { SEP_CHAR_REJECTED = '-' }; 56 static char const SEP_STR_GROUP[] = "--";
セパレータとして文字列を定義しているんですね。
続いてこの行。
1297 char eol = eolbyte;
eolなので、End of Lineですね。eolbyteということは行末の1Byteの文字でしょうか。
grep.c内を、eolbyteで検索してみます。
takk@deb9:~/tmp/grep-3.1/src$ grep -n 'eolbyte\>.*=' grep.c 2429: eolbyte = '\n'; 2676: eolbyte = '\0'; takk@deb9:~/tmp/grep-3.1/src$
行末の1Byte、改行またはNULL文字ってことですね。
prepending
1299 if (!out_quiet && pending > 0) 1300 prpending (beg);
out_quietは、outは出力、quietは静かな、なので、「静かな出力」。。。ん~。色を付けないってことでしょうか。
pendingは、日本語でも使いますね。保留って意味でしょう。
prependingは、prependの名詞ですね。prependは先頭に追加するという意味です。
各変数定義の説明を読んでみます。
1027 static intmax_t pending; /* Pending lines of output. 1028 Always kept 0 if out_quiet is true. */
Pending linesとあるので、pendingは、出力保留行の行数のようですね。
次行きます。
1301 1302 char *p = beg; 1303 1304 if (!out_quiet) 1305 { 1306 /* Deal with leading context. */ 1307 char const *bp = lastout ? lastout : bufbeg; 1308 intmax_t i; 1309 for (i = 0; i < out_before; ++i) 1310 if (p > bp) 1311 do 1312 --p; 1313 while (p[-1] != eol); 1314
コメントのDeal withは~対応する、で、contextは文脈、
先頭の文脈に対応する、でしょうか。
lastoutの定義を読んでみます。
1023 static char *lastout; /* Pointer after last character output; 1024 NULL if no character has been output 1025 or if it's conceptually before bufbeg. *
lastoutはそのままっぽいです。最後に出力した文字の後のポインタですね。
1309行目でout_beforeという変数も使われているので、定義箇所を見てみます。beforeもあればafterもあるようです。
1010 static intmax_t out_before; /* Lines of leading context. */ 1011 static intmax_t out_after; /* Lines of trailing context. */
こうして読んでいくと、意外にグローバル変数が多く使われていますね。
で、いろんなポインタやら行数やらを使って何をしているかというと、
この3行で、begポインタをEOLの位置まで戻しているだけのようです。
1311 do 1312 --p; 1313 while (p[-1] != eol);
すっきりした書き方の参考になります。
前の2行を合わせてみると、一切{}を使っていないのが、美しい。
1309 for (i = 0; i < out_before; ++i) 1310 if (p > bp) 1311 do 1312 --p; 1313 while (p[-1] != eol);
まあ、私の好みってだけかもしれません。
group_separator
1315 /* Print the group separator unless the output is adjacent to 1316 the previous output in the file. */ 1317 if ((0 <= out_before || 0 <= out_after) && used 1318 && p != lastout && group_separator) 1319 { 1320 pr_sgr_start_if (sep_color); 1321 fputs_errno (group_separator); 1322 pr_sgr_end_if (sep_color); 1323 putchar_errno ('\n'); 1324 }
1317,1318行目のif文から読み取ることが難しいので、コメント文が頼りです。
出力が前の出力と隣接しない限りはグループセパレータをPrintする、とありますね。
グループセパレータとはgroup_separatorで、このように定義されています。
182 /* The group separator used when context is requested. */ 183 static const char *group_separator = SEP_STR_GROUP;
SEP_STR_GROUPは前にも見ましたが、このような定義でしたね。
54 enum { SEP_CHAR_SELECTED = ':' }; 55 enum { SEP_CHAR_REJECTED = '-' }; 56 static char const SEP_STR_GROUP[] = "--";
grepの結果を仕切る文字列で、これ(緑色)のことです。
グループセパレータを引数にしている、この関数は何をしているのでしょう。
1321 fputs_errno (group_separator);
errnoのfputs?
よくわかりません。関数定義を見てみます。
382 static void 383 fputs_errno (char const *s) 384 { 385 if (fputs (s, stdout) < 0) 386 stdout_errno = errno; 387 }
ううっ、これはっ。引数をfputsした後、エラーが発生した場合に、errnoを記憶する処理のようですが、ん~。関数名が分かりにくいっ。
なるべくなら関数の内部を読まずに、ソースが読めることが理想なので、fputs_holding_errnoとかだったら中身見なかったかもしれません。まあholding errnoが正しい英語か分かりませんが。
まあそもそも関数化が必要だったのだろうかと思います。使用箇所は多くないので。
takk@deb9:~/tmp/grep-3.1/src$ grep fputs_errno grep.c fputs_errno (char const *s) fputs_errno (input_filename ()); fputs_errno (group_separator); takk@deb9:~/tmp/grep-3.1/src$
out_invert
1335 intmax_t n; 1336 if (out_invert) 1337 { 1338 /* One or more lines are output. */ 1339 for (n = 0; p < lim && n < outleft; n++) 1340 { 1341 char *nl = memchr (p, eol, lim - p); 1342 nl++; 1343 if (!out_quiet) 1344 prline (p, nl, SEP_CHAR_SELECTED); 1345 p = nl; 1346 } 1347 } 1348 else
invertとついているので反転ですね。しかし、out_invert、出力を反転するとは、どういうことなのでしょう。
定義を見てみます。
1006 static bool out_invert; /* Print nonmatching stuff. */
分かりました。マッチしていない文字列を出力するフラグですね。
さらに、オプション処理しているcase文を読めば理解できます。
2658 case 'v': 2659 out_invert = true; 2660 break;
-vオプションを使った時のフラグですね。
out_quiet
out_invertがfalseの場合の処理からです。
1348 else 1349 { 1350 /* Just one line is output. */ 1351 if (!out_quiet) 1352 prline (beg, lim, SEP_CHAR_SELECTED); 1353 n = 1; 1354 p = lim; 1355 } 1356
out_quietもおそらくオプションのフラグでしょう。定義を見てみます。
1005 static bool out_quiet; /* Suppress all normal output. */
mainで、以下のように処理しているので、他のフラグと関係しているフラグのように見受けられます。
2824 out_quiet = count_matches | done_on_match;
count_matchesとdone_on_matchはそれぞれ以下の定義です。
1012 static bool count_matches; /* Count matching lines. */ 1029 static bool done_on_match; /* Stop scanning file on first match. */
これらのフラグもやはり、他のフラグに依存しています。
2819 if ((exit_on_match | dev_null_output) || list_files != LISTFILES_NONE) 2820 { 2821 count_matches = false; 2822 done_on_match = true; 2823 }
依存しているフラグの元をたどると、
例えば、exit_on_matchは、mainで、qオプションのフラグとして設定していますので、ほとんどのフラグはオプションから設定されると考えて良いかと思います。
2641 case 'q': 2642 exit_on_match = true; 2643 exit_failure = 0; 2644 break;
dev_null_outputの場合もmainで設定しているようですが、少し複雑なことをしています。
2798 bool possibly_tty = false; 2799 struct stat tmp_stat; 2800 if (! exit_on_match && fstat (STDOUT_FILENO, &tmp_stat) == 0) 2801 { 2802 if (S_ISREG (tmp_stat.st_mode)) 2803 out_stat = tmp_stat; 2804 else if (S_ISCHR (tmp_stat.st_mode)) 2805 { 2806 struct stat null_stat; 2807 if (stat ("/dev/null", &null_stat) == 0 2808 && SAME_INODE (tmp_stat, null_stat)) 2809 dev_null_output = true; 2810 else 2811 possibly_tty = true; 2812 } 2813 }
なんとなくですが、grep実行時に、出力をどこへ渡すのか判断していて、フラグ設定しているように思えます。
プログラム中のフラグは、オプションによるものと、出力先によるものがあるようです。
caseからオプションを読む
オプションとフラグを関係を読むのが面倒なので、grepを使って整理します。
オプションはcase文でフラグ設定されるので、case文を検索。
takk@deb9:~/tmp/grep-3.1/src$ grep -n case grep.c 460: {"ignore-case", no_argument, NULL, 'i'}, 490:bool match_icase; 758: case LONGINT_OK: 759: case LONGINT_OVERFLOW: 1616: case FTS_D: 1625: case FTS_DC: 1631: case FTS_DNR: 1632: case FTS_ERR: 1633: case FTS_NS: 1637: case FTS_DEFAULT: 1638: case FTS_NSOK: 1661: case FTS_F: 1662: case FTS_SLNONE: 1665: case FTS_SL: 1666: case FTS_W: 1929: -i, --ignore-case ignore case distinctions\n\ 2026: Exit in case of conflicts or if M is not available. */ 2240: case folded counterparts and toupper translates none of its bytes. */ 2243:fgrep_icase_charlen (char const *pat, size_t patlen, mbstate_t *mbs) 2251: if (MB_LEN_MAX < wn || case_folded_counterparts (wc, folded)) 2265: single-byte characters or characters not subject to case folding, 2269:fgrep_icase_available (char const *pat, size_t patlen) 2275: int n = fgrep_icase_charlen (pat + i, patlen - i, &mbs); 2301: case (size_t) -2: 2308: case (size_t) -1: 2312: case 1: 2315: case '$': case '*': case '.': case '[': case '\\': case '^': 2349: case '$': case '*': case '.': case '[': case '^': 2352: case '(': case '+': case '?': case '{': case '|': 2357: case '\\': 2361: case '\n': 2362: case 'B': case 'S': case 'W': case'\'': case '<': 2363: case 'b': case 's': case 'w': case '`': case '>': 2364: case '1': case '2': case '3': case '4': 2365: case '5': case '6': case '7': case '8': case '9': 2368: case '(': case '+': case '?': case '{': case '|': 2381: if (match_icase) 2383: int ni = fgrep_icase_charlen (q, len, &mb_state); 2465: case 'A': 2469: case 'B': 2473: case 'C': 2479: case 'D': 省略 2732: case EXCLUDE_DIRECTORY_OPTION: 2743: case GROUP_SEPARATOR_OPTION: 2747: case LINE_BUFFERED_OPTION: 2751: case LABEL_OPTION: 2755: case 0: 2867: || (match_icase && !fgrep_icase_available (keys, keycc))))) takk@deb9:~/tmp/grep-3.1/src$
多すぎですね。
‘.’のパターンで絞ります。
takk@deb9:~/tmp/grep-3.1/src$ grep -n "case.*'.'" grep.c 460: {"ignore-case", no_argument, NULL, 'i'}, 2315: case '$': case '*': case '.': case '[': case '\\': case '^': 2349: case '$': case '*': case '.': case '[': case '^': 2352: case '(': case '+': case '?': case '{': case '|': 2362: case 'B': case 'S': case 'W': case'\'': case '<': 2363: case 'b': case 's': case 'w': case '`': case '>': 2364: case '1': case '2': case '3': case '4': 2365: case '5': case '6': case '7': case '8': case '9': 2368: case '(': case '+': case '?': case '{': case '|': 2465: case 'A': 2469: case 'B': 2473: case 'C': 2479: case 'D': 2488: case 'E': 2492: case 'F': 2496: case 'P': 2500: case 'G': 2504: case 'X': /* undocumented on purpose */ 2508: case 'H': 2513: case 'I': 2517: case 'T': 2521: case 'U': 2526: case 'u': 2531: case 'V': 省略 2646: case 'R': 2649: case 'r': 2654: case 's': 2658: case 'v': 2662: case 'w': 2667: case 'x': 2671: case 'Z': 2675: case 'z': takk@deb9:~/tmp/grep-3.1/src$
さらにcaseが複数出現する行は除外します。
takk@deb9:~/tmp/grep-3.1/src$ grep "case.*'.'" grep.c | grep -v 'case.*case' {"ignore-case", no_argument, NULL, 'i'}, case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'P': case 'G': case 'X': /* undocumented on purpose */ case 'H': case 'I': case 'T': case 'U': case 'u': case 'V': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'i': case 'y': /* For old-timers . . . */ case 'L': case 'l': case 'm': case 'n': case 'o': case 'q': case 'R': case 'r': case 's': case 'v': case 'w': case 'x': case 'Z': case 'z': takk@deb9:~/tmp/grep-3.1/src$
これらのcase文の下の行のフラグを抽出すればよいですね。
caseからオプションを読む その2
takk@deb9:~/tmp/grep-3.1/src$ grep "case.*'.'" grep.c | grep -v 'case.*case' {"ignore-case", no_argument, NULL, 'i'}, case 'A': case 'B': case 'C': case 'D': case 'E': case 'F': case 'P': case 'G': case 'X': /* undocumented on purpose */ case 'H': case 'I': case 'T': case 'U': case 'u': case 'V': case 'a': case 'b': case 'c': case 'd': case 'e': case 'f': case 'h': case 'i': case 'y': /* For old-timers . . . */ case 'L': case 'l': case 'm': case 'n': case 'o': case 'q': case 'R': case 'r': case 's': case 'v': case 'w': case 'x': case 'Z': case 'z': takk@deb9:~/tmp/grep-3.1/src$
ここから行番号を取得して、ファイルに落とします。
takk@deb9:~/tmp/grep-3.1/src$ grep -n "case.*'.'" grep.c | grep -v 'case.*case' | cut -d: -f1 > filter takk@deb9:~/tmp/grep-3.1/src$
このような行番号の一覧ができました。
takk@deb9:~/tmp/grep-3.1/src$ head filter 460 2465 2469 2473 2479 2488 2492 2496 2500 2504 takk@deb9:~/tmp/grep-3.1/src$
正規表現で先頭で検索できるように修正。
takk@deb9:~/tmp/grep-3.1/src$ sed 's/^/\^/' -i filter takk@deb9:~/tmp/grep-3.1/src$
このファイルをgrepに適用します。
takk@deb9:~/tmp/grep-3.1/src$ head filter ^460 ^2465 ^2469 ^2473 ^2479 ^2488 ^2492 ^2496 ^2500 ^2504 takk@deb9:~/tmp/grep-3.1/src$
nlでgrep.cの行頭に行番号を付与してから、 grepでさきほど作成したfilterで抽出します。
takk@deb9:~/tmp/grep-3.1/src$ nl -ba -nln grep.c | grep -A1 -f filter 460 {"ignore-case", no_argument, NULL, 'i'}, 461 {"initial-tab", no_argument, NULL, 'T'}, -- 2465 case 'A': 2466 context_length_arg (optarg, &out_after); -- 2469 case 'B': 2470 context_length_arg (optarg, &out_before); -- 2473 case 'C': 2474 /* Set output match context, but let any explicit leading or -- 2479 case 'D': 2480 if (STREQ (optarg, "read")) -- 2488 case 'E': 2489 matcher = setmatcher ("egrep", matcher); -- 2492 case 'F': 2493 matcher = setmatcher ("fgrep", matcher); -- 2496 case 'P': 2497 matcher = setmatcher ("perl", matcher); -- 2500 case 'G': 2501 matcher = setmatcher ("grep", matcher); -- 2504 case 'X': /* undocumented on purpose */ 2505 matcher = setmatcher (optarg, matcher); -- 2508 case 'H': 2509 with_filenames = true; -- 2513 case 'I': 2514 binary_files = WITHOUT_MATCH_BINARY_FILES; -- 2517 case 'T': 2518 align_tabs = true; -- 2521 case 'U': 2522 if (O_BINARY) -- 2526 case 'u': 2527 /* Obsolete option; it has no effect. FIXME: Diagnose use of -- 2531 case 'V': 2532 show_version = true; -- 2535 case 'a': 2536 binary_files = TEXT_BINARY_FILES; -- 2539 case 'b': 2540 out_byte = true; -- 2543 case 'c': 2544 count_matches = true; -- 2547 case 'd': 2548 directories = XARGMATCH ("--directories", optarg, -- 2554 case 'e': 2555 cc = strlen (optarg); -- 2568 case 'f': 2569 if (STREQ (optarg, "-")) -- 2601 case 'h': 2602 with_filenames = false; -- 2606 case 'i': 2607 case 'y': /* For old-timers . . . */ 2608 match_icase = true; -- 2611 case 'L': 2612 /* Like -l, except list files that don't contain matches. -- 2617 case 'l': 2618 list_files = LISTFILES_MATCHING; -- 2621 case 'm': 2622 switch (xstrtoimax (optarg, 0, 10, &max_count, "")) -- 2633 case 'n': 2634 out_line = true; -- 2637 case 'o': 2638 only_matching = true; -- 2641 case 'q': 2642 exit_on_match = true; -- 2646 case 'R': 2647 fts_options = basic_fts_options | FTS_LOGICAL; -- 2649 case 'r': 2650 directories = RECURSE_DIRECTORIES; -- 2654 case 's': 2655 suppress_errors = true; -- 2658 case 'v': 2659 out_invert = true; -- 2662 case 'w': 2663 wordinit (); -- 2667 case 'x': 2668 match_lines = true; -- 2671 case 'Z': 2672 filename_mask = 0; -- 2675 case 'z': 2676 eolbyte = '\0'; takk@deb9:~/tmp/grep-3.1/src$
460,461行目はcase文ではなかったので、どこかで条件を間違えたのでしょう。
caseからオプションを読む その3
実はもっと簡単なgrep指定がありました。こちらを使います。
takk@deb9:~/tmp/grep-3.1/src$ grep -A1 "^......case.*'.'" grep.c case 'A': context_length_arg (optarg, &out_after); -- case 'B': context_length_arg (optarg, &out_before); -- 省略 -- case 'Z': filename_mask = 0; -- case 'z': eolbyte = '\0'; takk@deb9:~/tmp/grep-3.1/src$
並び替えると見やすくなります。
takk@deb9:~/tmp/grep-3.1/src$ grep -A1 "^......case.*'.'" grep.c | tr -d '\n' | perl -pe 's/\bcase/\ncase/g' case 'A': context_length_arg (optarg, &out_after);-- case 'B': context_length_arg (optarg, &out_before);-- case 'C': /* Set output match context, but let any explicit leading or-- case 'D': if (STREQ (optarg, "read"))-- case 'E': matcher = setmatcher ("egrep", matcher);-- case 'F': matcher = setmatcher ("fgrep", matcher);-- case 'P': matcher = setmatcher ("perl", matcher);-- case 'G': matcher = setmatcher ("grep", matcher);-- case 'X': /* undocumented on purpose */ matcher = setmatcher (optarg, matcher);-- case 'H': with_filenames = true;-- case 'I': binary_files = WITHOUT_MATCH_BINARY_FILES;-- case 'T': align_tabs = true;-- case 'U': if (O_BINARY)-- case 'u': /* Obsolete option; it has no effect. FIXME: Diagnose use of-- case 'V': show_version = true;-- case 'a': binary_files = TEXT_BINARY_FILES;-- case 'b': out_byte = true;-- case 'c': count_matches = true;-- case 'd': directories = XARGMATCH ("--directories", optarg,-- case 'e': cc = strlen (optarg);-- case 'f': if (STREQ (optarg, "-"))-- case 'h': with_filenames = false;-- case 'i': case 'y': /* For old-timers . . . */ match_icase = true;-- case 'L': /* Like -l, except list files that don't contain matches.-- case 'l': list_files = LISTFILES_MATCHING;-- case 'm': switch (xstrtoimax (optarg, 0, 10, &max_count, ""))-- case 'n': out_line = true;-- case 'o': only_matching = true;-- case 'q': exit_on_match = true;-- case 'R': fts_options = basic_fts_options | FTS_LOGICAL;-- case 'r': directories = RECURSE_DIRECTORIES;-- case 's': suppress_errors = true;-- case 'v': out_invert = true;-- case 'w': wordinit ();-- case 'x': match_lines = true;-- case 'Z': filename_mask = 0;-- case 'z': eolbyte = '\0';takk@deb9:~/tmp/grep-3.1/src$
各オプションとフラグの関係がすぐに分かるようになりました。
一つピックアップして、manと見比べます。
takk@deb9:~/tmp/grep-3.1/src$ !! | shuf | head -1 grep -A1 "^......case.*'.'" grep.c | tr -d '\n' | perl -pe 's/case/\ncase/g' | shuf | head -1 case 'c': count_matches = true;-- takk@deb9:~/tmp/grep-3.1/src$
man grepの -cの説明はこのようになっています。
-c, --count 通常の出力はせず、各入力ファイルについてマッチした行数を表示しま す。 -v, --invert-match オプション (上記参照) と共に指定した場合 は、 マッチしなかった行数を表示します。 (-c オプションは POSIX で指定されています)
-cオプションのフラグは、count_matchesです。それはそれで分かりやすいのですが、ロングオプションの–countの名前を合わせても良かったのでは? と思ってしまいました。
pretext その2
オプションと各フラグの関係がおおむね分かったので、続きを読んでいきます。
prtextの最後の部分です。
1357 after_last_match = bufoffset - (buflim - p); 1358 pending = out_quiet ? 0 : MAX (0, out_after); 1359 used = true; 1360 outleft -= n; 1361 }
after_last_matchの定義を見てみます。
807 static off_t after_last_match; /* Pointer after last matching line that 808 would have been output if we were 809 outputting characters. */
時々みかけるoff_t、どんな型なのか気になります。
/usr/includeの中を探してみます。
takk@deb9:/usr/include$ grep -r 'define.*\<off_t\>' * numpy/npy_common.h: #define npy_off_t off_t zconf.h:# define z_off_t off_t takk@deb9:/usr/include$
見つかりません。
define定義ではなく、typdefですね。
takk@deb9:/usr/include$ grep -r 'typedef.*\<off_t\>' * fcntl.h:typedef __off_t off_t; fcntl.h:typedef __off64_t off_t; mysql/my_global.h:typedef off_t os_off_t; stdio.h:typedef __off_t off_t; stdio.h:typedef __off64_t off_t; unistd.h:typedef __off_t off_t; unistd.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/mman.h:typedef __off_t off_t; x86_64-linux-gnu/sys/mman.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/types.h:typedef __off_t off_t; x86_64-linux-gnu/sys/types.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/stat.h:typedef __off_t off_t; x86_64-linux-gnu/sys/stat.h:typedef __off64_t off_t; takk@deb9:/usr/include$
ありました、が、さらに__off_tまたは__off64_tの定義を見つけねばなりません。
off_t
off_tの検索結果をもう一度みてみます。
takk@deb9:/usr/include$ grep -r 'typedef.*\<off_t\>' * fcntl.h:typedef __off_t off_t; fcntl.h:typedef __off64_t off_t; mysql/my_global.h:typedef off_t os_off_t; stdio.h:typedef __off_t off_t; stdio.h:typedef __off64_t off_t; unistd.h:typedef __off_t off_t; unistd.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/mman.h:typedef __off_t off_t; x86_64-linux-gnu/sys/mman.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/types.h:typedef __off_t off_t; x86_64-linux-gnu/sys/types.h:typedef __off64_t off_t; x86_64-linux-gnu/sys/stat.h:typedef __off_t off_t; x86_64-linux-gnu/sys/stat.h:typedef __off64_t off_t; takk@deb9:/usr/include$
似たような定義をいろんな所でしてるんですね。
off_tを探すのは骨が折れる気がしますので、GNUのサイトでも見てみます。
13.3 Setting the File Position of a Descriptor
の章に、
Function: off_t lseek (int filedes, off_t offset, int whence)
を見つけることができますが、この関数に使われている引数の型や、戻り値の型について詳細の説明があります。
例えば、filedesに指定する値に関しては、
SEEK_SET Specifies that offset is a count of characters from the beginning of the file. SEEK_CUR Specifies that offset is a count of characters from the current file position. This count may be positive or negative. SEEK_END Specifies that offset is a count of characters from the end of the file. .. ~省略~
まあ、ここらへんはman lseekにもありますね。
で、off_tの説明を見てみると、
Data Type: off_t This is a signed integer type used to represent file sizes. In the GNU C Library, this type is no narrower than int. If the source is compiled with _FILE_OFFSET_BITS == 64 this type is transparently replaced by off64_t. Data Type: off64_t This type is used similar to off_t. The difference is that even on 32 bit machines, where the off_t type would have 32 bits, off64_t has 64 bits and so is able to address files up to 2^63 bytes in length. When compiling with _FILE_OFFSET_BITS == 64 this type is available under the name off_t.
ただの整数型でした。
できれば、Webを探さずに、ソースからぱっと見つけたいですね。
main関数
mainを読んでいきます。
mainなので、switch caseのかさばるオプション処理がほとんどだと思いますが。まあ、最初から見ていきましょう。
2413 int 2414 main (int argc, char **argv) 2415 { 2416 char *keys = NULL; 2417 size_t keycc = 0, oldcc, keyalloc = 0;
まずはkeys、keycc、oldcc、keyallocというローカル変数の登場。
ソースを読む時に楽しいことの一つが、変数の名前から処理を想像するってのがあります。
で、これらの変数名から、想像できるかというと・・・ちょっと敷居が高かったです。
さらに他のローカル変数も見てみましょう。
2418 int matcher = -1; 2419 bool with_filenames = false; 2420 size_t cc; 2421 int opt, prepended; 2422 int prev_optind, last_recursive; 2423 int fread_errno; 2424 intmax_t default_context; 2425 FILE *fp;
matcher。-1が初期値で代入されてるってことは、0以上の数が有効な数値に違いないです。マッチした数でしょうか。マッチ数を英語的にmatcherというかは謎です。
with_filenamesは、たぶんそのままですね。検索結果にファイル名を含めるかのフラグでしょう。
ccは、まったく分かりません。
optは、オプション関連かと思います。intなのでoptの数とかでしょうか。
FILE *fpは、grepをする対象のファイルをオープンするためのファイルポインタですね。
まあ、こんな風に、変数名で、いろいろ想像します。大半は間違っていますが。
さらに読み進めます。
2426 exit_failure = EXIT_TROUBLE; 2427 initialize_main (&argc, &argv); 2428 2429 eolbyte = '\n'; 2430 filename_mask = ~0; 2431 2432 max_count = INTMAX_MAX; 2433
グローバル変数の初期化ですね。exit_failureは、grepのプログラムが終了した時のエラーコードでしょう。
initialize_main。main処理の初期化ってよく分かりません。この処理が何をやっているか覚えたらステップアップできそうです。
eolbyte。当然End Of Lineの略ですね。改行コードで初期化されていますが、EOLのキャラクタが改行以外にも、変化するのでグローバル変数なんでしょう。
filename_mask。 0を反転。ん? ~って反転でしたっけ? 忘れたなら、プログラミングして即確認。
takk@deb9:~/tmp$ cat t.c #include <stdio.h> int main() { printf("~0 = %x\n",~0); } takk@deb9:~/tmp$
takk@deb9:~/tmp$ gcc t.c takk@deb9:~/tmp$ ./a.out ~0 = ffffffff takk@deb9:~/tmp$
~0は、bit反転で、合ってました。
filename_maskなのに、オール1のbitって、どんな意味なんでしょう。
setlocale
2434 /* The value -1 means to use DEFAULT_CONTEXT. */ 2435 out_after = out_before = -1; 2436 /* Default before/after context: changed by -C/-NUM options */ 2437 default_context = -1; 2438 /* Changed by -o option */ 2439 only_matching = false;
ようやくコメントが現れました。しかし、なくても意味のわかるコメントかもしれません。
デフォルト値としてよく-1を使ってますからね。
続きます。
2441 /* Internationalization. */ 2442 #if defined HAVE_SETLOCALE 2443 setlocale (LC_ALL, ""); 2444 #endif
おきまりのLOCALEの設定っぽいです。
man 3 setlocaleを読んでみます。
SETLOCALE(3) Linux Programmer's Manual SETLOCALE(3) 名前 setlocale - 現在のロケール (locale) を設定する 書式 #include <locale.h> char *setlocale(int category, const char *locale); 説明 setlocale() 関数はプログラムのカレントロケールを設定したり 問い合わせ たりするのに用いられる。 locale が NULL でなければ、プログラムのカレントロケールは引き数に従って 変更される。 引き数 category はプログラムのカレントロケールのどの部分を 変更するかを決める。
続きます。
2445 #if defined ENABLE_NLS 2446 bindtextdomain (PACKAGE, LOCALEDIR); 2447 textdomain (PACKAGE); 2448 #endif
また知らない関数が出てきました。
BINDTEXTDOMAIN(3) Library Functions Manual BINDTEXTDOMAIN(3) NAME bindtextdomain - set directory containing message catalogs SYNOPSIS #include <libintl.h> char * bindtextdomain (const char * domainname, const char * dirname); DESCRIPTION The bindtextdomain function sets the base directory of the hierarchy containing message catalogs for a given message domain.
今回初めて知りましたが、何をやる関数かは分かりませんが文章を読む限り、きっと便利な関数に違いありません。
コメント