2010-12-01 16 views
7

मेरा परीक्षण आवेदन पढ़नेगैर बफरिंग stdin

#include <sys/types.h> 
#include <sys/wait.h> 
#include <signal.h> 
#include <unistd.h> 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <fcntl.h> 

int main(int argc, char *argv[], char *envp[]) { 
    int fd[2]; 

    if(pipe(fd) < 0) { 
    printf("Can\'t create pipe\n"); 
    exit(-1); 
    } 

    pid_t fpid = fork(); 
    if (fpid == 0) { 
    close(0); 
    close(fd[1]); 
    char *s = (char *) malloc(sizeof(char)); 
    while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); 
    } 
    close(fd[0]); 
    char *c = (char *) malloc(sizeof(char)); 
    while (1) { 
    if (read(0, c, 1) > 0) write(fd[1], c, 1); 
    } 
    return 0; 
} 

मैं प्रत्येक में प्रवेश किया चार के बाद चार-कोड को देखने के लिए चाहते हैं। लेकिन वास्तव में * एस को कंसोल में '\ n' के बाद ही मुद्रित किया जाता है। ऐसा लगता है जैसे stdin (desc 0 के साथ फ़ाइल) buffered है। लेकिन पढ़ा गया कार्य बफर-कम है, है ना? मैं कहाँ गलत हूँ

यूपीडी: मैं लिनक्स का उपयोग करता हूं।

तो समाधान

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <termios.h> 

int main(int argc, char *argv[], char *envp[]) { 
    int fd[2]; 

    if(pipe(fd) < 0) { 
    printf("Can\'t create pipe\n"); 
    exit(-1); 
    } 

    struct termios term, term_orig; 

    if(tcgetattr(0, &term_orig)) { 
    printf("tcgetattr failed\n"); 
    exit(-1); 
    } 

    term = term_orig; 

    term.c_lflag &= ~ICANON; 
    term.c_lflag |= ECHO; 
    term.c_cc[VMIN] = 0; 
    term.c_cc[VTIME] = 0; 

    if (tcsetattr(0, TCSANOW, &term)) { 
    printf("tcsetattr failed\n"); 
    exit(-1); 
    } 

    pid_t fpid = fork(); 
    if (fpid == 0) { 
    close(0); 
    close(fd[1]); 
    char *s = (char *) malloc(sizeof(char)); 
    while(1) if (read(fd[0], s, 1)) printf("%i\n", *s); 
    } 
    close(fd[0]); 
    char *c = (char *) malloc(sizeof(char)); 
    while (1) { 
    if (read(0, c, 1) > 0) write(fd[1], c, 1); 
    } 
    return 0; 
} 
+1

ध्यान दें कि इसमें बफरिंग के साथ कुछ लेना देना नहीं है। –

उत्तर

12

दुर्भाग्य है, व्यवहार आप देख रहे हैं मानक एएनएसआई सी के साथ संभव नहीं है, और UNIX टर्मिनल के लिए डिफ़ॉल्ट मोड मैं/हे, लाइन उन्मुख है जो इसका मतलब है कि आपको इनपुट पुनर्प्राप्त करने के लिए हमेशा एक इनपुट \n वर्ण की आवश्यकता होगी। आपको टर्मिनल I/O सुविधाओं का उपयोग करने की आवश्यकता होगी जो आपको non-canonical मोड में प्रोग्राम करने दें, ताकि प्रत्येक कुंजी-प्रेस किसी ईवेंट को ट्रिगर करे। लिनक्स/यूनिक्स पर, आप <termios.h> शीर्षलेख, या ncurses लाइब्रेरी में देख सकते हैं।

+0

लेकिन बहुत सारे ऐप्स हैं, जो यह करते हैं: मैन, विम इत्यादि – Ximik

+4

@ एक्सिमिक, हाँ और वे मानक एएनएसआई सी का उपयोग नहीं कर रहे हैं। अधिकांश बाहरी पुस्तकालयों जैसे एनसीआरएसई या टर्म कैप कैप का उपयोग नहीं करते हैं। –

2

यूनिक्स कर्नेल के अंदर अपने टीटी अक्षरों को भाग में बफर करता है ताकि प्रोग्राम को व्यक्तिगत रूप से लाइन संपादन को संभालने की आवश्यकता न हो।

आप टीटी चालक को तत्काल बाइट देने के लिए निर्देश दे सकते हैं। विभिन्न पुस्तकालय हैं जो कच्चे ioctl का उपयोग करने से थोड़ा आसान बनाते हैं। आप termios(3) से शुरू कर सकते हैं।

+2

और दुख की बात यह है कि इस कर्नेल-स्तरीय लाइन संपादन को वास्तव में प्रयोग करने योग्य बनाने के लिए कोई भी नहीं मिला ... सिद्धांत रूप में यह 'रीडलाइन' के रूप में लगभग उतना ही अच्छा हो सकता है। –

3

ऐसा लगता है कि आपका समाधान थोड़ा जटिल है। अभी भी समझ में नहीं आता क्यों आपको पाइप और 2 प्रक्रिया की आवश्यकता है।

#include <stdio.h> 
#include <stdlib.h> 
#include <unistd.h> 
#include <termios.h> 

int main(int argc, char *argv[], char *envp[]) { 
    struct termios term, term_orig; 

    if(tcgetattr(0, &term_orig)) { 
    printf("tcgetattr failed\n"); 
    exit(-1); 
    } 

    term = term_orig; 

    term.c_lflag &= ~ICANON; 
    term.c_lflag |= ECHO; 
    term.c_cc[VMIN] = 0; 
    term.c_cc[VTIME] = 0; 

    if (tcsetattr(0, TCSANOW, &term)) { 
    printf("tcsetattr failed\n"); 
    exit(-1); 
    } 

    char ch; 
    while (1) { 
    if (read(0, &ch, 1) > 0) 
     printf(" %d\n", ch); 
    } 
    return 0; 
}