Annotation of embedaddon/readline/parse-colors.c, revision 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>