static char rcsid[] = "@(#)$Id: terminal.c,v 1.6.44.1 2007/08/25 07:45:27 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.6.44.1 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI>
* or Kari Hurtta <elm@elmme-mailer.org>
*****************************************************************************/
#include "def_misc.h"
#include "s_me.h"
#include "cs_imp.h"
#include "cs_terminal.h"
DEBUG_VAR(Debug,__FILE__,"charset");
#include <errno.h>
#ifndef ANSI_C
extern int errno;
#endif
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static unsigned char * s2us P_((char *str));
static unsigned char * s2us(str)
char *str;
{
return (unsigned char *)str;
}
enum terminal_flags { terminal_bad_flag = -1,
terminal_xterm_title = 1,
terminal_xwsh_title = 2
};
enum terminal_map_keyword { terminal_bad = -1, terminal_iso2022 = 0,
terminal_private = 1, terminal_iso2022_mb = 2,
terminal_flag = 3, terminal_iso2022_like = 4,
terminal_dw
};
struct terminal_map_item {
char * match;
enum terminal_map_keyword keyword;
union {
struct cset {
charset_t charset;
int is_def;
} iso2022;
struct privset {
struct term_cond * condition;
charset_t charset;
unsigned char * bytes;
} private;
enum terminal_flags flag;
struct cset2 {
charset_t charset;
struct setlist * iso2022_info;
} iso2022_like;
char * dw_charset;
} value;
};
static void strXcat P_((char **ret,char *val,
int maybe_signal, char *buffer, int size));
static void strXcat(ret,val,maybe_signal,buffer,size)
char **ret;
char *val;
int maybe_signal;
char *buffer;
int size;
{
if (maybe_signal) {
if (!*ret)
*ret = strfcpy(buffer,val,size);
else
*ret = strfcat(buffer,val,size);
} else
*ret = strmcat(*ret,val);
}
static enum terminal_map_keyword get_keyword P_((const char *word));
static enum terminal_map_keyword get_keyword(word)
CONST char *word;
{
if (0 == istrcmp(word,"ISO-2022"))
return terminal_iso2022;
if (0 == istrcmp(word,"ISO-2022-LIKE"))
return terminal_iso2022_like;
if (0 == istrcmp(word,"ISO-2022/DW"))
return terminal_iso2022_mb;
if (0 == istrcmp(word,"PRIVATE"))
return terminal_private;
if (0 == istrcmp(word,"FLAG"))
return terminal_flag;
if (0 == istrcmp(word,"DW"))
return terminal_dw;
return terminal_bad;
}
static char * sStr P_((unsigned char *p));
static char * sStr (p)
unsigned char *p;
{
return (char *)p;
}
struct term_cond {
enum tc_type { tt_value, tt_simple_var, tt_equal } X;
struct term_cond * p1;
struct term_cond * p2;
char * value;
};
static void zero_term_cond P_((struct term_cond *X));
static void zero_term_cond(X)
struct term_cond *X;
{
X->X = tt_value;
X->p1 = NULL;
X->p2 = NULL;
X->value = NULL;
}
static struct term_cond * copy_term_cond P_((struct term_cond *ptr));
static struct term_cond * copy_term_cond(ptr)
struct term_cond *ptr;
{
struct term_cond * ret = safe_malloc(sizeof (*ret));
zero_term_cond(ret);
ret->X = ptr->X;
if (ptr->p1)
ret->p1 = copy_term_cond(ptr->p1);
if (ptr->p2)
ret->p2 = copy_term_cond(ptr->p2);
if (ptr->value)
ret->value = safe_strdup(ptr->value);
return ret;
}
static void free_term_cond P_((struct term_cond **X));
static void free_term_cond(X)
struct term_cond **X;
{
struct term_cond *A = *X;
if (A->p1)
free_term_cond(&(A->p1));
if (A->p2)
free_term_cond(&(A->p2));
if (A->value) {
free(A->value);
A->value = NULL;
}
free(A);
A = NULL;
*X = A;
}
static int match_term_cond P_((struct term_cond *A, struct term_cond *B));
static int match_term_cond(A,B)
struct term_cond *A;
struct term_cond *B;
{
if (A->p1 && B->p1) {
if (! match_term_cond(A->p1,B->p1))
return 0;
} else if (A->p1 || B->p1)
return 0;
if (A->p2 && B->p2) {
if (! match_term_cond(A->p2,B->p2))
return 0;
} else if (A->p2 || B->p2)
return 0;
if (A->value && B->value) {
if (0 != strcmp(A->value,B->value))
return 0;
} else if (A->value || B->value)
return 0;
return 1;
}
enum tc_token_type { tc_left = '[', tc_rigth = ']', tc_equal = '=',
tc_quoted = '"', tc_plain = 'a', tc_simple_var = '$',
tc_none = 0 };
static enum tc_token_type tc_get_token P_((char **value, char **ptr));
static enum tc_token_type tc_get_token (value,ptr)
char **value;
char **ptr;
{
enum tc_token_type r = tc_none;
char *C = *ptr;
*value = NULL;
while (*C && whitespace (*C)) /* skip leading whitespace */
C++;
switch (*C) {
int L;
case '\0': goto fail;
case '[': r = tc_left; C++; break;
case ']': r = tc_rigth; C++; break;
case '=': r = tc_equal; C++; break;
case '"':
L = len_next_part(C);
*value = dequote_opt(C,L);
C += L;
r = tc_quoted;
break;
case '$':
L = strcspn(C+1," []=\"$/");
if (1 == L) {
r = tc_none;
goto fail;
}
*value = safe_malloc(L+1);
memcpy(*value,C+1,L);
(*value)[L] = '\0';
C += L +1;
r = tc_simple_var;
break;
default:
L = strcspn(C," []=\"$");
*value = safe_malloc(L+1);
memcpy(*value,C,L);
(*value)[L] = '\0';
C += L;
r = tc_plain;
break;
}
fail:
*ptr = C;
return r;
}
static struct term_cond * tc_get_expression P_((char **ptr));
static struct term_cond * tc_get_expression(ptr)
char **ptr;
{
struct term_cond *r = NULL;
char *value = NULL;
switch (tc_get_token(&value,ptr)) {
case tc_plain:
lib_error(CATGETS(elm_msg_cat, MeSet, MeTreatedAsQuoted,
"Unregonized token %s treated as quoted value"),
value);
/* FALLTHRU */
case tc_quoted:
r = safe_malloc(sizeof (*r));
zero_term_cond(r);
r->value = value;
r->X = tt_value;
value = NULL;
break;
case tc_simple_var:
r = safe_malloc(sizeof (*r));
zero_term_cond(r);
r->value = value;
r->X = tt_simple_var;
value = NULL;
break;
}
return r;
}
static struct term_cond * parse_condition P_((char **ptr));
static struct term_cond * parse_condition(ptr)
char **ptr;
{
struct term_cond *r = NULL;
struct term_cond *r1 = NULL;
struct term_cond *r2 = NULL;
char *value = NULL;
if (tc_left != tc_get_token(&value,ptr))
goto err;
r1 = tc_get_expression(ptr);
if (!r1)
goto err;
if (tc_equal != tc_get_token(&value,ptr))
goto err;
r2 = tc_get_expression(ptr);
if (!r2)
goto err;
if (tc_rigth != tc_get_token(&value,ptr))
goto err;
r = safe_malloc(sizeof (*r));
zero_term_cond(r);
r->X = tt_equal;
r->p1 = r1;
r->p2 = r2;
r1 = NULL; r2 = NULL;
err:
if (value)
free(value);
if (r1)
free_term_cond(&r1);
if (r2)
free_term_cond(&r2);
return r;
}
static void tc_dump_expression P_((FILE *f, struct term_cond * C));
static char * tc_eval_expression P_((struct term_cond * C));
static char * tc_eval_expression(C)
struct term_cond * C;
{
char * r = NULL;
switch (C->X) {
char buffer[1024];
int v;
case tt_value:
/* expand_path converts $VAR between / characters */
v = expand_path(buffer,C->value,sizeof buffer);
if (v > 0) {
DPRINT(Debug,9,(&Debug,"tc_eval_expression : \"%s\" expanded\n",
C->value));
r = safe_strdup(buffer);
} else if (v == 0) {
DPRINT(Debug,9,(&Debug,"tc_eval_expression : \"%s\" copied\n",
C->value));
r = safe_strdup(C->value);
} else {
DPRINT(Debug,9,(&Debug,"tc_eval_expression : \"%s\" failed\n",
C->value));
}
DPRINT(Debug,9,(&Debug,"tc_eval_expression \"%s\" = %s\n",
C->value,
r ? r : "NULL"));
break;
case tt_simple_var:
r = getenv(C->value);
if (r)
r = safe_strdup(r);
DPRINT(Debug,9,(&Debug,"tc_eval_expression $%s = %s\n",
C->value,
r ? r : "NULL"));
break;
default:
DPRINT(Debug,8,(&Debug,"tc_eval_expression %d (bad)\n",C->X));
}
return r;
}
static void dump_condition P_((FILE *f, struct term_cond * C));
static int eval_condition P_((struct term_cond * C));
static int eval_condition(C)
struct term_cond * C;
{
int r = 0;
char * v1 = NULL;
char * v2 = NULL;
#ifdef DEBUG
if (Debug.active >= 8) {
FILE *F;
DPRINT(Debug,8,(&Debug,"eval_condition "));
F = debug_to_FILE(&Debug);
if (F) {
dump_condition(F,C);
fputc('\n',F);
fclose(F);
}
}
#endif
if (C->p1)
v1 = tc_eval_expression(C->p1);
if (C->p2)
v2 = tc_eval_expression(C->p2);
switch (C->X) {
case tt_equal:
if (!v1 || !v2)
break;
r = 0 == strcmp(v1,v2);
DPRINT(Debug,8,(&Debug,"eval_condition \"%s\" = \"%s\"\n",v1,v2));
break;
}
if (v1)
free(v1);
if (v2)
free(v2);
DPRINT(Debug,8,(&Debug,"eval_condition=%d\n",r));
return r;
}
static void tc_dump_expression(f,C)
FILE *f;
struct term_cond * C;
{
switch (C->X) {
case tt_value:
elm_fprintf(f,FRM("%Q"),C->value);
break;
case tt_simple_var:
fprintf(f,"$%s",C->value);
break;
default:
fputc('?',f);
}
}
static void dump_condition(f,C)
FILE *f;
struct term_cond * C;
{
fputc('[',f);
fputc(' ',f);
if (C->p1)
tc_dump_expression(f,C->p1);
if (tt_equal == C->X)
fputc('=',f);
else
fputc('?',f);
if (C->p2)
tc_dump_expression(f,C->p2);
fputc(' ',f);
fputc(']',f);
}
static struct {
char *flag;
enum terminal_flags flag_value;
} terminal_flag_list[] = {
{ "xterm-title" , terminal_xterm_title },
{ "xwsh-title" , terminal_xwsh_title }
};
struct terminal_map_item * load_terminal_map(filename,errors)
CONST char *filename;
int *errors;
{
struct terminal_map_item *result;
int result_len = 0;
FILE * f;
int max_result = 0;
int c;
char * buf = NULL;
int err = can_open(filename,"r");
if (err) {
DPRINT(Debug,2,(&Debug,"load_terminal_map: %s: %s (can_open)\n",
filename,error_description(err)));
return NULL;
}
f = fopen(filename,"r");
if (!f) {
int err = errno;
DPRINT(Debug,2,(&Debug,"load_terminal_map: %s: %s\n",
filename,error_description(err)));
return NULL;
}
while(EOF != (c = fgetc(f)))
if ('\n' == c)
max_result++;
DPRINT(Debug,10,(&Debug,"load_terminal_map: %s, max_result=%d\n",
filename,max_result));
if (!max_result) {
fclose(f);
return NULL;
}
rewind(f);
result = safe_malloc((max_result +1) * sizeof (result[0]));
/* malloc_gets reallocates buf and do not return \n.
It returns -1 if line is longer than given limit (32000)
and -2 is returned on error (buffer may still be alloced)
*/
while (result_len < max_result &&
!feof(f) && !ferror(f)) {
int l1 = malloc_gets(&buf,32000,f);
char * c = buf,*c1,*c2;
enum terminal_map_keyword kw;
if (-1 == l1) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeTooLongLine,
"%.30s: Too long line: %.30s..."),
filename,buf ? buf : "???");
(*errors) ++;
goto OUT;
} else if (-2 == l1) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MeReadError,
"%.30s: Reading error: %s"),
filename,error_description(err));
(*errors) ++;
} else if (0 == l1)
continue;
while (l1-- > 0 && whitespace(buf[l1]))
buf[l1] = '\0';
c = buf;
while (*c && whitespace (*c)) /* skip leading whitespace */
c++;
if ('#' == *c)
continue;
if (!*c)
continue;
c1 = strpbrk(c," \t");
if (!c1) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
*c1 = '\0';
c1++;
while (*c1 && whitespace (*c1)) /* skip leading whitespace */
c1++;
if (!*c1) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
c2 = strpbrk(c1," \t");
if (!c2) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
*c2 = '\0';
c2++;
while (*c2 && whitespace (*c2)) /* skip leading whitespace */
c2++;
if (!*c2) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
kw = get_keyword(c1);
if (terminal_bad == kw) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
switch(kw) {
char * c3;
int size;
int i;
case terminal_dw:
result[result_len].keyword = kw;
result[result_len].value.dw_charset = safe_strdup(c2);
result[result_len].match = safe_strdup(c);
result_len++;
break;
case terminal_iso2022:
case terminal_iso2022_mb:
result[result_len].keyword = kw;
if (load_charset_map_info(&result[result_len].
value.iso2022.charset,c2))
result[result_len].value.iso2022.is_def =
((result[result_len].value.iso2022.charset->flags &
SET_nodata) != 0);
else {
result[result_len].value.iso2022.charset =
MIME_name_to_charset(c2,0);
result[result_len].value.iso2022.is_def = 0;
}
if (!result[result_len].value.iso2022.charset) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownTerminalCharset,
"Unknown terminal charset %s (file %s)"),
c2,filename);
(*errors) ++;
continue;
}
if (!result[result_len].value.iso2022.charset->map_info) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeCharsetNeedsMap,
"Charset %s needs map= defination (file %s)"),
result[result_len].value.iso2022.charset->MIME_name ?
result[result_len].value.iso2022.charset->MIME_name :
"<no MIME name>",
filename);
(*errors) ++;
continue;
}
if (!result[result_len].value.iso2022.charset->iso2022_info) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeCharsetNeedsIso2022,
"Charset %s needs iso2022 defination (file %s)"),
result[result_len].value.iso2022.charset->MIME_name ?
result[result_len].value.iso2022.charset->MIME_name :
"<no MIME name>",
filename);
(*errors) ++;
continue;
}
if (terminal_iso2022_mb == result[result_len].keyword &&
0 == (CS_printable_len &
charset_properties(result[result_len].value.iso2022.
charset))) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeCharsetNotMB,
"Charset %s does not support /DW flag (file %s)"),
result[result_len].value.iso2022.charset->MIME_name ?
result[result_len].value.iso2022.charset->MIME_name :
"<no MIME name>",
filename);
(*errors) ++;
continue;
}
result[result_len].match = safe_strdup(c);
result_len++;
break;
case terminal_iso2022_like: {
struct setlist new_setlist;
int setcount = 0;
char * opt;
char * WALK;
iso2022_clear_setlist(&new_setlist);
result[result_len].keyword = kw;
c3 = strpbrk(c2," \t");
if (!c3) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
*c3 = '\0';
c3++;
while (*c3 && whitespace (*c3)) /* skip leading whitespace */
c3++;
if (!*c3) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
continue;
}
result[result_len].value.iso2022_like.charset =
MIME_name_to_charset(c2,0);
if (!result[result_len].value.iso2022_like.charset) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownTerminalCharset,
"Unknown terminal charset %s (file %s)"),
c2,filename);
(*errors) ++;
continue;
}
if (';' == *c3)
c3++;
for (opt = mime_parse_content_opts(c3, &WALK);
opt;
opt = mime_parse_content_opts(NULL, &WALK)) {
char * q = strchr(opt,'=');
char *val;
if (!q) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
continue;
}
*q++ = '\0';
val = dequote_opt(q,strlen(q));
if (! parse_iso2022_specification(opt,val,
&setcount,
&new_setlist)) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
}
free(val);
}
if (0 == setcount) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
continue;
}
result[result_len].value.iso2022_like.iso2022_info =
loc_setlist(new_setlist);
result[result_len].match = safe_strdup(c);
result_len++;
}
break;
case terminal_private:
result[result_len].keyword = kw;
c3 = strpbrk(c2," \t");
if (!c3) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
break;
}
*c3 = '\0';
c3++;
while (*c3 && whitespace (*c3)) /* skip leading whitespace */
c3++;
if (!*c3) {
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
continue;
}
result[result_len].value.private.condition = NULL;
if ('[' == *c3) {
result[result_len].value.private.condition = parse_condition(&c3);
if (!result[result_len].value.private.condition)
goto err_3;
while (*c3 && whitespace (*c3)) /* skip leading whitespace */
c3++;
if (!*c3) {
err_3:
lib_error(CATGETS(elm_msg_cat, MeSet, MeBadLine,
"%.30s: Bad line: %.30s..."),
filename,buf);
(*errors) ++;
continue;
}
}
result[result_len].value.private.charset =
MIME_name_to_charset(c2,0);
if (!result[result_len].value.private.charset) {
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownTerminalCharset,
"Unknown terminal charset %s (file %s)"),
c2,filename);
(*errors) ++;
continue;
}
size = strlen(c3);
result[result_len].value.private.bytes = safe_malloc(size+1);
if (!parse_gen_spec(c3,result[result_len].
value.private.bytes,
size)) {
(*errors) ++;
continue;
}
result[result_len].value.private.bytes[size] = '\0';
result[result_len].match = safe_strdup(c);
result_len++;
break;
case terminal_flag:
result[result_len].keyword = kw;
result[result_len].value.flag = terminal_bad_flag;
for (i = 0;
i < sizeof terminal_flag_list / sizeof (terminal_flag_list[0]);
i++) {
if (0 == strcmp(terminal_flag_list[i].flag,c2)) {
result[result_len].value.flag =
terminal_flag_list[i].flag_value;
goto ok1;
}
}
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnknownTerminalFlag,
"Unknown terminal flag %s (file %s)"),
c2,filename);
(*errors) ++;
continue;
ok1:
result[result_len].match = safe_strdup(c);
result_len++;
break;
}
}
if (ferror(f)) {
int err = errno;
lib_error(CATGETS(elm_msg_cat, MeSet, MeReadError,
"%.30s: Reading error: %s"),
filename,error_description(err));
(*errors) ++;
}
OUT:
if (buf) {
free(buf);
}
result[result_len].match = NULL;
result[result_len].keyword = terminal_bad;
if (!feof(f)) {
DPRINT(Debug,3,(&Debug,
"load_terminal_map: %s, All results not readed\n",
filename));
}
fclose(f);
DPRINT(Debug,10,(&Debug,
"load_terminal_map: %s, result_len=%d\n",
filename,result_len));
return result;
}
static int name_ok P_((CONST char *name));
static int name_ok(name)
CONST char *name;
{
if ('\0' == *name)
return 0;
return strlen(name) == strspn(name,"ABCDEFGHIJKLMNOPQRSTUVXYZ-0123456789");
}
void dump_terminal_map(f,map)
FILE *f;
struct terminal_map_item *map;
{
struct terminal_map_item *ptr;
for (ptr = map; ptr && ptr->match; ptr++) {
switch(ptr->keyword) {
char *s;
int i;
case terminal_dw:
fputs(ptr->match,f);
fputc('\t',f);
fputs("DW",f);
fputc('\t',f);
fputs(ptr->value.dw_charset,f);
break;
case terminal_iso2022:
case terminal_iso2022_mb:
fputs(ptr->match,f);
fputc('\t',f);
if (terminal_iso2022_mb == ptr->keyword)
fputs("ISO-2022/DW",f);
else
fputs("ISO-2022",f);
fputc('\t',f);
if (ptr->value.iso2022.is_def)
dump_map_info(f,ptr->value.iso2022.charset);
else {
if (!ptr->value.iso2022.charset->MIME_name) {
fputs("# <No MIME name> ",f);
} else if (name_ok(ptr->value.iso2022.charset->MIME_name)) {
fputs(ptr->value.iso2022.charset->MIME_name,f);
} else {
elm_fprintf(f,FRM("%Q;!"),
ptr->value.iso2022.charset->MIME_name);
}
}
break;
case terminal_iso2022_like:
fputs(ptr->match,f);
fputc('\t',f);
fputs("ISO-2022-LIKE",f);
fputc('\t',f);
fputs(ptr->value.iso2022_like.charset->MIME_name,f);
fputc('\t',f);
print_setlist(f,ptr->value.iso2022_like.iso2022_info);
break;
case terminal_private:
fputs(ptr->match,f);
fputc('\t',f);
fputs("PRIVATE",f);
fputc('\t',f);
fputs(ptr->value.private.charset->MIME_name,f);
if (ptr->value.private.condition) {
fputc('\t',f);
dump_condition(f,ptr->value.private.condition);
}
fputc('\t',f);
s = iso2022_codestr(ptr->value.private.bytes,
strlen(sStr(ptr->value.private.bytes)));
if (s) {
fputs(s,f);
free(s);
}
break;
case terminal_flag:
fputs(ptr->match,f);
fputc('\t',f);
fputs("FLAG",f);
fputc('\t',f);
for (i = 0;
i < sizeof terminal_flag_list / sizeof (terminal_flag_list[0]);
i++) {
if (ptr->value.flag == terminal_flag_list[i].flag_value) {
fputs(terminal_flag_list[i].flag,f);
break;
}
}
break;
}
fputc('\n',f);
}
}
static int match_item P_((struct terminal_map_item *a,
struct terminal_map_item *b));
static int match_item(a,b)
struct terminal_map_item *a;
struct terminal_map_item*b;
{
if (a->keyword != b->keyword)
return 0;
if (0 != strcmp(a->match,b->match))
return 0;
switch(a->keyword) {
case terminal_dw:
if (0 != strcmp(a->value.dw_charset,
a->value.dw_charset))
return 0;
return 1;
case terminal_iso2022:
case terminal_iso2022_mb:
if (a->value.iso2022.is_def !=
b->value.iso2022.is_def)
return 0;
if (a->value.iso2022.charset ==
b->value.iso2022.charset)
return 1;
if (a->value.iso2022.charset->MIME_name &&
b->value.iso2022.charset->MIME_name) {
if (0 == strcmp(a->value.iso2022.charset->MIME_name,
b->value.iso2022.charset->MIME_name))
return 1;
else
return 0;
}
if (a->value.iso2022.charset->codeset &&
b->value.iso2022.charset->codeset &&
0 == strcmp(a->value.iso2022.charset->codeset,
b->value.iso2022.charset->codeset))
return 1;
return 0;
case terminal_iso2022_like:
if (a->value.iso2022_like.charset !=
b->value.iso2022_like.charset)
return 0;
if (a->value.iso2022_like.iso2022_info !=
b->value.iso2022_like.iso2022_info)
return 0;
return 1;
case terminal_private:
if (a->value.private.charset !=
b->value.private.charset)
return 0;
if (a->value.private.condition &&
b->value.private.condition) {
if (! match_term_cond(a->value.private.condition,
b->value.private.condition))
return 0;
} else if (a->value.private.condition ||
b->value.private.condition)
return 0;
return 1;
case terminal_flag:
if (a->value.flag != b->value.flag)
return 0;
return 1;
}
panic("CHARSET PANIC",__FILE__,__LINE__,"match_item",
"Unsupported type",0);
return 0;
}
void change_terminal_map(map,new)
struct terminal_map_item **map;
struct terminal_map_item *new;
{
int count = 0;
struct terminal_map_item *ptr;
for (ptr = *map; ptr && ptr->match; ptr++)
count++;
for (ptr = new; ptr && ptr->match; ptr++)
count++;
if (!count)
return;
if (!*map) {
*map = safe_malloc((count+1) * sizeof ((*map)[0]));
(*map)->match = NULL;
} else
*map = safe_realloc(*map, (count+1) * sizeof ((*map)[0]));
for (ptr = new; ptr && ptr->match; ptr++) {
struct terminal_map_item *ptr2;
for (ptr2 = *map; ptr2->match; ptr2++) {
if (match_item(ptr,ptr2)) {
goto set_it;
}
}
if (ptr2 > (*map) + count)
panic("CHARSET PANIC",__FILE__,__LINE__,"change_terminal_map",
"Overflow",0);
ptr2->match = safe_strdup(ptr->match);
ptr2->keyword = ptr->keyword;
bzero((void *)(& ptr2->value), sizeof (ptr2->value));
(ptr2+1)->match = NULL;
set_it:
switch(ptr2->keyword) {
case terminal_dw:
ptr2->value.dw_charset =
strmcpy(ptr2->value.dw_charset,
ptr->value.dw_charset);
break;
case terminal_iso2022:
case terminal_iso2022_mb:
ptr2->value.iso2022 = ptr->value.iso2022;
break;
case terminal_iso2022_like:
ptr2->value.iso2022_like = ptr->value.iso2022_like;
break;
case terminal_private:
ptr2->value.private.charset = ptr->value.private.charset;
ptr2->value.private.bytes =
s2us(strmcpy(us2s(ptr2->value.private.bytes),
us2s(ptr->value.private.bytes)));
if (ptr2->value.private.condition)
free_term_cond(& (ptr2->value.private.condition));
if (ptr->value.private.condition)
ptr2->value.private.condition =
copy_term_cond(ptr->value.private.condition);
break;
case terminal_flag:
ptr2->value.flag = ptr->value.flag;
break;
default:
panic("CHARSET PANIC",__FILE__,__LINE__,"change_terminal_map",
"unsupported type",0);
}
}
}
void free_terminal_map(map)
struct terminal_map_item **map;
{
struct terminal_map_item *ptr;
for (ptr = *map; ptr && ptr->match; ptr++) {
switch(ptr->keyword) {
case terminal_dw:
if (ptr->value.dw_charset)
free(ptr->value.dw_charset);
break;
case terminal_iso2022:
case terminal_iso2022_mb:
break;
case terminal_iso2022_like:
break;
case terminal_private:
if (ptr->value.private.bytes)
free(ptr->value.private.bytes);
ptr->value.private.bytes = NULL;
if (ptr->value.private.condition)
free_term_cond(& (ptr->value.private.condition));
break;
case terminal_flag:
break;
default:
panic("CHARSET PANIC",__FILE__,__LINE__,"free_terminal_map",
"unsupported type",0);
}
}
free(*map);
*map = NULL;
}
/* ----------------------------------------------------------------- */
/* Hopefully quite safe to be called from signal handler */
static struct terminal_map_item * loc_info P_((const char *terminal,
charset_t set,
int only_switch));
static struct terminal_map_item * loc_info(terminal,set, only_switch)
CONST char *terminal;
charset_t set;
int only_switch;
{
int i;
SIGDPRINT(Debug,9,(&Debug,"** Looking terminal %s (set %s)%s\n",
terminal,
set->MIME_name ? set->MIME_name : "<no MIME name>",
only_switch ? " charset switches only" : ""));
for (i = 0; i < 2; i++) {
struct terminal_map_item *ptr = user_terminal_map;
if (i)
ptr = system_terminal_map;
while (ptr && ptr->match) {
char * c = NULL;
if (0 == strcmp(ptr->match,terminal) ||
( (c = strchr(ptr->match,'*')) &&
*(c+1) == '\0' &&
0 == strncmp(ptr->match,terminal,c - ptr->match))) {
if (ptr->keyword == terminal_iso2022 &&
match_charset_name(ptr->value.iso2022.charset,set)) {
SIGDPRINT(Debug,9,(&Debug,"-- Found ISO2022 match %s\n",
ptr->match));
return ptr;
}
if (ptr->keyword == terminal_iso2022_mb &&
match_charset_name(ptr->value.iso2022.charset,set)) {
SIGDPRINT(Debug,9,(&Debug,"-- Found ISO2022 MB match %s\n",
ptr->match));
return ptr;
}
if (ptr->keyword == terminal_iso2022_like &&
match_charset_name(ptr->value.iso2022_like.charset,set)) {
SIGDPRINT(Debug,9,(&Debug,"-- Found ISO2022-LIKE match %s\n",
ptr->match));
return ptr;
}
if (ptr->keyword == terminal_private &&
match_charset_name(ptr->value.private.charset, set)) {
if (ptr->value.private.condition) {
if (!eval_condition(ptr->value.private.condition)) {
goto no_this;
}
}
SIGDPRINT(Debug,9,(&Debug,"-- Found provate match %s\n",
ptr->match));
return ptr;
}
if (ptr->keyword == terminal_dw && set->MIME_name &&
0 == istrcmp(set->MIME_name,ptr->value.dw_charset)) {
if (only_switch) {
SIGDPRINT(Debug,9,(&Debug,"-- Found DW match %s (ignored)\n",
ptr->match));
goto no_this;
}
SIGDPRINT(Debug,9,(&Debug,"-- Found DW match %s\n",
ptr->match));
return ptr;
}
}
no_this:
ptr++;
}
}
return NULL;
}
void terminal_can_switch(terminal,storage,n,max)
CONST char *terminal;
charset_t *storage;
int *n;
int max;
{
int i;
struct terminal_map_item * back;
/* Can not switch to other sets if can not
switch back to display_charset
*/
back = loc_info(terminal,display_charset,1);
if (!back)
return;
for (i = 0; i < 2; i++) {
struct terminal_map_item *ptr = user_terminal_map;
if (i)
ptr = system_terminal_map;
while (ptr && ptr->match && *n < max) {
char * c = NULL;
int j;
SIGDPRINT(Debug,9,(&Debug,"-- Looking %s ...\n",
ptr->match));
if (0 == strcmp(ptr->match,terminal) ||
( (c = strchr(ptr->match,'*')) &&
*(c+1) == '\0' &&
0 == strncmp(ptr->match,terminal,c - ptr->match))) {
switch (ptr->keyword) {
case terminal_iso2022:
case terminal_iso2022_mb:
SIGDPRINT(Debug,8,(&Debug,
"-- Adding %s (%p) to possible sets\n",
ptr->value.iso2022.charset->MIME_name ?
ptr->value.iso2022.charset->MIME_name :
"<no MIME name>",
ptr->value.iso2022.charset
));
storage[(*n)++] = ptr->value.iso2022.charset;
break;
case terminal_iso2022_like:
SIGDPRINT(Debug,8,(&Debug,
"-- Adding %s (%p) to possible sets\n",
ptr->value.iso2022_like.charset->MIME_name ?
ptr->value.iso2022_like.charset->MIME_name :
"<no MIME name>",
ptr->value.iso2022_like.charset
));
storage[(*n)++] = ptr->value.iso2022_like.charset;
break;
case terminal_private:
if (ptr->value.private.condition) {
if (!eval_condition(ptr->value.private.condition)) {
SIGDPRINT(Debug,8,(&Debug,
"-- NOT adding %s (%p) to possible sets (condition fail)\n",
ptr->value.private.charset->MIME_name ?
ptr->value.private.charset->MIME_name :
"<no MIME name>",
ptr->value.private.charset
));
goto no_this;
}
}
SIGDPRINT(Debug,8,(&Debug,
"-- Adding %s (%p) to possible sets\n",
ptr->value.private.charset->MIME_name ?
ptr->value.private.charset->MIME_name :
"<no MIME name>",
ptr->value.private.charset
));
storage[(*n)++] = ptr->value.private.charset;
break;
}
for (j = 0; j < (*n) -1; j++)
if (storage[j] == storage[(*n)-1]) {
SIGDPRINT(Debug,8,(&Debug,
"-- Removing duplicate %s from possible sets\n",
storage[(*n)-1]->MIME_name ?
storage[(*n)-1]->MIME_name :
"<no MIME name>"));
(*n)--; /* Remove duplicate */
break;
}
}
no_this:
ptr++;
}
}
}
int terminal_can_switch_to(terminal,set,silent)
CONST char *terminal;
charset_t set;
int silent;
{
struct terminal_map_item * a = loc_info(terminal,set,1);
if (!a) {
if (!silent)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeNoInformationToSwitchTerminal,
"No information to switch %s terminal to %s charset!"),
terminal,
set->MIME_name ? set->MIME_name : "<no MIME name>");
return 0;
}
a = loc_info(terminal,display_charset,1);
if (!a) {
if (!silent)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeNoInformationToSwitchBack,
"No information to switch %s terminal back to %s charset!"),
terminal,
display_charset->MIME_name ? display_charset->MIME_name :
"<no MIME name>");
return 0;
}
return 1;
}
/* Returns first flags found for terminal from list or terminal_bad_flag,
flags[] is terminated with terminal_bad_flag
Hopefully quite safe to be called from signal handler
*/
static enum terminal_flags find_terminal_flag P_((const char *terminal,
enum terminal_flags flags[]));
static enum terminal_flags find_terminal_flag(terminal,flags)
CONST char *terminal;
enum terminal_flags flags[];
{
int i,j;
SIGDPRINT(Debug,9,(&Debug,"** Looking terminal %s (flags",
terminal));
for (j = 0; terminal_bad_flag != flags[j]; j++) {
SIGDPRINT(Debug,9,(&Debug," %d",flags[j]));
}
SIGDPRINT(Debug,9,(&Debug,")\n"));
for (i = 0; i < 2; i++) {
struct terminal_map_item *ptr = user_terminal_map;
if (i)
ptr = system_terminal_map;
while (ptr && ptr->match) {
char * c = NULL;
if (0 == strcmp(ptr->match,terminal) ||
( (c = strchr(ptr->match,'*')) &&
*(c+1) == '\0' &&
0 == strncmp(ptr->match,terminal,c - ptr->match))) {
if (ptr->keyword == terminal_flag) {
int j;
for (j = 0; terminal_bad_flag != flags[j]; j++) {
if (ptr->value.flag == flags[j]) {
SIGDPRINT(Debug,9,(&Debug,
"-- Found flag match %s (flag %d)\n",
ptr->match,flags[j]));
return flags[j];
}
}
}
}
ptr++;
}
}
return terminal_bad_flag;
}
/* May be called from signal handler -- on that situation use
buffer specified as argument -- otherwise result is malloced
*/
char * terminal_set_title(terminal,window_title, icon_title,buffer,size)
char *terminal;
char *window_title;
char *icon_title;
char * buffer;
int size;
{
/* window_title and icon_title are assumed to be US-ASCII ... */
int maybe_signal = buffer != NULL;
char *ret = NULL;
static enum terminal_flags methods[] = {
terminal_xterm_title,
terminal_xwsh_title,
terminal_bad_flag
};
enum terminal_flags method = find_terminal_flag(terminal,methods);
if (maybe_signal) {
SIGDPRINT(Debug,8,(&Debug,
"terminal_set_title: buffer=%p size=%d\n",
buffer,size));
}
switch (method) {
case terminal_xterm_title:
if (window_title == icon_title) { /* Optimize */
if (window_title) {
strXcat(&ret,"\033]0;",
maybe_signal,buffer,size);
strXcat(&ret,window_title,
maybe_signal,buffer,size);
strXcat(&ret,"\007",
maybe_signal,buffer,size);
}
} else {
if (icon_title) {
strXcat(&ret,"\033]1;",
maybe_signal,buffer,size);
strXcat(&ret,icon_title,
maybe_signal,buffer,size);
strXcat(&ret,"\007",
maybe_signal,buffer,size);
}
if (window_title) {
strXcat(&ret,"\033]2;",
maybe_signal,buffer,size);
strXcat(&ret,window_title,
maybe_signal,buffer,size);
strXcat(&ret,"\007",
maybe_signal,buffer,size);
}
}
break;
case terminal_xwsh_title:
if (icon_title) {
strXcat(&ret,"\033P3.y",
maybe_signal,buffer,size);
strXcat(&ret,icon_title,
maybe_signal,buffer,size);
strXcat(&ret,"\033\\",
maybe_signal,buffer,size);
}
if (window_title) {
strXcat(&ret,"\033P1.y",
maybe_signal,buffer,size);
strXcat(&ret,window_title,
maybe_signal,buffer,size);
strXcat(&ret,"\033\\",
maybe_signal,buffer,size);
}
case terminal_bad_flag:
SIGDPRINT(Debug,8,(&Debug,
"terminal_set_title: No way to set title for %s\n",
terminal));
break;
}
if (maybe_signal && ret && ret != buffer)
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_set_title",
"buffer != ret when called from signal",1);
return ret;
}
void terminal_change_system_charset(terminal)
char *terminal;
{
struct terminal_map_item * a = loc_info(terminal,system_charset,0);
if (system_charset->charset_type == &cs_unknown) {
DPRINT(Debug,9,(&Debug,"terminal_change_system_charset: System charset is already type unknown\n"));
return;
}
#if defined(WCHAR) && defined(__STDC_ISO_10646__)
if (a && a->keyword == terminal_dw) {
change_system_charset_1();
}
#endif
}
static void change_helper_2 P_((char **ret,struct iso2022_setid ID,
screen_info_p terminal_info,
char * buffer,
int size,
int maybe_signal,
int setpos
));
static void change_helper_2(ret,ID,terminal_info,buffer,size,maybe_signal,setpos)
char **ret;
struct iso2022_setid ID;
screen_info_p terminal_info;
char * buffer;
int size;
int maybe_signal;
int setpos;
{
if (maybe_signal) {
if (!*ret)
*ret =
iso2022_change_helper_1(terminal_info,ID,
setpos,
buffer,size);
else {
char buffer1[100];
char *c =
iso2022_change_helper_1(terminal_info,ID,
setpos,
buffer1,sizeof buffer1);
if (c)
*ret = strfcat(buffer,c,size);
}
} else {
char *c =
iso2022_change_helper_1(terminal_info,ID,
setpos,
NULL,0);
if (c) {
*ret = strmcat(*ret,c);
free(c);
}
}
}
static void change_helper_3 P_((char **RET,struct setlist * iso2022_info,
screen_info_p terminal_info,
char * buffer,
int size,
int maybe_signal,
int MB));
static void change_helper_3(RET,iso2022_info,terminal_info,buffer,size,
maybe_signal,MB)
char **RET;
struct setlist * iso2022_info;
screen_info_p terminal_info;
char * buffer;
int size;
int maybe_signal;
int MB;
{
char * ret = *RET;
int i;
if (bank_unspecified != iso2022_info->initial_L) {
terminal_info->current_L = iso2022_info->initial_L;
if (maybe_signal) {
if (!ret)
ret = lock_shift(0,terminal_info->current_L,buffer,
size);
else {
char buffer1[10];
char * c = lock_shift(0,terminal_info->current_L,
buffer1,sizeof buffer1);
ret = strfcat(buffer,c,size);
}
} else {
char *c = lock_shift(0,terminal_info->current_L,NULL,0);
ret = strmcat(ret,c);
free(c);
}
}
if (bank_unspecified != iso2022_info->initial_R) {
terminal_info->current_R = iso2022_info->initial_R;
if (maybe_signal) {
if (!ret)
ret = lock_shift(1,terminal_info->current_R,
buffer,size);
else {
char buffer1[10];
char *c = lock_shift(1,terminal_info->current_R,
buffer1,sizeof buffer1);
ret = strfcpy(buffer,c,size);
}
} else {
char *c = lock_shift(1,terminal_info->current_R,NULL,0);
ret = strmcat(ret,c);
free(c);
}
}
for (i = 0;
i < sizeof (iso2022_info->initial_bank) /
sizeof (iso2022_info->initial_bank[0]);
i++) {
int x = iso2022_info->initial_bank[i];
if (-1 != x) {
int n;
struct iso2022_setid ID;
if (x < 0 ||
x >= sizeof (iso2022_info->sets) /
sizeof (iso2022_info->sets[0]) ||
! iso2022_info->sets[x])
panic("STRING PANIC",__FILE__,__LINE__,
"change_helper_3",
"Bad initial_bank (set)",
maybe_signal);
ID = * (iso2022_info->sets[x]);
if (ID.bank != i)
panic("STRING PANIC",__FILE__,__LINE__,
"change_helper_3",
"Bad initial_bank (bank number)",
maybe_signal);
n = set_initial_bank(&ret,ID,terminal_info,buffer,size,
maybe_signal);
/* Do not support variable width inside of bank */
if (MB &&
(iso2022_94x94 == ID.type ||
iso2022_96x96 == ID.type))
terminal_info->width[n] = 2;
else
terminal_info->width[n] = 1;
}
}
#ifdef WCHAR
terminal_info->wcwidth = MB;
#endif
for (i = 0;
i < sizeof (iso2022_info->sets) /
sizeof (iso2022_info->sets[0]) &&
iso2022_info->sets[i];
i++) {
int setpos;
struct iso2022_setid ID = * (iso2022_info->sets[i]);
/* iso2022_give_setpos does iso2022_setid_select_bank() */
setpos = iso2022_give_setpos(&ID,terminal_info);
if (-1 == setpos) {
if ((terminal_info)->set_count >=
sizeof ((terminal_info)->sets) /
sizeof ((terminal_info)->sets[0]))
panic("STRING PANIC",__FILE__,__LINE__,
"change_helper_3",
"Too many iso 2022 sets on display charset",
maybe_signal);
setpos = terminal_info->set_count++;
terminal_info->sets[setpos] = ID;
}
change_helper_2(&ret,ID,terminal_info,buffer,size,
maybe_signal,setpos);
/* Do not support variable width inside of bank */
if (MB &&
(iso2022_94x94 == ID.type ||
iso2022_96x96 == ID.type))
terminal_info->width[setpos] = 2;
else
terminal_info->width[setpos] = 1;
}
debug_display_settings(terminal_info,maybe_signal,0);
*RET = ret;
}
char * terminal_set_info (terminal,set,terminal_info)
char *terminal;
charset_t set;
screen_info_p terminal_info;
{
char * ret = NULL;
struct terminal_map_item * a;
if (!terminal_info) {
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_set_info",
"terminal_info not set",0);
}
if (DISPLAY_STATE_magic != terminal_info->magic)
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_set_info",
"Bad terminal_info (bad magic)",
0);
/* We do not reset bank settings on here */
#ifdef WCHAR
terminal_info->wcwidth = 0;
#endif
a = loc_info(terminal,set,0);
if (!a)
return ret;
switch (a->keyword) {
case terminal_dw: {
static int warned = 0;
#ifdef WCHAR
if (&cs_unknown != set->charset_type ||
0 == (CS_printable_len & charset_properties(set))) {
if (!warned)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedDW,
"Double wide characters are not supported"));
warned = 1;
return NULL;
}
terminal_info->wcwidth = 1;
#else
if (!warned)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedDW,
"Double wide characters are not supported"));
warned = 1;
#endif
}
break;
case terminal_iso2022_mb: {
static int warned = 0;
if (0 == (CS_printable_len & charset_properties(set))) {
if (!warned)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedDW,
"Double wide characters are not supported"));
warned = 1;
return ret;
}
if (set->iso2022_info)
change_helper_3(&ret,set->iso2022_info,terminal_info,NULL,0,0,1);
#ifdef WCHAR
terminal_info->wcwidth = 1;
#endif
}
break;
}
#ifdef WCHAR
SIGDPRINT(Debug,8,(&Debug,
"terminal_set_info: wcwidth=%d\n",
terminal_info->wcwidth));
#endif
return ret;
}
/* May be called from signal handler -- on that situation use
buffer specified as argument -- otherwise result is malloced
*/
char * terminal_switch_to(terminal,set,terminal_info,buffer,size,silent)
char *terminal;
charset_t set;
screen_info_p terminal_info;
char * buffer;
int size;
int silent;
{
int maybe_signal = buffer != NULL;
char *ret = NULL;
struct terminal_map_item * a = loc_info(terminal,set,1);
if (!terminal_info) {
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_switch_to",
"terminal_info not set",maybe_signal);
}
if (DISPLAY_STATE_magic != (terminal_info)->magic)
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_switch_to",
"Bad terminal_info (bad magic)",
maybe_signal);
if (!a) {
return NULL;
}
if (maybe_signal) {
SIGDPRINT(Debug,8,(&Debug,
"terminal_switch_to: buffer=%p size=%d\n",
buffer,size));
}
if ((terminal_info)->set_count > 0 &&
(terminal_info)->sets[0].type == iso2022_other) {
SIGDPRINT(Debug,8,(&Debug,
"Terminal was on no ISO2022 mode ... returning\n"));
if (maybe_signal)
ret = iso2022_setid_stream(return_to_iso2022,buffer,size);
else
ret = iso2022_setid_stream(return_to_iso2022,NULL,0);
}
reset_display_settings(terminal_info);
switch(a->keyword) {
int mb;
case terminal_iso2022:
case terminal_iso2022_mb:
if (set->iso2022_info) {
SIGDPRINT(Debug,8,(&Debug,
"Using ISO 2022 code for assignment\n"));
mb = 0;
if (a->keyword == terminal_iso2022_mb) {
if (0 != (CS_printable_len & charset_properties(set)))
mb = 1;
else if (!silent) {
static int warned = 0;
if (!warned)
lib_error(CATGETS(elm_msg_cat, MeSet,
MeUnsupportedDW,
"Double wide characters are not supported"));
warned = 1;
}
}
change_helper_3(&ret,set->iso2022_info,terminal_info,
buffer,size,maybe_signal,
mb);
} else {
SIGDPRINT(Debug,1,(&Debug,
"No ISO 2022 code for changing charset!\n"));
}
break;
case terminal_iso2022_like:
SIGDPRINT(Debug,8,(&Debug,
"Using ISO 2022 LIKE code for assignment\n"));
change_helper_3(&ret,a->value.iso2022_like.iso2022_info,
terminal_info,
buffer,size,maybe_signal,0);
break;
case terminal_private:
SIGDPRINT(Debug,8,(&Debug,
"Using terminal private code for assignment\n"));
strXcat(&ret,sStr(a->value.private.bytes),
maybe_signal,buffer,size);
break;
}
#ifdef WCHAR
SIGDPRINT(Debug,8,(&Debug,
"terminal_switch_to: wcwidth=%d\n",
(terminal_info)->wcwidth));
#endif
if (maybe_signal && ret && ret != buffer)
panic("STRING PANIC",__FILE__,__LINE__,
"terminal_switch_to",
"buffer != ret when called from signal",1);
return ret;
}
/*
* Local Variables:
* mode:c
* c-basic-offset:4
* buffer-file-coding-system: iso-8859-1
* End:
*/
syntax highlighted by Code2HTML, v. 0.9.1