{"id":5838,"date":"2023-04-15T00:01:11","date_gmt":"2023-04-15T07:01:11","guid":{"rendered":"https:\/\/c-for-dummies.com\/blog\/?p=5838"},"modified":"2023-04-08T12:10:24","modified_gmt":"2023-04-08T19:10:24","slug":"properly-padding-spaces-and-tab-widths","status":"publish","type":"post","link":"https:\/\/c-for-dummies.com\/blog\/?p=5838","title":{"rendered":"Properly Padding Spaces and Tab Widths"},"content":{"rendered":"<p>The task for <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=5819\">last week&#8217;s Lesson<\/a> was to convert tabs as well as spaces. The problem is that tab stops aren&#8217;t considered: On the terminal, a tab character generates a variable number of spaces based on where the next tab stop position is located. It isn&#8217;t a fixed value.<br \/>\n<!--more--><br \/>\nThe default tab stop on a Linux terminal is set to eight spaces. Like on a typewriter or word processor, when a tab character is encountered, the terminal generates spaces necessary to move the cursor to the next tab stop. In Figure 1, you see how the tab stops are set, and how spacing is calculated to position the cursor when a tab character is encountered.<\/p>\n<div id=\"attachment_5839\" style=\"width: 510px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5839\" src=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2023\/03\/0415-figure1.png\" alt=\"Terminal graphics\" width=\"500\" height=\"216\" class=\"size-full wp-image-5839\" srcset=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2023\/03\/0415-figure1.png 500w, https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2023\/03\/0415-figure1-300x130.png 300w\" sizes=\"auto, (max-width: 500px) 100vw, 500px\" \/><p id=\"caption-attachment-5839\" class=\"wp-caption-text\">Figure 1. How tab stops work on the terminal. Spaces are added to line-up text at the next interval.<\/p><\/div>\n<p>It&#8217;s possible to alter the terminal&#8217;s tab stops. The <em>tabs<\/em> command sets the interval, which means a user can adjust the tab stops to a value other than eight. For my <em>sconvert<\/em> utility, however, I assume the default value. Various trickery can be employed to obtain the current tab stop value, but that isn&#8217;t the point of this exercise.<\/p>\n<p>Two updates are required for the code to calculate the proper number of spaces to output to line up text at a tab stop. The first is to track the current cursor position or offset from the start of the line. The second is to determine how many spaces are necessary to move the cursor to the next tab stop.<\/p>\n<p>For the cursor offset, I use <em>int<\/em> variable <code>offset<\/code>. It&#8217;s initialized to zero at the start of each line, then incremented each time a character is output, which includes the <code>&amp;nbsp;<\/code> HTML code for a non-breakable space. The newline (<code>'\\n'<\/code>) and carriage return (<code>'\\r'<\/code>) characters are also intercepted to reset the <code>offset<\/code> value to zero.<\/p>\n<p>The expression I use to calculate spaces to the next tab stop is:<\/p>\n<p><code>spaces = TAB_STOP-(offset%TAB_STOP);<\/code><\/p>\n<p>The <code>offset<\/code> MOD <code>TAB_STOP<\/code> calculation must be subtracted from the <code>TAB_STOP<\/code> value to obtain the number of spaces to insert for the cursor to reach the next tab stop. The <code>spaces<\/code> value is then used to generate space characters <code>(&amp;nbsp;<\/code>) to fill the gap. Here is my updated <em>sconvert<\/em> code:<\/p>\n<h3><a href=\"https:\/\/github.com\/dangookin\/C-For-Dummies-Blog\/blob\/master\/2023_04_15-Lesson.c\" rel=\"noopener\" target=\"_blank\">2023_04_15-Lesson.c<\/a><\/h3>\n<pre class=\"screen\">\r\n#include &lt;stdio.h&gt;\r\n\r\n<span class=\"comments\">\/* assumptions *\/<\/span>\r\n#define TAB_STOP 8\r\n#define LINE_LEN 80\r\n\r\nint main()\r\n{\r\n    int ch,offset,spaces,x;\r\n\r\n    offset = 0;\r\n    while(1)\r\n    {\r\n        ch = getchar();\r\n        if( ch==EOF )\r\n            break;\r\n        switch(ch)\r\n        {\r\n            case ' ':\r\n                printf(\"&amp;nbsp;\");\r\n                offset++;\r\n                break;\r\n            case '\\t':\r\n                spaces = TAB_STOP-(offset%TAB_STOP);\r\n                for( x=0; x&lt;spaces; x++ )\r\n                {\r\n                    offset++;\r\n                    printf(\"&amp;nbsp;\");\r\n                }\r\n                break;\r\n            case '\\n':\r\n            case '\\r':\r\n                putchar(ch);\r\n                offset = 0;\r\n                break;\r\n            default:\r\n                putchar(ch);\r\n                offset++;\r\n        }\r\n        if( offset==LINE_LEN )\r\n            offset = 0;\r\n    }\r\n\r\n    return(0);\r\n}<\/pre>\n<p>The two defined constants, <code>TAB_STOP<\/code> and <code>LINE_LEN<\/code>, are assumptions based on standard terminal settings: eight-character tab stops and an 80-character line width.<\/p>\n<p>Variable <code>offset<\/code> is initialized before the endless <em>while<\/em> loop.<\/p>\n<p>The code&#8217;s <em>switch-case<\/em> structure is now more involved. Each character output modifies the <code>offset<\/code> value, with the newline and carriage return characters resetting the value.<\/p>\n<p>For the tab, variable <code>spaces<\/code> represents the spaces to move forward the cursor by using the expression outlined earlier in this post. It&#8217;s important to use this value and not <code>offset<\/code> directly as variable <code>offset<\/code> is modified within the <em>for<\/em> loop that outputs the spaces (or <code>&amp;nbsp;<\/code> HTML codes).<\/p>\n<p>After the <em>switch-case<\/em> structure, a test is made to see whether offset is greater than the line length, which happens for a long line that overflows. If so, variable <code>offset<\/code> is again reset to zero.<\/p>\n<p>Here&#8217;s a sample run, filtering output from the <em>days<\/em> program used in last week&#8217;s Lesson:<\/p>\n<p><code>Monday&nbsp;&nbsp;0<br \/>\nTuesday&nbsp;1<br \/>\nWednesday&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;2<br \/>\nThursday&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;3<br \/>\nFriday&nbsp;&nbsp;4<br \/>\nSaturday&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;5<br \/>\nSunday&nbsp;&nbsp;6<\/code><\/p>\n<div id=\"attachment_5828\" style=\"width: 285px\" class=\"wp-caption aligncenter\"><img loading=\"lazy\" decoding=\"async\" aria-describedby=\"caption-attachment-5828\" src=\"https:\/\/c-for-dummies.com\/blog\/wp-content\/uploads\/2023\/04\/0408-figure1.png\" alt=\"Screenshot\" width=\"275\" height=\"207\" class=\"size-full wp-image-5828\" \/><p id=\"caption-attachment-5828\" class=\"wp-caption-text\">Figure 1. Text output with tabs may not line up perfectly. (Tab stops set every eight positions.)<\/p><\/div>\n<p>For reference, Figure 1 is shown nearby. The output is properly converted, which means the <em>sconvert<\/em> program is one step closer to being complete. All that remains is accounting for the special characters: <code>&lt;<\/code>, <code>&gt;<\/code>, <code>&amp;<\/code>. I cover this final update in next week&#8217;s Lesson.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Beyond converting tab characters, tab stops must be accounted for. <a href=\"https:\/\/c-for-dummies.com\/blog\/?p=5838\">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-5838","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\/5838","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=5838"}],"version-history":[{"count":7,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/5838\/revisions"}],"predecessor-version":[{"id":5854,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=\/wp\/v2\/posts\/5838\/revisions\/5854"}],"wp:attachment":[{"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fmedia&parent=5838"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Fcategories&post=5838"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/c-for-dummies.com\/blog\/index.php?rest_route=%2Fwp%2Fv2%2Ftags&post=5838"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}