সি তে টার্মিনাল প্রস্থ পাচ্ছেন?


91

আমি আমার সি প্রোগ্রামের মধ্যে থেকে টার্মিনাল প্রস্থ পাওয়ার জন্য একটি উপায় খুঁজছি। আমি যা নিয়ে আসছি তা হ'ল লাইন দিয়ে কিছু:

#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’ isn’t 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.)

এটি করার এটি কি সেরা উপায়, না এর থেকে আরও ভাল উপায় আছে? যদি না হয় তবে আমি কীভাবে এটি কাজ করতে পারি?

সম্পাদনা: স্থির কোড হয়

#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;
}

4
প্রস্তাবিত উত্তরগুলির কোনওটিই অর্ধেকের বেশি সঠিক নয়।
টমাস ডিকি

4
@ থমাসডিকি, আপনার উত্তর কোথায়?
অ্যালেক্সিস উইল্ক

উত্তর:


127

আপনি getenv () ব্যবহার বিবেচনা করেছেন ? এটি আপনাকে সিস্টেমের পরিবেশের ভেরিয়েবলগুলি পেতে দেয় যা টার্মিনাল কলাম এবং লাইন ধারণ করে।

বিকল্পভাবে আপনার পদ্ধতিটি ব্যবহার করে, যদি আপনি দেখতে চান যে কার্নেলটি টার্মিনাল আকার হিসাবে কী দেখছে (টার্মিনাল পুনরায় আকার দেওয়ার ক্ষেত্রে আরও ভাল), আপনার TIOCGSINZE এর বিপরীতে, TIOCGWINSZ ব্যবহার করা দরকার:

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
হ্যাঁ তবে শব্দটির প্রস্থ কোনও পরিবেশগত পরিবর্তনশীল নয়, পদটির স্থায়ী ic
অস্টিন

4
প্রোগ্রামের সঞ্চালনের সময় কেউ যদি টার্মিনালের আকার পরিবর্তন করে তবে এটি আপনাকে বর্তমান টার্মিনাল আকার দেয় না ।
ক্রিস জেস্টার-ইয়ং

হ্যাঁ, যোগ করা হয়েছে :)
জন টি

পিক্সেল আকারে পেতে কিভাবে? আমি ব্যবহার করেছি ws_xpixelএবং ws_ypixel, তবে এটি কেবল শূন্যগুলি প্রিন্ট করে!
দেবাশীষ

@ দেবাশিষ নির্ভর করে। যেমন লিনাক্স সেই ক্ষেত্রগুলিকে মোটেই সমর্থন করে না।
মেলপোমেন

16

এই উদাহরণটি লম্বা দিক থেকে কিছুটা হলেও আমি বিশ্বাস করি এটি টার্মিনালের মাত্রা সনাক্তকরণের সর্বাধিক বহনযোগ্য উপায়। এটি পুনরায় আকারের ইভেন্টগুলি পরিচালনা করে।

টাইম এবং আরলবন্ডের পরামর্শ অনুসারে, আমি ncurses ব্যবহার করছি। এটি সরাসরি পরিবেশের ভেরিয়েবলগুলি পড়ার তুলনায় টার্মিনাল সামঞ্জস্যতার একটি দুর্দান্ত উন্নতির গ্যারান্টি দেয়।

#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);
}

4
তবে কি সিগন্যাল হ্যান্ডলার থেকে ইনসাইটকার এবং এন্ডউইন কল করা সত্যিই নিরাপদ? তারা অন্তত না ASYNC-সংকেত-নিরাপদ API গুলি মধ্যে তালিকাভুক্ত করছিman 7 signal
এনএভি

4
এটি একটি ভাল পয়েন্ট @ নাভ, আমি কখনই এটি সম্পর্কে ভেবে দেখিনি ! সিগন্যাল হ্যান্ডলারটি একটি পতাকা বাড়াতে এবং তারপরে বাকী অপারেশনগুলি মূল লুপটিতে সম্পাদন করাই সম্ভবত আরও ভাল সমাধান হতে পারে?
গেমন

4
@ গেমেন, হ্যাঁ, এটি আরও ভাল হবে;) - সিগন্যালের পরিবর্তে সিগিকেশন ব্যবহার করাও ভাল।
বোডো থিয়েসন

তাহলে কি সিওএলএস এবং লাইনগুলি বিশ্বব্যাপী পরিবর্তনশীল?
einpoklum

4
@ অ্যালেক্সিসওয়িল্ক: সহ 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 দিয়েও সংকলন করতে পারেন।
কাম্বুস

4
আমি জানি এই মন্তব্যটি সত্যের 6 বছর পরে আসে, তবে দয়া করে আপনার 2048 এর যাদু নম্বরটি ব্যাখ্যা করুন ...
einpoklum

4
@ আইনপোকলুম এটি প্রায় তিন বছর পরে এখনও রয়েছে, তবে এটি কি মোটেও পরিষ্কার নয় যে 2048 কেবল বাফারের জন্য একটি স্বেচ্ছাসেবী আকার যা সেখানে ইনপুট স্ট্রিং যা চলছে তার জন্য "সম্ভবত যথেষ্ট বড় হওয়া উচিত"?
Roflcopter4

4
আসলে, এই উত্তরটি সঠিক হওয়ার জন্য অনেক বেশি অনুমান করে।
টমাস ডিকি

4
কৌতূহলী কারও জন্য, 2048 বাফার আকারটি এখানে জিএনইউ টার্মক্যাপ ডকুমেন্টেশনে ব্যাখ্যা করা হয়েছে: gnu.org/software/termutils/manual/termcap-1.3/html_mono/… এই পোস্টে পড়া লোকেরা দরকারী খুঁজে পেতে পারে সেখানে প্রচুর অন্যান্য স্টাফ রয়েছে ।

3

যদি আপনার এনক্রেন্স ইনস্টল থাকে এবং এটি ব্যবহার করে থাকেন তবে আপনি getmaxyx()টার্মিনালের মাত্রাগুলি খুঁজে পেতে ব্যবহার করতে পারেন ।


4
হ্যাঁ, এবং নোট করুন যে Y প্রথমে আসে এবং তারপরে এক্স
ড্যানিয়েল

0

ধরে নিই যে আপনি লিনাক্সে রয়েছেন , আমি মনে করি আপনি পরিবর্তে ncurses লাইব্রেরিটি ব্যবহার করতে চান । আমি নিশ্চিত যে আপনার কাছে থাকা টিটিসাইজ স্টাফ স্টাডলিবায় নেই।


ঠিক আছে, আমি যা করছি তা সত্যিই ncurses স্থাপনের জন্য উপযুক্ত নয়
অস্টিন

ncurses হয় না stdlib। উভয়ই ioctl
পসিএক্সে মানীকৃত

0

সুতরাং এখানে একটি উত্তর প্রস্তাব না, কিন্তু:

linux-pc:~/scratch$ echo $LINES

49

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

linux-pc:~/scratch$

ঠিক আছে, এবং আমি লক্ষ্য করেছি যে আমি যদি জিনোম টার্মিনালের আকার পরিবর্তন করি তবে লাইনগুলি এবং COLUMNS ভেরিয়েবলগুলি এটি অনুসরণ করে।

কিন্ডাকে দেখে মনে হচ্ছে জিনোম টার্মিনাল নিজেই এই পরিবেশের পরিবর্তনশীল তৈরি করছে?


4
এবং নিশ্চিতভাবেই এটি সি কোডে প্রবেশ করে না। গেটেনভ ("লাইনস") নুল দেয়।
স্কট ফ্রাঙ্কো

চলকগুলি একটি শেল জিনিস, টার্মিনাল জিনিস নয়।
মেলপোমেন

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
পরিবেশের ভেরিয়েবলগুলি নির্ভরযোগ্য নয়। এই মানগুলি শেল দ্বারা সেট করা হয়, তাই এগুলির অস্তিত্বের নিশ্চয়তা নেই। এছাড়াও, যদি ব্যবহারকারী টার্মিনালের আকার পরিবর্তন করে তবে সেগুলি আপ টু ডেট হবে না।
জুলিয়ানো

4
অনেকগুলি শেল SIGWINCHসংকেতটির জন্য একটি হ্যান্ডলার স্থাপন করে , যাতে তারা ভেরিয়েবলগুলি আপ টু ডেট রাখতে পারে (তাদের এটির প্রয়োজনও হয় যাতে তারা ইনপুট সম্পাদকটিতে সঠিক লাইন মোড়ানো করতে পারে)।
বার্মার

4
তারা এটি ভালভাবে করতে পারে তবে কোনও প্রোগ্রামের পরিবেশ চলমান হিসাবে আপডেট হবে না।
Functino

অবশ্যই, কোডটি ক্র্যাশ হওয়ার খুব সম্ভাবনা রয়েছে কারণ আপনি পরীক্ষা করেন না যে getenv()NUL দেয় কি না এবং এটি আমার লিনাক্স টার্মিনালে আসে (কারণ সেই পরিবর্তনগুলি রফতানি হয় না)) এছাড়াও শেলটি যদি এই ভেরিয়েবলগুলি আপডেট করে তবে আপনি দেখতে পাবেন না আপনার প্রোগ্রামটি চলাকালীন পরিবর্তিত হয় (আপনার নিজের SIGWINCHহ্যান্ডলারটি ছাড়া না )।
অ্যালেক্সিস উইল্ক
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.