werror.c 6.13 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
#include <unistd.h>
Niels Möller's avatar
Niels Möller committed
37

38 39
int debug_flag = 0;
int quiet_flag = 0;
40
int verbose_flag = 0;
41

42 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 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 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 126 127 128 129 130 131 132
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;
}

/* 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);
    }
}

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);
	}
    }
}
  
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
133
void werror(const char *format, ...) 
Niels Möller's avatar
Niels Möller committed
134 135 136
{
  va_list args;

137 138 139
  if (!quiet_flag)
    {
      va_start(args, format);
140
      w_vnprintf(WERROR_MAX, format, args);
141
      va_end(args);
142
      werror_flush();
143 144 145
    }
}

146
void debug(const char *format, ...) 
147 148 149 150 151 152
{
  va_list args;

  if (debug_flag)
    {
      va_start(args, format);
153
      w_vnprintf(WERROR_MAX, format, args);
154
      va_end(args);
155
      werror_flush();
156 157 158
    }
}

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

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

Niels Möller's avatar
Niels Möller committed
172
static void wash_char(UINT8 c)
173
{
174
  switch(c)
175
    {
176
    case '\\':
177 178
      werror_putc('\\');
      werror_putc('\\');
179 180 181 182 183 184
      break;
    case '\r':
      /* Ignore */
      break;
    default:
      if (!isprint(c))
185
	{
186 187 188
	  werror_putc('\\');
	  werror_putc(c / 16);
	  werror_putc(c % 16);
189 190
	  break;
	}
191 192
      /* Fall through */
    case '\n':
193
      werror_putc(c);
194
      break;
195 196 197
    }
}

198
/* Escape non-printable characters. */
199
static void write_washed(UINT32 length, UINT8 *msg)
200
{
201
  UINT32 i;
202 203 204

  for(i = 0; i<length; i++)
    wash_char(msg[i]);
205 206

  werror_flush();
207 208
}

Niels Möller's avatar
Niels Möller committed
209
/* For outputting data received from the other end */
210 211 212
void werror_safe(UINT32 length, UINT8 *msg)
{
  if (!quiet_flag)
213
    write_washed(length, msg);
214 215 216 217 218
}

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

222 223 224
void verbose_safe(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
225
    write_washed(length, msg);
226 227
}

228
static void write_utf8(UINT32 length, UINT8 *msg)
229
{
Niels Möller's avatar
Niels Möller committed
230
  struct simple_buffer buffer;
231 232
  
  simple_buffer_init(&buffer, length, msg);
Niels Möller's avatar
Niels Möller committed
233 234
  
  while(1)
235
    {
Niels Möller's avatar
Niels Möller committed
236 237 238 239 240 241 242
      UINT32 ucs4;
      
      switch (parse_utf8(&buffer, &ucs4))
	{
	case -1:
	  return;
	case 0:
243 244
	  werror_putc('\\');
	  werror_putc('!');
Niels Möller's avatar
Niels Möller committed
245 246 247 248 249
	  return;
	case 1:
	  {
	    int local = ucs4_to_local(ucs4);
	    if (local < 0)
250 251 252 253
	      {
		werror_putc('\\');
		werror_putc('?');
	      }
Niels Möller's avatar
Niels Möller committed
254 255
	    else
	      wash_char(local);
Niels Möller's avatar
Niels Möller committed
256
	    break;
Niels Möller's avatar
Niels Möller committed
257 258 259 260
	  }
	default:
	  fatal("Internal error");
	}
261
    }
262
  werror_flush();
Niels Möller's avatar
Niels Möller committed
263
}
264 265

void werror_utf8(UINT32 length, UINT8 *msg)
Niels Möller's avatar
Niels Möller committed
266
{
267 268 269
  if (!quiet_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
270

271 272 273 274 275
void verbose_utf8(UINT32 length, UINT8 *msg)
{
  if (verbose_flag)
    write_utf8(length, msg);
}
Niels Möller's avatar
Niels Möller committed
276

277 278 279 280
void debug_utf8(UINT32 length, UINT8 *msg)
{
  if (debug_flag)
    write_utf8(length, msg);
Niels Möller's avatar
Niels Möller committed
281
}
Niels Möller's avatar
Niels Möller committed
282

283
/* Bignums */
284 285 286 287 288 289 290 291
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
292 293
void werror_mpz(mpz_t n)
{
Niels Möller's avatar
Niels Möller committed
294
  if (!quiet_flag)
295
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
296 297 298 299 300
}

void debug_mpz(mpz_t n)
{
  if (debug_flag)
301
    write_mpz(n);
Niels Möller's avatar
Niels Möller committed
302 303 304 305 306 307
}

void verbose_mpz(mpz_t n)
{
  if (verbose_flag)
    mpz_out_str(stderr, 16, n);
Niels Möller's avatar
Niels Möller committed
308
}
309 310 311 312

/* hex dumps */
static void write_hex(UINT32 length, UINT8 *data)
{
313
  UINT32 i;
314
  
315
  w_nprintf(40, "(size %d = 0x%x)", length, length);
316 317 318 319

  for(i=0; i<length; i++)
  {
    if (! (i%16))
320
      w_nprintf(20, "\n%08x: ", i);
321
    
322
    w_nprintf(4, "%02x ", data[i]);
323
  }
324 325
  w_nprintf(1, "\n");
  werror_flush();
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345
}

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);
}

346
void fatal(const char *format, ...) 
347 348 349 350
{
  va_list args;

  va_start(args, format);
351
  w_vnprintf(WERROR_MAX, format, args);
352
  va_end(args);
353
  werror_flush();
354 355 356

  abort();
}