EDIT
問題の解決策は、Ctrl-D が実際に行っていたことを理解することでした。
新しい空の行では、単一の Ctrl-D が EOF を通知します。
ただし、行にすでに文字がある場合、最初の Ctrl-D によって、行の内容が画面にエコーされます (ただし、 には書き込まれませんSTDOUT
)。文字がすでにバッファにある場合は、2 回目の Ctrl-D を signalEOF
に発行して、バッファを に書き込む必要がありますSTDOUT
。
これは、出力をファイルにリダイレクトすることで実証できます。
編集
から入力を読み取るために fgetc() を使用していますstdin
。EOF を受け取るまでループします。ループでは、Ctrl-D が押される前に入力された文字に基づいて文字列を作成します。しかし、ch = fgetc() が読み取るバッファには EOF が含まれていないため、ループを終了する方法がわかりません。(EOF は、最初の値を返すために fgetc() のみをトリガーします。)
ungetc() は EOF をバッファにプッシュすることを許可しません。他の文字をプッシュすると、実際のデータと混同する危険性があります。私は多くの回答を読みましたが、それらはこの問題に対処していないか、実装しようとしているユースケースには当てはまりません。
stdin バッファーでカウント、ピークなどを実行できるようにしたいと考えています。
fgetc() から到着 ( edit )するたびに各文字を処理しているため、行全体 (または一度に X 文字) を読みたくありません。
このジレンマを克服する方法について何か提案はありますか? (NCurses を使用しない場合)
私はUbuntuを使用しています。EOF = Ctrl-D ここに私が取り組んでいるいくつかのコードがあります:
これは機能し、ジョナサンの単純な例と同じですが、私が望むものではありません:
int main(int argc, char **argv) {
int inputChr;
do {
inputChr = fgetc(stdin);
if (inputChr != EOF) {
fputc( inputChr, stdout);
}
if (feof(stdin)) {
if (ferror(stdin)) {
perror(NULL);
return errno;
}
}
} while (inputChr != EOF);
return EXIT_SUCCESS;
}
ただし、これはスタックしていますが、やりたいことを実行しようとしています ( edit ) が、もう一度 Ctrl-D が必要です:
char *buildLine (FILE *inputSource, char *currLine, int showTabs, int showNonPrint, int *haveLF) {
int inputChr;
char *thisLine = malloc(1);
int inputSize;
*haveLF = FALSE;
while ( (inputChr = fgetc(inputSource)) != EOF ) {
if (ferror(inputSource)) {
perror(NULL);
} else {
if (inputChr == LF) {
*haveLF = TRUE;
} else {
thisLine = strconcat(thisLine,(char *)&inputChr);
}
}
}
return thisLine;
}
質問されたその他のコード:
char * strconcat ( char *str1, char * str2) {
char *newStr = malloc(strlen(str1)+strlen(str2)+1);
if (newStr == NULL) {
return NULL;
}
strcpy(newStr,str1);
strcat(newStr,str2);
return newStr;
}
以下のこのバージョンは、入力文字を 1 文字ずつ処理し、 と同じように機能しcat
ます。しかし、実装する必要がある追加の変換を適用する前に、最初に各文字を行に処理することにしました。これによりステートマシンの設計が簡素化されましたが、(NCurses を使用せずに) ラインを構築しようとするのは適切なオプションではなかったかもしれません。:(
int echoInput( FILE *inputSource, FILE *outputDestination, int numbers, int showEnds) {
int haveNewLine = TRUE;
int lineNo = 1;
int inputChr;
do {
inputChr = fgetc(inputSource);
if (inputChr != EOF) {
if (numbers && haveNewLine) {
long lineNoSize = (long) log10(lineNo)+1; // effectively floor(log10(lineNo)+1) = number digits
char *lineNoStr = (lineNoSize<6)?malloc(8):malloc(lineNoSize+2); // If less than 6 digits, allow for minimum 6 plus tab. Also +1 for terminator.
if (lineNoStr == NULL) {
printf ("Error::Out of Memory");
return ENOMEM;
}
sprintf(lineNoStr,"%6d\t",lineNo); // format lineNo string
fputs(lineNoStr, outputDestination); // send string to output
lineNo++;
haveNewLine = FALSE;
}
if (inputChr == LF) {
if (showEnds) {
fputc('$', outputDestination); // send char to output
}
haveNewLine = TRUE;
}
fputc( inputChr, outputDestination);
}
if (feof(inputSource)) {
if (ferror(inputSource)) {
perror(NULL);
return errno;
}
}
if (ferror(outputDestination)) {
perror(NULL);
return errno;
}
} while (inputChr != EOF);
return EXIT_SUCCESS;
}