{"id":424,"date":"2013-12-07T00:01:01","date_gmt":"2013-12-07T08:01:01","guid":{"rendered":"http:\/\/c-for-dummies.com\/blog\/?p=424"},"modified":"2019-04-07T08:39:27","modified_gmt":"2019-04-07T15:39:27","slug":"variable-tab-width-part-ii","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=424","title":{"rendered":"Variable Tab Width, Part II"},"content":{"rendered":"<p>Last week&#8217;s <a href=\"http:\/\/c-for-dummies.com\/blog\/?p=409\">Lesson<\/a> discussed the tab character and how it&#8217;s used to line up text in a terminal window. This Lesson shows you how such a calculation is made and coded.<br \/>\n<!--more--><br \/>\nTabs are a topic of confusion mostly when it comes to word processing. The issue there is that you&#8217;re really dealing with two separate items: The tab character itself and the tab stop.<\/p>\n<p>The tab character is just that: a character. Its code is <code>0x09<\/code>, escape sequence is <code>\\t<\/code>. When that character is encountered, the word processor or terminal window reacts by jumping the cursor in a horizontal direction to the next tab stop position. The tab character doesn&#8217;t make that jump; the jump is calculated and either the cursor position is updated or spaces are output.<\/p>\n<p>For C standard output, the tabs and tab stops are calculated by the terminal. If you want to code the tab yourself, say to set your own tab stop position, you have to translate the tab character into the appropriate number of spaces to have it line up with the next tab stop. Therefore it&#8217;s necessary for your code to calculate the proper number of spaces.<\/p>\n<p>The code below is a modification of the last Lesson&#8217;s final code example, It does the superficially obvious thing, which is to translate a single tab character into 8 consecutive spaces:<\/p>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\nvoid tabby(void);\r\n\r\nint main()\r\n{\r\n    char *text[3] = {\r\n      \"\\tHello\\tHello\",\r\n      \"\\tHi\\tHi\",\r\n      \"\\tFelicitations\\tFelicitations\"\r\n    };\r\n    int x,i;\r\n\r\n    for(x=0;x<3;x++)\r\n    {\r\n        i = 0;\r\n        while(*(text[x]+i))\r\n        {\r\n            if( *(text[x]+i) == '\\t')\r\n                tabby();\r\n            else\r\n                putchar(*(text[x]+i));\r\n            i++;\r\n            i++;\r\n        }\r\n        putchar('\\n');\r\n    }\r\n\r\n    return(0);\r\n}\r\n\r\n\/* calculate and display a tab *\/\r\nvoid tabby(void)\r\n{\r\n    int t;\r\n\r\n    for(t=0;t&lt;8;t++)\r\n        putchar(' ');\r\n}<\/pre>\n<p>A simple <em>for<\/em> loop in the <em>tabby()<\/em> function generates 8 spaces each time a tab character is encountered. Here's the output:<\/p>\n<pre><code>        Hello        Hello\r\n        Hi        Hi\r\n        Felicitations        Felicitations<\/code><\/pre>\n<p>That looks radically different from this output, where the terminal handles the tab stops:<\/p>\n<pre><code>\tHello\tHello\r\n\tHi\tHi\r\n\tFelicitations\tFelicitations<\/code><\/pre>\n<p>In the code's output, tab stops are essentially ignored. Instead, each tab simply translated into 8 spaces. That's probably not the best solution.<\/p>\n<p>To best handle the tab character's output you need to code the second half of the tab equation: the tab stop.<\/p>\n<p>As an example, and what is true for most terminals, assume that tab stops are set at every eighth character position. Therefore, to calculate the tab stop, you must track the current horizontal text position. If the code can read the terminal directly, that's easy; just fetch the cursor position. Otherwise, the code has to keep track of the position virtually. Here's my solution:<\/p>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\nint tabby(int);\r\n\r\nint main()\r\n{\r\n    char *text[3] = {\r\n      \"\\tHello\\tHello\",\r\n      \"\\tHi\\tHi\",\r\n      \"\\tFelicitations\\tFelicitations\"\r\n    };\r\n    int x,i,column;\r\n\r\n    for(x=0;x&lt;3;x++)\r\n    {\r\n        i = column = 0;\r\n        while(*(text[x]+i))\r\n        {\r\n            if( *(text[x]+i) == '\\t')\r\n                column += tabby(column);\r\n            else\r\n            {\r\n                putchar(*(text[x]+i));\r\n                column++;\r\n            }\r\n            i++;\r\n        }\r\n        putchar('\\n');\r\n    }\r\n\r\n    return(0);\r\n}\r\n\r\n\/* calculate and display a tab *\/\r\nint tabby(int p)\r\n{\r\n    int t,s;\r\n\r\n    s = 8 - (p % 8);    \/* number of spaces to jump *\/\r\n    for(t=0;t&lt;s;t++)\r\n        putchar(' ');\r\n\r\n    return(s);\r\n}<\/pre>\n<p>To keep track of the text's horizontal position, I added the <em>int<\/em> variable <code>column<\/code> (Line 12), and initialized it to zero at Line 16. You might think that you could use variable <code>i<\/code>, but that's an index into the string displayed. Because of the tab characters, the index won't always accurately reflect the text's column position. That's why another variable had to be created.<\/p>\n<p>The <code>column<\/code> variable's is updated at Lines 20 and 24. That's how the code keeps track of the text's virtual position across the screen or page.<\/p>\n<p>The <em>tabby()<\/em> function had to be re-written (and re-prototyped at Line 3) to account for the text's column position. The function accepts the current position as an argument. That value is used to calculate the distance to the next tab stop. After that calculation is made, the function returns the number of spaces jumped, which is how the code keeps track of the virtual column position.<\/p>\n<p>Within the <em>tabby()<\/em> function, the number of spaces to jump is calculated at Line 39. I hard-coded 8 as the tab stop, although the function could be modified to reset the tab stop to any distance. The modulus operator is used to determine the distance to the next tab stop based on the text's current position. The result, in the range of 0 to 7, is placed in the <code>s<\/code> variable.<\/p>\n<p>A <em>for<\/em> loop at Line 40 displays the proper number of spaces. Line 43 then returns that number of spaces, so that the code can continue to properly keep track of the column position.<\/p>\n<p>In the end, the output from this modified code is the same as generated by the terminal. The bonus is that you can adjust the tab stop, setting it to a value such as 15. Here's the output in that case:<\/p>\n<pre><code>               Hello          Hello\r\n               Hi             Hi\r\n               Felicitations  Felicitations<\/code><\/pre>\n<p>I'll leave it up to you to modify the <em>tabby()<\/em> function to accept variable tab stop widths. You can edit the tab stop value directly (Line 39), or make it part of the function's arguments (hint), which would be far more flexible.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>The <em>tabby()<\/em> function displays a number of space characters designed to line up text at the next given tab stop. It&#8217;s not as easy to write as you think. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=424\">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-424","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\/424","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=424"}],"version-history":[{"count":4,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/424\/revisions"}],"predecessor-version":[{"id":3571,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/424\/revisions\/3571"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=424"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=424"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=424"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}