/* $OpenBSD: charset.c,v 1.4 2003/03/13 09:09:32 deraadt Exp $ */ /* * Copyright (c) 1984,1985,1989,1994,1995 Mark Nudelman * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice in the documentation and/or other materials provided with * the distribution. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN * IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /* * Functions to define the character set * and do things specific to the character set. */ #include "less.h" #if HAVE_LOCALE #include #include #endif /* * Predefined character sets, * selected by the LESSCHARSET environment variable. */ struct charset { char *name; char *desc; } charsets[] = { { "ascii", "8bcccbcc18b95.b" }, { "latin1", "8bcccbcc18b95.33b." }, { "dos", "8bcccbcc12bc5b95.b." }, { "koi8-r", "8bcccbcc18b95.b128." }, { "next", "8bcccbcc18b95.bb125.bb" }, { NULL } }; #define IS_BINARY_CHAR 01 #define IS_CONTROL_CHAR 02 static char chardef[256]; static char *binfmt = NULL; public int binattr = AT_STANDOUT; /* * Define a charset, given a description string. * The string consists of 256 letters, * one for each character in the charset. * If the string is shorter than 256 letters, missing letters * are taken to be identical to the last one. * A decimal number followed by a letter is taken to be a * repetition of the letter. * * Each letter is one of: * . normal character * b binary character * c control character */ static void ichardef(s) char *s; { char *cp; int n; char v; n = 0; v = 0; cp = chardef; while (*s != '\0') { switch (*s++) { case '.': v = 0; break; case 'c': v = IS_CONTROL_CHAR; break; case 'b': v = IS_BINARY_CHAR|IS_CONTROL_CHAR; break; case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': n = (10 * n) + (s[-1] - '0'); continue; default: error("invalid chardef", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ } do { if (cp >= chardef + sizeof(chardef)) { error("chardef longer than 256", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ } *cp++ = v; } while (--n > 0); n = 0; } while (cp < chardef + sizeof(chardef)) *cp++ = v; } /* * Define a charset, given a charset name. * The valid charset names are listed in the "charsets" array. */ static int icharset(name) char *name; { struct charset *p; if (name == NULL || *name == '\0') return (0); for (p = charsets; p->name != NULL; p++) { if (strcmp(name, p->name) == 0) { ichardef(p->desc); return (1); } } error("invalid charset name", NULL_PARG); quit(QUIT_ERROR); /*NOTREACHED*/ } #if HAVE_LOCALE /* * Define a charset, given a locale name. */ static void ilocale() { int c; setlocale(LC_CTYPE, ""); for (c = 0; c < sizeof(chardef); c++) { if (isprint(c)) chardef[c] = 0; else if (iscntrl(c)) chardef[c] = IS_CONTROL_CHAR; else chardef[c] = IS_BINARY_CHAR|IS_CONTROL_CHAR; } } #endif /* * Define the printing format for control chars. */ public void setbinfmt(s) char *s; { if (s == NULL || *s == '\0') s = "*s<%X>"; /* * Select the attributes if it starts with "*". */ if (*s == '*') { switch (s[1]) { case 'd': binattr = AT_BOLD; break; case 'k': binattr = AT_BLINK; break; case 's': binattr = AT_STANDOUT; break; case 'u': binattr = AT_UNDERLINE; break; default: binattr = AT_NORMAL; break; } s += 2; } binfmt = s; } /* * Initialize charset data structures. */ public void init_charset() { char *s; s = getenv("LESSBINFMT"); setbinfmt(s); /* * See if environment variable LESSCHARSET is defined. */ s = getenv("LESSCHARSET"); if (icharset(s)) return; /* * LESSCHARSET is not defined: try LESSCHARDEF. */ s = getenv("LESSCHARDEF"); if (s != NULL && *s != '\0') { ichardef(s); return; } #if HAVE_LOCALE /* * Use setlocale. */ ilocale(); #else /* * Default to "ascii". */ (void) icharset("ascii"); #endif } /* * Is a given character a "binary" character? */ public int binary_char(c) int c; { c &= 0377; return (chardef[c] & IS_BINARY_CHAR); } /* * Is a given character a "control" character? */ public int control_char(c) int c; { c &= 0377; return (chardef[c] & IS_CONTROL_CHAR); } /* * Return the printable form of a character. * For example, in the "ascii" charset '\3' is printed as "^C". */ public char * prchar(c) int c; { static char buf[8]; c &= 0377; if (!control_char(c)) snprintf(buf, sizeof buf, "%c", c); else if (c == ESC) snprintf(buf, sizeof buf, "ESC"); else if (c < 128 && !control_char(c ^ 0100)) snprintf(buf, sizeof buf, "^%c", c ^ 0100); else snprintf(buf, sizeof buf, binfmt, c); return (buf); }