{"id":6579,"date":"2024-09-28T00:01:19","date_gmt":"2024-09-28T07:01:19","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=6579"},"modified":"2024-10-05T09:55:05","modified_gmt":"2024-10-05T16:55:05","slug":"playing-with-the-terminal","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=6579","title":{"rendered":"Playing with the Terminal"},"content":{"rendered":"<p>I miss the bad old days, back when I first learned to program. The <em>microcomputers<\/em> of the day were single user, single task. The hardware was directly accessible. You can truly do some messing around, which was quite entertaining for a budding programmer.<br \/>\n<!--more--><br \/>\nOne of those early tasks I attempted on my original IBM PC was to plop an asterisk into the center of the screen. The computer then paused for a second. The program quit. If I were asked to write such a program today in Linux, I&#8217;d use the Ncurses library. Cinchy. But such a task is also possible to perform by using tricks revealed in this blog. Here are the relevant items:<\/p>\n<ol>\n<li>Discover the terminal&#8217;s row and column dimensions<\/li>\n<li>Deactivate line buffering for standard output<\/li>\n<li>Use ANSI codes to clear the screen and position the cursor<\/li>\n<li>Pause for one second<\/li>\n<li>Use ANSI codes to home the cursor<\/li>\n<\/ol>\n<p>To reveal the terminal&#8217;s row and column dimensions, I referred to <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=5730\">this previous post<\/a>. The <em>ioctl()<\/em> function handily obtains data from the current terminal window.<\/p>\n<p>Standard output is normally line buffered, which means data isn&#8217;t output until the buffer is full or a newline is encountered in the stream. You can use the <em>setvbuf()<\/em> function to disable line buffering for <em>stdout<\/em>, which means any character output appears immediately.<\/p>\n<p>I cover ANSI codes to manipulate the screen and the cursor in several posts: <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6457\">Clear the Screen<\/a> and <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6482\">manipulate the cursor<\/a> among them.<\/p>\n<p>To pause program execution, you can use the <em>sleep()<\/em> function, but it&#8217;s limited to one second intervals. But in <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=69\">this old post<\/a>, I introduce my <em>delay()<\/em> function. It uses the <em>clock()<\/em> function to obtain values in milliseconds, which are used to create a delay.<\/p>\n<p>Combining all these programming tidbits, I was able to cobble together the following program that sticks an asterisk in the center of the terminal screen and pauses one second.<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2024_09_28-Lesson.c\" rel=\"noopener\" target=\"_blank\">2024_09_28-Lesson.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n#include &lt;time.h&gt;                *\r\n#include &lt;unistd.h&gt;\r\n#include &lt;sys\/ioctl.h&gt;\r\n\r\n#define home() printf(\"\\e[H\")\r\n#define clear() printf(\"\\e[H\\e[2J\")\r\n\r\n<span class=\"comments\">\/* set the cursor to position x (columns)\r\n   and y (rows ) *\/<\/span>\r\nvoid locate(x,y)\r\n{\r\n    printf(\"\\e[%d;%dH\",y,x);\r\n}\r\n\r\n<span class=\"comments\">\/* pause for m milliseconds *\/<\/span>\r\nvoid delay(int m)\r\n{\r\n    long pause;\r\n    clock_t now,then;\r\n\r\n    pause = m*(CLOCKS_PER_SEC\/1000);\r\n    now = then = clock();\r\n    while( (now-then) &lt; pause )\r\n        now = clock();\r\n}\r\n\r\n<span class=\"comments\">\/* set an asterisk in the center of the screen *\/<\/span>\r\nint main()\r\n{\r\n    int rows,columns;\r\n    struct winsize w;\r\n    char buffer[BUFSIZ];\r\n\r\n    <span class=\"comments\">\/* obtain the window size *\/<\/span>\r\n    ioctl(STDOUT_FILENO, TIOCGWINSZ, &amp;w);\r\n    rows = w.ws_row;\r\n    columns = w.ws_col;\r\n\r\n    <span class=\"comments\">\/* remove line buffering *\/<\/span>\r\n    setvbuf(stdout,buffer,_IONBF,BUFSIZ);\r\n\r\n    <span class=\"comments\">\/* position the asterisk *\/<\/span>\r\n    clear();\r\n    locate(columns\/2,rows\/2);\r\n    putchar('*');\r\n\r\n    <span class=\"comments\">\/* wait 1 second *\/<\/span>\r\n    delay(1000);\r\n    <span class=\"comments\">\/* home the cursor *\/<\/span>\r\n    home();\r\n\r\n    return 0;\r\n}<\/pre>\n<p>The <em>home()<\/em> and <em>clear()<\/em> functions are macros that output the proper ANSI sequence to home the cursor and to clear the screen, respectively.<\/p>\n<p>The <em>locate()<\/em> function uses ANSI sequences to position the cursor at a specific row and column.<\/p>\n<p>The <em>delay()<\/em> function was lifted from an older post.<\/p>\n<p>Within the <em>main()<\/em> function, I obtain the window size with a call to the <em>ioctl()<\/em> function. Then I use <em>setvbuf()<\/em> to disable line buffering for the standard output device, making it unbuffered.<\/p>\n<p>The rest of the code positions the cursor, outputs the asterisk, and waits one second.<\/p>\n<p>This code is just a warmup. For <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6595\">next week&#8217;s Lesson<\/a>, I do some screen drawing that I would have otherwise though only possible when using a screen manipulating tool like the Ncurses library.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>How about some old fashioned terminal screen manipulation? <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=6579\">Continue reading <span class=\"meta-nav\">&rarr;<\/span><\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[2],"tags":[],"class_list":["post-6579","post","type-post","status-publish","format-standard","hentry","category-main"],"_links":{"self":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6579","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcomments&post=6579"}],"version-history":[{"count":6,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6579\/revisions"}],"predecessor-version":[{"id":6618,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/6579\/revisions\/6618"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=6579"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=6579"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=6579"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}