|
Packit Service |
a2489d |
/*
|
|
Packit Service |
a2489d |
* lftp - file transfer program
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* Copyright (c) 1996-2015 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* This program is free software; you can redistribute it and/or modify
|
|
Packit Service |
a2489d |
* it under the terms of the GNU General Public License as published by
|
|
Packit Service |
a2489d |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit Service |
a2489d |
* (at your option) any later version.
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* This program is distributed in the hope that it will be useful,
|
|
Packit Service |
a2489d |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit Service |
a2489d |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit Service |
a2489d |
* GNU General Public License for more details.
|
|
Packit Service |
a2489d |
*
|
|
Packit Service |
a2489d |
* You should have received a copy of the GNU General Public License
|
|
Packit Service |
a2489d |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit Service |
a2489d |
*/
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
#include <config.h>
|
|
Packit Service |
a2489d |
#include "DirColors.h"
|
|
Packit Service |
a2489d |
#include "ResMgr.h"
|
|
Packit Service |
a2489d |
#include "FileSet.h"
|
|
Packit Service |
a2489d |
#include "buffer.h"
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
DirColors *DirColors::instance;
|
|
Packit Service |
a2489d |
const char DirColors::resource[]="color:dir-colors";
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
/* Parse a string as part of the LS_COLORS variable; this may involve
|
|
Packit Service |
a2489d |
decoding all kinds of escape characters. If equals_end is set an
|
|
Packit Service |
a2489d |
unescaped equal sign ends the string, otherwise only a : or \0
|
|
Packit Service |
a2489d |
does. Returns the number of characters output, or -1 on failure.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
The resulting string is *not* null-terminated, but may contain
|
|
Packit Service |
a2489d |
embedded nulls.
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
Note that both dest and src are char **; on return they point to
|
|
Packit Service |
a2489d |
the first free byte after the array and the character that ended
|
|
Packit Service |
a2489d |
the input string, respectively. */
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
static int
|
|
Packit Service |
a2489d |
get_funky_string (char **dest, const char **src, int equals_end)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
int num; /* For numerical codes */
|
|
Packit Service |
a2489d |
int count; /* Something to count with */
|
|
Packit Service |
a2489d |
enum {
|
|
Packit Service |
a2489d |
ST_GND, ST_BACKSLASH, ST_OCTAL, ST_HEX, ST_CARET, ST_END, ST_ERROR
|
|
Packit Service |
a2489d |
} state;
|
|
Packit Service |
a2489d |
const char *p;
|
|
Packit Service |
a2489d |
char *q;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
p = *src; /* We don't want to double-indirect */
|
|
Packit Service |
a2489d |
q = *dest; /* the whole darn time. */
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
count = 0; /* No characters counted in yet. */
|
|
Packit Service |
a2489d |
num = 0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
state = ST_GND; /* Start in ground state. */
|
|
Packit Service |
a2489d |
while (state < ST_END) {
|
|
Packit Service |
a2489d |
switch (state) {
|
|
Packit Service |
a2489d |
case ST_GND: /* Ground state (no escapes) */
|
|
Packit Service |
a2489d |
switch (*p) {
|
|
Packit Service |
a2489d |
case ':':
|
|
Packit Service |
a2489d |
case '\0':
|
|
Packit Service |
a2489d |
state = ST_END; /* End of string */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '\\':
|
|
Packit Service |
a2489d |
state = ST_BACKSLASH; /* Backslash scape sequence */
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '^':
|
|
Packit Service |
a2489d |
state = ST_CARET; /* Caret escape */
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '=':
|
|
Packit Service |
a2489d |
if (equals_end)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
state = ST_END; /* End */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
/* else fall through */
|
|
Packit Service |
a2489d |
default:
|
|
Packit Service |
a2489d |
*(q++) = *(p++);
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case ST_BACKSLASH: /* Backslash escaped character */
|
|
Packit Service |
a2489d |
switch (*p) {
|
|
Packit Service |
a2489d |
case '0':
|
|
Packit Service |
a2489d |
case '1':
|
|
Packit Service |
a2489d |
case '2':
|
|
Packit Service |
a2489d |
case '3':
|
|
Packit Service |
a2489d |
case '4':
|
|
Packit Service |
a2489d |
case '5':
|
|
Packit Service |
a2489d |
case '6':
|
|
Packit Service |
a2489d |
case '7':
|
|
Packit Service |
a2489d |
state = ST_OCTAL; /* Octal sequence */
|
|
Packit Service |
a2489d |
num = *p - '0';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'x':
|
|
Packit Service |
a2489d |
case 'X':
|
|
Packit Service |
a2489d |
state = ST_HEX; /* Hex sequence */
|
|
Packit Service |
a2489d |
num = 0;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'a': /* Bell */
|
|
Packit Service |
a2489d |
num = 7; /* Not all C compilers know what \a means */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'b': /* Backspace */
|
|
Packit Service |
a2489d |
num = '\b';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'e': /* Escape */
|
|
Packit Service |
a2489d |
num = 27;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'f': /* Form feed */
|
|
Packit Service |
a2489d |
num = '\f';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'n': /* Newline */
|
|
Packit Service |
a2489d |
num = '\n';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'r': /* Carriage return */
|
|
Packit Service |
a2489d |
num = '\r';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 't': /* Tab */
|
|
Packit Service |
a2489d |
num = '\t';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'v': /* Vtab */
|
|
Packit Service |
a2489d |
num = '\v';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '?': /* Delete */
|
|
Packit Service |
a2489d |
num = 127;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '_': /* Space */
|
|
Packit Service |
a2489d |
num = ' ';
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case '\0': /* End of string */
|
|
Packit Service |
a2489d |
state = ST_ERROR; /* Error! */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
default: /* Escaped character like \ ^ : = */
|
|
Packit Service |
a2489d |
num = *p;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
if (state == ST_BACKSLASH) {
|
|
Packit Service |
a2489d |
*(q++) = num;
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
state = ST_GND;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case ST_OCTAL: /* Octal sequence */
|
|
Packit Service |
a2489d |
if (*p < '0' || *p > '7') {
|
|
Packit Service |
a2489d |
*(q++) = num;
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
state = ST_GND;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
num = (num << 3) + (*(p++) - '0');
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case ST_HEX: /* Hex sequence */
|
|
Packit Service |
a2489d |
switch (*p) {
|
|
Packit Service |
a2489d |
case '0':
|
|
Packit Service |
a2489d |
case '1':
|
|
Packit Service |
a2489d |
case '2':
|
|
Packit Service |
a2489d |
case '3':
|
|
Packit Service |
a2489d |
case '4':
|
|
Packit Service |
a2489d |
case '5':
|
|
Packit Service |
a2489d |
case '6':
|
|
Packit Service |
a2489d |
case '7':
|
|
Packit Service |
a2489d |
case '8':
|
|
Packit Service |
a2489d |
case '9':
|
|
Packit Service |
a2489d |
num = (num << 4) + (*(p++) - '0');
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'a':
|
|
Packit Service |
a2489d |
case 'b':
|
|
Packit Service |
a2489d |
case 'c':
|
|
Packit Service |
a2489d |
case 'd':
|
|
Packit Service |
a2489d |
case 'e':
|
|
Packit Service |
a2489d |
case 'f':
|
|
Packit Service |
a2489d |
num = (num << 4) + (*(p++) - 'a') + 10;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
case 'A':
|
|
Packit Service |
a2489d |
case 'B':
|
|
Packit Service |
a2489d |
case 'C':
|
|
Packit Service |
a2489d |
case 'D':
|
|
Packit Service |
a2489d |
case 'E':
|
|
Packit Service |
a2489d |
case 'F':
|
|
Packit Service |
a2489d |
num = (num << 4) + (*(p++) - 'A') + 10;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
default:
|
|
Packit Service |
a2489d |
*(q++) = num;
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
state = ST_GND;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case ST_CARET: /* Caret escape */
|
|
Packit Service |
a2489d |
state = ST_GND; /* Should be the next state... */
|
|
Packit Service |
a2489d |
if (*p >= '@' && *p <= '~') {
|
|
Packit Service |
a2489d |
*(q++) = *(p++) & 037;
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
} else if (*p == '?') {
|
|
Packit Service |
a2489d |
*(q++) = 127;
|
|
Packit Service |
a2489d |
++count;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
state = ST_ERROR;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
default:
|
|
Packit Service |
a2489d |
abort ();
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
*(q++) = 0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
*dest = q;
|
|
Packit Service |
a2489d |
*src = p;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(state == ST_ERROR) return -1;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
return count;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void DirColors::Parse(const char *p)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Empty();
|
|
Packit Service |
a2489d |
Add(".lc", "\033[");
|
|
Packit Service |
a2489d |
Add(".rc", "m");
|
|
Packit Service |
a2489d |
Add(".no", "");
|
|
Packit Service |
a2489d |
Add(".fi", "");
|
|
Packit Service |
a2489d |
Add(".di", "");
|
|
Packit Service |
a2489d |
Add(".ln", "");
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!p)
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
char *buf; /* color_buf buffer pointer */
|
|
Packit Service |
a2489d |
int state; /* State of parser */
|
|
Packit Service |
a2489d |
char label[4]; /* Indicator label */
|
|
Packit Service |
a2489d |
const char *ext;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
label[0] = '.';
|
|
Packit Service |
a2489d |
label[3] = 0;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
ext = NULL;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
buf = alloca_strdup (p);
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
state = 1;
|
|
Packit Service |
a2489d |
while (state > 0) {
|
|
Packit Service |
a2489d |
switch (state) {
|
|
Packit Service |
a2489d |
case 1: /* First label character */
|
|
Packit Service |
a2489d |
switch (*p) {
|
|
Packit Service |
a2489d |
case ':':
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case '*':
|
|
Packit Service |
a2489d |
/* Allocate new extension block and add to head of
|
|
Packit Service |
a2489d |
linked list (this way a later definition will
|
|
Packit Service |
a2489d |
override an earlier one, which can be useful for
|
|
Packit Service |
a2489d |
having terminal-specific defs override global). */
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
++p;
|
|
Packit Service |
a2489d |
/* next should be . */
|
|
Packit Service |
a2489d |
if(*p++ != '.') {
|
|
Packit Service |
a2489d |
state = -1;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
ext = buf;
|
|
Packit Service |
a2489d |
state = get_funky_string (&buf, &p, 1) < 0 ? -1 : 4;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case '\0':
|
|
Packit Service |
a2489d |
state = 0; /* Done! */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
default: /* Assume it is file type label */
|
|
Packit Service |
a2489d |
label[1] = *(p++);
|
|
Packit Service |
a2489d |
state = 2;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case 2: /* Second label character */
|
|
Packit Service |
a2489d |
if (*p)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
label[2] = *(p++);
|
|
Packit Service |
a2489d |
state = 3;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
state = -1; /* Error */
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case 3: /* Equal sign after indicator label */
|
|
Packit Service |
a2489d |
state = -1; /* Assume failure... */
|
|
Packit Service |
a2489d |
if (*(p++) == '=')/* It *should* be... */
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *b = buf;
|
|
Packit Service |
a2489d |
state = get_funky_string (&buf, &p, 0) < 0 ? -1 : 1;
|
|
Packit Service |
a2489d |
Add(label, b);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
case 4: /* Equal sign after *.ext */
|
|
Packit Service |
a2489d |
if (*(p++) == '=')
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *b = buf;
|
|
Packit Service |
a2489d |
state = get_funky_string (&buf, &p, 0) < 0 ? -1 : 1;
|
|
Packit Service |
a2489d |
Add(ext, b);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else
|
|
Packit Service |
a2489d |
state = -1;
|
|
Packit Service |
a2489d |
break;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
// if (color_indicator[C_LINK].len == 6
|
|
Packit Service |
a2489d |
// && !strncmp (color_indicator[C_LINK].string, "target", 6))
|
|
Packit Service |
a2489d |
// color_symlink_as_referent = 1;
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
if(!Lookup(".ec"))
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *no=Lookup(".no");
|
|
Packit Service |
a2489d |
const char *lc=Lookup(".lc");
|
|
Packit Service |
a2489d |
const char *rc=Lookup(".rc");
|
|
Packit Service |
a2489d |
Add(".ec",xstring::cat(lc,no,rc,NULL));
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
DirColors::DirColors()
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
Reconfig(resource);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *DirColors::GetColor(const char *name,int type)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *ret=0;
|
|
Packit Service |
a2489d |
if(type==FileInfo::DIRECTORY)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
ret=Lookup(".di");
|
|
Packit Service |
a2489d |
if(ret)
|
|
Packit Service |
a2489d |
return ret;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(type==FileInfo::SYMLINK)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
ret=Lookup(".ln");
|
|
Packit Service |
a2489d |
if(ret)
|
|
Packit Service |
a2489d |
return ret;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
else if(type==FileInfo::NORMAL)
|
|
Packit Service |
a2489d |
ret=Lookup(".fi");
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *ext = strrchr(name, '.');
|
|
Packit Service |
a2489d |
if(ext && *++ext)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *l=Lookup(ext);
|
|
Packit Service |
a2489d |
if(l)
|
|
Packit Service |
a2489d |
return l;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
return ret?ret:"";
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
const char *DirColors::GetColor(const FileInfo *fi)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
return GetColor(fi->name,fi->defined&fi->TYPE?fi->filetype:-1);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void DirColors::PutColored(const Ref<Buffer>& buf,const char *name,int type)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *color=GetColor(name,type);
|
|
Packit Service |
a2489d |
const char *lc=Lookup(".lc");
|
|
Packit Service |
a2489d |
const char *rc=Lookup(".rc");
|
|
Packit Service |
a2489d |
if(!color || !*color || !lc || !rc)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
buf->Put(name);
|
|
Packit Service |
a2489d |
return;
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
buf->Put(lc);
|
|
Packit Service |
a2489d |
buf->Put(color);
|
|
Packit Service |
a2489d |
buf->Put(rc);
|
|
Packit Service |
a2489d |
buf->Put(name);
|
|
Packit Service |
a2489d |
PutReset(buf);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
void DirColors::PutReset(const Ref<Buffer>& buf)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
const char *reset=Lookup(".ec");
|
|
Packit Service |
a2489d |
buf->Put(reset);
|
|
Packit Service |
a2489d |
}
|
|
Packit Service |
a2489d |
|
|
Packit Service |
a2489d |
void DirColors::Reconfig(const char *name)
|
|
Packit Service |
a2489d |
{
|
|
Packit Service |
a2489d |
if(!xstrcmp(name,resource))
|
|
Packit Service |
a2489d |
Parse(ResMgr::Query(resource,0));
|
|
Packit Service |
a2489d |
}
|