1/*
2 * misc. functions for the "dc" Desk Calculator language.
3 *
4 * Copyright (C) 1994, 1997, 1998, 2000 Free Software Foundation, Inc.
5 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14 * GNU General Public License for more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, you can either send email to this
18 * program's author (see below) or write to:
19 *   The Free Software Foundation, Inc.
20 *   59 Temple Place, Suite 330
21 *   Boston, MA 02111 USA
22 */
23
24/* This module contains miscelaneous functions that have no
25 * special knowledge of any private data structures.
26 * They could all be moved to their own separate modules, but
27 * are agglomerated here for convenience.
28 */
29
30#include "config.h"
31
32#include <stdio.h>
33#ifdef HAVE_STDLIB_H
34# include <stdlib.h>
35#endif
36#ifdef HAVE_STRING_H
37# include <string.h>
38#else
39# ifdef HAVE_STRINGS_H
40#  include <strings.h>
41# endif
42#endif
43#include <ctype.h>
44#ifndef isgraph
45# ifndef HAVE_ISGRAPH
46#  define isgraph isprint
47# endif
48#endif
49#include <getopt.h>
50#include "dc.h"
51#include "dc-proto.h"
52
53#ifndef EXIT_FAILURE	/* C89 <stdlib.h> */
54# define EXIT_FAILURE	1
55#endif
56
57
58/* print an "out of memory" diagnostic and exit program */
59void
60dc_memfail DC_DECLVOID()
61{
62	fprintf(stderr, "%s: out of memory\n", progname);
63	exit(EXIT_FAILURE);
64}
65
66/* malloc or die */
67void *
68dc_malloc DC_DECLARG((len))
69	size_t len DC_DECLEND
70{
71	void *result = malloc(len);
72
73	if (!result)
74		dc_memfail();
75	return result;
76}
77
78
79/* print the id in a human-understandable form
80 *  fp is the output stream to place the output on
81 *  id is the name of the register (or command) to be printed
82 *  suffix is a modifier (such as "stack") to be printed
83 */
84void
85dc_show_id DC_DECLARG((fp, id, suffix))
86	FILE *fp DC_DECLSEP
87	int id DC_DECLSEP
88	const char *suffix DC_DECLEND
89{
90	if (isgraph(id))
91		fprintf(fp, "'%c' (%#o)%s", id, id, suffix);
92	else
93		fprintf(fp, "%#o%s", id, suffix);
94}
95
96
97/* report that corrupt data has been detected;
98 * use the msg and regid (if nonnegative) to give information
99 * about where the garbage was found,
100 *
101 * will abort() so that a debugger might be used to help find
102 * the bug
103 */
104/* If this routine is called, then there is a bug in the code;
105 * i.e. it is _not_ a data or user error
106 */
107void
108dc_garbage DC_DECLARG((msg, regid))
109	const char *msg DC_DECLSEP
110	int regid DC_DECLEND
111{
112	if (regid < 0) {
113		fprintf(stderr, "%s: garbage %s\n", progname, msg);
114	} else {
115		fprintf(stderr, "%s:%s register ", progname, msg);
116		dc_show_id(stderr, regid, " is garbage\n");
117	}
118	abort();
119}
120
121
122/* call system() with the passed string;
123 * if the string contains a newline, terminate the string
124 * there before calling system.
125 * Return a pointer to the first unused character in the string
126 * (i.e. past the '\n' if there was one, to the '\0' otherwise).
127 */
128const char *
129dc_system DC_DECLARG((s))
130	const char *s DC_DECLEND
131{
132	const char *p;
133	char *tmpstr;
134	size_t len;
135
136	p = strchr(s, '\n');
137	if (p) {
138		len = p - s;
139		tmpstr = dc_malloc(len + 1);
140		strncpy(tmpstr, s, len);
141		tmpstr[len] = '\0';
142		system(tmpstr);
143		free(tmpstr);
144		return p + 1;
145	}
146	system(s);
147	return s + strlen(s);
148}
149
150
151/* print out the indicated value */
152void
153dc_print DC_DECLARG((value, obase, newline_p, discard_p))
154	dc_data value DC_DECLSEP
155	int obase DC_DECLSEP
156	dc_newline newline_p DC_DECLSEP
157	dc_discard discard_p DC_DECLEND
158{
159	if (value.dc_type == DC_NUMBER) {
160		dc_out_num(value.v.number, obase, newline_p, discard_p);
161	} else if (value.dc_type == DC_STRING) {
162		dc_out_str(value.v.string, newline_p, discard_p);
163	} else {
164		dc_garbage("in data being printed", -1);
165	}
166}
167
168/* return a duplicate of the passed value, regardless of type */
169dc_data
170dc_dup DC_DECLARG((value))
171	dc_data value DC_DECLEND
172{
173	if (value.dc_type!=DC_NUMBER && value.dc_type!=DC_STRING)
174		dc_garbage("in value being duplicated", -1);
175	if (value.dc_type == DC_NUMBER)
176		return dc_dup_num(value.v.number);
177	/*else*/
178	return dc_dup_str(value.v.string);
179}
180