ソフトウェア工学入門
今後のスケジュール
5/28.コマンド作成2 (本日)
6/4.ファイルシステム、プロセス、ハードウェア
6/11.
第2回個別試験
grepプログラム ①
次のプログラムを作成し、grep.cという名前で保存しなさい #include <stdio.h> #include <stdlib.h> #include <string.h> #include <sys/types.h> #include <regex.h>static void do_grep(regex_t *pat, FILE *f); int main(int argc, char *argv[])
{
regex_t pat; int err; int i;
if (argc < 2) {
fputs("no pattern\n", stderr); exit(1);
}
err = regcomp(&pat, argv[1], REG_EXTENDED | REG_NOSUB | REG_NEWLINE); if (err != 0) {
char buf[1024];
grepプログラム ②
つづき puts(buf); exit(1); } if (argc == 2) { do_grep(&pat, stdin); } else {for (i = 2; i < argc; i++) { FILE *f; f = fopen(argv[i], "r"); if (!f) { perror(argv[i]); exit(1); } do_grep(&pat, f); fclose(f); } }
grepプログラム ③
regfree(&pat); exit(0);
}
static void do_grep(regex_t *pat, FILE *src) {
char buf[4096];
while (fgets(buf, sizeof buf, src)) {
if (regexec(pat, buf, 0, NULL, 0) == 0) { fputs(buf, stdout);
} } }
練習 ビルドして実行してみましょう
>./grep opt head3.c
int opt;
while ((opt = getopt(argc, argv, "n:")) != -1) { switch (opt) {
nlines = atoi(optarg); if (optind == argc) {
grepの機能
grep : ファイル内を検索し、固定文字列を含む行を表示する grepで検索できる文字列は正規表現を含む 正規表現 記号 意味 . 任意の1文字 * 直前のパターンの0文字以上の繰り返し ? 直前のパターンは省略可能 ¥ 特殊な意味を持つ文字を除外する 正規表現の例 a.*t → a で始まって t で終わる文字列 Books? → Book か Books (?の直前が s なので) \* → *を検索する正規表現を処理するAPI
#include <sys/types.h> #include <regex.h>
int regcomp (regex_t *reg , const char *pattern , int flags ) ; void regfree (regex_t *reg ) ;
int regexec ( const regex_t *reg , const char *string , size_t nmatch , regmatch_t pmatch[ ] , int flags ) ;
size_t regerror ( int errcode , const regex_t *reg , char *msgbuf , size_t msgbuf_size ) ;
regcomp : 文字列で表現されている正規表現 pattern を reg に書き込む
regfree : regcompで確保したregex_t 領域を解放する
regexec : regex_t を使って文字列を照合し、regが文字列 string に適合すれば 0 を返し 適合しなければ、定数REG_NOMATCHを返す
grep分析 ① do_grep
static void do_grep(regex_t *pat, FILE *src) {
char buf[4096];
while (fgets(buf, sizeof buf, src)) {
if (regexec(pat, buf, 0, NULL, 0) == 0) { fputs(buf, stdout); } } } 文字列をチェックするため1行単位で読み込まなければならない 故に、 getc()ではなくfgets()を使用して、1行単位で読み込んでいる ストリームsrc より1行づつ読み込み、patと適合する行bufを出力する
grep分析 ② main
int main(int argc, char *argv[]) { regex_t pat;
int err; int i;
if (argc < 2) {
fputs("no pattern\n", stderr); exit(1); }
err = regcomp(&pat, argv[1], REG_EXTENDED | REG_NOSUB | REG_NEWLINE); if (err != 0) {
char buf[1024];
regerror(err, &pat, buf, sizeof buf); puts(buf);
exit(1); } if (argc == 2) {
do_grep(&pat, stdin); } else {
for (i = 2; i < argc; i++) { FILE *f; f = fopen(argv[i], "r"); if (!f) { perror(argv[i]); exit(1); } do_grep(&pat, f); fclose(f); } } regfree(&pat); exit(0); } コマンドライン引数を正規表現とみなしてregex_tに変換し、regerrorでエラーチェック表示
せっかくなので
、
文字コードを学習
日本で利用されている主要文字コード
EUC: UNIXで主流の文字コード
Shift JIS: WINDOWSやMAC OS9以前のOSなどで主流の文字コード
ISO-2022-JP: インターネットメールで使用される文字コード UTF-8(Unicode): 既存の文字コードを包括した最新の文字コード UTF-16(Unicode): JAVAで使用される文字コード 文字コードの仕組み 文字コード 符号化文字集合 エンコーディング
文字コード
符号化文字集合 : 文字コードで表現可能な範囲 JIS X : EUC 、Shift JIS 、ISO-2022-JP で使用される符号化文字集合 UCS : Unicode で使用される符号化文字集合 エンコーディング : 符号化文字集合に含まれる文字に割り当てられた特定数字を実際 のバイト列に変換する計算式 ワイドキャラクタ : 全ての文字に対して同じバイト数を使用するエンコーディング マルチバイトキャラクタ : 文字の種類によってバイト数を変えるエンコーディング文字化けとは?
文字コード エンコーディング 符号化文字集合 採用規格
ISO-2022-JP マルチバイト JIS X メール
EUC マルチバイト JIS X UNIX
Shift JIS マルチバイト JIS X WINDOWS, MAC OS 9
UTF-8 マルチバイト UCS XML, Perl, MAC OS 10
UTF-16 ワイドキャラクタ UCS JAVA
ディレクトリ構造
UNIXファイルシステムはルートディレクトリを頂点とする階層構造 ルート直下の重要ディレクトリ /etc : 各マシンごとの設定ファイルが置かれている /dev : ハードウェアと接続するためのデバイスファイルが置かれている /proc : プロセスファイルシステムがマウントされている /boot : カーネルのファイルが置かれている /root : スーパーユーザ専用のホームディレクトリ /home : 一般ユーザのホームディレクトリ /var : 頻繁に書き換えられるファイル専用のディレクトリ(メール情報など) /usr : 複数のユーザで共有可能なファイルが置かれているプロセスファイルシステム
プロセスファイルシステム : ファイルシステム上にプロセス情報を表現する仕組み 練習 プロセスファイルシステムを見てみましょう >ls /proc ここにプロセスファイルが表示されます 練習 ファイルの負荷情報を確認してみましょう >cat /proc/loadavg ここに使用しているシステムの負荷情報が表示されますディレクトリエントリー
ストリーム 構造体 構造体 構造体 構造体 構造体 構造体 read ディレクトリに記録されている情報はファイル情報の構造体 ディレクトリとはファイル情報を記録した構造体列 この構造体のことをディレクトリエントリーと呼ぶディレクトリ操作のシステムコール
ディレクトリを開く
#include <sys/types.h> #include <dirent.h>
DIR *opendir ( const char *path ) ;
Pathにあるディレクトリを読み込み、ポインタDIRに構造体を返す
ディレクトリの読み込み
#include <sys/types.h> #include <dirent.h>
struct dirent *readdir ( DIR *d ) ;
ディレクトリストリームd からエントリを1つ読み込み、エントリを返す
ディレクトリを閉じる
#include <sys/types.h> #include <dirent.h>
int closedir ( DIR *d ) ;
lsコマンド作成 ①
#include <stdio.h> #include <stdlib.h> #include <sys/types.h> #include <dirent.h>
static void do_ls(char *path); int main(int argc, char *argv[]) { int i;
if (argc < 2) {
fprintf(stderr, "%s: no arguments\n", argv[0]); exit(1);
}
for (i = 1; i < argc; i++) { do_ls(argv[i]);
}
exit(0); }
static void do_ls(char *path) { DIR *d;
struct dirent *ent;
d = opendir(path);
lsコマンド作成 ②
if (!d) {
perror(path); exit(1);
}
while (ent = readdir(d)) {
printf("%s\n", ent->d_name); } closedir(d); } 次のプログラムを作成し、ls.cという名前で保存しなさい 練習 lsを実行しましょう >gcc -o ls ls.c >./ls . ディレクトリの中身が表示されます
lsコマンド分析
static void do_ls(char *path) { DIR *d;
struct dirent *ent;
d = opendir(path); if (!d) {
perror(path); exit(1);
}
while (ent = readdir(d)) {
printf("%s\n", ent->d_name); } closedir(d); } パスpathにあるディレクトリをopendir()で開く pathが存在しなかったり、ディレクトリでなかったりするとNULLを返す ディレクトリエントリーがなくなるまでreaddir()を使ってエントリを読み込む 読み込んだエントリの名前を出力する
ディレクトリ作成
ディレクトリパスの作成
#include <sys/stat.h> #include <sys/types.h>
int mkdir ( const char *path , mode_t mode ) ;
ディレクトリpathを作成する。成功すれば0、失敗したらー1を返しerrnoをセットする。 第二引数はパーミッション設定。 パーミッション設定 パーミッションは第二引数 mode のビットから umask に含まれるビットを落とす ※ umask はプロセス属性(デフォルトは022がセットされている) 例 mask = 777 | 1 1 1 1 1 1 1 1 1 umask= 022 | 0 0 0 0 1 0 0 1 0 --- 結果 = 755 | 1 1 1 1 0 1 1 0 1
mkdirコマンド作成
次のプログラムを作成し、mkdir.cという名前で保存しなさい #include <stdio.h> #include <stdlib.h> #include <sys/stat.h> #include <sys/types.h>int main(int argc, char *argv[]) { int i;
if (argc < 2) {
fprintf(stderr, "%s: no arguments\n", argv[0]); exit(1);
}
for (i = 1; i < argc; i++) {
if (mkdir(argv[i], 0777) < 0) { perror(argv[i]); exit(1); } } exit(0); }
mkdir実行とrmdir
練習 次のプログラムを実行しましょう >gcc -o mkdir mkdir.c >./mkdir dir >ls dir ディレクトリを削除する #include <unistd.h>int rmdir ( const char *path )
ディレクトリpathを削除する。成功すれば0、失敗すればー1を返す。 削除するディレクトリは必ず空でなければならない
rmdirコマンド作成
次のプログラムを作成し、rmdir.cという名前で保存しなさい
#include <stdio.h> #include <stdlib.h> #include <unistd.h>
int main(int argc, char *argv[]) { int i;
if (argc < 2) {
fprintf(stderr, "%s: no arguments\n", argv[0]); exit(1);
}
for (i = 1; i < argc; i++) { if (rmdir(argv[i]) < 0) { perror(argv[i]); exit(1); } } exit(0); }
rmdir実行
練習 次のプログラムを実行しましょう >gcc -o rmdir rmdir.c >ls dir >./rmdir dir >ls なくなっていれば成功cat2.cの行数を確認してみる