Back to index

tetex-bin  3.0
comp_expand.c
Go to the documentation of this file.
00001 /****************************************************************************
00002  * Copyright (c) 1998,2000,2001 Free Software Foundation, Inc.              *
00003  *                                                                          *
00004  * Permission is hereby granted, free of charge, to any person obtaining a  *
00005  * copy of this software and associated documentation files (the            *
00006  * "Software"), to deal in the Software without restriction, including      *
00007  * without limitation the rights to use, copy, modify, merge, publish,      *
00008  * distribute, distribute with modifications, sublicense, and/or sell       *
00009  * copies of the Software, and to permit persons to whom the Software is    *
00010  * furnished to do so, subject to the following conditions:                 *
00011  *                                                                          *
00012  * The above copyright notice and this permission notice shall be included  *
00013  * in all copies or substantial portions of the Software.                   *
00014  *                                                                          *
00015  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
00016  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
00017  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
00018  * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
00019  * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
00020  * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
00021  * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
00022  *                                                                          *
00023  * Except as contained in this notice, the name(s) of the above copyright   *
00024  * holders shall not be used in advertising or otherwise to promote the     *
00025  * sale, use or other dealings in this Software without prior written       *
00026  * authorization.                                                           *
00027  ****************************************************************************/
00028 
00029 /****************************************************************************
00030  *  Author: Thomas E. Dickey <dickey@clark.net> 1998                        *
00031  ****************************************************************************/
00032 
00033 #include <curses.priv.h>
00034 
00035 #include <ctype.h>
00036 #include <tic.h>
00037 
00038 MODULE_ID("$Id: comp_expand.c,v 1.17 2001/09/22 19:16:52 tom Exp $")
00039 
00040 static int
00041 trailing_spaces(const char *src)
00042 {
00043     while (*src == ' ')
00044        src++;
00045     return *src == 0;
00046 }
00047 
00048 /* this deals with differences over whether 0x7f and 0x80..0x9f are controls */
00049 #define REALCTL(s) (UChar(*(s)) < 127 && iscntrl(UChar(*(s))))
00050 #define REALPRINT(s) (UChar(*(s)) < 127 && isprint(UChar(*(s))))
00051 
00052 NCURSES_EXPORT(char *)
00053 _nc_tic_expand
00054 (const char *srcp, bool tic_format, int numbers)
00055 {
00056     static char *buffer;
00057     static size_t length;
00058 
00059     int bufp;
00060     const char *str = VALID_STRING(srcp) ? srcp : "";
00061     bool islong = (strlen(str) > 3);
00062     size_t need = (2 + strlen(str)) * 4;
00063     int ch;
00064 
00065     if (buffer == 0 || need > length) {
00066        if ((buffer = typeRealloc(char, length = need, buffer)) == 0)
00067              return 0;
00068     }
00069 
00070     bufp = 0;
00071     while ((ch = UChar(*str)) != 0) {
00072        if (ch == '%' && REALPRINT(str + 1)) {
00073            buffer[bufp++] = *str++;
00074            /*
00075             * Though the character literals are more compact, most
00076             * terminal descriptions use numbers and are not easy
00077             * to read in character-literal form.
00078             */
00079            switch (numbers) {
00080            case -1:
00081               if (str[0] == S_QUOTE
00082                   && str[1] != '\\'
00083                   && REALPRINT(str + 1)
00084                   && str[2] == S_QUOTE) {
00085                   sprintf(buffer + bufp, "{%d}", str[1]);
00086                   bufp += strlen(buffer + bufp);
00087                   str += 2;
00088               } else {
00089                   buffer[bufp++] = *str;
00090               }
00091               break;
00092               /*
00093                * If we have a "%{number}", try to translate it into
00094                * a "%'char'" form, since that will run a little faster
00095                * when we're interpreting it.  Also, having one form
00096                * for the constant makes it simpler to compare terminal
00097                * descriptions.
00098                */
00099            case 1:
00100               if (str[0] == L_BRACE
00101                   && isdigit(UChar(str[1]))) {
00102                   char *dst = 0;
00103                   long value = strtol(str + 1, &dst, 0);
00104                   if (dst != 0
00105                      && *dst == R_BRACE
00106                      && value < 127
00107                      && value != '\\'     /* FIXME */
00108                      && isprint((int) value)) {
00109                      ch = (int) value;
00110                      buffer[bufp++] = S_QUOTE;
00111                      if (ch == '\\'
00112                          || ch == S_QUOTE)
00113                          buffer[bufp++] = '\\';
00114                      buffer[bufp++] = ch;
00115                      buffer[bufp++] = S_QUOTE;
00116                      str = dst;
00117                   } else {
00118                      buffer[bufp++] = *str;
00119                   }
00120               } else {
00121                   buffer[bufp++] = *str;
00122               }
00123               break;
00124            default:
00125               buffer[bufp++] = *str;
00126               break;
00127            }
00128        } else if (ch == 128) {
00129            buffer[bufp++] = '\\';
00130            buffer[bufp++] = '0';
00131        } else if (ch == '\033') {
00132            buffer[bufp++] = '\\';
00133            buffer[bufp++] = 'E';
00134        } else if (ch == '\\' && tic_format && (str == srcp || str[-1] != '^')) {
00135            buffer[bufp++] = '\\';
00136            buffer[bufp++] = '\\';
00137        } else if (ch == ' ' && tic_format && (str == srcp ||
00138                                           trailing_spaces(str))) {
00139            buffer[bufp++] = '\\';
00140            buffer[bufp++] = 's';
00141        } else if ((ch == ',' || ch == ':' || ch == '^') && tic_format) {
00142            buffer[bufp++] = '\\';
00143            buffer[bufp++] = ch;
00144        } else if (REALPRINT(str)
00145                  && (ch != ','
00146                      && ch != ':'
00147                      && !(ch == '!' && !tic_format)
00148                      && ch != '^'))
00149            buffer[bufp++] = ch;
00150 #if 0                       /* FIXME: this would be more readable (in fact the whole 'islong' logic should be removed) */
00151        else if (ch == '\b') {
00152            buffer[bufp++] = '\\';
00153            buffer[bufp++] = 'b';
00154        } else if (ch == '\f') {
00155            buffer[bufp++] = '\\';
00156            buffer[bufp++] = 'f';
00157        } else if (ch == '\t' && islong) {
00158            buffer[bufp++] = '\\';
00159            buffer[bufp++] = 't';
00160        }
00161 #endif
00162        else if (ch == '\r' && (islong || (strlen(srcp) > 2 && str[1] == '\0'))) {
00163            buffer[bufp++] = '\\';
00164            buffer[bufp++] = 'r';
00165        } else if (ch == '\n' && islong) {
00166            buffer[bufp++] = '\\';
00167            buffer[bufp++] = 'n';
00168        }
00169 #define UnCtl(c) ((c) + '@')
00170        else if (REALCTL(str) && ch != '\\'
00171                && (!islong || isdigit(UChar(str[1])))) {
00172            (void) sprintf(&buffer[bufp], "^%c", UnCtl(ch));
00173            bufp += 2;
00174        } else {
00175            (void) sprintf(&buffer[bufp], "\\%03o", ch);
00176            bufp += 4;
00177        }
00178 
00179        str++;
00180     }
00181 
00182     buffer[bufp] = '\0';
00183     return (buffer);
00184 }