1 /* ----------------------------------------------------------------------- * 2 * 3 * Copyright 2009 Erwan Velu - All Rights Reserved 4 * 5 * Permission is hereby granted, free of charge, to any person 6 * obtaining a copy of this software and associated documentation 7 * files (the "Software"), to deal in the Software without 8 * restriction, including without limitation the rights to use, 9 * copy, modify, merge, publish, distribute, sublicense, and/or 10 * sell copies of the Software, and to permit persons to whom 11 * the Software is furnished to do so, subject to the following 12 * conditions: 13 * 14 * The above copyright notice and this permission notice shall 15 * be included in all copies or substantial portions of the Software. 16 * 17 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 18 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES 19 * OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT 21 * HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 22 * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 23 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 24 * OTHER DEALINGS IN THE SOFTWARE. 25 * 26 * ----------------------------------------------------------------------- 27 * Ansi Sequences can be found here : 28 * http://ascii-table.com/ansi-escape-sequences-vt-100.php 29 * http://en.wikipedia.org/wiki/ANSI_escape_code 30 */ 31 32 #include <stdlib.h> 33 #include <stdio.h> 34 #include <string.h> 35 #include <stdbool.h> 36 #include <stdint.h> 37 38 #include "libansi.h" 39 40 void display_cursor(bool status) 41 { 42 if (status == true) { 43 fputs(CSI "?25h", stdout); 44 } else { 45 fputs(CSI "?25l", stdout); 46 } 47 } 48 49 void clear_end_of_line(void) 50 { 51 fputs(CSI "0K", stdout); 52 } 53 54 void move_cursor_left(int count) 55 { 56 char buffer[10]; 57 memset(buffer,0,sizeof(buffer)); 58 sprintf(buffer,CSI "%dD",count); 59 fputs(buffer, stdout); 60 } 61 62 void move_cursor_right(int count) 63 { 64 char buffer[10]; 65 memset(buffer,0,sizeof(buffer)); 66 sprintf(buffer, CSI "%dC", count); 67 fputs(buffer, stdout); 68 } 69 70 void set_cursor_blink(bool status) { 71 if (status == true) 72 fputs("\033[05m",stdout); 73 else 74 fputs("\033[0m",stdout); 75 } 76 77 void clear_line(void) 78 { 79 fputs(CSI "2K", stdout); 80 } 81 82 void clear_beginning_of_line(void) 83 { 84 fputs(CSI "1K", stdout); 85 } 86 87 void move_cursor_to_column(int count) 88 { 89 char buffer[10]; 90 memset(buffer,0,sizeof(buffer)); 91 sprintf(buffer, CSI "%dG", count); 92 fputs(buffer, stdout); 93 } 94 95 void move_cursor_to_next_line(void) 96 { 97 fputs("\033e", stdout); 98 } 99 100 void disable_utf8(void) 101 { 102 fputs("\033%@", stdout); 103 } 104 105 void set_g1_special_char(void){ 106 fputs("\033)0", stdout); 107 } 108 109 void set_us_g0_charset(void) 110 { 111 fputs("\033(B\1#0", stdout); 112 } 113 114 void clear_entire_screen(void) 115 { 116 fputs(CSI "2J", stdout); 117 } 118 119 /** 120 * cprint_vga2ansi - given a VGA attribute, print a character 121 * @chr: character to print 122 * @attr: vga attribute 123 * 124 * Convert the VGA attribute @attr to an ANSI escape sequence and 125 * print it. 126 * For performance, SGR parameters are cached. To reset them, 127 * call cprint_vga2ansi('0', '0'). 128 **/ 129 static void cprint_vga2ansi(const char chr, const char attr) 130 { 131 static const char ansi_char[8] = "04261537"; 132 static uint16_t last_attr = 0x300; 133 char buf[16], *p; 134 135 if (chr == '0' && attr == '0') { 136 last_attr = 0x300; 137 return; 138 } 139 140 if (attr != last_attr) { 141 bool reset = false; 142 p = buf; 143 *p++ = '\033'; 144 *p++ = '['; 145 146 if (last_attr & ~attr & 0x88) { 147 *p++ = '0'; 148 *p++ = ';'; 149 /* Reset last_attr to unknown to handle 150 * background/foreground attributes correctly */ 151 last_attr = 0x300; 152 reset = true; 153 } 154 if (attr & 0x08) { 155 *p++ = '1'; 156 *p++ = ';'; 157 } 158 if (attr & 0x80) { 159 *p++ = '4'; 160 *p++ = ';'; 161 } 162 if (reset || (attr ^ last_attr) & 0x07) { 163 *p++ = '3'; 164 *p++ = ansi_char[attr & 7]; 165 *p++ = ';'; 166 } 167 if (reset || (attr ^ last_attr) & 0x70) { 168 *p++ = '4'; 169 *p++ = ansi_char[(attr >> 4) & 7]; 170 *p++ = ';'; 171 } 172 p[-1] = 'm'; /* We'll have generated at least one semicolon */ 173 p[0] = '\0'; 174 175 last_attr = attr; 176 177 fputs(buf, stdout); 178 } 179 180 putchar(chr); 181 } 182 183 /* 184 * cls - clear and initialize the entire screen 185 * 186 * Note: when initializing xterm, one has to specify that 187 * G1 points to the alternate character set (this is not true 188 * by default). Without the initial printf "\033)0", line drawing 189 * characters won't be displayed. 190 */ 191 void cls(void) 192 { 193 fputs("\033e\033%@\033)0\033(B\1#0\033[?25l\033[2J", stdout); 194 195 /* Reset SGR parameters cache */ 196 cprint_vga2ansi('0', '0'); 197 } 198 199 void reset_colors(void) 200 { 201 csprint(CSI "1D", 0x07); 202 } 203 204 /** 205 * cprint - given a VGA attribute, print a single character at cursor 206 * @chr: character to print 207 * @attr: VGA attribute 208 * @times: number of times to print @chr 209 * 210 * Note: @attr is a VGA attribute. 211 **/ 212 void cprint(const char chr, const char attr, unsigned int times) 213 { 214 while (times--) 215 cprint_vga2ansi(chr, attr); 216 } 217 218 /** 219 * csprint - given a VGA attribute, print a NULL-terminated string 220 * @str: string to print 221 * @attr: VGA attribute 222 **/ 223 void csprint(const char *str, const char attr) 224 { 225 while (*str) { 226 cprint(*str, attr, 1); 227 str++; 228 } 229 } 230 231 /** 232 * clearwindow - fill a given a region on the screen 233 * @top, @left, @bot, @right: coordinates to fill 234 * @fillchar: character to use to fill the region 235 * @fillattr: character attribute (VGA) 236 **/ 237 void clearwindow(const char top, const char left, const char bot, 238 const char right, const char fillchar, const char fillattr) 239 { 240 char x; 241 for (x = top; x < bot + 1; x++) { 242 gotoxy(x, left); 243 cprint(fillchar, fillattr, right - left + 1); 244 } 245 } 246 247 248