home *** CD-ROM | disk | FTP | other *** search
/ Chip 2005 August (Alt) / CHIP 2005-08.1.iso / program / guvenlik / syslinux-3.07.exe / com32 / lib / sys / ansicon_write.c next >
Encoding:
C/C++ Source or Header  |  2005-01-05  |  10.9 KB  |  539 lines

  1. #ident "$Id: ansicon_write.c,v 1.9 2005/01/05 07:45:23 hpa Exp $"
  2. /* ----------------------------------------------------------------------- *
  3.  *   
  4.  *   Copyright 2004 H. Peter Anvin - All Rights Reserved
  5.  *
  6.  *   Permission is hereby granted, free of charge, to any person
  7.  *   obtaining a copy of this software and associated documentation
  8.  *   files (the "Software"), to deal in the Software without
  9.  *   restriction, including without limitation the rights to use,
  10.  *   copy, modify, merge, publish, distribute, sublicense, and/or
  11.  *   sell copies of the Software, and to permit persons to whom
  12.  *   the Software is furnished to do so, subject to the following
  13.  *   conditions:
  14.  *   
  15.  *   The above copyright notice and this permission notice shall
  16.  *   be included in all copies or substantial portions of the Software.
  17.  *   
  18.  *   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
  19.  *   EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
  20.  *   OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
  21.  *   NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
  22.  *   HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
  23.  *   WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  24.  *   FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
  25.  *   OTHER DEALINGS IN THE SOFTWARE.
  26.  *
  27.  * ----------------------------------------------------------------------- */
  28.  
  29. /*
  30.  * ansicon_write.c
  31.  *
  32.  * Write to the screen using ANSI control codes (about as capable as
  33.  * DOS' ANSI.SYS.)
  34.  */
  35.  
  36. #include <errno.h>
  37. #include <string.h>
  38. #include <com32.h>
  39. #include <minmax.h>
  40. #include <klibc/compiler.h>
  41. #include "file.h"
  42.  
  43. struct curxy {
  44.   uint8_t x, y;
  45. } __attribute__((packed));
  46. #define BIOS_CURXY ((struct curxy *)0x450) /* Array for each page */
  47. #define BIOS_ROWS (*(uint8_t *)0x484)      /* Minus one; if zero use 24 (= 25 lines) */
  48. #define BIOS_COLS (*(uint16_t *)0x44A)
  49. #define BIOS_PAGE (*(uint8_t *)0x462)
  50.  
  51. enum ansi_state {
  52.   st_init,            /* Normal (no ESC seen) */
  53.   st_esc,            /* ESC seen */
  54.   st_csi,            /* CSI seen */
  55. };
  56.  
  57. #define MAX_PARMS    16
  58.  
  59. struct term_state {
  60.   int disabled;
  61.   int attr;            /* Current display attribute */
  62.   int vtgraphics;        /* VT graphics on/off */
  63.   int intensity;
  64.   int underline;
  65.   int blink;
  66.   int reverse;
  67.   int fg;
  68.   int bg;
  69.   int autocr;
  70.   struct curxy saved_xy;
  71.   uint16_t cursor_type;
  72.   enum ansi_state state;
  73.   int pvt;            /* Private code? */
  74.   int nparms;            /* Number of parameters seen */
  75.   int parms[MAX_PARMS];
  76. };
  77.  
  78. static const struct term_state default_state =
  79. {
  80.   .disabled = 0,
  81.   .attr = 0x07,            /* Grey on black */
  82.   .vtgraphics = 0,
  83.   .intensity = 1,
  84.   .underline = 0,
  85.   .blink = 0,
  86.   .reverse = 0,
  87.   .fg = 7,
  88.   .bg = 0,
  89.   .autocr = 0,
  90.   .saved_xy = { 0, 0 },
  91.   .cursor_type = 0x0607,
  92.   .state = st_init,
  93.   .pvt = 0,
  94.   .nparms = 0,
  95. };
  96.  
  97. static struct term_state st;
  98.  
  99. /* DEC VT graphics to codepage 437 table (characters 0x60-0x7F only) */
  100. static const char decvt_to_cp437[] =
  101.   { 0004, 0261, 0007, 0007, 0007, 0007, 0370, 0361, 0007, 0007, 0331, 0277, 0332, 0300, 0305, 0304,
  102.     0304, 0304, 0137, 0137, 0303, 0264, 0301, 0302, 0263, 0363, 0362, 0343, 0330, 0234, 0007, 00 };
  103.  
  104. /* Common setup */
  105. static void __constructor ansicon_init(void)
  106. {
  107.   static com32sys_t ireg;    /* Auto-initalized to all zero */
  108.   com32sys_t oreg;
  109.  
  110.   /* Initial state */
  111.   memcpy(&st, &default_state, sizeof st);
  112.  
  113.   /* Are we disabled? */
  114.   ireg.eax.w[0] = 0x000b;
  115.   __intcall(0x22, &ireg, &oreg);
  116.  
  117.   if ( (signed char)oreg.ebx.b[1] < 0 ) {
  118.     st.disabled = 1;
  119.     return;
  120.   }
  121.  
  122.   /* Force text mode */
  123.   ireg.eax.w[0] = 0x0005;
  124.   __intcall(0x22, &ireg, NULL);
  125.  
  126.   /* Get cursor shape */
  127.   ireg.eax.b[1] = 0x03;
  128.   ireg.ebx.b[1] = BIOS_PAGE;
  129.   __intcall(0x10, &ireg, &oreg);
  130.   st.cursor_type = oreg.ecx.w[0];
  131. }
  132.  
  133. /* Erase a region of the screen */
  134. static void ansicon_erase(int x0, int y0, int x1, int y1)
  135. {
  136.   static com32sys_t ireg;
  137.   
  138.   ireg.eax.w[0] = 0x0600;    /* Clear window */
  139.   ireg.ebx.b[1] = st.attr;    /* Fill with current attribute */
  140.   ireg.ecx.b[0] = x0;
  141.   ireg.ecx.b[1] = y0;
  142.   ireg.edx.b[0] = x1;
  143.   ireg.edx.b[1] = y1;
  144.   __intcall(0x10, &ireg, NULL);
  145. }
  146.  
  147. /* Show or hide the cursor */
  148. static void showcursor(int yes)
  149. {
  150.   static com32sys_t ireg;
  151.  
  152.   ireg.eax.b[1] = 0x01;
  153.   ireg.ecx.w[0] = yes ? st.cursor_type : 0x2020;
  154.   __intcall(0x10, &ireg, NULL);
  155. }
  156.  
  157. static void ansicon_putchar(int ch)
  158. {
  159.   static com32sys_t ireg;
  160.   const int rows  = BIOS_ROWS ? BIOS_ROWS+1 : 25;
  161.   const int cols  = BIOS_COLS;
  162.   const int page  = BIOS_PAGE;
  163.   struct curxy xy = BIOS_CURXY[page];
  164.  
  165.   switch ( st.state ) {
  166.   case st_init:
  167.     switch ( ch ) {
  168.     case '\b':
  169.       if ( xy.x > 0 ) xy.x--;
  170.       break;
  171.     case '\t':
  172.       {
  173.     int nsp = 8 - (xy.x & 7);
  174.     while ( nsp-- )
  175.       ansicon_putchar(' ');
  176.       }
  177.       return;            /* Cursor already updated */
  178.     case '\n':
  179.     case '\v':
  180.     case '\f':
  181.       xy.y++;
  182.       if ( st.autocr )
  183.     xy.x = 0;
  184.       break;
  185.     case '\r':
  186.       xy.x = 0;
  187.       break;
  188.     case 127:
  189.       /* Ignore delete */
  190.       break;
  191.     case 14:
  192.       st.vtgraphics = 1;
  193.       break;
  194.     case 15:
  195.       st.vtgraphics = 0;
  196.       break;
  197.     case 27:
  198.       st.state = st_esc;
  199.       break;
  200.     default:
  201.       /* Print character */
  202.       if ( ch >= 32 ) {
  203.     if ( st.vtgraphics && (ch & 0xe0) == 0x60 )
  204.       ch = decvt_to_cp437[ch - 0x60];
  205.  
  206.     ireg.eax.b[1] = 0x09;
  207.     ireg.eax.b[0] = ch;
  208.     ireg.ebx.b[1] = page;
  209.     ireg.ebx.b[0] = st.attr;
  210.     ireg.ecx.w[0] = 1;
  211.     __intcall(0x10, &ireg, NULL);
  212.     xy.x++;
  213.       }
  214.       break;
  215.     }
  216.     break;
  217.       
  218.   case st_esc:
  219.     switch ( ch ) {
  220.     case '%':
  221.     case '(':
  222.     case ')':
  223.     case '#':
  224.       /* Ignore this plus the subsequent character, allows
  225.      compatibility with Linux sequence to set charset */
  226.       break;
  227.     case '[':
  228.       st.state = st_csi;
  229.       st.nparms = st.pvt = 0;
  230.       memset(st.parms, 0, sizeof st.parms);
  231.       break;
  232.     case 'c':
  233.       /* Reset terminal */
  234.       memcpy(&st, &default_state, sizeof st);
  235.       ansicon_erase(0, 0, cols-1, rows-1);
  236.       xy.x = xy.y = 1;
  237.       break;
  238.     default:
  239.       /* Ignore sequence */
  240.       st.state = st_init;
  241.       break;
  242.     }
  243.     break;
  244.       
  245.   case st_csi:
  246.     {
  247.       int p0 = st.parms[0] ? st.parms[0] : 1;
  248.  
  249.       if ( ch >= '0' && ch <= '9' ) {
  250.     st.parms[st.nparms] = st.parms[st.nparms]*10 + (ch-'0');
  251.       } else if ( ch == ';' ) {
  252.     st.nparms++;
  253.     if ( st.nparms >= MAX_PARMS )
  254.       st.nparms = MAX_PARMS-1;
  255.     break;
  256.       } else if ( ch == '?' ) {
  257.     st.pvt = 1;
  258.       } else {
  259.     switch ( ch ) {
  260.     case 'A':
  261.       {
  262.         int y = xy.y - p0;
  263.         xy.y = (y < 0) ? 0 : y;
  264.       }
  265.       break;
  266.     case 'B':
  267.       {
  268.         int y = xy.y + p0;
  269.         xy.y = (y >= rows) ? rows-1 : y;
  270.       }
  271.       break;
  272.     case 'C':
  273.       {
  274.         int x = xy.x + p0;
  275.         xy.x = (x >= cols) ? cols-1 : x;
  276.       }
  277.       break;
  278.     case 'D':
  279.       {
  280.         int x = xy.x - p0;
  281.         xy.x = (x < 0) ? 0 : x;
  282.       }
  283.       break;
  284.     case 'E':
  285.       {
  286.         int y = xy.y + p0;
  287.         xy.y = (y >= rows) ? rows-1 : y;
  288.         xy.x = 0;
  289.       }
  290.       break;
  291.     case 'F':
  292.       {
  293.         int y = xy.y - p0;
  294.         xy.y = (y < 0) ? 0 : y;
  295.         xy.x = 0;
  296.       }
  297.       break;
  298.     case 'G':
  299.     case '\'':
  300.       {
  301.         int x = st.parms[0] - 1;
  302.         xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
  303.       }
  304.       break;
  305.     case 'H':
  306.     case 'f':
  307.       {
  308.         int y = st.parms[0] - 1;
  309.         int x = st.parms[1] - 1;
  310.  
  311.         xy.x = (x >= cols) ? cols-1 : (x < 0) ? 0 : x;
  312.         xy.y = (y >= rows) ? rows-1 : (y < 0) ? 0 : y;
  313.       }
  314.       break;
  315.     case 'J':
  316.       {
  317.         switch ( st.parms[0] ) {
  318.         case 0:
  319.           ansicon_erase(xy.x, xy.y, cols-1, xy.y);
  320.           if ( xy.y < rows-1 )
  321.         ansicon_erase(0, xy.y+1, cols-1, rows-1);
  322.           break;
  323.  
  324.         case 1:
  325.           if ( xy.y > 0 )
  326.         ansicon_erase(0, 0, cols-1, xy.y-1);
  327.           if ( xy.y > 0 )
  328.         ansicon_erase(0, xy.y, xy.x-1, xy.y);
  329.           break;
  330.  
  331.         case 2:
  332.           ansicon_erase(0, 0, cols-1, rows-1);
  333.           break;
  334.  
  335.         default:
  336.           /* Ignore */
  337.           break;
  338.         }
  339.       }
  340.       break;
  341.     case 'K':
  342.       {
  343.         switch ( st.parms[0] ) {
  344.         case 0:
  345.           ansicon_erase(xy.x, xy.y, cols-1, xy.y);
  346.           break;
  347.  
  348.         case 1:
  349.           if ( xy.x > 0 )
  350.         ansicon_erase(0, xy.y, xy.x-1, xy.y);
  351.           break;
  352.  
  353.         case 2:
  354.           ansicon_erase(0, xy.y, cols-1, xy.y);
  355.           break;
  356.       
  357.         default:
  358.           /* Ignore */
  359.           break;
  360.         }
  361.       }
  362.       break;
  363.     case 'h':
  364.     case 'l':
  365.       {
  366.         int set = (ch == 'h');
  367.         switch ( st.parms[0] ) {
  368.         case 20:
  369.           st.autocr = set;
  370.           break;
  371.         case 25:
  372.           showcursor(set);
  373.           break;
  374.         default:
  375.           /* Ignore */
  376.           break;
  377.         }
  378.       }
  379.       break;
  380.     case 'm':
  381.       {
  382.         static const int ansi2pc[8] = { 0, 4, 2, 6, 1, 5, 3, 7 };
  383.  
  384.         int i;
  385.         for ( i = 0 ; i <= st.nparms ; i++ ) {
  386.           int a = st.parms[i];
  387.           switch ( a ) {
  388.           case 0:
  389.         st.fg = 7;
  390.         st.bg = 0;
  391.         st.intensity = 1;
  392.         st.underline = 0;
  393.         st.blink = 0;
  394.         st.reverse = 0;
  395.         break;
  396.           case 1:
  397.         st.intensity = 2;
  398.         break;
  399.           case 2:
  400.         st.intensity = 0;
  401.         break;
  402.           case 4:
  403.         st.underline = 1;
  404.         break;
  405.           case 5:
  406.         st.blink = 1;
  407.         break;
  408.           case 7:
  409.         st.reverse = 1;
  410.         break;
  411.           case 21:
  412.           case 22:
  413.         st.intensity = 1;
  414.         break;
  415.           case 24:
  416.         st.underline = 0;
  417.         break;
  418.           case 25:
  419.         st.blink = 0;
  420.         break;
  421.           case 27:
  422.         st.reverse = 0;
  423.         break;
  424.           case 30 ... 37:
  425.         st.fg = ansi2pc[a-30];
  426.         break;
  427.           case 38:
  428.         st.fg = 7;
  429.         st.underline = 1;
  430.         break;
  431.           case 39:
  432.         st.fg = 7;
  433.         st.underline = 0;
  434.         break;
  435.           case 40 ... 47:
  436.         st.bg = ansi2pc[a-40];
  437.         break;
  438.           case 49:
  439.         st.bg = 7;
  440.         break;
  441.           default:
  442.         /* Do nothing */
  443.         break;
  444.           }
  445.         }
  446.       
  447.         /* Turn into an attribute code */
  448.         {
  449.           int bg = st.bg;
  450.           int fg;
  451.  
  452.           if ( st.underline )
  453.         fg = 0x01;
  454.           else if ( st.intensity == 0 )
  455.         fg = 0x08;
  456.           else
  457.         fg = st.fg;
  458.  
  459.           if ( st.reverse ) {
  460.         bg = fg & 0x07;
  461.         fg &= 0x08;
  462.         fg |= st.bg;
  463.           }
  464.  
  465.           if ( st.blink )
  466.         bg ^= 0x08;
  467.  
  468.           if ( st.intensity == 2 )
  469.         fg ^= 0x08;
  470.  
  471.           st.attr = (bg << 4) | fg;
  472.         }
  473.       }
  474.       break;
  475.     case 's':
  476.       st.saved_xy = xy;
  477.       break;
  478.     case 'u':
  479.       xy = st.saved_xy;
  480.       break;
  481.     default:        /* Includes CAN and SUB */
  482.       break;        /* Drop unknown sequence */
  483.     }
  484.     st.state = st_init;
  485.       }
  486.     }
  487.     break;
  488.   }
  489.  
  490.   /* If we fell off the end of the screen, adjust */
  491.   if ( xy.x >= cols ) {
  492.     xy.x = 0;
  493.     xy.y++;
  494.   }
  495.   while ( xy.y >= rows ) {
  496.     xy.y--;
  497.     ireg.eax.w[0] = 0x0601;
  498.     ireg.ebx.b[1] = st.attr;
  499.     ireg.ecx.w[0] = 0;
  500.     ireg.edx.b[1] = rows-1;
  501.     ireg.edx.b[0] = cols-1;
  502.     __intcall(0x10, &ireg, NULL); /* Scroll */
  503.   }
  504.  
  505.   /* Update cursor position */
  506.   ireg.eax.b[1] = 0x02;
  507.   ireg.ebx.b[1] = page;
  508.   ireg.edx.b[1] = xy.y;
  509.   ireg.edx.b[0] = xy.x;
  510.   __intcall(0x10, &ireg, NULL);
  511. }    
  512.       
  513.  
  514. ssize_t __ansicon_write(struct file_info *fp, const void *buf, size_t count)
  515. {
  516.   const unsigned char *bufp = buf;
  517.   size_t n = 0;
  518.  
  519.   (void)fp;
  520.  
  521.   if ( st.disabled )
  522.     return n;            /* Nothing to do */
  523.  
  524.   while ( count-- ) {
  525.     ansicon_putchar(*bufp++);
  526.     n++;
  527.   }
  528.  
  529.   return n;
  530. }
  531.  
  532. const struct output_dev dev_ansicon_w = {
  533.   .dev_magic  = __DEV_MAGIC,
  534.   .flags      = __DEV_TTY | __DEV_OUTPUT,
  535.   .fileflags  = O_WRONLY | O_CREAT | O_TRUNC | O_APPEND,
  536.   .write      = __ansicon_write,
  537.   .close      = NULL,
  538. };
  539.