150276Speter/**************************************************************************** 2184989Srafan * Copyright (c) 1998-2007,2008 Free Software Foundation, Inc. * 350276Speter * * 450276Speter * Permission is hereby granted, free of charge, to any person obtaining a * 550276Speter * copy of this software and associated documentation files (the * 650276Speter * "Software"), to deal in the Software without restriction, including * 750276Speter * without limitation the rights to use, copy, modify, merge, publish, * 850276Speter * distribute, distribute with modifications, sublicense, and/or sell * 950276Speter * copies of the Software, and to permit persons to whom the Software is * 1050276Speter * furnished to do so, subject to the following conditions: * 1150276Speter * * 1250276Speter * The above copyright notice and this permission notice shall be included * 1350276Speter * in all copies or substantial portions of the Software. * 1450276Speter * * 1550276Speter * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 1650276Speter * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 1750276Speter * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 1850276Speter * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 1950276Speter * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 2050276Speter * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 2150276Speter * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 2250276Speter * * 2350276Speter * Except as contained in this notice, the name(s) of the above copyright * 2450276Speter * holders shall not be used in advertising or otherwise to promote the * 2550276Speter * sale, use or other dealings in this Software without prior written * 2650276Speter * authorization. * 2750276Speter ****************************************************************************/ 2850276Speter 2950276Speter/**************************************************************************** 3050276Speter * Author: Thomas E. Dickey <dickey@clark.net> 1998 * 3150276Speter ****************************************************************************/ 3250276Speter 3350276Speter#include <curses.priv.h> 3450276Speter 3550276Speter#include <ctype.h> 3650276Speter#include <tic.h> 3750276Speter 38184989SrafanMODULE_ID("$Id: comp_expand.c,v 1.20 2008/08/16 19:29:42 tom Exp $") 3950276Speter 4076726Speterstatic int 4176726Spetertrailing_spaces(const char *src) 4250276Speter{ 4376726Speter while (*src == ' ') 4476726Speter src++; 4576726Speter return *src == 0; 4650276Speter} 4750276Speter 4850276Speter/* this deals with differences over whether 0x7f and 0x80..0x9f are controls */ 4997049Speter#define REALCTL(s) (UChar(*(s)) < 127 && iscntrl(UChar(*(s)))) 5097049Speter#define REALPRINT(s) (UChar(*(s)) < 127 && isprint(UChar(*(s)))) 5150276Speter 5276726SpeterNCURSES_EXPORT(char *) 53166124Srafan_nc_tic_expand(const char *srcp, bool tic_format, int numbers) 5450276Speter{ 5576726Speter static char *buffer; 5676726Speter static size_t length; 5750276Speter 5876726Speter int bufp; 59184989Srafan const char *str = VALID_STRING(srcp) ? srcp : "\0\0"; 6076726Speter bool islong = (strlen(str) > 3); 6176726Speter size_t need = (2 + strlen(str)) * 4; 6276726Speter int ch; 6350276Speter 64166124Srafan#if NO_LEAKS 65166124Srafan if (srcp == 0) { 66166124Srafan if (buffer != 0) { 67166124Srafan FreeAndNull(buffer); 68166124Srafan length = 0; 69166124Srafan } 70166124Srafan return 0; 71166124Srafan } 72166124Srafan#endif 7376726Speter if (buffer == 0 || need > length) { 7476726Speter if ((buffer = typeRealloc(char, length = need, buffer)) == 0) 7576726Speter return 0; 7676726Speter } 7750276Speter 7876726Speter bufp = 0; 7997049Speter while ((ch = UChar(*str)) != 0) { 8076726Speter if (ch == '%' && REALPRINT(str + 1)) { 8176726Speter buffer[bufp++] = *str++; 8276726Speter /* 8376726Speter * Though the character literals are more compact, most 8476726Speter * terminal descriptions use numbers and are not easy 8576726Speter * to read in character-literal form. 8676726Speter */ 8776726Speter switch (numbers) { 8876726Speter case -1: 8976726Speter if (str[0] == S_QUOTE 9076726Speter && str[1] != '\\' 9176726Speter && REALPRINT(str + 1) 9276726Speter && str[2] == S_QUOTE) { 9376726Speter sprintf(buffer + bufp, "{%d}", str[1]); 9476726Speter bufp += strlen(buffer + bufp); 9576726Speter str += 2; 9676726Speter } else { 9776726Speter buffer[bufp++] = *str; 9850276Speter } 9976726Speter break; 10076726Speter /* 10176726Speter * If we have a "%{number}", try to translate it into 10276726Speter * a "%'char'" form, since that will run a little faster 10376726Speter * when we're interpreting it. Also, having one form 10476726Speter * for the constant makes it simpler to compare terminal 10576726Speter * descriptions. 10676726Speter */ 10776726Speter case 1: 10876726Speter if (str[0] == L_BRACE 10997049Speter && isdigit(UChar(str[1]))) { 11076726Speter char *dst = 0; 11176726Speter long value = strtol(str + 1, &dst, 0); 11276726Speter if (dst != 0 11376726Speter && *dst == R_BRACE 11476726Speter && value < 127 11576726Speter && value != '\\' /* FIXME */ 11676726Speter && isprint((int) value)) { 11776726Speter ch = (int) value; 11876726Speter buffer[bufp++] = S_QUOTE; 11976726Speter if (ch == '\\' 12076726Speter || ch == S_QUOTE) 12176726Speter buffer[bufp++] = '\\'; 122184989Srafan buffer[bufp++] = (char) ch; 12376726Speter buffer[bufp++] = S_QUOTE; 12476726Speter str = dst; 12576726Speter } else { 12676726Speter buffer[bufp++] = *str; 12776726Speter } 12876726Speter } else { 12976726Speter buffer[bufp++] = *str; 13050276Speter } 13176726Speter break; 13276726Speter default: 13376726Speter buffer[bufp++] = *str; 13476726Speter break; 13576726Speter } 13676726Speter } else if (ch == 128) { 13776726Speter buffer[bufp++] = '\\'; 13876726Speter buffer[bufp++] = '0'; 13976726Speter } else if (ch == '\033') { 14076726Speter buffer[bufp++] = '\\'; 14176726Speter buffer[bufp++] = 'E'; 14276726Speter } else if (ch == '\\' && tic_format && (str == srcp || str[-1] != '^')) { 14376726Speter buffer[bufp++] = '\\'; 14476726Speter buffer[bufp++] = '\\'; 14576726Speter } else if (ch == ' ' && tic_format && (str == srcp || 14676726Speter trailing_spaces(str))) { 14776726Speter buffer[bufp++] = '\\'; 14876726Speter buffer[bufp++] = 's'; 14976726Speter } else if ((ch == ',' || ch == ':' || ch == '^') && tic_format) { 15076726Speter buffer[bufp++] = '\\'; 151184989Srafan buffer[bufp++] = (char) ch; 15276726Speter } else if (REALPRINT(str) 15376726Speter && (ch != ',' 15476726Speter && ch != ':' 15576726Speter && !(ch == '!' && !tic_format) 15676726Speter && ch != '^')) 157184989Srafan buffer[bufp++] = (char) ch; 15876726Speter#if 0 /* FIXME: this would be more readable (in fact the whole 'islong' logic should be removed) */ 15976726Speter else if (ch == '\b') { 16076726Speter buffer[bufp++] = '\\'; 16176726Speter buffer[bufp++] = 'b'; 16276726Speter } else if (ch == '\f') { 16376726Speter buffer[bufp++] = '\\'; 16476726Speter buffer[bufp++] = 'f'; 16576726Speter } else if (ch == '\t' && islong) { 16676726Speter buffer[bufp++] = '\\'; 16776726Speter buffer[bufp++] = 't'; 16876726Speter } 16950276Speter#endif 17076726Speter else if (ch == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) { 17176726Speter buffer[bufp++] = '\\'; 17276726Speter buffer[bufp++] = 'r'; 17376726Speter } else if (ch == '\n' && islong) { 17476726Speter buffer[bufp++] = '\\'; 17576726Speter buffer[bufp++] = 'n'; 17676726Speter } 17750276Speter#define UnCtl(c) ((c) + '@') 17876726Speter else if (REALCTL(str) && ch != '\\' 17997049Speter && (!islong || isdigit(UChar(str[1])))) { 18076726Speter (void) sprintf(&buffer[bufp], "^%c", UnCtl(ch)); 18176726Speter bufp += 2; 18276726Speter } else { 18376726Speter (void) sprintf(&buffer[bufp], "\\%03o", ch); 18476726Speter bufp += 4; 18550276Speter } 18650276Speter 18776726Speter str++; 18876726Speter } 18976726Speter 19076726Speter buffer[bufp] = '\0'; 19176726Speter return (buffer); 19250276Speter} 193