C में टर्मिनल चौड़ाई प्राप्त करना?


89

मैं अपने C प्रोग्राम के भीतर से टर्मिनल की चौड़ाई प्राप्त करने का एक तरीका ढूंढ रहा हूं। क्या मैं साथ आ रहा हूँ कुछ की तर्ज पर है:

#include <sys/ioctl.h>
#include <stdio.h>

int main (void)
{
    struct ttysize ts;
    ioctl(0, TIOCGSIZE, &ts);

    printf ("lines %d\n", ts.ts_lines);
    printf ("columns %d\n", ts.ts_cols);
}

लेकिन हर बार कोशिश करता हूं कि मुझे मिल जाए

austin@:~$ gcc test.c -o test
test.c: In function main’:
test.c:6: error: storage size of ts isnt known
test.c:7: error: TIOCGSIZE undeclared (first use in this function)
test.c:7: error: (Each undeclared identifier is reported only once
test.c:7: error: for each function it appears in.)

क्या ऐसा करने का यह सबसे अच्छा तरीका है, या बेहतर तरीका है? यदि नहीं, तो मुझे यह काम करने के लिए कैसे मिल सकता है?

EDIT: निश्चित कोड है

#include <sys/ioctl.h>
#include <stdio.h>

int main (void)
{
    struct winsize w;
    ioctl(0, TIOCGWINSZ, &w);

    printf ("lines %d\n", w.ws_row);
    printf ("columns %d\n", w.ws_col);
    return 0;
}

1
सुझाए गए उत्तरों में से कोई भी आधा सही से अधिक नहीं है।
थॉमस डिकी

2
@ThomasDickey, तो आपका जवाब कहाँ है?
एलेक्सिस विलके

जवाबों:


126

क्या आपने गेटेनव () का उपयोग करने पर विचार किया है ? यह आपको सिस्टम के पर्यावरण चर प्राप्त करने की अनुमति देता है जिसमें टर्मिनल कॉलम और रेखाएं होती हैं।

वैकल्पिक रूप से अपनी पद्धति का उपयोग करते हुए, यदि आप यह देखना चाहते हैं कि कर्नेल टर्मिनल आकार के रूप में क्या देखता है (केस टर्मिनल में बेहतर है), तो आपको TIOCGWINSZ का उपयोग करने की आवश्यकता होगी, जैसा कि आपके TIOCGSIZE के विपरीत है, जैसे:

struct winsize w;
ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

और पूर्ण कोड:

#include <sys/ioctl.h>
#include <stdio.h>
#include <unistd.h>

int main (int argc, char **argv)
{
    struct winsize w;
    ioctl(STDOUT_FILENO, TIOCGWINSZ, &w);

    printf ("lines %d\n", w.ws_row);
    printf ("columns %d\n", w.ws_col);
    return 0;  // make sure your main returns int
}

7
हाँ, लेकिन शब्द चौड़ाई एक पर्यावरणीय चर नहीं है, शब्द के लिए इसका स्थिर होना।
आस्टिन

4
यह आपको वर्तमान टर्मिनल आकार प्रदान नहीं करता है , अगर कोई प्रोग्राम के निष्पादन के दौरान टर्मिनल का आकार बदलता है।
क्रिस जस्टर-यंग

हाँ, वह जोड़ रहा था :)
जॉन टी

पिक्सेल में आकार कैसे प्राप्त करें? मैं इस्तेमाल किया ws_xpixelऔर ws_ypixel, लेकिन यह सिर्फ शून्य प्रिंट करता है!
देबाशीष

@ देबाशीष निर्भर करता है। उदा। लिनक्स उन क्षेत्रों का बिल्कुल समर्थन नहीं करता है।
मेलेपोमिन

16

यह उदाहरण थोड़ा लंबा है, लेकिन मेरा मानना ​​है कि यह टर्मिनल आयामों का पता लगाने का सबसे पोर्टेबल तरीका है। यह भी आकार बदलने वाली घटनाओं को संभालता है।

जैसा कि टिम और आरएलबोंड बताते हैं, मैं नर्सों का उपयोग कर रहा हूं। यह सीधे पर्यावरण चर पढ़ने की तुलना में टर्मिनल संगतता में एक महान सुधार की गारंटी देता है।

#include <ncurses.h>
#include <string.h>
#include <signal.h>

// SIGWINCH is called when the window is resized.
void handle_winch(int sig){
  signal(SIGWINCH, SIG_IGN);

  // Reinitialize the window to update data structures.
  endwin();
  initscr();
  refresh();
  clear();

  char tmp[128];
  sprintf(tmp, "%dx%d", COLS, LINES);

  // Approximate the center
  int x = COLS / 2 - strlen(tmp) / 2;
  int y = LINES / 2 - 1;

  mvaddstr(y, x, tmp);
  refresh();

  signal(SIGWINCH, handle_winch);
}

int main(int argc, char *argv[]){
  initscr();
  // COLS/LINES are now set

  signal(SIGWINCH, handle_winch);

  while(getch() != 27){
    /* Nada */
  }

  endwin();

  return(0);
}

3
लेकिन क्या सिग्नल हैंडलर से इनसिट्रस और एंडविन को कॉल करना वास्तव में सुरक्षित है? वे कम से कम async-signal-safe APIs के बीच में सूचीबद्ध नहीं हैंman 7 signal
nav

1
यह एक अच्छी बात है @nav, मैंने ऐसा कभी नहीं सोचा है! एक बेहतर समाधान शायद सिग्नल हैंडलर ने एक झंडा उठाया होगा, और फिर मुख्य लूप में शेष संचालन करेंगे?
गैमन

1
@ वीमेन, हाँ, यह बेहतर होगा;) - सिग्नल के बजाय सिगनेशन का उपयोग करना भी बेहतर होगा।
बोडो थिसेन

तो क्या COLS और LINES वैश्विक चर हैं?
ईनपोकलूम

1
@AlexisWilke: सहित OKऔर ERR। उनमें से "दया" कैसे हमारे जीवन में उस अंतर को भरने में हमारी मदद करता है :-(
ईंपोक्लम

12
#include <stdio.h>
#include <stdlib.h>
#include <termcap.h>
#include <error.h>

static char termbuf[2048];

int main(void)
{
    char *termtype = getenv("TERM");

    if (tgetent(termbuf, termtype) < 0) {
        error(EXIT_FAILURE, 0, "Could not access the termcap data base.\n");
    }

    int lines = tgetnum("li");
    int columns = tgetnum("co");
    printf("lines = %d; columns = %d.\n", lines, columns);
    return 0;
}

के साथ संकलित करने की आवश्यकता है -ltermcap। कई अन्य उपयोगी जानकारी है जो आप टर्मकैप का उपयोग करके प्राप्त कर सकते हैं। info termcapअधिक विवरण के लिए उपयोग किए गए मैनुअल मैनुअल की जांच करें ।


आप इसे -lcurses के साथ भी संकलित कर सकते हैं।
कंबस

2
मुझे पता है कि यह टिप्पणी इस तथ्य के 6 साल बाद आई है, लेकिन कृपया 2048 के अपने जादुई नंबर की व्याख्या करें ...
einpoklum

1
@einpoklum यह लगभग तीन साल बाद अभी तक है, लेकिन क्या यह बिल्कुल स्पष्ट नहीं है कि 2048 बफर के लिए सिर्फ एक मनमाना आकार है कि जो भी इनपुट स्ट्रिंग हो रहा है उसके लिए "शायद बहुत बड़ा होना चाहिए"?
Roflcopter4

2
दरअसल, यह जवाब सही होने के लिए बहुत सारी धारणाएं बनाता है।
थॉमस डिकी

1
किसी भी जिज्ञासु के लिए, 2048 बफर साइज़ को GNU टर्मकैप डॉक्यूमेंटेशन में समझाया गया है: gnu.org/software/termutils/manual/termcap-1.3/html_mono/… इस पोस्ट को पढ़ने वाले लोगों को उपयोगी लगने वाले अन्य सामानों में भी बहुत कुछ है। ।

3

यदि आपके पास ncurses स्थापित है और इसका उपयोग कर रहे हैं, तो आप getmaxyx()टर्मिनल के आयामों को खोजने के लिए उपयोग कर सकते हैं ।


2
हाँ, और ध्यान दें कि Y पहले आता है और फिर X.
डैनियल

0

यह मानते हुए कि आप लिनक्स पर हैं, मुझे लगता है कि आप इसके बजाय ncurses लाइब्रेरी का उपयोग करना चाहते हैं । मुझे पूरा यकीन है कि ttysize सामान आपके पास stdlib में नहीं है।


अच्छी तरह से, मैं क्या कर रहा हूँ वास्तव में के लिए ncurses स्थापित करने के लायक नहीं है
ऑस्टिन

ncurses stdlib में नहीं है। दोनों POSIX में मानकीकृत हैं, लेकिन इसका ioctlतरीका सरल और साफ-सुथरा है, क्योंकि आपको शाप आदि को आरंभ करने की आवश्यकता नहीं है
गैंडारो

0

तो यहाँ एक उत्तर का सुझाव नहीं है, लेकिन:

linux-pc:~/scratch$ echo $LINES

49

linux-pc:~/scratch$ printenv | grep LINES

linux-pc:~/scratch$

ठीक है, और मुझे लगता है कि अगर मैं गनोम टर्मिनल का आकार बदलता हूं, तो LINES और COLUMNS चर इसका अनुसरण करते हैं।

Kinda लगता है जैसे गनोम टर्मिनल इन पर्यावरण चर खुद बना रहा है?


1
और यकीन है कि यह सी कोड के लिए नीचे पारित नहीं करता है। getenv ("LINES") NULL देता है।
स्कॉट फ्रेंको

चर एक शेल चीज़ हैं, न कि टर्मिनल चीज़।
मेलेपोमिन

0

अधिक पूर्ण उत्तर जोड़ने के लिए, मुझे जो कुछ भी मेरे लिए काम करने के लिए मिला है वह रोसेट्टा कोड से जोड़े गए कुछ बिट्स के साथ @ जॉन के समाधान का उपयोग करने के लिए है , साथ ही कुछ निर्भरता का पता लगाने में कुछ समस्या निवारण के साथ। यह थोड़ा अक्षम हो सकता है, लेकिन स्मार्ट प्रोग्रामिंग के साथ आप इसे काम कर सकते हैं और हर समय अपनी टर्मिनल फ़ाइल नहीं खोल सकते हैं।

#include <stdio.h>
#include <stdlib.h>
#include <sys/ioctl.h> // ioctl, TIOCGWINSZ
#include <err.h>       // err
#include <fcntl.h>     // open
#include <unistd.h>    // close
#include <termios.h>   // don't remember, but it's needed

size_t* get_screen_size()
{
  size_t* result = malloc(sizeof(size_t) * 2);
  if(!result) err(1, "Memory Error");

  struct winsize ws;
  int fd;

  fd = open("/dev/tty", 0_RDWR);
  if(fd < 0 || ioctl(fd, TIOCGWINSZ, &ws) < 0) err(8, "/dev/tty");

  result[0] = ws.ws_row;
  result[1] = ws.ws_col;

  close(fd);

  return result;
}

यदि आप यह सुनिश्चित करते हैं कि यह सब कॉल न हो, लेकिन हो सकता है कि थोड़ी देर में आप ठीक हो जाएं, तो यह तब भी अपडेट होना चाहिए जब उपयोगकर्ता टर्मिनल विंडो का आकार बदल दे (क्योंकि आप फ़ाइल खोल रहे हैं और इसे हर बार पढ़ रहे हैं )।

यदि आप TIOCGWINSZइस फॉर्म का पहला उत्तर https://www.linuxquestions.org/questions/programming-9/get-width-height-of-a-terminal-window-in-c-810739/ पर नहीं देख रहे हैं ।

ओह, और करने के लिए मत भूलना ।free()result


-1

यहाँ पहले से सुझाई गई पर्यावरणीय परिवर्तनशील चीज़ों के लिए फ़ंक्शन कॉल हैं:

int lines = atoi(getenv("LINES"));
int columns = atoi(getenv("COLUMNS"));

11
पर्यावरण चर विश्वसनीय नहीं हैं। ये मान शेल द्वारा सेट किए गए हैं, इसलिए उन्हें अस्तित्व की गारंटी नहीं है। यदि उपयोगकर्ता टर्मिनल आकार में परिवर्तन करता है, तो भी वे अद्यतित नहीं होंगे।
जुलियानो

1
कई गोले SIGWINCHसिग्नल के लिए एक हैंडलर स्थापित करते हैं , इसलिए वे चर को अद्यतित रख सकते हैं (उन्हें इसकी आवश्यकता भी होती है ताकि वे इनपुट संपादक में उचित लाइन रैपिंग कर सकें)।
बारमर

5
वे अच्छी तरह से ऐसा कर सकते हैं, लेकिन एक कार्यक्रम के वातावरण को अपडेट नहीं किया जाएगा क्योंकि यह चल रहा है।
फंपीनो

बेशक, यह कोड क्रैश होने की संभावना है क्योंकि आप यह परीक्षण नहीं करते हैं कि क्या getenv()NULL लौटाता है या नहीं और यह मेरे लिनक्स टर्मिनल में होता है (क्योंकि उन वेरिएबल्स को निर्यात नहीं किया जाता है।) भले ही शेल उन वेरिएबल्स को अपडेट करता हो, तो भी आपको नहीं दिखाई देगा। जब आपका प्रोग्राम चल रहा हो तब बदलाव करें (बिना आपके अपने SIGWINCHहैंडलर के)।
एलेक्सिस विलके
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.