File: [local] / src / usr.bin / dc / inout.c (download)
Revision 1.15, Tue Oct 27 23:59:37 2009 UTC (14 years, 7 months ago) by deraadt
Branch: MAIN
CVS Tags: OPENBSD_5_2_BASE, OPENBSD_5_2, OPENBSD_5_1_BASE, OPENBSD_5_1, OPENBSD_5_0_BASE, OPENBSD_5_0, OPENBSD_4_9_BASE, OPENBSD_4_9, OPENBSD_4_8_BASE, OPENBSD_4_8, OPENBSD_4_7_BASE, OPENBSD_4_7 Changes since 1.14: +1 -5 lines
rcsid[] and sccsid[] and copyright[] are essentially unmaintained (and
unmaintainable). these days, people use source. these id's do not provide
any benefit, and do hurt the small install media
(the 33,000 line diff is essentially mechanical)
ok with the idea millert, ok dms
|
/* $OpenBSD: inout.c,v 1.15 2009/10/27 23:59:37 deraadt Exp $ */
/*
* Copyright (c) 2003, Otto Moerbeek <otto@drijf.net>
*
* Permission to use, copy, modify, and distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <ssl/ssl.h>
#include <ctype.h>
#include <err.h>
#include <string.h>
#include "extern.h"
#define MAX_CHARS_PER_LINE 68
static int lastchar;
static int charcount;
static int src_getcharstream(struct source *);
static void src_ungetcharstream(struct source *);
static char *src_getlinestream(struct source *);
static void src_freestream(struct source *);
static int src_getcharstring(struct source *);
static void src_ungetcharstring(struct source *);
static char *src_getlinestring(struct source *);
static void src_freestring(struct source *);
static void flushwrap(FILE *);
static void putcharwrap(FILE *, int);
static void printwrap(FILE *, const char *);
static char *get_digit(u_long, int, u_int);
static struct vtable stream_vtable = {
src_getcharstream,
src_ungetcharstream,
src_getlinestream,
src_freestream
};
static struct vtable string_vtable = {
src_getcharstring,
src_ungetcharstring,
src_getlinestring,
src_freestring
};
void
src_setstream(struct source *src, FILE *stream)
{
src->u.stream = stream;
src->vtable = &stream_vtable;
}
void
src_setstring(struct source *src, char *p)
{
src->u.string.buf = (u_char *)p;
src->u.string.pos = 0;
src->vtable = &string_vtable;
}
static int
src_getcharstream(struct source *src)
{
return src->lastchar = getc(src->u.stream);
}
static void
src_ungetcharstream(struct source *src)
{
(void)ungetc(src->lastchar, src->u.stream);
}
/* ARGSUSED */
static void
src_freestream(struct source *src)
{
}
static char *
src_getlinestream(struct source *src)
{
char buf[BUFSIZ];
if (fgets(buf, BUFSIZ, src->u.stream) == NULL)
return bstrdup("");
return bstrdup(buf);
}
static int
src_getcharstring(struct source *src)
{
src->lastchar = src->u.string.buf[src->u.string.pos];
if (src->lastchar == '\0')
return EOF;
else {
src->u.string.pos++;
return src->lastchar;
}
}
static void
src_ungetcharstring(struct source *src)
{
if (src->u.string.pos > 0) {
if (src->lastchar != '\0')
--src->u.string.pos;
}
}
static char *
src_getlinestring(struct source *src)
{
char buf[BUFSIZ];
int ch, i;
i = 0;
while (i < BUFSIZ-1) {
ch = src_getcharstring(src);
if (ch == EOF)
break;
buf[i++] = ch;
if (ch == '\n')
break;
}
buf[i] = '\0';
return bstrdup(buf);
}
static void
src_freestring(struct source *src)
{
free(src->u.string.buf);
}
static void
flushwrap(FILE *f)
{
if (lastchar != -1)
(void)putc(lastchar, f);
}
static void
putcharwrap(FILE *f, int ch)
{
if (charcount >= MAX_CHARS_PER_LINE) {
charcount = 0;
(void)fputs("\\\n", f);
}
if (lastchar != -1) {
charcount++;
(void)putc(lastchar, f);
}
lastchar = ch;
}
static void
printwrap(FILE *f, const char *p)
{
char buf[12];
char *q = buf;
(void)strlcpy(buf, p, sizeof(buf));
while (*q)
putcharwrap(f, *q++);
}
struct number *
readnumber(struct source *src, u_int base)
{
struct number *n;
int ch;
bool sign = false;
bool dot = false;
BN_ULONG v;
u_int i;
n = new_number();
bn_check(BN_zero(n->number));
while ((ch = (*src->vtable->readchar)(src)) != EOF) {
if ('0' <= ch && ch <= '9')
v = ch - '0';
else if ('A' <= ch && ch <= 'F')
v = ch - 'A' + 10;
else if (ch == '_') {
sign = true;
continue;
} else if (ch == '.') {
if (dot)
break;
dot = true;
continue;
} else {
(*src->vtable->unreadchar)(src);
break;
}
if (dot)
n->scale++;
bn_check(BN_mul_word(n->number, base));
#if 0
/* work around a bug in BN_add_word: 0 += 0 is buggy.... */
if (v > 0)
#endif
bn_check(BN_add_word(n->number, v));
}
if (base != 10) {
scale_number(n->number, n->scale);
for (i = 0; i < n->scale; i++)
(void)BN_div_word(n->number, base);
}
if (sign)
negate(n);
return n;
}
char *
read_string(struct source *src)
{
int count, i, sz, new_sz, ch;
char *p;
bool escape;
escape = false;
count = 1;
i = 0;
sz = 15;
p = bmalloc(sz + 1);
while ((ch = (*src->vtable->readchar)(src)) != EOF) {
if (!escape) {
if (ch == '[')
count++;
else if (ch == ']')
count--;
if (count == 0)
break;
}
if (ch == '\\' && !escape)
escape = true;
else {
escape = false;
if (i == sz) {
new_sz = sz * 2;
p = brealloc(p, new_sz + 1);
sz = new_sz;
}
p[i++] = ch;
}
}
p[i] = '\0';
return p;
}
static char *
get_digit(u_long num, int digits, u_int base)
{
char *p;
if (base <= 16) {
p = bmalloc(2);
p[0] = num >= 10 ? num + 'A' - 10 : num + '0';
p[1] = '\0';
} else {
if (asprintf(&p, "%0*lu", digits, num) == -1)
err(1, NULL);
}
return p;
}
void
printnumber(FILE *f, const struct number *b, u_int base)
{
struct number *int_part, *fract_part;
int digits;
char buf[11];
size_t sz;
int i;
struct stack stack;
char *p;
charcount = 0;
lastchar = -1;
if (BN_is_zero(b->number))
putcharwrap(f, '0');
int_part = new_number();
fract_part = new_number();
fract_part->scale = b->scale;
if (base <= 16)
digits = 1;
else {
digits = snprintf(buf, sizeof(buf), "%u", base-1);
}
split_number(b, int_part->number, fract_part->number);
i = 0;
stack_init(&stack);
while (!BN_is_zero(int_part->number)) {
BN_ULONG rem = BN_div_word(int_part->number, base);
stack_pushstring(&stack, get_digit(rem, digits, base));
i++;
}
sz = i;
if (BN_cmp(b->number, &zero) < 0)
putcharwrap(f, '-');
for (i = 0; i < sz; i++) {
p = stack_popstring(&stack);
if (base > 16)
putcharwrap(f, ' ');
printwrap(f, p);
free(p);
}
stack_clear(&stack);
if (b->scale > 0) {
struct number *num_base;
BIGNUM mult, stop;
putcharwrap(f, '.');
num_base = new_number();
bn_check(BN_set_word(num_base->number, base));
BN_init(&mult);
bn_check(BN_one(&mult));
BN_init(&stop);
bn_check(BN_one(&stop));
scale_number(&stop, b->scale);
i = 0;
while (BN_cmp(&mult, &stop) < 0) {
u_long rem;
if (i && base > 16)
putcharwrap(f, ' ');
i = 1;
bmul_number(fract_part, fract_part, num_base);
split_number(fract_part, int_part->number, NULL);
rem = BN_get_word(int_part->number);
p = get_digit(rem, digits, base);
int_part->scale = 0;
normalize(int_part, fract_part->scale);
bn_check(BN_sub(fract_part->number, fract_part->number,
int_part->number));
printwrap(f, p);
free(p);
bn_check(BN_mul_word(&mult, base));
}
free_number(num_base);
BN_free(&mult);
BN_free(&stop);
}
flushwrap(f);
free_number(int_part);
free_number(fract_part);
}
void
print_value(FILE *f, const struct value *value, const char *prefix, u_int base)
{
(void)fputs(prefix, f);
switch (value->type) {
case BCODE_NONE:
if (value->array != NULL)
(void)fputs("<array>", f);
break;
case BCODE_NUMBER:
printnumber(f, value->u.num, base);
break;
case BCODE_STRING:
(void)fputs(value->u.string, f);
break;
}
}
void
print_ascii(FILE *f, const struct number *n)
{
BIGNUM *v;
int numbits, i, ch;
v = BN_dup(n->number);
bn_checkp(v);
if (BN_cmp(v, &zero) < 0)
bn_check(BN_sub(v, &zero, v));
numbits = BN_num_bytes(v) * 8;
while (numbits > 0) {
ch = 0;
for (i = 0; i < 8; i++)
ch |= BN_is_bit_set(v, numbits-i-1) << (7 - i);
(void)putc(ch, f);
numbits -= 8;
}
BN_free(v);
}