static char rcsid[] = "@(#)$Id: output.c,v 1.37 2006/04/09 07:37:06 hurtta Exp $";
/******************************************************************************
* The Elm (ME+) Mail System - $Revision: 1.37 $ $State: Exp $
*
* Author: Kari Hurtta <hurtta+elm@posti.FMI.FI> (was hurtta+elm@ozone.FMI.FI)
*****************************************************************************/
#include "headers.h"
DEBUG_VAR(Debug,__FILE__,"ui");
static unsigned char *s2us P_((char *str));
static unsigned char *s2us(str)
char *str;
{
return (unsigned char *)str;
}
static char *us2s P_((unsigned char *str));
static char *us2s(str)
unsigned char *str;
{
return (char *)str;
}
static CONST unsigned char *cs2us P_((const char *str));
static CONST unsigned char *cs2us(str)
CONST char *str;
{
return (CONST unsigned char *)str;
}
static int def_err_handler P_((CONST char *str));
static int def_err_handler (str)
CONST char *str;
{
int ret;
int l = strlen(str);
ret = fprintf(stderr,"%s",str);
if (ret > 0 && l && str[l-1] != '\n')
ret += fprintf(stderr,"\n");
return ret;
}
static err_handler *H = def_err_handler;
extern void set_error_handler (h)
err_handler *h;
{
H = h;
}
static err_handler *T = def_err_handler;
void set_transient_handler(h)
err_handler *h;
{
T = h;
}
static char * def_prompt_handler P_((const char *str, int pass));
static char * def_prompt_handler (str,pass)
CONST char *str;
int pass;
{
int l = strlen(str);
char buffer[200], *x;
FILE * f = fopen("/dev/tty","r+");
if (!f)
return NULL;
if (pass)
x = getpass(str);
else {
int ret = fprintf(f,"%s",str);
char *y;
fflush(f);
x = fgets(buffer,sizeof buffer,f);
if (x && (y = strchr(x,'\n')))
*y = '\0';
if (ret > 0 && l && str[l-1] != '\n')
ret += fprintf(f,"\n");
}
fclose(f);
if (!x)
return NULL;
return safe_strdup(x);
}
static prompt_handler *P = def_prompt_handler;
void set_prompt_handler(h)
prompt_handler *h;
{
P = h;
}
/* Returns number of args parsed: -1 is parse error,
- this routine can be called from interrupt handler,
so this does not malloc anything or call charset routines ...
- this routine is also part of debugging output routine,
so do not call debugging output on here...
*/
int parse_format_args (elems,max_elems,format,args,format_error)
struct format_elem *elems;
int max_elems;
CONST char * format;
va_list args;
char **format_error;
{
CONST char * s;
int idx;
#define INC(p) { (p)++; if (!*(p)) break; }
*format_error = NULL;
idx = 0;
for (s = format; *s; s++) {
/* It is better that program code
is ascii only.
Non ascii text may be given on catalog,
but it should be on 'msg' parameter'
*/
if (!isascii(*s)) {
*format_error = "NONASCII: Non ascii characters on format";
}
if (*s != '%') {
continue;
}
INC(s);
if ('%' == *s) {
continue;
}
if (idx >= max_elems) {
*format_error = "OVERFLOW: Too many format elements";
break;
}
elems[idx].fill = ' ';
elems[idx].left = 0;
elems[idx].plus = 0;
elems[idx].val1 = 0;
elems[idx].val2 = 0;
elems[idx].long_f = 0;
if ('0' == *s) { elems[idx].fill = '0'; INC(s); }
else if ('-' == *s) { elems[idx].left = 1; INC(s); }
else if ('+' == *s) { elems[idx].plus = 1; INC(s); }
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
elems[idx].val1 = elems[idx].val1 * 10 + *s - '0';
INC(s);
}
if (*s == '$') {
elems[idx].val1 = 0;
INC(s);
*format_error = "Positional args are not allowed in format";
return -1;
}
} else if ('*' == *s) {
elems[idx].val1 = va_arg(args,int);
INC(s);
}
if ('.' == *s) {
INC(s);
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
elems[idx].val2 = elems[idx].val2 * 10 + *s - '0';
INC(s);
}
} else if ('*' == *s) {
elems[idx].val2 = va_arg(args,int);
INC(s);
}
}
if ('l' == *s) {
elems[idx].long_f = 1;
INC(s);
}
elems[idx].format_chr = *s;
switch(*s) {
case 'c':
elems[idx].type = V_chr_val;
elems[idx].value.chr_val = va_arg(args, int);
break;
case 'C':
elems[idx].type = V_cs_val;
elems[idx].value.cs_val = va_arg(args, struct charset_state *);
break;
case 'S':
elems[idx].type = V_string_val;
elems[idx].value.string_val = va_arg(args, struct string *);
break;
case 'p':
elems[idx].type = V_ptr_val;
elems[idx].value.ptr_val = va_arg(args, void *);
break;
case 's': case 'Q':
elems[idx].type = V_str_val;
elems[idx].value.str_val = va_arg(args, char *);
break;
case 'f':
elems[idx].type = V_double_val;
elems[idx].value.double_val = va_arg(args, double);
break;
case 'd': case 'i':
elems[idx].type = V_signed_val;
if (elems[idx].long_f)
elems[idx].value.signed_val = va_arg(args, long);
else
elems[idx].value.signed_val = va_arg(args, int);
break;
case 'x': case 'X': case 'u': case 'o':
elems[idx].type = V_unsigned_val;
if (elems[idx].long_f)
elems[idx].value.unsigned_val = va_arg(args, unsigned long);
else
elems[idx].value.unsigned_val = va_arg(args, unsigned int);
break;
default:
elems[idx].type = V_none;
*format_error = "Bad format character in format";
return -1;
}
idx++;
}
return idx;
}
/* convert_number may be callled form signal handler, therefore
it must not malloc annything ...
*/
int convert_number (buffer,buffer_size,elem)
char * buffer;
int buffer_size;
struct format_elem *elem;
{
int base = 0;
char *seq = NULL;
int c = 0;
int x;
unsigned long valz, valu;
unsigned long r;
double desimal = 0;
long val;
int I = 0;
int l = 0;
#define PUT(c) \
if (I < buffer_size -1) buffer[I++] = (c); \
else { buffer[I-1] = '*'; buffer[I] = '\0'; return I; }
if (buffer_size < 2)
return 0;
switch(elem->format_chr) {
case 'd': seq = "0123456789"; base = 10; break;
case 'i': seq = "0123456789"; base = 10; break;
case 'u': seq = "0123456789"; base = 10; break;
case 'o': seq = "01234567"; base = 8; break;
case 'x': seq = "0123456789abcdef"; base = 16; break;
case 'X': seq = "0123456789ABCDEF"; base = 16; break;
case 'p': seq = "0123456789ABCDEF"; base = 16; break;
case 'f': seq = "0123456789"; base = 10; break;
default:
return 0;
}
if (V_signed_val == elem->type) {
val = elem->value.signed_val;
if (val < 0) {
c = '-';
valu = -val;
elem->val1--;
} else {
valu = val;
if (elem->plus) {
c = '+';
elem->val1--;
}
}
} else if (V_double_val == elem->type) {
desimal = elem->value.double_val;
if (desimal < 0) {
c = '-';
desimal = -desimal;
elem->val1--;
} else {
if (elem->plus) {
c = '+';
elem->val1--;
}
}
valu = (unsigned int)desimal;
desimal -= valu;
if (desimal < 0) /* ??? */
desimal = 0;
l++; /* Desimal point */
if (elem->val2 > 0)
l += elem->val2; /* Desimals */
} else if (V_unsigned_val == elem->type) {
valu = elem->value.unsigned_val;
if (elem->plus) {
c = '+';
elem->val1--;
}
} else if (V_ptr_val == elem->type) {
valu = (unsigned long)elem->value.ptr_val;
} else {
return 0;
}
valz = valu;
x = buffer_size;
do {
unsigned long tmp;
tmp = (valz % base);
r = (valz / base);
valz = r;
l++;
x--;
buffer[x] = seq[tmp];
} while(r && l < buffer_size -3 && x > I);
/* This can overwrite buffer ... */
while (l < elem->val1 &&
!elem->left && elem->fill != '0') {
PUT(elem->fill); l++;
}
if (c) { /* sign */
PUT(c);
}
while (l < elem->val1 &&
! elem->left && elem->fill == '0') {
PUT('0'); l++;
}
while(x < buffer_size) {
if (x < I) { /* Indicate OVERFLOW */
PUT('*');
} else {
PUT(buffer[x]);
}
x++;
}
/* Desimal value ... l */
if (V_double_val == elem->type) {
PUT('.');
while (elem->val2 > 0) {
unsigned long tmp;
desimal *= 10;
tmp = (unsigned long) desimal;
desimal -= tmp;
if (desimal < 0) /* ??? */
desimal = 0;
if (tmp > 10) {
PUT('?');
} else {
PUT(seq[tmp]);
}
elem->val2--;
}
}
while (l < elem->val1 && elem->left) {
PUT(' '); l++;
}
if (0 == I) {
PUT('?');
}
#undef PUT
buffer[I] = '\0';
return I;
}
#define MAX_WIDTH 64
#ifndef NOCHARSET /* Used by nls/gencat */
char *elm_message P_((const char * format, const char *msg, ...));
int elm_sfprintf P_((char *buffer, int size,
const char * format, const char *msg, ...));
struct string * elm_smessage P_((int max_alloc,
const char *format, const char *msg,
va_list args));
struct string * elm_smessage(max_alloc,format,msg,args)
int max_alloc;
CONST char *format;
CONST char *msg;
va_list args;
{
CONST unsigned char * s; /* add_streambyte_to_string requires
unsigned char */
struct string * store1 = NULL, * msg1 = NULL;
charset_t msg_charset = display_charset;
struct string ** store2 = NULL;
int store2_len = 0,i,pos;
int max_elems = 0;
struct format_elem *elems = NULL;
int elem_count, idx;
char * format_error = NULL;
DPRINT(Debug,62,(&Debug,
"elm_smessage: max_alloc=%d, format='%s', msg='%s'\n",
max_alloc,format,msg));
for (s = cs2us(format); *s; s++)
if ('%' == *s && '%' != *(s+1))
max_elems++;
DPRINT(Debug,62,(&Debug,
"elm_smessage: max_elems=%d\n",max_elems));
if (max_elems > 0)
elems = safe_malloc(max_elems * sizeof (*elems));
else
elems = NULL;
elem_count = parse_format_args(elems, max_elems, format,args,
&format_error);
DPRINT(Debug,62,(&Debug,
"elm_smessage: elem_count=%d\n", elem_count));
if (format_error) {
DPRINT(Debug,1,(&Debug,
"FORMAT ERROR (%s): %s\n",format,format_error));
}
/* If there is error, elem_count == -1 and therefore loop is not run */
for (idx = 0; idx < elem_count; idx++) {
struct string * param_value = NULL;
DPRINT(Debug,63,(&Debug,
"# %d [%d.%d %c]: \n",
idx,elems[idx].val1,elems[idx].val2,
elems[idx].format_chr));
switch(elems[idx].format_chr) {
CONST char *str, *a;
int l,c;
int quote,X;
struct string * S, *S2, *S3;
char width[MAX_WIDTH+1];
char * stemp, *sptr;
struct charset_state * ch;
int I;
void * valp;
char DUMMY[256];
case 'c':
if (V_chr_val == elems[idx].type)
c = elems[idx].value.chr_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [c] ERROR\n",idx));
c = '?';
}
param_value = new_string(display_charset);
DPRINT(Debug,63,(&Debug,
"-- %d [c] val1=%d, c=%c, param_value=%p\n",
idx,elems[idx].val1,c,param_value));
l = 1;
if (l < elems[idx].val1 && !elems[idx].left) {
fill_ascii_to_string(param_value,
elems[idx].val1-l,
elems[idx].fill);
l += elems[idx].val1-l;
}
add_streambyte_to_string(param_value,c);
if (l < elems[idx].val1 && elems[idx].left) {
fill_ascii_to_string(param_value,elems[idx].val1-l,' ');
l += elems[idx].val1-l;
}
break;
case 'C':
if (V_cs_val == elems[idx].type)
ch = elems[idx].value.cs_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [C] ERROR\n",idx));
goto error1;
}
param_value = new_string(ch->charset);
DPRINT(Debug,63,(&Debug,
"-- %d [C] val1=%d, param_value=%p\n",
idx,elems[idx].val1,param_value));
l = 1;
if (l < elems[idx].val1 && !elems[idx].left) {
fill_ascii_to_string(param_value,
elems[idx].val1-l,
elems[idx].fill);
l += elems[idx].val1-l;
}
add_state_to_string(param_value,ch);
if (l < elems[idx].val1 && elems[idx].left) {
fill_ascii_to_string(param_value,elems[idx].val1-l,' ');
l += elems[idx].val1-l;
}
break;
case 'S':
if (V_string_val == elems[idx].type)
S = elems[idx].value.string_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [S] ERROR\n",idx));
goto error1;
}
if (!verify_string(S)) {
DPRINT(Debug,1,(&Debug,
"elm_smessage: BAD %%S argument\n"));
goto error1;
}
l = string_len(S);
if (elems[idx].val2 <= 0) elems[idx].val2 = l;
X = 0;
if (max_alloc > 0 && elems[idx].val2 > max_alloc) {
DPRINT(Debug,62,(&Debug,
"-- adjusting val2 =%d -> %d (max_alloc)\n",
elems[idx].val2,max_alloc));
elems[idx].val2 = max_alloc;
}
S2 = clip_from_string(S,&X,elems[idx].val2);
DPRINT(Debug,63,(&Debug,
"-- %d [S] val1=%d, S=%S, val2=%d,(clip)S2=%S\n",
idx,elems[idx].val1,S,elems[idx].val2,S2));
S3 = new_string(S->string_type);
if (l < elems[idx].val1 && !elems[idx].left) {
fill_ascii_to_string(S3,
elems[idx].val1-l,
elems[idx].fill);
l += elems[idx].val1-l;
}
param_value = cat_strings(S3,S2,0);
DPRINT(Debug,63,(&Debug,
"-- param_value=%p\n",param_value));
free_string(&S2);
free_string(&S3);
if (l < elems[idx].val1 && elems[idx].left) {
fill_ascii_to_string(param_value,elems[idx].val1-l,' ');
l += elems[idx].val1-l;
}
break;
case 'p':
if (V_ptr_val == elems[idx].type)
valp = elems[idx].value.ptr_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [p] ERROR\n",idx));
goto error1;
}
sprintf(DUMMY,"%p",valp);
str = DUMMY;
goto jump_dummy;
case 's': case 'Q':
if (V_str_val == elems[idx].type)
str = elems[idx].value.str_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [%c] ERROR\n",
idx,elems[idx].format_chr));
goto error1;
}
if (!str)
goto error1;
jump_dummy:
quote = ('Q' == elems[idx].format_chr);
l = strlen(str);
if (quote) {
l += 2;
for (a=str; *a; a++) {
if (*a == '\\' || *a == '"')
l++;
}
}
if (elems[idx].val2 <= 0) elems[idx].val2 = l;
if (quote)
elems[idx].val2 -= 2;
if (max_alloc > 0 && elems[idx].val2 > max_alloc) {
DPRINT(Debug,62,(&Debug,
"-- adjusting val2 =%d -> %d (max_alloc)\n",
elems[idx].val2,max_alloc));
elems[idx].val2 = max_alloc;
}
stemp = safe_malloc(l+2);
sptr = stemp;
for (a = str;
*a && a - str < elems[idx].val2 && sptr - stemp < l; a++) {
if (quote && (*a == '\\' || *a == '"')) {
*sptr++ = '\\';
}
*sptr++ = *a;
}
*sptr = '\0';
S2 = new_string2(display_charset,s2us(stemp));
DPRINT(Debug,63,(&Debug,
"-- %d [%c] val1=%d, val2=%d, str=%s, ",
idx,elems[idx].format_chr,
elems[idx].val1,elems[idx].val2,str));
DPRINT(Debug,63,(&Debug,
"S2=%p, stemp=%s\n",S2,stemp));
free(stemp); stemp = NULL;
S3 = new_string(display_charset);
if (l < elems[idx].val1 && !elems[idx].left) {
fill_ascii_to_string(S3,elems[idx].val1-l,elems[idx].fill);
l += elems[idx].val1-l;
}
if (quote) {
add_ascii_to_string(S3,s2us("\""));
}
param_value = cat_strings(S3,S2,0);
DPRINT(Debug,63,(&Debug,
"-- param_value=%p\n",param_value));
free_string(&S2);
free_string(&S3);
if (quote) {
add_ascii_to_string(param_value,s2us("\""));
}
if (l < elems[idx].val1 && elems[idx].left) {
fill_ascii_to_string(param_value,elems[idx].val1-l,' ');
l += elems[idx].val1-l;
}
break;
case 'd': case 'i': case 'x': case 'X': case 'o': case 'u':
case 'f':
I = convert_number(width, sizeof width, & (elems[idx]));
if (0 == I) {
DPRINT(Debug,63,(&Debug,
"-- %d [%c] I=%d, ERROR\n",
idx,elems[idx].format_chr,I));
goto error1;
}
DPRINT(Debug,63,(&Debug,
"-- %d [%c] I=%d, buffer=%s\n",
idx,elems[idx].format_chr,I,width));
param_value = new_string(display_charset);
add_ascii_to_string(param_value,s2us(width));
break;
default:
DPRINT(Debug,1,(&Debug,
"elm_smessage: BAD %d [%c] ????\n",
idx,elems[idx].format_chr));
error1:
param_value = new_string(display_charset);
add_ascii_to_string(param_value,s2us("[?-ERROR-?]"));
DPRINT(Debug,63,(&Debug,
" --- error, param_value=%p\n",
param_value));
}
store2 = safe_realloc(store2, (store2_len+1) *
sizeof (struct string *));
store2[store2_len++] = param_value;
DPRINT(Debug,63,(&Debug,
" -- adding param[%d] = %p\n",
store2_len-1,store2[store2_len-1]));
}
if (elems) {
free(elems);
elems = NULL;
}
for (i = 0; i < store2_len; i++) {
DPRINT(Debug,63,(&Debug,
" - %d: %S\n",
i,store2[i]));
}
pos = -1;
/* Actual printing */
for (s = cs2us(msg); *s; s++) {
int val1 = 0;
if (*s != '%') {
add_character: /* Jump position for %% */
if (!msg1) {
msg1 = new_string(msg_charset);
DPRINT(Debug,63,(&Debug,
"** msg_charset={'%s'; type=%p }, msg1=%p\n",
msg_charset->MIME_name ? msg_charset->MIME_name : "<none>",
msg_charset->charset_type,
msg1));
}
add_streambyte_to_string(msg1,*s);
continue;
}
INC(s);
if ('%' == *s)
goto add_character; /* Back jump */
pos++;
if (msg1) {
if (!store1)
store1 = msg1;
else {
struct string * temp = cat_strings(store1,msg1,0);
free_string(&store1);
free_string(&msg1);
store1 = temp;
}
msg1 = NULL;
}
again2:
if ('0' == *s) { INC(s); }
else if ('-' == *s) { INC(s); }
else if ('+' == *s) { INC(s); }
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
val1 = val1 * 10 + *s - '0';
INC(s);
}
if ('$' == *s) {
pos = val1;
val1 = 0;
goto again2;
}
} else if ('*' == *s) {
INC(s);
}
if ('.' == *s) {
INC(s);
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
INC(s);
}
} else if ('*' == *s) {
INC(s);
}
}
if ('l' == *s) {
INC(s);
}
switch(*s) {
CONST struct string *str;
case 's': case 'Q': case 'd': case 'c': case 'C':
case 'x': case 'X': case 'S': case 'p': case 'o':
case 'i': case 'u': case 'f':
if (pos < 0 || pos >= store2_len)
goto error2;
str = store2[pos];
if (!str)
goto error2;
DPRINT(Debug,63,(&Debug,
"-- [%c] str=%p=%S\n",
*s,str,str));
if (!store1)
store1 = dup_string(str);
else {
struct string * temp = cat_strings(store1,str,0);
free_string(&store1);
store1 = temp;
}
break;
default:
DPRINT(Debug,62,(&Debug,
"-- [%c] ????\n",*s));
error2:
DPRINT(Debug,62,(&Debug,
"--- error\n"));
if (!store1)
store1 = new_string(display_charset);
add_ascii_to_string(store1,s2us("[???]"));
}
}
for (i = 0; i < store2_len; i++) {
if (store2[i])
free_string(&store2[i]);
}
if (store2)
free(store2);
if (msg1) {
if (!store1)
store1 = msg1;
else {
struct string * temp = cat_strings(store1,msg1,0);
free_string(&store1);
free_string(&msg1);
store1 = temp;
}
msg1 = NULL;
}
if (!store1)
store1 = new_string(display_charset);
#undef INC
DPRINT(Debug,62,(&Debug, "elm_smessage=%p=%S\n",store1,store1));
return store1;
}
#endif /* NOCHARSET */
char *elm_vmessage P_((int max_alloc,
const char *format, const char *msg,
va_list args));
char *elm_vmessage (max_alloc,format,msg,vl)
int max_alloc;
CONST char *format;
CONST char *msg;
va_list vl;
{
char * store1 = NULL;
#ifndef NOCHARSET /* Used by nls/gencat */
if (display_charset &&
0 /* Alternate implementation used for testing... */
) {
struct string * R = elm_smessage(max_alloc,format,msg,vl);
struct string * R1 = convert_string(display_charset,R,1);
store1 = us2s(stream_from_string(R1,0,NULL));
free_string(&R1);
free_string(&R);
} else
#endif /* NOCHARSET */
{
int max_elems = 0;
struct format_elem *elems = NULL;
int elem_count, idx;
char * format_error = NULL;
CONST char * s;
int ptr1 = 0, alloced1 = 0;
struct store2 {
char * store;
int ptr;
int alloced;
} * store2 = NULL;
int store2_len = 0;
int i,pos;
DPRINT(Debug,62,(&Debug,
"elm_vmessage: max_alloc=%d, format=%s\n",
max_alloc,format));
DPRINT(Debug,62,(&Debug,
" msg=%s\n",msg));
for (s = format; *s; s++)
if ('%' == *s && '%' != *(s+1))
max_elems++;
DPRINT(Debug,62,(&Debug,
"elm_vmessage: max_elems=%d\n",max_elems));
if (max_elems > 0)
elems = safe_malloc(max_elems * sizeof (*elems));
else
elems = NULL;
elem_count = parse_format_args(elems, max_elems, format,vl,
&format_error);
DPRINT(Debug,62,(&Debug,
"elm_vmessage: elem_count=%d\n", elem_count));
if (format_error) {
DPRINT(Debug,1,(&Debug,
"FORMAT ERROR (%s): %s\n",
format,format_error));
}
#define ENLARGE(ptr,alloced,S) do { \
if (ptr >= alloced) { \
DPRINT(Debug,99,(&Debug, \
"ENLARGE(%d,%d,..) -- reallocing\n",ptr,alloced)); \
S = safe_realloc(S,alloced+10); alloced += 10; } } while(0)
#define PUTC1(c) do { ENLARGE(ptr1,alloced1,store1); store1[ptr1++] = c; } \
while(0)
#define PUTC2(c) do { ENLARGE(store2[store2_len-1].ptr,\
store2[store2_len-1].alloced,store2[store2_len-1].store); \
store2[store2_len-1].store[store2[store2_len-1].ptr++] = c; } \
while(0)
#define NEW_STORE do { \
DPRINT(Debug,99,(&Debug, \
"NEW_STORE -- %d\n",store2_len)); \
store2 = safe_realloc(store2, \
(store2_len+1) * sizeof (struct store2)); store2_len++; \
store2[store2_len-1].store = NULL; store2[store2_len-1].alloced = 0; \
store2[store2_len-1].ptr = 0; } while(0);
#define INC(p) { (p)++; if (!*(p)) break; }
/* If there is error, elem_count == -1 and therefore loop is not run */
for (idx = 0; idx < elem_count; idx++) {
/* We should prealloc sufficien number of elements ... */
NEW_STORE;
DPRINT(Debug,63,(&Debug,
"# %d [%d.%d %c]: \n",
idx,elems[idx].val1,elems[idx].val2,
elems[idx].format_chr));
switch(elems[idx].format_chr) {
CONST char *str, *a;
int l,c;
int quote,X;
#ifndef NOCHARSET /* Used by nls/gencat */
struct charset_state *ch;
struct string * S, *S1;
#endif
char * temp;
void * valp;
char DUMMY[256];
char width[MAX_WIDTH+1];
int I;
case 'c':
if (V_chr_val == elems[idx].type)
c = elems[idx].value.chr_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [c] ERROR\n",idx));
c = '?';
}
DPRINT(Debug,63,(&Debug,
"-- %d [c] val1=%d, c=%c\n",
idx,elems[idx].val1,c));
l = 1;
while (l < elems[idx].val1 && !elems[idx].left) {
PUTC2(elems[idx].fill); l++;
}
PUTC2(c);
while (l < elems[idx].val1 && elems[idx].left) {
PUTC2(' '); l++;
}
break;
#ifndef NOCHARSET /* Used by nls/gencat */
case 'C':
if (V_cs_val == elems[idx].type)
ch = elems[idx].value.cs_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [C] ERROR\n",idx));
goto error1;
}
S = new_string(display_charset);
add_state_to_string(S,ch);
temp = us2s(stream_from_string(S,1,NULL));
DPRINT(Debug,63,(&Debug,
"-- %d [C] val1=%d, str=%s\n",
idx,elems[idx].val1,temp));
l = 1;
while (l < elems[idx].val1 && !elems[idx].left) {
PUTC2(elems[idx].fill); l++;
}
for (a=temp; *a; a++) {
PUTC2(*a);
}
while (l < elems[idx].val1 && elems[idx].left) {
PUTC2(' '); l++;
}
free(temp);
free_string(&S);
break;
case 'S':
if (V_string_val == elems[idx].type)
S = elems[idx].value.string_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [S] ERROR\n",idx));
goto error1;
}
if (!verify_string(S)) {
DPRINT(Debug,1,(&Debug,
"elm_vmessage: BAD %%S argument\n"));
goto error1;
}
S1 = convert_string(display_charset,S,1);
l = string_len(S1);
if (elems[idx].val2 <= 0)
elems[idx].val2 = l;
X = 0;
temp = us2s(streamclip_from_string(S1,&X,elems[idx].val2,
NULL,NULL)); /* TODO: Should use printable len? */
DPRINT(Debug,63,(&Debug,
"-- %d [S] val1=%d, val2=%d,(clip)str=%s\n",
idx,
elems[idx].val1,elems[idx].val2,temp));
while (l < elems[idx].val1 && !elems[idx].left) {
PUTC2(elems[idx].fill); l++;
}
for (a=temp; *a; a++) {
PUTC2(*a);
if (max_alloc > 0 && a - temp > max_alloc) {
DPRINT(Debug,1,(&Debug,
" --- too long string (max=%d): %.30s...\n",
max_alloc,temp));
break;
}
}
free(temp);
free_string(&S1);
while (l < elems[idx].val1 && elems[idx].left) {
PUTC2(' '); l++;
}
break;
#endif /* NOCHARSET */ /* Used by nls/gencat */
case 'p':
if (V_ptr_val == elems[idx].type)
valp = elems[idx].value.ptr_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [p] ERROR\n",idx));
goto error1;
}
sprintf(DUMMY,"%p",valp);
str = DUMMY;
goto jump_dummy;
case 's': case 'Q':
if (V_str_val == elems[idx].type)
str = elems[idx].value.str_val;
else {
DPRINT(Debug,63,(&Debug,
" %d [%c] ERROR\n",
idx,elems[idx].format_chr));
goto error1;
}
if (!str)
goto error1;
jump_dummy:
quote = ('Q' == elems[idx].format_chr);
l = strlen(str);
if (quote) {
l += 2;
for (a=str; *a; a++) {
if (*a == '\\' || *a == '"')
l++;
}
}
if (elems[idx].val2 <= 0)
elems[idx].val2 = l;
if (quote)
elems[idx].val2 -= 2;
DPRINT(Debug,63,(&Debug,
"-- %d [%c] val1=%d, val2=%d, str=%s\n",
idx,elems[idx].format_chr,
elems[idx].val1,elems[idx].val2,str));
while (l < elems[idx].val1 && !elems[idx].left) {
PUTC2(elems[idx].fill); l++;
}
if (quote) {
PUTC2('"');
}
for (a = str; *a && a - str < elems[idx].val2; a++) {
if (quote && (*a == '\\' || *a == '"')) {
PUTC2('\\');
}
PUTC2(*a);
if (max_alloc > 0 && a - str > max_alloc) {
DPRINT(Debug,1,(&Debug,
"--- too long string (max=%d): %.30s...\n",
max_alloc,str));
break;
}
}
if (quote) {
PUTC2('"');
}
while (l < elems[idx].val1 && elems[idx].left) {
PUTC2(' '); l++;
}
break;
case 'd': case'i': case 'x': case 'X': case 'o': case 'u':
case 'f':
I = convert_number(width, sizeof width, & (elems[idx]));
if (0 == I) {
DPRINT(Debug,63,(&Debug,
"-- %d [%c] I=%d, ERROR\n",
idx,elems[idx].format_chr,I));
goto error1;
}
for (l = 0; l < I; l++) {
PUTC2(width[l]);
}
break;
default:
DPRINT(Debug,1,(&Debug,
"elm_vmessage: BAD %d [%c] ????\n",
idx,elems[idx].format_chr));
error1:
DPRINT(Debug,63,(&Debug,
"-- error\n"));
PUTC2('?');
break;
}
PUTC2('\0');
}
if (elems) {
free(elems);
elems = NULL;
}
for (i = 0; i < store2_len; i++) {
DPRINT(Debug,63,(&Debug,
" -- %d: %.*s\n",i,
store2[i].ptr,NONULL(store2[i].store)));
}
pos = -1;
/* Actual printing */
for (s = msg; *s; s++) {
int val1 = 0;
if (*s != '%') {
PUTC1(*s);
continue;
}
INC(s);
if ('%' == *s) {
PUTC1(*s);
continue;
}
pos++;
again2:
if ('0' == *s) { INC(s); }
else if ('-' == *s) { INC(s); }
else if ('+' == *s) { INC(s); }
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
val1 = val1 * 10 + *s - '0';
INC(s);
}
if ('$' == *s) {
pos = val1;
val1 = 0;
goto again2;
}
} else if ('*' == *s) {
INC(s);
}
if ('.' == *s) {
INC(s);
if (*s >= '1' && *s <= '9') {
while (*s >= '0' && *s <= '9') {
INC(s);
}
} else if ('*' == *s) {
INC(s);
}
}
if ('l' == *s) {
INC(s);
}
switch(*s) {
CONST char *str,*a;
case 's': case 'Q': case 'd': case 'c': case 'C': case 'x':
case 'X': case 'S': case 'p': case 'o':
case 'i': case 'u': case 'f':
if (pos < 0 || pos >= store2_len)
goto error2;
str = store2[pos].store;
if (!str)
goto error2;
DPRINT(Debug,63,(&Debug,
"-- [%c] str=%s\n",*s,str));
for (a = str; *a; a++) {
PUTC1(*a);
}
break;
default:
DPRINT(Debug,63,(&Debug,
"-- [%c] ????\n",*s));
error2:
DPRINT(Debug,63,(&Debug,
"--- error\n"));
PUTC1('[');
PUTC1('?');
PUTC1(']');
}
}
PUTC1('\0');
#undef PUTC1
#undef INC
#undef PUTC2
#undef NEW_STORE
for (i = 0; i < store2_len; i++) {
if (store2[i].store)
free(store2[i].store);
}
if (store2)
free(store2);
}
return store1;
}
int lib_error P_((const char * format, const char *msg, ...));
int lib_error (
#if ANSI_C
const char * format,
const char *msg, ...
#else
format, msg, va_alist
#endif
)
#if !ANSI_C
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
int ret = 0;
va_list vl;
char * store1;
DPRINT(Debug,60,(&Debug,
"lib_error: format=%s\n",format));
DPRINT(Debug,60,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(0,format,msg,vl);
va_end(vl);
#if DEBUG
panic_dprint ("error message=%s\n",store1);
#endif
ret = H(store1);
free(store1);
return ret;
}
int lib_transient P_((const char * format, const char *msg, ...));
int lib_transient (
#if ANSI_C
const char * format,
const char *msg, ...
#else
format, msg, va_alist
#endif
)
#if !ANSI_C
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
int ret = 0;
va_list vl;
char * store1;
DPRINT(Debug,60,(&Debug,
"lib_transient: format=%s\n",format));
DPRINT(Debug,60,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(0,format,msg,vl);
va_end(vl);
if (def_err_handler == T)
ret = H(store1);
else
ret = T(store1);
free(store1);
return ret;
}
char * lib_prompt P_((int prompt, CONST char * format, CONST char *msg, ...));
char * lib_prompt (
#if ANSI_C
int prompt, CONST char * format, CONST char *msg, ...
#else
prompt,format,msg,va_alist
#endif
)
#if !ANSI_C
int prompt;
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
va_list vl;
char * store1, *ret;
DPRINT(Debug,60,(&Debug,
"lib_prompt: prompt=%d, format=%s\n",prompt,format));
DPRINT(Debug,62,(&Debug,
" msg=%s\n",msg));
if (getppid() == 1) {
/* we've lost our shell! */
DPRINT(Debug,4,(&Debug,
"lib_prompt=NULL: Lost our shell (getppid=1)\n"));
return NULL;
}
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(0,format,msg,vl);
va_end(vl);
ret = P(store1,prompt);
free(store1);
return ret;
}
char *elm_message (
#if ANSI_C
CONST char * format,
CONST char *msg, ...
#else
format, msg, va_alist
#endif
)
#if !ANSI_C
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
va_list vl;
char * store1;
DPRINT(Debug,61,(&Debug,
"elm_message: format=%s\n",format));
DPRINT(Debug,61,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(0,format,msg,vl);
va_end(vl);
return store1;
}
#ifndef NOCHARSET /* Used by nls/gencat */
struct string * format_string (
#if ANSI_C
CONST char * format,
CONST char *msg, ...
#else
format, msg, va_alist
#endif
)
#if !ANSI_C
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
va_list vl;
struct string * store1;
DPRINT(Debug,61,(&Debug,
"format_string: format=%s\n",format));
DPRINT(Debug,61,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_smessage(0,format,msg,vl);
va_end(vl);
return store1;
}
#endif /* NOCHARSET */
int elm_sfprintf (
#if ANSI_C
char * buffer, int size,
CONST char * format,
CONST char *msg, ...
#else
buffer, size, format, msg, va_alist
#endif
)
#if !ANSI_C
char * buffer;
int size;
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
va_list vl;
char * store1;
DPRINT(Debug,61,(&Debug,
"elm_sfprintf: size=%d, format=%s\n",size, format));
DPRINT(Debug,61,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(size-1,format,msg,vl);
va_end(vl);
strfcpy(buffer,store1,size);
free(store1);
return strlen(buffer);
}
int elm_fprintf (
#if ANSI_C
FILE *f, CONST char * format, CONST char *msg, ...
#else
f, format,msg, va_alist
#endif
)
#if !ANSI_C
FILE *f;
CONST char * format;
CONST char *msg;
va_dcl
#endif
{
int ret;
va_list vl;
char * store1;
DPRINT(Debug,61,(&Debug,
"elm_fprintf: format=%s\n",format));
DPRINT(Debug,61,(&Debug,
" msg=%s\n",msg));
Va_start(vl, msg); /* defined in defs.h */
store1 = elm_vmessage(0,format,msg,vl);
va_end(vl);
ret = fputs(store1,f);
if (ret != EOF)
ret = strlen(store1);
free(store1);
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