编辑
问题的解决方案是了解 Ctrl-D 实际在做什么。
在新的空行上,单个 Ctrl-D 将发出 EOF 信号。
但如果该行中已有字符,则第一个 Ctrl-D 会使该行的内容回显到屏幕(但不写入STDOUT
)。如果字符已经在缓冲区中,则必须向 发出第二个 Ctrl-D 信号EOF
,从而将缓冲区写入STDOUT
。
这可以通过将输出重定向到文件来证明。
编辑
我正在使用 fgetc() 从stdin
. 我循环直到收到 EOF。在循环中,我根据在按下 Ctrl-D 之前键入的字符构建一个字符串。但我无法找出退出循环的方法,因为从中读取的缓冲区 ch = fgetc() 不包含 EOF。(EOF 只触发 fgetc() 返回它的第一个值。)
ungetc() 不允许将 EOF 推入缓冲区,推入任何其他字符都有与真实数据混淆的风险,我被卡住了!我已经阅读了很多答案,但它们没有解决这个问题或不适用于我试图实现的用例。
我希望能够在标准输入缓冲区上计数、窥视等。
我真的不想读一整行(或一次 X 个字符),因为我正在处理从 fgetc()到达(编辑)的每个字符。
关于如何克服这一困境的任何建议?(不使用 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;
}
但是,这被卡住了,但正在尝试做我想做的事情(编辑),但需要 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;
}
下面的这个版本会逐个字符地处理输入的字符,并且工作起来就像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;
}