2013-10-03 1 views
4

내 프로그램은 C++로 작성하려고하는 일반적인 셸입니다. 명령 줄에서 명령을받는 것 외에도 명령을 파일에서 읽을 수 있어야합니다. 파일 이름은 리디렉션이 아닌 선택적 arg로 전달됩니다.ifstream이 stdin에 연결되어 있는지 확인하는 멋진 방법이 있습니까?

arg가 있으면 전달 된 파일 이름을 열고 그렇지 않으면 "/ dev/stdin"을 엽니 다. 나는 dev 파일을 여는 것에 대해 흥분하지 않고 나의 주된 질문은 아니지만 누군가가 더 좋은 방법을 가지고 있다면 나는 그것을 듣고 싶어한다.

결국 셸에 주어진 명령을 읽어야하지만 입력이 파일에서 오는 경우 프롬프트를 건너 뛰거나 프롬프트를 건너 뛰려면 먼저 프롬프트를 제시해야합니다. 내 질문은 : getCommand에서 입력 스트림이 전역인지 또는 bool 또는 이와 유사한 해킹을 전달하는 것보다 더 좋은지 결정하는 더 좋은 방법이 있습니까?

내가 어떻게 든 std :: cin을/dev 파일을 열지 않고 사용할 수 있다면 스트림을 istream으로 전달할 수있다. 그 둘을 쉽게 구별 할 수 있을까요? E.G. if (source == cin)?

모든 제안을 주셔서 감사합니다. 당신이 당신의 변수의 유형으로 std::istream&를 사용하는 경우

bool getCommand(ifstream source, std::string command) 
{ 
    if (source == stdin) 
     //print prompt to stdout 

    // do the rest of stuff 

    return true; 
} 


int main(int argc, char *argv[]) 
{ 
    std::ifstream input; 
    std::string command; 

    if (argc == 2) 
    { 
     input.open(argv[1], std::ifstream::in); 

     if (! input) 
     { 
      perror("input command file stream open"); 
      exit(EXIT_FAILURE); 
     } 
    } 
    else 
    { 
     input.open("/dev/stdin", std::ifstream::in); 

     if (! input) 
     { 
      perror("input stdin stream open"); 
      exit(EXIT_FAILURE); 
     } 
    } 

    //....... 

    if (getCommand(input, command)) 
     //....... 
} 
+1

는 "나는 내가 표준 입력에서 읽고 있습니다 경우 프롬프트를 제시해야"-이 잘못된 상태 것 같다 . 터미널에서 읽는 중이면 프롬프트를 제시해야합니다. 누군가에게 파이핑을하거나 프로그램으로 입력을 리디렉션하는 특별한 코드를 작성하는 것은 반 사회적입니다 :-) –

+0

예, 터미널 인 입력을 찾습니다. bash로 소스 코드를 사용하여 사용할 함수를 찾을 수 있습니다. 또는 bash 쉘을 strace하여 파일 디스크립터 0을 확인하기 위해 무엇을 호출하는지 확인하십시오. –

+0

예제 코드에는 다른 많은 문제점이 있습니다. std :: ifstream을 값으로 전달하고, out 매개 변수 일 때 참조로 std :: string을 전달하지 않습니다. – goji

답변

3

당신은 대신 개방 /dev/stdinstd::cin를 사용할 수 있습니다

std::ifstream fileinput; 
if (argc == 2) 
{ 
    fileinput.open(argv[1], std::ifstream::in); 

    if (! fileinput) 
    { 
     perror("input command file stream open"); 
     exit(EXIT_FAILURE); 
    } 
} 
std::istream &input = (argc == 2) ? fileinput : std::cin; 

질문 의 나머지 부분을 청각 장애를 식별에 대해해야한다 (Detect if stdin is a terminal or pipe?를) . 그러나 위의 변경 한 후에는 std::cin의 주소와 비교할 수 있다는 실패 : 분명히 그 명령 행 인수가 /dev/stdin 인 경우를 식별하지 않습니다

if (&input == &std::cin) { 
    std::cout << "prompt:"; 
} 

, 그래서는 약간의 교묘히 피하다. 그러나 나는 누군가가 최소한 yourprogram /dev/stdin < input.txt 또는 sort input.txt | yourprogram /dev/stdin을 작성하여 제한 사항을 해결하고 프롬프트를 피할 수 있기 때문에 재미있는 요구 사항이 실제로 개선되었다고 주장 할 것입니다 :-)

2

먼저, 원하는 경우 내가 std::istream의 관점에서 작업을 구현하는 것이, std::cin에서 또는 std::ifstream에서 하나 읽고 확실히 피하기 개방 /dev/stdin : 당신이 실제로가 충분하지 않다 프롬프트를 작성해야하는 경우 지금

std::istream in(std::cin.rdbuf()); 
std::ifstream fin; 
if (argc == 2) { 
    fin.open(av[1]); 
    // check that the file is actually open or produce an error 
    in.rdbuf(fin.rdbuf()); 
} 
else { 
    // determine if you need to create a prompt 
} 

if (getCommand(in, command)) { 
    ... 
} 

는 결정 표준 입력에서 읽는 지 여부를 결정할 수 있지만 표준 입력은 화면과 키보드로 무언가에 연결됩니다. 그러나 이식성있는 방법은 없습니다. 유닉스에는 파일 디스크립터 0이 tty에 연결되어 있는지를 결정하는 데 사용할 수있는 isatty()과 같은 함수가 있습니다. 당신은 당신이 std::ostream에 매여 사용자 정의 std::streambuf를 만들 수 있습니다 공상을 얻고 싶은 경우에

static int const needs_prompt = std::ios_base::xalloc(); 
... 
in.iword(needs_prompt) = isatty(0); 
... 
if (in.iword(needs_prompt)) { 
    std::cout << "pompt>"; 
} 

: 나는 스트림이 프롬프트가 필요한 경우 다음 확인하는 데 사용할 수있는 iword()을 설정하려면이 정보를 사용합니다 입력 스트림 스트림에 대해 tie()이고 입력 프롬프트 스트림에 tie() ed std::ostream이 플러시 될 때마다 프롬프트가 씁니다. sync() : 입력 스트림에 대한 읽기 작업이 완료 될 때마다 tie() ed 플러시가 플러시됩니다.그러나 이렇게하려면 생성되는 각 프롬프트에 대해 한 번만 읽어야합니다. std::getline(in, line)을 사용하십시오. 당연히 프롬프트가 필요하지 않으면 tie()std::ostream을 입력하지 않아도됩니다. 다음 (다른 사업의 수행하지 않고) 자동 프롬프트 접근 방법을 보여주는 간단한 프로그램입니다 :

#include <iostream> 
#include <streambuf> 

struct prompt 
    : std::streambuf 
{ 
    std::string d_prompt; 
    std::ostream& d_out; 
    prompt(std::string const& p, std::ostream& out) 
     : d_prompt(p) 
     , d_out(out) 
    { 
    } 
    int sync() { 
     this->d_out << this->d_prompt << std::flush; 
     return 0; 
    } 
}; 

int main() 
{ 
    prompt  p("prompt>", std::cout); 
    std::ostream helper(&p); 
    std::cin.tie(&helper); 

    for (std::string line; std::getline(std::cin, line);) { 
     std::cout << "read '" << line << "'\n"; 
    } 
} 
관련 문제