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 (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 : "", 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: */