File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / readline / parse-colors.c
Revision 1.1.1.2 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Mar 17 01:01:01 2021 UTC (3 years, 3 months ago) by misho
Branches: readline, MAIN
CVS tags: v8_2p0, v8_1p0, HEAD
readline 8.1

    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, 2017
    6:    Free Software Foundation, 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(void)
  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>