werror.c 6.5 KB
Newer Older
Niels Möller's avatar
Niels Möller committed
1 2
/* werror.c
 *
3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
 *
 *
 * $Id$ */

/* lsh, an implementation of the ssh protocol
 *
 * Copyright (C) 1998 Niels Mller
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License as
 * published by the Free Software Foundation; either version 2 of the
 * License, or (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
 * General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
Niels Möller's avatar
Niels Möller committed
24 25 26 27
 */

#include "werror.h"

Niels Möller's avatar
Niels Möller committed
28
#include "charset.h"
29 30
#include "gc.h"
#include "io.h"
31
#include "parse.h"
Niels Möller's avatar
Niels Möller committed
32

Niels Möller's avatar
Niels Möller committed
33 34
#include <stdio.h>
#include <stdarg.h>
Niels Möller's avatar
Niels Möller committed
35
#include <ctype.h>
36
#if HAVE_UNISTD_H
37
#include <unistd.h>
38
#endif
Niels Möller's avatar
Niels Möller committed
39

40 41
int debug_flag = 0;
int quiet_flag = 0;
42
int verbose_flag = 0;
43

44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77
int error_fd = STDERR_FILENO;

#define BUF_SIZE 500
static UINT8 error_buffer[BUF_SIZE];
static UINT32 error_pos = 0;

static int (*error_write)(int fd, UINT32 length, UINT8 *data) = write_raw;

#define WERROR(l, d) (error_write(error_fd, (l), (d)))

static void werror_flush(void)
{
  if (error_pos)
    {
      WERROR(error_pos, error_buffer);
      error_pos = 0;
    }
}

static void werror_putc(UINT8 c)
{
  if (error_pos == BUF_SIZE)
    werror_flush();

  error_buffer[error_pos++] = c;
}

void set_error_stream(int fd, int with_poll)
{
  error_fd = fd;

  error_write = with_poll ? write_raw_with_poll : write_raw;
}

78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100
void wwrite(char *msg)
{
  if (!quiet_flag)
    {
      UINT32 size = strlen(msg);

      if (error_pos + size <= BUF_SIZE)
	{
	  memcpy(error_buffer + error_pos, msg, size);
	  error_pos += size;
      
	  if (size && (msg[size-1] == '\n'))
	    werror_flush();	
	}
      else
	{
	  werror_flush();
	  WERROR(size, msg);
	}
    }
}

#ifdef HAVE_VSNPRINTF
101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125
/* FIXME: Too bad we can't create a custom FILE * using werror_putc to
 * output each character. */
static void w_vnprintf(unsigned size, const char *format, va_list args)
{
  int written;
  
  if (error_pos + size <= BUF_SIZE)
    {
      written = vsnprintf(error_buffer + error_pos, size, format, args);

      error_pos += (written >= 0) ? written : size;
    }
  else
    {
      UINT8 *s = alloca(size);

      werror_flush();
      written = vsnprintf(s, size, format, args);

      if (written >= 0)
	size = written;
      
      WERROR(size, s);
    }
}
126
#else /* !HAVE_VSNPRINTF */
127

128
#warning No vsnprintf. Some output to stderr will be lost.
129

130 131 132 133
static void w_vnprintf(unsigned size, const char *format, va_list args)
{
  /* NOTE: This loses the interesting parts of the messages. */
  wwrite(format);
134
}
135 136
#endif /* !HAVE_VSNPRINTF */

137 138 139 140 141 142 143 144 145
static void w_nprintf(UINT32 size, const char *format, ...)
{
  va_list args;
  va_start(args, format);
  w_vnprintf(size, format, args);
  va_end(args);
}

#define WERROR_MAX 150
146
void werror(const char *format, ...) 
Niels Möller's avatar
Niels Möller committed
147 148 149
{
  va_list args;

150 151 152
  if (!quiet_flag)
    {
      va_start(args, format);
153
      w_vnprintf(WERROR_MAX, format, args);
154
      va_end(args);
155
      werror_flush();
156 157 158
    }
}

159
void debug(const char *format, ...) 
160 161 162 163 164 165
{
  va_list args;

  if (debug_flag)
    {
      va_start(args, format);
166
      w_vnprintf(WERROR_MAX, format, args);
167
      va_end(args);
168
      werror_flush();
169 170 171
    }
}

172
void verbose(const char *format, ...) 
173 174 175 176 177 178
{
  va_list args;

  if (verbose_flag)
    {
      va_start(args, format);
179
      w_vnprintf(WERROR_MAX, format, args);
180
      va_end(args);
181
      werror_flush();
182 183 184
    }
}

Niels Möller's avatar
Niels Möller committed
185
static void wash_char(UINT8 c)
186
{
Niels Möller's avatar
Niels Möller committed
187 188
  static const char hex[16] = "0123456789abcdef";
  
189
  switch(c)
190
    {
191
    case '\\':
192 193
      werror_putc('\\');
      werror_putc('\\');
194 195 196 197 198 199
      break;
    case '\r':
      /* Ignore */
      break;
    default:
      if (!isprint(c))
200
	{
201
	  werror_putc('\\');
Niels Möller's avatar
Niels Möller committed
202 203
	  werror_putc(hex[c / 16]);
	  werror_putc(hex[c % 16]);
204 205
	  break;
	}
206 207
      /* Fall through */
    case '\n':
208
      werror_putc(c);
209
      break;
210 211 212
    }
}

213
/* Escape non-printable characters. */
214
static void write_washed(UINT32 length, UINT8 *msg)
215
{
216
  UINT32 i;
217 218 219

  for(i = 0; i<length; i++)
    wash_char(msg[i]);
220 221

  werror_flush();
222 223
}

Niels Möller's avatar
Niels Möller committed
224
/* For outputting data received from the other end */
225 226 227
void werror_safe(UINT32 length, UINT8 *msg)
{
  if (!quiet_flag)
228
    write_washed(length, msg);
229 230 231 232 233
}

void debug_safe(UINT32 length, UINT8 *msg)
{
  if (debug_flag)
234
    write_washed(length, msg);
Niels Möller's avatar
Niels Möller committed
235 236
}

237 238 239
void verbose_safe(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
240
    write_washed(length, msg);
241 242
}

243
static void write_utf8(UINT32 length, UINT8 *msg)
244
{
Niels Möller's avatar
Niels Möller committed
245
  struct simple_buffer buffer;
246 247
  
  simple_buffer_init(&buffer, length, msg);
Niels Möller's avatar
Niels Möller committed
248 249
  
  while(1)
250
    {
Niels Möller's avatar
Niels Möller committed
251 252 253 254 255 256 257
      UINT32 ucs4;
      
      switch (parse_utf8(&buffer, &ucs4))
	{
	case -1:
	  return;
	case 0:
258 259
	  werror_putc('\\');
	  werror_putc('!');
Niels Möller's avatar
Niels Möller committed
260 261 262 263 264
	  return;
	case 1:
	  {
	    int local = ucs4_to_local(ucs4);
	    if (local < 0)
265 266 267 268
	      {
		werror_putc('\\');
		werror_putc('?');
	      }
Niels Möller's avatar
Niels Möller committed
269 270
	    else
	      wash_char(local);
Niels Möller's avatar
Niels Möller committed
271
	    break;
Niels Möller's avatar
Niels Möller committed
272 273 274 275
	  }
	default:
	  fatal("Internal error");
	}
276
    }
277
  werror_flush();
Niels Möller's avatar
Niels Möller committed
278
}
279 280

void werror_utf8(UINT32 length, UINT8 *msg)
Niels Möller's avatar
Niels Möller committed
281
{
282 283 284
  if (!quiet_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
285

286 287 288 289 290
void verbose_utf8(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
291

292 293 294 295
void debug_utf8(UINT32 length, UINT8 *msg)
{
  if (debug_flag)
    write_utf8(length, msg);
Niels Möller's avatar
Niels Möller committed
296
}
Niels Möller's avatar
Niels Möller committed
297

298
/* Bignums */
299 300 301 302 303 304 305 306
static void write_mpz(mpz_t n)
{
  UINT8 *s = alloca(mpz_sizeinbase(n, 16) + 2);
  mpz_get_str(s, 16, n);

  WERROR(strlen(s), s);
}

Niels Möller's avatar
Niels Möller committed
307 308
void werror_mpz(mpz_t n)
{
Niels Möller's avatar
Niels Möller committed
309
  if (!quiet_flag)
310
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
311 312 313 314 315
}

void debug_mpz(mpz_t n)
{
  if (debug_flag)
316
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
317 318 319 320 321 322
}

void verbose_mpz(mpz_t n)
{
  if (verbose_flag)
    mpz_out_str(stderr, 16, n);
Niels Möller's avatar
Niels Möller committed
323
}
324 325 326 327

/* hex dumps */
static void write_hex(UINT32 length, UINT8 *data)
{
328
  UINT32 i;
329
  
330
  w_nprintf(40, "(size %d = 0x%x)", length, length);
331 332 333 334

  for(i=0; i<length; i++)
  {
    if (! (i%16))
335
      w_nprintf(20, "\n%08x: ", i);
336
    
337
    w_nprintf(4, "%02x ", data[i]);
338
  }
Niels Möller's avatar
Niels Möller committed
339
  w_nprintf(2, "\n");
340
  werror_flush();
341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360
}

void werror_hex(UINT32 length, UINT8 *data)
{
  if (!quiet_flag)
    write_hex(length, data);
}

void debug_hex(UINT32 length, UINT8 *data)
{
  if (debug_flag)
    write_hex(length, data);
}

void verbose_hex(UINT32 length, UINT8 *data)
{
  if (verbose_flag)
    write_hex(length, data);
}

361
void fatal(const char *format, ...) 
362 363 364 365
{
  va_list args;

  va_start(args, format);
366
  w_vnprintf(WERROR_MAX, format, args);
367
  va_end(args);
368
  werror_flush();
369 370 371

  abort();
}