Annotation of embedaddon/readline/parse-colors.c, revision 1.1.1.1

1.1       misho       1: /* `dir', `vdir' and `ls' directory listing programs for GNU.
                      2: 
                      3:    Modified by Chet Ramey for Readline.
                      4: 
                      5:    Copyright (C) 1985, 1988, 1990-1991, 1995-2010, 2012 Free Software Foundation,
                      6:    Inc.
                      7: 
                      8:    This program is free software: you can redistribute it and/or modify
                      9:    it under the terms of the GNU General Public License as published by
                     10:    the Free Software Foundation, either version 3 of the License, or
                     11:    (at your option) any later version.
                     12: 
                     13:    This program is distributed in the hope that it will be useful,
                     14:    but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     16:    GNU General Public License for more details.
                     17: 
                     18:    You should have received a copy of the GNU General Public License
                     19:    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
                     20: 
                     21: /* Written by Richard Stallman and David MacKenzie.  */
                     22: 
                     23: /* Color support by Peter Anvin <Peter.Anvin@linux.org> and Dennis
                     24:    Flaherty <dennisf@denix.elk.miles.com> based on original patches by
                     25:    Greg Lee <lee@uhunix.uhcc.hawaii.edu>.  */
                     26: 
                     27: #define READLINE_LIBRARY
                     28: 
                     29: #if defined (HAVE_CONFIG_H)
                     30: #  include <config.h>
                     31: #endif
                     32: 
                     33: #include <stdio.h>
                     34: 
                     35: // strdup() / strcpy()
                     36: #if defined (HAVE_STRING_H)
                     37: #  include <string.h>
                     38: #else /* !HAVE_STRING_H */
                     39: #  include <strings.h>
                     40: #endif /* !HAVE_STRING_H */
                     41: 
                     42: // abort()
                     43: #if defined (HAVE_STDLIB_H)
                     44: #  include <stdlib.h>
                     45: #else
                     46: #  include "ansi_stdlib.h"
                     47: #endif /* HAVE_STDLIB_H */
                     48: 
                     49: #include "rldefs.h"    // STREQ, savestring
                     50: #include "readline.h"
                     51: #include "rlprivate.h"
                     52: #include "rlshell.h"
                     53: #include "xmalloc.h"
                     54: 
                     55: #include "colors.h"
                     56: #include "parse-colors.h"
                     57: 
                     58: #if defined (COLOR_SUPPORT)
                     59: 
                     60: static bool get_funky_string (char **dest, const char **src, bool equals_end, size_t *output_count);
                     61: 
                     62: struct bin_str _rl_color_indicator[] =
                     63:   {
                     64:     { LEN_STR_PAIR ("\033[") },         //  lc: Left of color sequence
                     65:     { LEN_STR_PAIR ("m") },             //  rc: Right of color sequence
                     66:     { 0, NULL },                        //  ec: End color (replaces lc+no+rc)
                     67:     { LEN_STR_PAIR ("0") },             //  rs: Reset to ordinary colors
                     68:     { 0, NULL },                        //  no: Normal
                     69:     { 0, NULL },                        //  fi: File: default
                     70:     { LEN_STR_PAIR ("01;34") },         //  di: Directory: bright blue
                     71:     { LEN_STR_PAIR ("01;36") },         //  ln: Symlink: bright cyan
                     72:     { LEN_STR_PAIR ("33") },            //  pi: Pipe: yellow/brown
                     73:     { LEN_STR_PAIR ("01;35") },         //  so: Socket: bright magenta
                     74:     { LEN_STR_PAIR ("01;33") },         //  bd: Block device: bright yellow
                     75:     { LEN_STR_PAIR ("01;33") },         //  cd: Char device: bright yellow
                     76:     { 0, NULL },                        //  mi: Missing file: undefined
                     77:     { 0, NULL },                        //  or: Orphaned symlink: undefined
                     78:     { LEN_STR_PAIR ("01;32") },         //  ex: Executable: bright green
                     79:     { LEN_STR_PAIR ("01;35") },         //  do: Door: bright magenta
                     80:     { LEN_STR_PAIR ("37;41") },         //  su: setuid: white on red
                     81:     { LEN_STR_PAIR ("30;43") },         //  sg: setgid: black on yellow
                     82:     { LEN_STR_PAIR ("37;44") },         //  st: sticky: black on blue
                     83:     { LEN_STR_PAIR ("34;42") },         //  ow: other-writable: blue on green
                     84:     { LEN_STR_PAIR ("30;42") },         //  tw: ow w/ sticky: black on green
                     85:     { LEN_STR_PAIR ("30;41") },         //  ca: black on red
                     86:     { 0, NULL },                        //  mh: disabled by default
                     87:     { LEN_STR_PAIR ("\033[K") },        //  cl: clear to end of line
                     88:   };
                     89: 
                     90: /* Parse a string as part of the LS_COLORS variable; this may involve
                     91:    decoding all kinds of escape characters.  If equals_end is set an
                     92:    unescaped equal sign ends the string, otherwise only a : or \0
                     93:    does.  Set *OUTPUT_COUNT to the number of bytes output.  Return
                     94:    true if successful.
                     95: 
                     96:    The resulting string is *not* null-terminated, but may contain
                     97:    embedded nulls.
                     98: 
                     99:    Note that both dest and src are char **; on return they point to
                    100:    the first free byte after the array and the character that ended
                    101:    the input string, respectively.  */
                    102: 
                    103: static bool
                    104: get_funky_string (char **dest, const char **src, bool equals_end, size_t *output_count) {
                    105:   char num;                    /* For numerical codes */
                    106:   size_t count;                        /* Something to count with */
                    107:   enum {
                    108:     ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
                    109:   } state;
                    110:   const char *p;
                    111:   char *q;
                    112: 
                    113:   p = *src;                    /* We don't want to double-indirect */
                    114:   q = *dest;                   /* the whole darn time.  */
                    115: 
                    116:   count = 0;                   /* No characters counted in yet.  */
                    117:   num = 0;
                    118: 
                    119:   state = ST_GND;              /* Start in ground state.  */
                    120:   while (state < ST_END)
                    121:     {
                    122:       switch (state)
                    123:         {
                    124:         case ST_GND:           /* Ground state (no escapes) */
                    125:           switch (*p)
                    126:             {
                    127:             case ':':
                    128:             case '\0':
                    129:               state = ST_END;  /* End of string */
                    130:               break;
                    131:             case '\\':
                    132:               state = ST_BACKSLASH; /* Backslash scape sequence */
                    133:               ++p;
                    134:               break;
                    135:             case '^':
                    136:               state = ST_CARET; /* Caret escape */
                    137:               ++p;
                    138:               break;
                    139:             case '=':
                    140:               if (equals_end)
                    141:                 {
                    142:                   state = ST_END; /* End */
                    143:                   break;
                    144:                 }
                    145:               /* else fall through */
                    146:             default:
                    147:               *(q++) = *(p++);
                    148:               ++count;
                    149:               break;
                    150:             }
                    151:           break;
                    152: 
                    153:         case ST_BACKSLASH:     /* Backslash escaped character */
                    154:           switch (*p)
                    155:             {
                    156:             case '0':
                    157:             case '1':
                    158:             case '2':
                    159:             case '3':
                    160:             case '4':
                    161:             case '5':
                    162:             case '6':
                    163:             case '7':
                    164:               state = ST_OCTAL;        /* Octal sequence */
                    165:               num = *p - '0';
                    166:               break;
                    167:             case 'x':
                    168:             case 'X':
                    169:               state = ST_HEX;  /* Hex sequence */
                    170:               num = 0;
                    171:               break;
                    172:             case 'a':          /* Bell */
                    173:               num = '\a';
                    174:               break;
                    175:             case 'b':          /* Backspace */
                    176:               num = '\b';
                    177:               break;
                    178:             case 'e':          /* Escape */
                    179:               num = 27;
                    180:               break;
                    181:             case 'f':          /* Form feed */
                    182:               num = '\f';
                    183:               break;
                    184:             case 'n':          /* Newline */
                    185:               num = '\n';
                    186:               break;
                    187:             case 'r':          /* Carriage return */
                    188:               num = '\r';
                    189:               break;
                    190:             case 't':          /* Tab */
                    191:               num = '\t';
                    192:               break;
                    193:             case 'v':          /* Vtab */
                    194:               num = '\v';
                    195:               break;
                    196:             case '?':          /* Delete */
                    197:               num = 127;
                    198:               break;
                    199:             case '_':          /* Space */
                    200:               num = ' ';
                    201:               break;
                    202:             case '\0':         /* End of string */
                    203:               state = ST_ERROR;        /* Error! */
                    204:               break;
                    205:             default:           /* Escaped character like \ ^ : = */
                    206:               num = *p;
                    207:               break;
                    208:             }
                    209:           if (state == ST_BACKSLASH)
                    210:             {
                    211:               *(q++) = num;
                    212:               ++count;
                    213:               state = ST_GND;
                    214:             }
                    215:           ++p;
                    216:           break;
                    217: 
                    218:         case ST_OCTAL:         /* Octal sequence */
                    219:           if (*p < '0' || *p > '7')
                    220:             {
                    221:               *(q++) = num;
                    222:               ++count;
                    223:               state = ST_GND;
                    224:             }
                    225:           else
                    226:             num = (num << 3) + (*(p++) - '0');
                    227:           break;
                    228: 
                    229:         case ST_HEX:           /* Hex sequence */
                    230:           switch (*p)
                    231:             {
                    232:             case '0':
                    233:             case '1':
                    234:             case '2':
                    235:             case '3':
                    236:             case '4':
                    237:             case '5':
                    238:             case '6':
                    239:             case '7':
                    240:             case '8':
                    241:             case '9':
                    242:               num = (num << 4) + (*(p++) - '0');
                    243:               break;
                    244:             case 'a':
                    245:             case 'b':
                    246:             case 'c':
                    247:             case 'd':
                    248:             case 'e':
                    249:             case 'f':
                    250:               num = (num << 4) + (*(p++) - 'a') + 10;
                    251:               break;
                    252:             case 'A':
                    253:             case 'B':
                    254:             case 'C':
                    255:             case 'D':
                    256:             case 'E':
                    257:             case 'F':
                    258:               num = (num << 4) + (*(p++) - 'A') + 10;
                    259:               break;
                    260:             default:
                    261:               *(q++) = num;
                    262:               ++count;
                    263:               state = ST_GND;
                    264:               break;
                    265:             }
                    266:           break;
                    267: 
                    268:         case ST_CARET:         /* Caret escape */
                    269:           state = ST_GND;      /* Should be the next state... */
                    270:           if (*p >= '@' && *p <= '~')
                    271:             {
                    272:               *(q++) = *(p++) & 037;
                    273:               ++count;
                    274:             }
                    275:           else if (*p == '?')
                    276:             {
                    277:               *(q++) = 127;
                    278:               ++count;
                    279:             }
                    280:           else
                    281:             state = ST_ERROR;
                    282:           break;
                    283: 
                    284:         default:
                    285:          /* should we ? */
                    286:           /* abort (); no, we should not */
                    287:           state = ST_ERROR;
                    288:           break;
                    289:         }
                    290:     }
                    291: 
                    292:   *dest = q;
                    293:   *src = p;
                    294:   *output_count = count;
                    295: 
                    296:   return state != ST_ERROR;
                    297: }
                    298: #endif /* COLOR_SUPPORT */
                    299: 
                    300: void _rl_parse_colors()
                    301: {
                    302: #if defined (COLOR_SUPPORT)
                    303:   const char *p;               /* Pointer to character being parsed */
                    304:   char *buf;                   /* color_buf buffer pointer */
                    305:   int state;                   /* State of parser */
                    306:   int ind_no;                  /* Indicator number */
                    307:   char label[3];               /* Indicator label */
                    308:   COLOR_EXT_TYPE *ext;         /* Extension we are working on */
                    309: 
                    310:   p = sh_get_env_value ("LS_COLORS");
                    311:   if (p == 0 || *p == '\0')
                    312:     {
                    313:       _rl_color_ext_list = NULL;
                    314:       return;
                    315:     }
                    316: 
                    317:   ext = NULL;
                    318:   strcpy (label, "??");
                    319: 
                    320:   /* This is an overly conservative estimate, but any possible
                    321:      LS_COLORS string will *not* generate a color_buf longer than
                    322:      itself, so it is a safe way of allocating a buffer in
                    323:      advance.  */
                    324:   buf = color_buf = savestring (p);
                    325: 
                    326:   state = 1;
                    327:   while (state > 0)
                    328:     {
                    329:       switch (state)
                    330:         {
                    331:         case 1:                /* First label character */
                    332:           switch (*p)
                    333:             {
                    334:             case ':':
                    335:               ++p;
                    336:               break;
                    337: 
                    338:             case '*':
                    339:               /* Allocate new extension block and add to head of
                    340:                  linked list (this way a later definition will
                    341:                  override an earlier one, which can be useful for
                    342:                  having terminal-specific defs override global).  */
                    343: 
                    344:               ext = (COLOR_EXT_TYPE *)xmalloc (sizeof *ext);
                    345:               ext->next = _rl_color_ext_list;
                    346:               _rl_color_ext_list = ext;
                    347: 
                    348:               ++p;
                    349:               ext->ext.string = buf;
                    350: 
                    351:               state = (get_funky_string (&buf, &p, true, &ext->ext.len)
                    352:                        ? 4 : -1);
                    353:               break;
                    354: 
                    355:             case '\0':
                    356:               state = 0;       /* Done! */
                    357:               break;
                    358: 
                    359:             default:   /* Assume it is file type label */
                    360:               label[0] = *(p++);
                    361:               state = 2;
                    362:               break;
                    363:             }
                    364:           break;
                    365: 
                    366:         case 2:                /* Second label character */
                    367:           if (*p)
                    368:             {
                    369:               label[1] = *(p++);
                    370:               state = 3;
                    371:             }
                    372:           else
                    373:             state = -1;        /* Error */
                    374:           break;
                    375: 
                    376:         case 3:                /* Equal sign after indicator label */
                    377:           state = -1;  /* Assume failure...  */
                    378:           if (*(p++) == '=')/* It *should* be...  */
                    379:             {
                    380:               for (ind_no = 0; indicator_name[ind_no] != NULL; ++ind_no)
                    381:                 {
                    382:                   if (STREQ (label, indicator_name[ind_no]))
                    383:                     {
                    384:                       _rl_color_indicator[ind_no].string = buf;
                    385:                       state = (get_funky_string (&buf, &p, false,
                    386:                                                  &_rl_color_indicator[ind_no].len)
                    387:                                ? 1 : -1);
                    388:                       break;
                    389:                     }
                    390:                 }
                    391:               if (state == -1)
                    392:                {
                    393:                   _rl_errmsg ("LS_COLORS: unrecognized prefix: %s", label);
                    394:                   /* recover from an unrecognized prefix */
                    395:                   while (p && *p && *p != ':')
                    396:                    p++;
                    397:                  if (p && *p == ':')
                    398:                    state = 1;
                    399:                  else if (p && *p == 0)
                    400:                    state = 0;
                    401:                }
                    402:             }
                    403:           break;
                    404: 
                    405:         case 4:                /* Equal sign after *.ext */
                    406:           if (*(p++) == '=')
                    407:             {
                    408:               ext->seq.string = buf;
                    409:               state = (get_funky_string (&buf, &p, false, &ext->seq.len)
                    410:                        ? 1 : -1);
                    411:             }
                    412:           else
                    413:             state = -1;
                    414:           /* XXX - recover here as with an unrecognized prefix? */
                    415:           if (state == -1 && ext->ext.string)
                    416:            _rl_errmsg ("LS_COLORS: syntax error: %s", ext->ext.string);
                    417:           break;
                    418:         }
                    419:     }
                    420: 
                    421:   if (state < 0)
                    422:     {
                    423:       COLOR_EXT_TYPE *e;
                    424:       COLOR_EXT_TYPE *e2;
                    425: 
                    426:       _rl_errmsg ("unparsable value for LS_COLORS environment variable");
                    427:       free (color_buf);
                    428:       for (e = _rl_color_ext_list; e != NULL; /* empty */)
                    429:         {
                    430:           e2 = e;
                    431:           e = e->next;
                    432:           free (e2);
                    433:         }
                    434:       _rl_color_ext_list = NULL;
                    435:       _rl_colored_stats = 0;   /* can't have colored stats without colors */
                    436:     }
                    437: #else /* !COLOR_SUPPORT */
                    438:   ;
                    439: #endif /* !COLOR_SUPPORT */
                    440: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>