36827f1540d4c724206d752b43a86c7a0655e8c3
[oweals/cde.git] / cde / programs / dtcalc / calctool.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these libraries and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: calctool.c /main/9 1996/09/25 11:28:16 rswiston $ */
24 /*                                                                      *
25  *  calctool.c                                                          *
26  *   Contains the none user interface portion of the Desktop            *
27  *   Calculator.                                                        *
28  *                                                                      *
29  * (c) Copyright 1993, 1994 Hewlett-Packard Company                     *
30  * (c) Copyright 1993, 1994 International Business Machines Corp.       *
31  * (c) Copyright 1993, 1994 Sun Microsystems, Inc.                      *
32  * (c) Copyright 1993, 1994 Novell, Inc.                                *
33  */
34
35 #include <stdio.h>
36 #include <ctype.h>
37 #include <string.h>
38 #include <stdlib.h>
39 #include <unistd.h>
40 #include <sys/types.h>
41 #include <sys/file.h>
42 #include <sys/param.h>
43 #include <pwd.h>
44 #include <math.h>
45 #include "patchlevel.h"
46 #include "calctool.h"
47 #include "ds_common.h"
48
49 #ifdef legacysun
50
51 /* Copied from math.h */
52 struct exception {
53         int type;
54         char *name;
55         double arg1;
56         double arg2;
57         double retval;
58 };
59
60 #endif
61
62 time_t time() ;
63
64 double max_fix[4] = {
65           6.871947674e+10, 3.245185537e+32,
66           1.000000000e+36, 2.230074520e+43
67 } ;
68 double min_fix0[4] = {
69           2.500000000e-1, 3.750000000e-1,
70           1.000000000e-1, 4.375000000e-1
71 } ;
72 double min_fix1[4] = {
73           1.250000000e-1, 4.687500000e-2,
74           1.000000000e-2, 2.734375000e-2
75 } ;
76 double min_fix2[4] = {
77           6.250000000e-2, 5.859375000e-3,
78           1.000000000e-3, 1.708984375e-3
79 } ;
80 double min_fix3[4] = {
81           3.125000000e-2, 7.324218750e-4,
82           1.000000000e-4, 1.068115234e-4
83 } ;
84 double min_fix4[4] = {
85           1.562500000e-2, 9.155273437e-5,
86           1.000000000e-5, 6.675720215e-6
87 } ;
88 double min_fix5[4] = {
89           7.812500000e-3, 1.144409180e-5,
90           1.000000000e-6, 4.172325134e-7
91 } ;
92 double min_fix6[4] = {
93           6.906250000e-3, 1.430511475e-6,
94           1.000000000e-7, 2.607703209e-8
95 } ;
96 double min_fix7[4] = {
97           1.953125000e-3, 1.788139343e-7,
98           1.000000000e-8, 1.629814506e-9
99 } ;
100 double min_fix8[4] = {
101           9.765625000e-4, 2.235174179e-8,
102           1.000000000e-9, 1.018634066e-10
103 } ;
104 double min_fix9[4] = {
105           4.882812500e-4, 2.793967724e-9,
106           1.000000000e-10, 6.366462912e-12
107 } ;
108
109 extern char *base_str[] ;       /* Strings for each base value. */
110 extern char *cmdstr[] ;         /* Strings for each command line option. */
111 extern char *dtype_str[] ;      /* Strings for each display mode value. */
112 extern char *lstrs[] ;          /* Labels for various Motif items. */
113 extern char *mess[] ;           /* Message strings. */
114 extern char *mode_str[] ;       /* Strings for each mode value. */
115 extern char *opts[] ;           /* Command line option strings. */
116 extern char *ttype_str[] ;      /* Strings for each trig type value. */
117 extern char *ustrs[] ;          /* Usage message strings. */
118 extern char *vstrs[] ;          /* Various strings. */
119
120 char digits[] = "0123456789ABCDEF" ;
121 int basevals[4] = { 2, 8, 10, 16 } ;
122
123 int left_pos[BCOLS]  = { 3, 2, 1, 0 } ;  /* Left positions. */
124 int right_pos[BCOLS] = { 0, 1, 2, 3 } ;  /* "Right" positions. */
125
126 /* Valid keys when an error condition has occurred. */
127 /*                            MEM  KEYS clr     clr     QUIT REDRAW */
128 char validkeys[MAXVKEYS]  = { 'm', 'k', '\177', '\013', 'q', '\f' } ;
129
130 Vars v ;            /* Calctool variables and options. */
131
132 struct menu_entry menu_entries[MAXENTRIES] ;
133
134 struct menu cmenus[MAXMENUS] = {                 /* Calculator menus. */
135 /*      title     total index defval                           */
136   { (char *) NULL, 10,    0,    2  /* 2 places */    },    /* ACC */
137   { (char *) NULL,  4,   20,    2  /* Decimal  */    },    /* BASE TYPE */
138   { (char *) NULL, 10,    0,    0  /* Con. 0   */    },    /* CON */
139   { (char *) NULL, 10,   10,    0  /* Reg. 0   */    },    /* EXCH */
140   { (char *) NULL, 10,    0,    0  /* Fun. 0   */    },    /* FUN */
141   { (char *) NULL,  4,   30,    0  /* Basic    */    },    /* MODE */
142   { (char *) NULL,  3,   24,    1  /* Fixed    */    },    /* NUM TYPE */
143   { (char *) NULL, 10,   10,    0  /* Reg. 0   */    },    /* RCL */
144   { (char *) NULL, 10,   10,    0  /* Reg. 0   */    },    /* STO */
145   { (char *) NULL,  3,   27,    0  /* Degrees  */    },    /* TRIG TYPE */
146 } ;
147
148 /*  This table shows the keyboard values that are currently being used:
149  *
150  *           | a b c d e f g h i j k l m n o p q r s t u v w x y z
151  *-------------+--------------------------------------------------
152  *  Control: | a   c d   f   h i     l m         r s t u       y
153  *  Lower:   | a b c d e f   h i   k   m n   p q r s     v   x y
154  *  Upper:   | A B C D E F G           M N   P Q R S T       X
155  *  Numeric: | 0 1 2 3 4 5 6 7 8 9
156  *  Other:   | @ . + - * / = % ( ) # < > [ ] { } | & ~ ^ ? ! \177
157  *----------------------------------------------------------------
158  */
159
160 /* Calculator button values. */
161
162 struct button buttons[TITEMS] = {
163 /*     str       str2      value opdisp   menutype   resname  func */
164
165 /* Row 1. */
166 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
167 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_FUN,    "fun",    do_pending },
168 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_CON,    "con",    do_pending },
169 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "keys",   do_keys    },
170
171 /* Row 2. */
172 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "int",    do_portion },
173 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "frac",   do_portion },
174 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "abs",    do_portion },
175 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "exp",    do_expno   },
176
177 /* Row 3. */
178 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_ACC,    "acc",    do_pending },
179 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_STO,    "sto",    do_pending },
180 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_RCL,    "rcl",    do_pending },
181 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_EXCH,   "exch",   do_pending },
182
183 /* Row 4. */
184 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
185 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
186 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
187 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
188
189 /* Row 5. */ 
190 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
191 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
192 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
193 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
194
195 /* Row 6. */ 
196 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
197 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
198 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
199 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "blank",  do_none },
200
201 /* Row 7. */
202 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "recip",   do_immed   },
203 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "square",  do_immed   },
204 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "sqrt",    do_immed   },
205 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "percent", do_calc   },
206
207 /* Row 8. */
208 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "lparen", do_paren   },
209 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "rparen", do_paren   },
210 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "bsp",    do_delete  },
211 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "clr",    do_clear   },
212
213 /* Row 9. */
214 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "numd",   do_number  },
215 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "nume",   do_number  },
216 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "numf",   do_number  },
217 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "chs",    do_immed   },
218
219 /* Row 10. */
220 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "numa",   do_number  },
221 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "numb",   do_number  },
222 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "numc",   do_number  },
223 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "mul",    do_calc    },
224
225 /* Row 11. */
226 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num7",   do_number  },
227 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num8",   do_number  },
228 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num9",   do_number  },
229 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "div",    do_calc    },
230
231 /* Row 12. */
232 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num4",   do_number  },
233 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num5",   do_number  },
234 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num6",   do_number  },
235 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "sub",    do_calc    },
236
237 /* Row 13. */
238 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num1",   do_number  },
239 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num2",   do_number  },
240 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num3",   do_number  },
241 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "add",    do_calc    },
242
243 /* Row 14. */
244 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "num0",   do_number  },
245 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "point",  do_point   },
246 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "equals", do_calc    },
247 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "quit",   do_frame   },
248
249 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_BASE,   "base",   do_pending },
250 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NUM,    "disp",   do_pending },
251 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_MODE,   "mode",   do_pending },
252 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_TRIG,   "trig",   do_pending },
253 } ; 
254
255 struct button mode_buttons[MAXMODES * MODEKEYS] = {
256 /*     str       str2      value opdisp   menutype   resname  func */
257
258 /* Financial. */
259 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "term",   do_business},
260 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "rate",   do_business},
261 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "pv",     do_business},
262 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "pmt",    do_business},
263 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "fv",     do_business},
264 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "ppy",    do_business},
265 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "clrreg", do_business},
266 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "ctrm",   do_business},
267 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "ddb",    do_business},
268 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "sln",    do_business},
269 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "syd",    do_business},
270 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
271 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
272 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
273 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
274 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
275
276 /* Logical. */
277 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "lshift", do_pending },
278 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "rshift", do_pending },
279 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "and16",  do_immed   },
280 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "and32",  do_immed   },
281 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "or",     do_calc    },
282 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "and",    do_calc    },
283 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "not",    do_immed   },
284 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "xor",    do_calc    },
285 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "xnor",   do_calc    },
286 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
287 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
288 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
289 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
290 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
291 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
292 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
293
294 /* Scientific. */
295 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "inv",    do_immed   },
296 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "hyp",    do_immed   },
297 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "etox",   do_immed   },
298 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "tentox", do_immed   },
299 { (char *)NULL, (char *)NULL, 0, OP_SET,   M_NONE,   "ytox",   do_calc    },
300 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "xfact",  do_immed   },
301 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "cos",    do_trig    },
302 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "sin",    do_trig    },
303 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "tan",    do_trig    },
304 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "ln",     do_immed   },
305 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "log",    do_immed   },
306 { (char *)NULL, (char *)NULL, 0, OP_CLEAR, M_NONE,   "rand",   do_immed   },
307 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
308 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
309 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
310 { (char *)NULL, (char *)NULL, 0, OP_NOP,   M_NONE,   "",       do_none    },
311 } ;
312
313
314 int
315 char_val(char chr)
316 {
317        if (chr >= '0' && chr <= '9') return(chr - '0') ;
318   else if (chr >= 'a' && chr <= 'f') return(chr - 'a' + 10) ;
319   else if (chr >= 'A' && chr <= 'F') return(chr - 'A' + 10) ;
320   else return(-1) ;
321 }
322
323
324 void
325 clear_display(void)
326 {
327   int i ;
328  
329   v->pointed = 0 ;
330   v->toclear = 1 ;
331   v->defState = 1 ;
332   i = 0 ;
333   mpcim(&i, v->MPdisp_val) ;
334   STRCPY(v->display, make_number(v->MPdisp_val, FALSE)) ;
335   set_item(DISPLAYITEM, v->display) ;
336   
337   v->hyperbolic = 0 ;
338   v->inverse    = 0 ;
339   v->show_paren = 0 ;
340   v->opsptr     = 0 ;            /* Clear parentheses stacks. */
341   v->numsptr    = 0 ;
342   set_item(HYPITEM, "    ") ;
343   set_item(INVITEM, "    ") ;
344 }
345
346 /* Convert .dtcalcrc line to ascii values. */
347 /* line    Input line to be converted. */
348 char *
349 convert(char *line)
350 {
351   static char output[MAXLINE] ;   /* Converted output record. */
352   int ctrl = 0       ;     /* Set if we are processing a control character. */
353   int i ;                  /* Position within input line. */
354   int len ;
355   int n = 0 ;              /* Position within output line. */
356  
357   len = strlen(line) ;
358   for (i = 0; i < len; i++)
359     {
360            if (line[i] == ' ') continue ;
361       else if (line[i] == '\\') ctrl = 1 ;
362       else if (ctrl)
363         {
364           output[n++] = CTL(line[i]) ;
365           ctrl = 0 ;
366         }
367       else output[n++] = line[i] ;
368     }
369   output[n] = '\0' ;
370   return(output) ;
371 }
372
373
374 void
375 do_dtcalc(int argc, char **argv)
376 {
377   char *ptr ;
378
379   v->progname = argv[0] ;     /* Save programs name. */
380   v->appname  = NULL ;
381   init_cmdline_opts() ;       /* Initialize command line option strings. */
382
383   if ((ptr = strrchr(argv[0], '/')) != NULL)
384     read_str(&v->appname, ptr+1) ;
385   else read_str(&v->appname, argv[0]) ;
386
387   init_text() ;               /* Setup text strings depending upon language. */
388   init_vars() ;               /* Setup default values for variables. */
389   key_init() ;                /* Determine numeric function keys. */
390   load_resources() ;          /* Get resources from various places. */
391   read_resources() ;          /* Read resources from merged database. */
392   get_options(argc, argv) ;   /* Get command line arguments. */
393   if(application_args.session != NULL)
394   {
395       RestoreSession(); 
396   }
397   read_rcfiles() ;            /* Read .dtcalcrc's files. */
398   init_graphics() ;
399   make_frames() ;             /* Create dtcalc window frames. */
400
401   v->shelf      = NULL ;      /* No selection for shelf initially. */
402   v->noparens   = 0 ;         /* No unmatched brackets initially. */
403   v->opsptr     = 0 ;         /* Nothing on the parentheses op stack. */
404   v->numsptr    = 0 ;         /* Nothing on the parenthese numeric stack. */
405   v->pending    = 0 ;         /* No initial pending command. */
406   if(application_args.session == NULL)
407      v->tstate     = 0 ;      /* Button values displayed first. */
408   v->hyperbolic = 0 ;         /* Normal trig functions initially. */
409   v->inverse    = 0 ;         /* No inverse functions initially. */
410
411   srand48((long) time((time_t *) 0)) ;   /* Seed random number generator. */
412
413   make_items() ;              /* Create server images and fir frames. */
414   if(v->display[0] == 0)
415      do_clear() ;                /* Initialize and clear display. */
416
417   if (v->rstate == TRUE)      /* Show the memory register window? */
418     {
419       make_registers(MEM) ;
420       if (!v->iconic) win_display(FCP_REG, TRUE) ;
421     }
422   if (!v->iconic) win_display(FCP_MODE, TRUE) ;
423   show_display(v->MPdisp_val) ;     /* Output in correct display mode. */
424   save_cmdline(argc, argv) ;        /* Setup dtcalc command line. */
425   start_tool() ;                    /* Display the calculator. */
426 }
427
428
429 /* Dtcalc's customised math library error-handling routine. */
430
431 void
432 doerr(char *errmes)
433 {
434   if (!v->started) return ;
435   STRCPY(v->display, errmes) ;
436   set_item(DISPLAYITEM, v->display) ;
437   v->error = 1 ;
438   beep() ;
439   set_item(OPITEM, vstrs[(int) V_CLR]) ;
440 }
441
442 /* Get boolean resource from database. */
443 int
444 get_bool_resource(enum res_type rtype, int *boolval)
445 {
446   char *val, tempstr[MAXLINE] ;
447   int len, n ;
448  
449   if ((val = get_resource(rtype)) == NULL) return(0) ;
450   STRCPY(tempstr, val) ;
451   len = strlen(tempstr) ;
452   for (n = 0; n < len; n++)
453     if (isupper(tempstr[n])) tempstr[n] = tolower(tempstr[n]) ;
454   if (EQUAL(tempstr, vstrs[(int) V_TRUE])) *boolval = TRUE ;
455   else                                     *boolval = FALSE ;
456   return(1) ;
457 }
458
459
460 /*  Get button index for given character value, setting curwin,
461  *  row and column appropriately. Note that if the value isn't found,
462  *  then a value of TITEMS is returned. This is "chucked out" by
463  *  process_item as being invalid.
464  *
465  *  XXX: This routine can be improved by using a hash lookup table.
466  */
467  
468 int
469 get_index(char ch)
470 {
471   int n ;
472  
473   for (n = 0; n < TITEMS; n++) {
474     if (ch == buttons[n].value)  
475        break ;
476   }
477   if (n < TITEMS) 
478      v->curwin = FCP_KEY ;
479   else
480   {
481      return(TITEMS) ;
482   }
483   v->row = n / MAXCOLS ;
484   v->column = n - (v->row * MAXCOLS) ;
485   return(n) ;
486 }
487
488  /* Get integer resource from database. */
489 int
490 get_int_resource(enum res_type rtype, int *intval)
491 {
492   char *val ;
493
494   if ((val = get_resource(rtype)) == NULL) return(0) ;
495   *intval = atoi(val) ;
496   return(1) ;
497 }
498
499
500 /* Get keyboard equivalent from first character of localised string. */
501
502 void
503 get_key_val(char *val, char *str)
504 {
505   *val = str[0] ;
506 }
507
508
509 void
510 get_label(int n)
511 {
512   char *temp;
513
514   if (v->tstate)
515      temp = buttons[n].str2;
516   else 
517      temp = buttons[n].str;
518
519   if(temp != NULL)
520      STRCPY(v->pstr, temp) ;
521   else
522      STRCPY(v->pstr, "");
523 }
524
525 /* Extract command line options. */
526 void
527 get_options(int argc, char *argv[])
528 {
529   char next[MAXLINE] ;       /* The next command line parameter. */
530   char strval[MAXLINE] ;
531   char *msg;
532   int i, len;
533
534   INC ;
535   while (argc > 0)
536     {
537       if (argv[0][0] == '-' || argv[0][0] == '+')
538         {
539           switch (argv[0][1])
540             {
541               case 'D' : v->MPdebug = TRUE ;   /* MP debug info. to stderr. */
542                          break ;
543               case 'a' : INC ;
544                          getparam(next, argv, opts[(int) O_ACCVAL]) ;
545                          v->accuracy = atoi(next) ;
546                          if (v->accuracy < 0 || v->accuracy > 9)
547                            {
548                              msg = (char *) XtMalloc(strlen(
549                                                    opts[(int) O_ACCRANGE]) + 3);
550                              sprintf(msg, "%s", opts[(int) O_ACCRANGE]);
551                              _DtSimpleError (v->appname, DtWarning, NULL, msg);
552                              XtFree(msg);
553                              v->accuracy = 2 ;
554                            }
555                          break ;
556               case 'm' : INC ;
557                          msg = (char *) XtMalloc(strlen(opts[(int) O_MODE])+
558                                                              strlen(next) + 3);
559                          sprintf(msg, opts[(int) O_MODE], next);
560                          getparam(next, argv, msg) ;
561                          XtFree(msg);
562                          STRCPY(strval, next) ;
563                          len = strlen(strval) ;
564                          for (i = 0; i < len; i++)
565                          {
566                            if (islower(strval[i])) 
567                               strval[i] = toupper(strval[i]) ;
568                          }
569                          if(strcmp(strval, "FINANCIAL") == 0)
570                              v->modetype = FINANCIAL ;
571                          else if(strcmp(strval, "LOGICAL") == 0)
572                              v->modetype = LOGICAL ;
573                          else if(strcmp(strval, "SCIENTIFIC") == 0)
574                              v->modetype = SCIENTIFIC ;
575                          else
576                            {
577                              msg = (char *) XtMalloc(strlen(opts[(int) O_MODE])+
578                                                     strlen(next) + 3);
579                              sprintf(msg, opts[(int) O_MODE], next);
580                              _DtSimpleError (v->appname, DtWarning, NULL, msg);
581                              XtFree(msg);
582                              v->modetype = SCIENTIFIC ;
583                            }
584                          break ;
585               case 'b' : INC ;
586                          getparam(next, argv, opts[(int) O_BASE]) ;
587                          STRCPY(strval, next) ;
588                          len = strlen(strval) ;
589                          for (i = 0; i < len; i++)
590                          {
591                            if (islower(strval[i]))
592                               strval[i] = toupper(strval[i]) ;
593                          }
594                          if(strncmp(strval, "BIN", 3) == 0)
595                              v->base = BIN ;
596                          else if(strncmp(strval, "OCT", 3) == 0)
597                              v->base = OCT ;
598                          else if(strncmp(strval, "DEC", 3) == 0)
599                              v->base = DEC ;
600                          else if(strncmp(strval, "HEX", 3) == 0)
601                              v->base = HEX ;
602                          else
603                            {
604                              msg = (char *) XtMalloc(strlen(
605                                                     opts[(int) O_BASE]) + 3);
606                              sprintf(msg, "%s", opts[(int) O_BASE]);
607                              _DtSimpleError (v->appname, DtWarning, NULL, msg);
608                              XtFree(msg);
609                              v->base = DEC ;
610                            }
611                          break ;
612               case 'n' : if(strcmp(&argv[0][1], "notation") == 0) 
613                          {
614                             INC ;
615                             msg = (char *) XtMalloc(strlen(
616                                                  opts[(int) O_DISPLAY]) + 
617                                                  strlen(next) + 3);
618                             sprintf(msg, opts[(int) O_DISPLAY], next);
619                             getparam(next, argv, msg) ;
620                             XtFree(msg);
621                             STRCPY(strval, next) ;
622                             len = strlen(strval) ;
623                             for (i = 0; i < len; i++)
624                             {
625                               if (islower(strval[i]))
626                                  strval[i] = toupper(strval[i]) ;
627                             }
628                             if(strncmp(strval, "FIX", 3) == 0)
629                                 v->dtype = FIX ;
630                             else if(strncmp(strval, "ENG", 3) == 0)
631                                 v->dtype = ENG ;
632                             else if(strncmp(strval, "SCI", 3) == 0)
633                                 v->dtype = SCI ;
634                             else
635                               {
636                                 msg = (char *) XtMalloc(strlen(
637                                                     opts[(int) O_DISPLAY]) + 
638                                                     strlen(next) + 3);
639                                 sprintf(msg, opts[(int) O_DISPLAY], next);
640                                 _DtSimpleError (v->appname, DtWarning, NULL, msg);
641                                 XtFree(msg);
642                                 v->dtype = FIX ;
643                               }
644                             break ;
645                          }
646                          else if(strcmp(&argv[0][1], "no_menu_bar") == 0)
647                          {
648                             INC ;
649                             application_args.menuBar = False;
650                             break ;
651                          }
652               case 't' : if(strcmp(&argv[0][1], "trig") == 0)
653                          {
654                             INC ;
655                             msg = (char *) XtMalloc(strlen(
656                                                     opts[(int) O_TRIG]) + 
657                                                     strlen(next) + 3);
658                             sprintf(msg, opts[(int) O_TRIG], next);
659                             getparam(next, argv, msg) ;
660                             XtFree(msg);
661                             STRCPY(strval, next) ;
662                             len = strlen(strval) ;
663                             for (i = 0; i < len; i++)
664                             {
665                               if (islower(strval[i]))
666                                  strval[i] = toupper(strval[i]) ;
667                             }
668                             if(strncmp(strval, "DEG", 3) == 0)
669                                 v->ttype = DEG ;
670                             else if(strncmp(strval, "RAD", 3) == 0)
671                                 v->ttype = RAD ;
672                             else if(strncmp(strval, "GRAD", 4) == 0)
673                                 v->ttype = GRAD ;
674                             else
675                               {
676                                 msg = (char *) XtMalloc(strlen(
677                                                     opts[(int) O_TRIG]) + 
678                                                     strlen(next) + 3);
679                                 sprintf(msg, opts[(int) O_TRIG], next);
680                                 _DtSimpleError (v->appname, DtWarning, NULL, msg);
681                                 XtFree(msg);
682                                 v->ttype = DEG ;
683                               }
684                             break ;
685                          }
686               case 's' : if(strcmp(&argv[0][1], "session") == 0)
687                          {
688                             INC ;
689                             getparam(next, argv, opts[(int) O_SESSION]) ;
690                             application_args.session = XtNewString(next);
691                             break ;
692                          }
693               case '?' :
694               case 'v' : usage(v->progname) ;
695                          break ;
696               default  :
697                          usage(v->progname) ;
698             }
699           INC ;
700         }
701       else INC ;
702     }
703 }
704
705
706 void
707 getparam(char *s, char *argv[], char *errmes)
708 {
709   char *msg;
710
711   if (*argv != NULL && argv[0][0] != '-') STRCPY(s, *argv) ;
712   else
713     { 
714       msg = (char *) XtMalloc(strlen(mess[(int) MESS_PARAM]) + 
715                               strlen(errmes) + 3);
716       sprintf(msg, mess[(int) MESS_PARAM], errmes);
717       _DtSimpleError (v->appname, DtError, NULL, msg);
718       FPRINTF(stderr, mess[(int) MESS_PARAM], errmes) ;
719       exit(1) ;
720     }
721 }
722
723
724 /* Read .dtcalcrc file. */
725 void
726 get_rcfile(char *name)
727 {
728   char line[MAXLINE] ;    /* Current line from the .dtcalcrc file. */
729   char tmp[MAXLINE] ;     /* Used to extract definitions. */
730   double cval ;           /* Current constant value being converted. */
731   int i ;                 /* Index to constant or function array. */
732   int isval ;             /* Set to 'c' or 'f' for convertable line. */
733   int len, n ;            
734   FILE *rcfd ;            /* File descriptor for dtcalc rc file. */
735  
736   if ((rcfd = fopen(name, "r")) == NULL) return ;
737  
738 /*  Process the .dtcalcrc file. There are currently four types of
739  *  records to look for:
740  *
741  *  1) Those starting with a hash in the first column are comments.
742  *
743  *  2) Lines starting with 'c' or 'C' in the first column are
744  *     definitions for constants. The cC is followed by a digit in
745  *     the range 0-9, then a space. This is followed by a number
746  *     in fixed or scientific notation. Following this is an optional
747  *     comment, which if found, will be used in the popup menu for
748  *     the constants. If the comment is present, there must be at
749  *     least one space between this and the preceding number.
750  *
751  *  3) Those starting with a 'f' or a 'F' in the first column are
752  *     definitions for functions. The fF is followed by a digit in
753  *     the range 0-9, then a space. This is followed by a function
754  *     definition. Following this is an optional comment, which if
755  *     found, will be used in the popup menu for the functions.
756  *     If the comment is present, there must be at least one space
757  *     between this and the preceding function definition.
758  *
759  *  4) Lines starting with a 'r' or a 'R' in the first column are
760  *     definitions for the initial contents of the calculators
761  *     memory registers. The rR is followed by a digit in the
762  *     range 0-9, then a space. This is followed by a number in
763  *     fixed or scientific notation. The rest of the line is ignored.
764  *
765  *  All other lines are ignored.
766  *
767  *  Two other things to note. There should be no embedded spaces in
768  *  the function definitions, and whenever a backslash is found, that
769  *  and the following character signify a control character, for
770  *  example \g would be ascii 7.
771  */
772
773   while (fgets(line, MAXLINE, rcfd) != NULL)
774     {
775       isval = 0 ;
776            if (line[0] == 'c' || line[0] == 'C') isval = 'c' ;
777       else if (line[0] == 'f' || line[0] == 'F') isval = 'f' ;
778       else if (line[0] == 'r' || line[0] == 'R') isval = 'r' ;
779       if (isval)
780         if (line[1] >= '0' && line[1] <= '9' && line[2] == ' ')
781           {
782             i = char_val(line[1]) ;
783             if (isval == 'c')
784               {  
785                 n = sscanf(&line[3], "%lf", &cval) ;
786                 if (n == 1) 
787                 {
788                    if(line[3] == '-')
789                    {
790                       MPstr_to_num(&line[4], DEC, v->MPcon_vals[i]) ;
791                       mpneg(v->MPcon_vals[i], v->MPcon_vals[i]) ;
792                    }
793                    else
794                       MPstr_to_num(&line[3], DEC, v->MPcon_vals[i]) ;
795                 }
796               }  
797             else if (isval == 'f')
798               {
799                 SSCANF(&line[3], "%s", tmp) ;
800                 STRCPY(v->fun_vals[i], convert(tmp)) ;
801               }  
802             else if (isval == 'r')
803               {  
804                 n = sscanf(&line[3], "%lf", &cval) ;
805                 if (n == 1) MPstr_to_num(&line[3], DEC, v->MPmvals[i]) ;
806                 continue ;
807               }  
808             len = strlen(line) ;
809             for (n = 3; n < len; n++)
810               if (line[n] == ' ' || line[n] == '\n')
811                 {
812                   while (line[n] == ' ') n++ ;
813                   line[strlen(line)-1] = '\0' ;
814                   if (isval == 'c')
815                     {
816                       STRCPY(tmp, make_number(v->MPcon_vals[i], TRUE)) ;
817                       SPRINTF(v->con_names[i], "%1d: %s [%s]",
818                               i, tmp, &line[n]) ;
819                     }
820                   else
821                     SPRINTF(v->fun_names[i], "%1d: %s [%s]",
822                             i, tmp, &line[n]) ;
823                   break ;
824                 }
825           }
826     }
827   FCLOSE(rcfd) ;
828 }
829
830 /* Get a string resource from database. */
831 int
832 get_str_resource(enum res_type rtype, char *strval)
833 {
834   char *val ;
835   int i, len ;
836
837   if ((val = get_resource(rtype)) == NULL) return(0) ;
838   STRCPY(strval, val) ;
839   len = strlen(strval) ;
840   if(rtype != R_TRIG && rtype != R_DISPLAY)
841   {
842      for (i = 0; i < len; i++)
843        if (islower(strval[i])) strval[i] = toupper(strval[i]) ;
844   }
845   return(1) ;
846 }
847
848 /* Grey out numeric buttons depending upon base. */
849 void
850 grey_buttons(enum base_type base)
851 {
852   char val ;
853   int column, dim, i, n, row ;
854
855   for (i = 0; i < 16; i++)
856     {
857       val = digits[i] ;
858       if (isupper(val)) val = tolower(val) ;
859       for (n = 0; n < TITEMS; n++)
860         if (val == buttons[n].value) break ;
861       row = n / MAXCOLS ;
862       column = n - (row * MAXCOLS) ;
863
864       if (i < basevals[(int) base]) dim = FALSE ;
865       else                          dim = TRUE ;
866       grey_button(row, column, dim) ;
867     }
868 }
869
870 /* Process right button menu selection. */
871 void
872 handle_menu_selection(int n, int item)
873 {
874   if (item != -1)
875     {
876       if (IS_KEY(v->pending, KEY_LPAR))     /* Are we inside parentheses? */
877         {
878           v->current = buttons[n].value ;
879           do_paren() ;
880           v->current = item ;
881           do_paren() ;
882         }
883       else
884         { 
885           save_pending_values(buttons[n].value) ;
886           v->current = item ;
887           v->ismenu = 1 ;       /* To prevent grey buttons being redrawn. */
888           do_pending() ;
889           v->ismenu = 0 ;
890         }
891     }
892 }
893
894 /* Setup default values for various variables. */
895 void
896 init_vars(void)
897 {
898   int acc, i, n, size ;
899
900   v->accuracy   = 2 ;        /* Initial accuracy. */
901   v->base       = DEC ;      /* Initial base. */
902   v->dtype      = FIX ;      /* Initial number display mode. */
903   v->ttype      = DEG ;      /* Initial trigonometric type. */
904   v->modetype   = SCIENTIFIC;    /* Initial calculator mode. */
905   v->rstate     = 0 ;        /* No memory register frame display initially. */
906   v->frstate    = 0 ;        /* No fin. memory register frame display 
907                                 initially. */
908   v->iconic     = FALSE ;    /* Calctool not iconic by default. */
909   v->MPdebug    = FALSE ;    /* No debug info by default. */
910   v->MPerrors   = TRUE ;               /* No error information. */
911   acc           = MAX_DIGITS + 12 ;     /* MP internal accuracy. */
912   size          = MP_SIZE ;
913   mpset(&acc, &size, &size) ;
914
915   v->hasicon     = FALSE ;        /* Use standard dtcalc icon by default. */
916   v->beep        = TRUE ;         /* Beep on error by default. */
917   v->error       = 0 ;            /* No calculator error initially. */
918   v->key_exp     = 0 ;            /* Not entering an exponent number. */
919   v->pending_op  = 0 ;            /* No pending arithmetic operation. */
920   v->titleline   = NULL ;         /* No User supplied title line. */
921   v->display[0]  = 0 ;         
922
923   v->x  = 0;
924   v->x  = 0;
925   v->width  = 0;
926   v->height = 0; 
927
928   v->workspaces = NULL; 
929
930   read_str(&v->iconlabel, lstrs[(int) L_LCALC]) ;  /* Default icon label. */
931
932   MPstr_to_num("0.621", DEC, v->MPcon_vals[0]) ;  /* kms/hr <=> miles/hr. */
933   MPstr_to_num("1.4142135623", DEC, v->MPcon_vals[1]) ;  /* square root of 2 */
934   MPstr_to_num("2.7182818284", DEC, v->MPcon_vals[2]) ;  /* e */
935   MPstr_to_num("3.1415926535", DEC, v->MPcon_vals[3]) ;  /* pi */
936   MPstr_to_num("2.54",         DEC, v->MPcon_vals[4]) ;  /* cms <=> inch. */
937   MPstr_to_num("57.295779513", DEC, v->MPcon_vals[5]) ;  /* degrees/radian. */
938   MPstr_to_num("1048576.0",    DEC, v->MPcon_vals[6]) ;  /* 2 ^ 20. */
939   MPstr_to_num("0.0353", DEC, v->MPcon_vals[7]) ;  /* grams <=> ounce. */
940   MPstr_to_num("0.948",  DEC, v->MPcon_vals[8]) ;  /* Kjoules <=> BTU's. */
941   MPstr_to_num("0.0610", DEC, v->MPcon_vals[9]) ;  /* cms3 <=> inches3. */
942
943   n = 0 ;
944   for (i = 0; i < MAXREGS; i++) mpcim(&n, v->MPmvals[i]) ;
945   for (i = 0; i < FINREGS; i++)  
946      v->MPfvals[i] = (double)n;
947   v->MPfvals[FINREGS - 1] = (double)12;
948 }
949
950
951 void
952 initialize(void)
953 {
954   int i ;
955
956   v->error         = 0 ;           /* Currently no display error. */
957   v->cur_op        = '?' ;         /* No arithmetic operator defined yet. */
958   v->old_cal_value = '?' ;
959   i = 0 ;
960   mpcim(&i, v->MPresult) ;         /* No previous result yet. */
961   mpcim(&i, v->MPlast_input) ;
962 }
963
964
965 /* Convert engineering or scientific number. */
966 char *
967 make_eng_sci(int *MPnumber)
968 {
969   char fixed[MAX_DIGITS+1], *optr ;
970   int MP1[MP_SIZE], MPatmp[MP_SIZE], MPval[MP_SIZE] ;
971   int MP1base[MP_SIZE], MP3base[MP_SIZE], MP10base[MP_SIZE] ;
972   int i, dval, len, n ;
973   int MPmant[MP_SIZE] ;        /* Mantissa. */
974   int ddig ;                   /* Number of digits in exponent. */
975   int eng = 0 ;                /* Set if this is an engineering number. */
976   int exp = 0 ;                /* Exponent */
977  
978   if (v->dtype == ENG) eng = 1 ;
979   optr = v->snum ;
980   mpabs(MPnumber, MPval) ;
981   n = 0 ;
982   mpcim(&n, MP1) ;
983   if (mplt(MPnumber, MP1)) *optr++ = '-' ;
984   mpstr(MPval, MPmant) ;
985  
986   mpcim(&basevals[(int) v->base], MP1base) ;
987   n = 3 ;
988   mppwr(MP1base, &n, MP3base) ;
989  
990   n = 10 ;
991   mppwr(MP1base, &n, MP10base) ;
992  
993   n = 1 ;
994   mpcim(&n, MP1) ;
995   mpdiv(MP1, MP10base, MPatmp) ;
996  
997   n = 0 ;
998   mpcim(&n, MP1) ;
999   if (!mpeq(MPmant, MP1))
1000     {
1001       while (mpge(MPmant, MP10base))
1002         {
1003           exp += 10 ;
1004           mpmul(MPmant, MPatmp, MPmant) ;
1005         }
1006
1007       while ((!eng &&  mpge(MPmant, MP1base)) ||
1008               (eng && (mpge(MPmant, MP3base) || exp % 3 != 0)))
1009         {
1010           exp += 1 ;
1011           mpdiv(MPmant, MP1base, MPmant) ;
1012         }
1013
1014       while (mplt(MPmant, MPatmp))
1015         {
1016           exp -= 10 ;
1017           mpmul(MPmant, MP10base, MPmant) ;
1018         }
1019
1020       n = 1 ;
1021       mpcim(&n, MP1) ;
1022       while (mplt(MPmant, MP1) || (eng && exp % 3 != 0))
1023         {
1024           exp -= 1 ;
1025           mpmul(MPmant, MP1base, MPmant) ;
1026         }
1027     }    
1028
1029   STRCPY(fixed, make_fixed(MPmant, MAX_DIGITS-6)) ;
1030   len = strlen(fixed) ;
1031   for (i = 0; i < len; i++) *optr++ = fixed[i] ;
1032
1033   *optr++ = 'e' ;
1034
1035   if (exp < 0)
1036     {
1037       exp = -exp ;
1038       *optr++ = '-' ;
1039     }
1040   else *optr++ = '+' ;
1041
1042   MPstr_to_num("0.5", DEC, MP1) ;
1043   mpaddi(MP1, &exp, MPval) ;
1044   n = 1 ;
1045   mpcim(&n, MP1) ;
1046   for (ddig = 0; mpge(MPval, MP1); ddig++)
1047     mpdiv(MPval, MP1base, MPval) ;
1048
1049   if (ddig == 0) *optr++ = '0' ;
1050
1051   while (ddig-- > 0)
1052     {
1053       mpmul(MPval, MP1base, MPval) ;
1054       mpcmi(MPval, &dval) ;
1055       *optr++ = digits[dval] ;
1056       dval = -dval ;
1057       mpaddi(MPval, &dval, MPval) ;
1058     }
1059   *optr++    = '\0' ;
1060   v->toclear = 1 ;
1061   v->pointed = 0 ;
1062   return(v->snum) ;
1063 }
1064
1065 /* Convert MP number to fixed number string. */
1066 /* cmax    Maximum characters to generate. */
1067 char *
1068 make_fixed(int *MPnumber, int cmax)
1069 {
1070   char *optr ;
1071   int MP1base[MP_SIZE], MP1[MP_SIZE], MP2[MP_SIZE], MPval[MP_SIZE] ;
1072   int ndig ;                   /* Total number of digits to generate. */
1073   int ddig ;                   /* Number of digits to left of . */
1074   int dval, n ;
1075  
1076   optr = v->fnum ;
1077   mpabs(MPnumber, MPval) ;
1078   n = 0 ;
1079   mpcim(&n, MP1) ;
1080   if (mplt(MPnumber, MP1)) *optr++ = '-' ;
1081  
1082   mpcim(&basevals[(int) v->base], MP1base) ;
1083  
1084   mppwr(MP1base, &v->accuracy, MP1) ;
1085   MPstr_to_num("0.5", DEC, MP2) ;
1086   mpdiv(MP2, MP1, MP1) ;
1087   mpadd(MPval, MP1, MPval) ;
1088  
1089   n = 1 ;
1090   mpcim(&n, MP2) ;
1091   if (mplt(MPval, MP2))
1092     {
1093       ddig = 0 ;
1094       *optr++ = '0' ;
1095       cmax-- ;
1096     }
1097   else
1098     for (ddig = 0; mpge(MPval, MP2); ddig++)
1099       mpdiv(MPval, MP1base, MPval) ;
1100
1101   ndig = MIN(ddig + v->accuracy, --cmax) ;
1102
1103   while (ndig-- > 0)
1104     {
1105       if (ddig-- == 0) *optr++ = '.' ;
1106       mpmul(MPval, MP1base, MPval) ;
1107       mpcmi(MPval, &dval) ;
1108       *optr++ = digits[dval] ;
1109       dval = -dval ;
1110       mpaddi(MPval, &dval, MPval) ;
1111     }
1112   *optr++    = '\0' ;
1113   v->toclear = 1 ;
1114   v->pointed = 0 ;
1115   return(v->fnum) ;
1116 }
1117
1118
1119 void
1120 make_items(void)
1121 {
1122   set_item(DISPLAYITEM, v->display) ;
1123   set_item(OPITEM,      "    ") ;
1124   set_item(HYPITEM,     "    ") ;
1125   set_item(INVITEM,     "    ") ;
1126 }
1127
1128 /* Convert MP number to character string. */
1129 char *
1130 make_number(int *MPnumber, BOOLEAN mkFix)
1131 {
1132   double number, val ;
1133
1134 /*  NOTE: make_number can currently set v->error when converting to a double.
1135  *        This is to provide the same look&feel as V3 even though dtcalc
1136  *        now does internal arithmetic to "infinite" precision.
1137  *
1138  *  XXX:  Needs to be improved. Shouldn't need to convert to a double in
1139  *        order to do these tests.
1140  */  
1141      
1142   mpcmd(MPnumber, &number) ;
1143   val = fabs(number) ;
1144   if (v->error) return(vstrs[(int) V_ERROR]) ;
1145   if (v->dtype == ENG || v->dtype == SCI ||
1146        (v->dtype == FIX && val != 0.0 && (val > max_fix[(int) v->base])))
1147      return(make_eng_sci(MPnumber)) ;
1148   else if (v->dtype == FIX && val != 0.0 && mkFix)
1149   {
1150      if(v->accuracy == 0)
1151      {
1152         if(val <= min_fix0[(int) v->base])
1153            return(make_eng_sci(MPnumber)) ;
1154         else
1155            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1156      }
1157      else if(v->accuracy == 1)
1158      {
1159         if(val <= min_fix1[(int) v->base])
1160            return(make_eng_sci(MPnumber)) ;
1161         else
1162            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1163      }
1164      else if(v->accuracy == 2)
1165      {
1166         if(val <= min_fix2[(int) v->base])
1167            return(make_eng_sci(MPnumber)) ;
1168         else
1169            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1170      }
1171      else if(v->accuracy == 3)
1172      {
1173         if(val <= min_fix3[(int) v->base])
1174            return(make_eng_sci(MPnumber)) ;
1175         else
1176            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1177      }
1178      else if(v->accuracy == 4)
1179      {
1180         if(val <= min_fix4[(int) v->base])
1181            return(make_eng_sci(MPnumber)) ;
1182         else
1183            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1184      }
1185      else if(v->accuracy == 5)
1186      {
1187         if(val <= min_fix5[(int) v->base])
1188            return(make_eng_sci(MPnumber)) ;
1189         else
1190            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1191      }
1192      else if(v->accuracy == 6)
1193      {
1194         if(val <= min_fix6[(int) v->base])
1195            return(make_eng_sci(MPnumber)) ;
1196         else
1197            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1198      }
1199      else if(v->accuracy == 7)
1200      {
1201         if(val <= min_fix7[(int) v->base])
1202            return(make_eng_sci(MPnumber)) ;
1203         else
1204            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1205      }
1206      else if(v->accuracy == 8)
1207      {
1208         if(val <= min_fix8[(int) v->base])
1209            return(make_eng_sci(MPnumber)) ;
1210         else
1211            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1212      }
1213      else if(v->accuracy == 9)
1214      {
1215         if(val <= min_fix9[(int) v->base])
1216            return(make_eng_sci(MPnumber)) ;
1217         else
1218            return(make_fixed(MPnumber, MAX_DIGITS)) ;
1219      }
1220      else 
1221      {
1222         return(make_fixed(MPnumber, MAX_DIGITS)) ;
1223      }
1224   }
1225   else 
1226      return(make_fixed(MPnumber, MAX_DIGITS)) ;
1227 }
1228
1229
1230 /*ARGSUSED*/
1231 /* Default math library exception handling routine. */
1232 int
1233 matherr(struct exception *exc)
1234 {
1235 #if 0
1236   char msg[100];
1237   
1238   if (exc) {
1239           strcpy(msg, exc->name);
1240           strcat(msg, ": ");
1241           if(exc->type == DOMAIN)
1242              strcat(msg, "DOMAIN ");
1243           else if(exc->type == SING)
1244              strcat(msg, "SING ");
1245           else if(exc->type == OVERFLOW)
1246              strcat(msg, "OVERFLOW ");
1247           else if(exc->type == UNDERFLOW)
1248              strcat(msg, "UNDERFLOW ");
1249           else if(exc->type == TLOSS)
1250              strcat(msg, "TLOSS ");
1251           else if(exc->type == PLOSS)
1252              strcat(msg, "PLOSS ");
1253           
1254           strcat(msg, vstrs[(int) V_ERROR]);
1255
1256           _DtSimpleError (v->appname, DtWarning, NULL, msg);
1257   }
1258 #endif
1259
1260   doerr(vstrs[(int) V_ERROR]) ;
1261   return(1) ;                     /* Value ignored. */
1262 }
1263
1264 /* Convert string into an MP number. */
1265 void
1266 MPstr_to_num(char *str, enum base_type base, int *MPval)
1267 {
1268   char   *optr ;
1269   int MP1[MP_SIZE], MP2[MP_SIZE], MPbase[MP_SIZE] ;
1270   int    i, inum ;
1271   int    neg      = 0 ;
1272   int    exp      = 0 ;
1273   int    exp_sign = 1 ;
1274
1275   i = 0 ;
1276   mpcim(&i, MPval) ;
1277   mpcim(&basevals[(int) base], MPbase) ;
1278   optr = str ;
1279   while (*optr == ' ') optr++ ;
1280   if(*optr == '-')
1281   {
1282      /* negative number */
1283      optr++ ;
1284      neg = 1;
1285   }
1286   while ((inum = char_val(*optr)) >= 0)
1287     {
1288       mpmul(MPval, MPbase, MPval) ;
1289       mpaddi(MPval, &inum, MPval) ;
1290       optr++ ;
1291     }
1292
1293   if (*optr == '.')
1294     for (i = 1; (inum = char_val(*++optr)) >= 0; i++)
1295       {  
1296         mppwr(MPbase, &i, MP1) ;
1297         mpcim(&inum, MP2) ;
1298         mpdiv(MP2, MP1, MP1) ;
1299         mpadd(MPval, MP1, MPval) ;
1300       }
1301  
1302   while (*optr == ' ') optr++ ;
1303
1304   if (*optr != '\0')
1305     {
1306       if (*optr == '-') exp_sign = -1 ;
1307
1308       while ((inum = char_val(*++optr)) >= 0)
1309         exp = exp * basevals[(int) base] + inum ;
1310     }
1311   exp *= exp_sign ;
1312
1313   if (v->key_exp || exp_sign == -1) 
1314     {
1315       mppwr(MPbase, &exp, MP1) ;
1316       mpmul(MPval, MP1, MPval) ;
1317     }
1318   if( neg == 1)
1319   {
1320       i = -1 ;
1321       mpcim(&i, MP1) ;
1322       mpmul(MPval, MP1, MPval) ;
1323   }
1324 }
1325
1326 /* Append the latest parenthesis char to the display item. */
1327 void
1328 paren_disp(char c)
1329 {
1330   int i, n ;
1331
1332 /*  If the character is a Delete, clear the whole line, and exit parenthesis
1333  *  processing.
1334  *
1335  *  If the character is a Back Space, remove the last character. If the last
1336  *  character was a left parenthesis, decrement the parentheses count. If
1337  *  the parentheses count is zero, exit parenthesis processing.
1338  *
1339  *  If the character is a control character (not Ctrl-h), then append ^(char).
1340  *
1341  *  Otherwise just append the character.
1342  */
1343  
1344   n = strlen(v->display) ;
1345   if (IS_KEY(c, KEY_CLR))             /* Is it a Delete character? */
1346     {
1347       v->noparens = v->pending = v->opsptr = v->numsptr = 0 ;
1348       v->cur_op = '?' ;
1349       set_item(OPITEM, "") ;
1350       i = 0 ;
1351       mpcim(&i, v->MPdisp_val) ;
1352       show_display(v->MPdisp_val) ;
1353       set_base(v->base);
1354       set_numtype(v->dtype);
1355       set_option_menu((int) TTYPEITEM, (int)v->ttype);
1356       make_modewin() ;
1357       v->curwin = FCP_KEY ;
1358       v->defState = 1;
1359       return ;
1360     }
1361   else if (IS_KEY(c, KEY_BSP))        /* Is is a Back Space character? */
1362     {
1363       if (!n) return ;
1364       if (v->display[n-1] == '(')
1365         {
1366           v->noparens-- ;
1367           if (!v->noparens)
1368             {
1369               v->pending = v->opsptr = v->numsptr = 0 ;
1370               v->cur_op = '?' ;
1371               set_item(OPITEM, "") ;
1372               show_display(v->MPdisp_val) ;
1373               return ;
1374             }
1375         }
1376       v->display[n-1] = '\0' ;
1377     }
1378   else if (c <= CTL('z'))             /* Is it a control character? */
1379     {
1380       if (n < MAXLINE-2)
1381         {
1382           v->display[n]   = '^' ;
1383           v->display[n+1] = c + 96 ;
1384           v->display[n+2] = '\0' ;
1385         }
1386     }    
1387   else                                /* It must be an ordinary character. */
1388     {
1389       if (n < MAXLINE-1)
1390         {
1391           v->display[n]   = c ;
1392           v->display[n+1] = '\0' ;
1393         }
1394     }    
1395
1396   n = (n < MAX_DIGITS) ? 0 : n - MAX_DIGITS ;
1397   v->show_paren = 1 ;       /* Hack to get set_item to really display it. */
1398   set_item(DISPLAYITEM, &v->display[n]) ;
1399   v->show_paren = 0 ;
1400 }
1401
1402 /* Process this event. */
1403 void
1404 process_event(int type)
1405 {
1406   int ival ;
1407
1408   switch (type)
1409     {
1410       case KEYBOARD_DOWN   : if (v->pending)
1411                                {
1412                                  v->current = v->cur_ch ;
1413                                  do_pending() ;
1414                                }
1415                              else
1416                                { 
1417                                  ival = get_index(v->cur_ch) ;
1418                                  if (ival < TITEMS - EXTRA) {
1419                                     if ((v->modetype == FINANCIAL && 
1420                                                                  ival == 23) ||
1421                                         (v->modetype == LOGICAL && (
1422                                                     ival == 21 || ival == 22 || 
1423                                                                  ival == 23)))
1424                                        break;
1425                                     else
1426                                        /* go arm the button */
1427                                        draw_button(ival, v->curwin, v->row, 
1428                                                    v->column, TRUE) ;
1429                                  }
1430                                  process_item(ival) ;
1431                                }
1432                              break ;
1433
1434       case KEYBOARD_UP     : ival = get_index(v->cur_ch) ;
1435                              if (ival < TITEMS - EXTRA) {
1436                                  if ((v->modetype == FINANCIAL && 
1437                                                               ival == 23) ||
1438                                      (v->modetype == LOGICAL && (
1439                                                  ival == 21 || ival == 22 ||
1440                                                               ival == 23)))
1441                                     break;
1442                                  else
1443                                     /* go disarm the button */
1444                                     draw_button(ival, v->curwin, v->row, 
1445                                                 v->column, FALSE) ;
1446                              }
1447                              /* go disarm the button */
1448                              draw_button(ival, v->curwin, v->row, 
1449                                                 v->column, FALSE) ;
1450                              break ;
1451  
1452     }
1453 }
1454
1455
1456 void
1457 process_item(int n)
1458 {
1459   int i,isvalid ;
1460
1461   if (n < 0 || n >= TITEMS)
1462     {
1463       beep() ;
1464       v->error = TRUE;
1465     }
1466
1467   v->current = buttons[n].value ;
1468   if (v->current == '*') v->current = 'x' ;      /* Reassign "extra" values. */
1469   if (v->current == '\015') v->current = '=' ;
1470   if (v->current == 'Q') v->current = 'q' ;
1471
1472   if (v->error)
1473     {
1474       isvalid = 0 ;                    /* Must press a valid key first. */
1475       for (i = 0; i < MAXVKEYS; i++)
1476         if (v->current == validkeys[i]) isvalid = 1 ;
1477       if (v->pending == '?') isvalid = 1 ;
1478       if (!isvalid) return ;
1479       v->error = 0 ;
1480     }
1481
1482   if (v->pending)
1483     {
1484       if (v->pending_win == FCP_KEY) (*buttons[v->pending_n].func)() ;
1485       else (*mode_buttons[MODEKEYS * ((int) v->pending_mode - 1) +
1486             v->pending_n].func)() ;
1487       return ;
1488     }
1489   switch (buttons[n].opdisp)
1490     {
1491       case OP_SET   : 
1492          if (v->current == 'T') 
1493          {
1494              if (v->modetype == SCIENTIFIC)
1495                 set_item(OPITEM, buttons[n].str) ;
1496              else
1497                 v->pending = 0;
1498          }
1499          else
1500             set_item(OPITEM, buttons[n].str) ;
1501          break ;
1502       case OP_CLEAR : 
1503          if (v->error) 
1504             set_item(OPITEM, vstrs[(int) V_CLR]) ;
1505          else 
1506             set_item(OPITEM, "") ;
1507          break;
1508       default:
1509          break;
1510     }
1511   (*buttons[n].func)() ;
1512
1513   if(strcmp(buttons[n].resname, "clr") != 0)
1514       v->defState = 0;
1515 }
1516
1517
1518 /* Process a portion of the parentheses stack.
1519  startop   Initial position in the operand stack.
1520  startnum  Initial position in the numeric stack.
1521  n         Number of items to process.
1522 */
1523
1524 void
1525 process_stack(int startop, int startnum, int n)
1526 {
1527   char sdisp[MAXLINE] ;     /* Used to save display contents. */
1528   int i ;
1529   int nptr ;                /* Pointer to next number from numeric stack. */
1530
1531   STRCPY(sdisp, v->display) ;  /* Save current display. */
1532   nptr = startnum ;
1533   v->pending = 0 ;
1534   v->cur_op = '?' ;            /* Current operation is initially undefined. */
1535   for (i = 0; i < n; i++)
1536     {
1537       if (v->opstack[startop + i] == -1)
1538         {
1539           mpstr(v->MPnumstack[nptr++], v->MPdisp_val) ;
1540         }
1541       else
1542         { 
1543           v->cur_ch = v->opstack[startop + i] ;
1544           if (v->cur_ch == '^')                    /* Control character? */
1545             {
1546               i++ ;
1547               v->cur_ch = CTL(v->opstack[startop + i]) ;
1548             }
1549           if (v->pending)
1550             {
1551               v->current = v->cur_ch ;
1552               do_pending() ;
1553             }
1554           else process_item(get_index(v->cur_ch)) ;
1555         }
1556     }    
1557   v->numsptr = startnum ;
1558   push_num(v->MPdisp_val) ;
1559   v->opsptr = startop - 1 ;
1560   push_op(-1) ;
1561   save_pending_values(KEY_LPAR) ;
1562   STRCPY(v->display, sdisp) ;  /* Restore current display. */
1563 }
1564
1565
1566 void
1567 process_str(char *str, enum menu_type mtype)
1568 {
1569   int i, len ;
1570   char save[80];
1571
1572   len = strlen(str) ;
1573   STRCPY(save, v->display) ;
1574   STRCPY(v->display, " ") ;
1575   set_item(DISPLAYITEM, v->display);
1576   for (i = 0 ; i < len; i++)
1577     {    
1578       if(str[i] == '*')
1579          str[i] = 'x';
1580       if (v->error) 
1581       {
1582         if(mtype == M_FUN)
1583         {
1584            STRCPY(v->display, save);
1585            set_item(DISPLAYITEM, v->display);
1586            v->error = 0;
1587         }
1588         return ;
1589       }
1590       if (v->pending)
1591         {
1592           v->current = str[i] ;
1593           do_pending() ;
1594         }
1595       else 
1596         switch(v->base)
1597         {
1598            case DEC:
1599               if(str[i] == 'a' ||
1600                  str[i] == 'b' ||
1601                  str[i] == 'c' ||
1602                  str[i] == 'd' ||
1603                  str[i] == 'e' ||
1604                  str[i] == 'f')
1605               {
1606                  v->error = True;
1607                  beep();
1608                  break;
1609               }
1610            default:
1611               process_item(get_index(str[i])) ;
1612         }
1613     }
1614 }
1615
1616
1617 void
1618 read_rcfiles(void)   /* Read .dtcalcrc's from home and current directories. */
1619 {
1620   char *home ;                  /* Pathname for users home directory. */
1621   char name[MAXPATHLEN + 50] ;          /* Full name of users .dtcalcrc file. */
1622   char pathname[MAXPATHLEN + 5] ;   /* Current working directory. */
1623   char tmp[MAXLINE] ;           /* For temporary constant string creation. */
1624   int n ;
1625   struct passwd *entry ;
1626
1627   for (n = 0; n < MAXREGS; n++)
1628     {
1629       STRCPY(tmp, make_number(v->MPcon_vals[n], FALSE)) ;
1630       SPRINTF(name, "%1d: %s [%s]", n, tmp, v->con_names[n]) ;
1631
1632       STRCPY(v->con_names[n], name) ;
1633       STRCPY(v->fun_vals[n], "") ;    /* Initially empty function strings. */
1634     }
1635
1636   if ((home = getenv("HOME")) == NULL)
1637     {
1638       if ((entry = getpwuid(getuid())) == NULL) return ;
1639       home = entry->pw_dir ;
1640     }
1641   snprintf(name, MAXPATHLEN, "%s/%s", home, RCNAME) ;
1642   get_rcfile(name) ;      /* Read .dtcalcrc from users home directory. */
1643  
1644   snprintf(name, MAXPATHLEN, "%s/%s", getcwd(pathname, MAXPATHLEN+1), RCNAME) ;
1645   get_rcfile(name) ;      /* Read .dtcalcrc file from current directory. */
1646 }
1647
1648
1649 void
1650 show_display(int *MPval)
1651 {
1652   if (!v->error)
1653     {
1654       STRCPY(v->display, make_number(MPval, TRUE)) ;
1655       set_item(DISPLAYITEM, v->display) ;
1656     }
1657 }
1658
1659
1660 void
1661 usage(char *progname)
1662 {
1663   FPRINTF(stderr, ustrs[(int) USAGE1], PATCHLEVEL) ;
1664   FPRINTF(stderr, "%s", ustrs[(int) USAGE2]) ;
1665   FPRINTF(stderr, "%s", ustrs[(int) USAGE3]) ;
1666   exit(1) ;
1667 }
1668
1669 void
1670 write_rcfile(enum menu_type mtype, int exists, int cfno, char *val, char *comment)
1671 {
1672   char *home ;                  /* Pathname for users home directory. */
1673   char pathname[MAXPATHLEN] ;   /* Current working directory. */
1674   char rcname[MAXPATHLEN] ;     /* Full name of users .dtcalcrc file. */
1675   char str[MAXLINE] ;           /* Temporary buffer. */
1676   char sval[3] ;                /* Used for string comparisons. */
1677   char tmp_filename[MAXLINE] ;  /* Used to construct temp filename. */
1678   int rcexists ;                /* Set to 1, if .dtcalcrc file exists. */
1679   FILE *rcfd ;                  /* File descriptor for .dtcalcrc file. */
1680   FILE *tmpfd ;                 /* File descriptor for new temp .dtcalcrc. */
1681   struct passwd *entry ;        /* The user's /etc/passwd entry. */
1682
1683   rcexists = 0 ;
1684   SPRINTF(rcname, "%s/%s", getcwd(pathname, MAXPATHLEN), RCNAME) ;
1685   if (access(rcname, F_OK) == 0) rcexists = 1 ;
1686   else
1687     { 
1688       if ((home = getenv("HOME")) == NULL)
1689         {
1690           if ((entry = getpwuid(getuid())) == NULL) return ;
1691           home = entry->pw_dir ;
1692         }
1693       SPRINTF(rcname, "%s/%s", home, RCNAME) ;
1694       if (access(rcname, F_OK) == 0) rcexists = 1 ;
1695     }
1696   STRCPY(tmp_filename, "/tmp/.dtcalcrcXXXXXX") ;
1697   MKTEMP(tmp_filename) ;
1698   if ((tmpfd = fopen(tmp_filename, "w+")) == NULL) return ;
1699
1700   if (rcexists)
1701     {
1702       rcfd = fopen(rcname, "r") ;
1703       SPRINTF(sval, " %1d", cfno) ;
1704       while (fgets(str, MAXLINE, rcfd))
1705         {
1706           if (exists)
1707             {
1708               switch (mtype)
1709                 {
1710                   case M_CON : sval[0] = 'c' ;
1711                                if (!strncmp(str, sval, 2)) FPUTS("#", tmpfd) ;
1712                                sval[0] = 'C' ;
1713                                if (!strncmp(str, sval, 2)) FPUTS("#", tmpfd) ;
1714                                break ;
1715                   case M_FUN : sval[0] = 'f' ;
1716                                if (!strncmp(str, sval, 2)) FPUTS("#", tmpfd) ;
1717                                sval[0] = 'F' ;
1718                                if (!strncmp(str, sval, 2)) FPUTS("#", tmpfd) ;
1719                                break;
1720                   default: break;
1721                 }
1722             }    
1723           FPRINTF(tmpfd, "%s", str) ;
1724         }
1725       FCLOSE(rcfd) ;
1726     }
1727
1728   switch (mtype)
1729     {
1730       case M_CON : FPRINTF(tmpfd, "\nC%1d %s %s\n", cfno, val, comment) ;
1731                    break ;
1732       case M_FUN : 
1733                if(strcmp(val, "") != 0)
1734                   FPRINTF(tmpfd, "\nF%1d %s %s\n", cfno, val, comment) ;
1735                break;
1736       default: break;
1737     }
1738   UNLINK(rcname) ;
1739   rcfd = fopen(rcname, "w") ;
1740   REWIND(tmpfd) ;
1741   while (fgets(str, MAXLINE, tmpfd)) FPRINTF(rcfd, "%s", str) ;
1742   FCLOSE(rcfd) ;
1743   FCLOSE(tmpfd);
1744   UNLINK(tmp_filename) ;
1745 }
1746
1747
1748 void
1749 write_resources(char *filename)
1750 {
1751   char intval[5] ;
1752   int MPtemp[MP_SIZE];
1753
1754   SPRINTF(intval, "%d", v->accuracy) ;
1755   put_resource(R_ACCURACY, intval) ;
1756   put_resource(R_DISPLAYED, v->display) ;
1757   put_resource(R_BASE,     base_str[(int) v->base]) ;
1758   put_resource(R_DISPLAY,  dtype_str[(int) v->dtype]) ;
1759   put_resource(R_MODE,     mode_str[(int) v->modetype]) ;
1760   put_resource(R_TRIG,     ttype_str[(int) v->ttype]) ;
1761   put_resource(R_REGS,     set_bool(v->rstate     == TRUE)) ;
1762
1763   put_resource(R_REG0,     make_number(v->MPmvals[0], FALSE)) ;
1764   put_resource(R_REG1,     make_number(v->MPmvals[1], FALSE)) ;
1765   put_resource(R_REG2,     make_number(v->MPmvals[2], FALSE)) ;
1766   put_resource(R_REG3,     make_number(v->MPmvals[3], FALSE)) ;
1767   put_resource(R_REG4,     make_number(v->MPmvals[4], FALSE)) ;
1768   put_resource(R_REG5,     make_number(v->MPmvals[5], FALSE)) ;
1769   put_resource(R_REG6,     make_number(v->MPmvals[6], FALSE)) ;
1770   put_resource(R_REG7,     make_number(v->MPmvals[7], FALSE)) ;
1771   put_resource(R_REG8,     make_number(v->MPmvals[8], FALSE)) ;
1772   put_resource(R_REG9,     make_number(v->MPmvals[9], FALSE)) ;
1773
1774   mpcdm(&(v->MPfvals[0]), MPtemp);
1775   put_resource(R_FREG0,     make_number(MPtemp, FALSE)) ;
1776   mpcdm(&(v->MPfvals[1]), MPtemp);
1777   put_resource(R_FREG1,     make_number(MPtemp, FALSE)) ;
1778   mpcdm(&(v->MPfvals[2]), MPtemp);
1779   put_resource(R_FREG2,     make_number(MPtemp, FALSE)) ;
1780   mpcdm(&(v->MPfvals[3]), MPtemp);
1781   put_resource(R_FREG3,     make_number(MPtemp, FALSE)) ;
1782   mpcdm(&(v->MPfvals[4]), MPtemp);
1783   put_resource(R_FREG4,     make_number(MPtemp, FALSE)) ;
1784   mpcdm(&(v->MPfvals[5]), MPtemp);
1785   put_resource(R_FREG5,     make_number(MPtemp, FALSE)) ;
1786
1787   save_resources(filename) ;
1788 }