みけCATのにっき(仮)
つれづれなるまゝに、日くらし、PCにむかひて、心に移りゆくよしなし事を、そこはかとなく書きつくれば、あやしうこそものぐるほしけれ。
(本当か!?)
出典

catコマンドを作ってみた

アバター
みけCAT
記事: 6734
登録日時: 14年前
住所: 千葉県
連絡を取る:

catコマンドを作ってみた

投稿記事 by みけCAT » 12年前

catコマンドの自作というトピックの課題をやってみました。
まず課題をおさらいすると
1.指定されたファイル内容を順番につなげて標準出力に出力する。
  ファイル名が1つも指定されない場合は、標準入力から入力する。

2.オプションは -n, -h, -t の3種類とし、オプションの指定の順序に関係なく自由に組み合わせることが可能とする。
  -nオプション: 各行の先頭に行番号を表示。
  -hオプション: 出力開始行の指定。たとえば -h3 で3行目から出力する。
  -tオプション: 出力終了行の指定。たとえば -t5 で5行目まで表示する。

※文字列の比較には以下に示すstrncmp関数を使うこと。

  int strncmp(const char *s1, const char *s2, size_t n)
  2つの文字列s1とs2で、最初のn文字だけを較べる。この関数は、s1がs2に較べて1)小さい、2)同じ、3)大きい場合に、
  0よりも1)小さい、2)同じ、3)大きい整数を返す。

また、文字列から整数値を得るために、以下の関数を利用してもよい。

  int atoi(const char *nptr)
  atoi関数は,notrによって支持される文字列の初めの部分をint型整数に変換する。

3.エラー処理をすること。少なくとも、オプションが正しくない場合に、オプションの指定を知らせるようにする。
というものでした。

そして、自分が書いたコードはこれです。

CODE:

#include 
#include 
#include 

void doOneCat(const char* fileName,int* newLineFlag,
		int* nowLine,int start,int end,int printLineFlag) {
	FILE* fp=stdin;
	int buffer;
	if(fileName!=NULL) {
		fp=fopen(fileName,"r");
		if(fp==NULL) {
			fprintf(stderr,"error: failed to open file \"%s\"\n",fileName);
			exit(1);
		}
	}
	while((buffer=fgetc(fp))!=EOF) {
		if(*newLineFlag) {
			if(printLineFlag && start : set first line to output.\n");
	fprintf(stderr,"  -t : set last line to output.\n");
	exit(1);
}

int main(int argc,char* argv[]) {
	int argcCount;
	int start=0,end=0;
	int printLineFlag=0;
	int fileCameFlag=0;
	int nowLine=1;
	int newLineFlag=1;
	for(argcCount=1;argcCount<argc;argcCount++) {
		if(argv[argcCount][0]=='-') {
			if(argv[argcCount][1]==0) {
				fileCameFlag=1;
				doOneCat(NULL,&newLineFlag,&nowLine,start,end,printLineFlag);
			} else {
				if(fileCameFlag) {
					fprintf(stderr,"error: option cannot appear after file name.\n");
					exit(1);
				}
				if(strncmp(argv[argcCount],"-n",2)==0) {
					if(argv[argcCount][2]==0) {
				 		printLineFlag=1;
				 	} else {
				 		printUsage();
				 	}
				} else if(strncmp(argv[argcCount],"-h",2)==0) {
				 	char* last;
				 	start=strtod(&argv[argcCount][2],&last);
				 	if(*last!=0)printUsage();
				 	if(start<=0) {
				 		fprintf(stderr,"error: start line must be positive.\n");
				 		exit(1);
				 	}
				} else if(strncmp(argv[argcCount],"-t",2)==0) {
				 	char* last;
				 	end=strtod(&argv[argcCount][2],&last);
				 	if(*last!=0)printUsage();
				 	if(end<=0) {
				 		fprintf(stderr,"error: end line must be positive.\n");
				 		exit(1);
				 	}
				} else {
					printUsage();
				}
				if(end<start && end!=0) {
					fprintf(stderr,"error; start line cannot be larger than end line.\n");
					exit(1);
				}
			}
		} else {
			fileCameFlag=1;
			doOneCat(argv[argcCount],&newLineFlag,&nowLine,start,end,printLineFlag);
		}
	}
	if(!fileCameFlag)doOneCat(NULL,&newLineFlag,&nowLine,start,end,printLineFlag);
	return 0;
}
atoi関数は「利用してもよい」であり、またほかの関数を利用してはいけないとは書いていないので、利用しませんでした。
元のトピックの質問者のコードのような、バッファサイズの制限はありません!
また、「あまり褒められた実装ではない」実装(=同じコードのコピペ)を避けるため、出力動作を別関数に分ける工夫をしました。
やはりstrncmpを利用しなければならない縛りが謎ですが、条件なので仕方ないですね。
最後に改行がないファイルを入力に使うと、次のファイルが同じ行に繋がるのは仕様です。
(本物のcatもそうなっているようです)

感想、意見、改善点、バグ報告などありましたら、どしどしコメントを下さい。待ってます!

アバター
h2so5
副管理人
記事: 2212
登録日時: 14年前

Re: catコマンドを作ってみた

投稿記事 by h2so5 » 12年前

mikecatコマンド欲しい