aome further corrections to copyright notices.
[AROS.git] / workbench / tools / Calculator.c
blobf8b081225e58ab7147bb43df12777a6fe99cd31a
1 /*
2 Copyright © 1995-2018, The AROS Development Team. All rights reserved.
3 $Id$
4 Command line options:
6 1. PUBSCREEN <name>: the name of the public screen to open the window on
7 2. TAPE <filename>: the name of a file to record the user interactions
8 into
9 */
10 #include <exec/types.h>
11 #include <dos/dos.h>
12 #include <intuition/intuition.h>
13 #include <intuition/classes.h>
14 #include <libraries/mui.h>
16 #include <proto/exec.h>
17 #include <proto/dos.h>
18 #include <proto/intuition.h>
19 #include <proto/locale.h>
20 #include <proto/alib.h>
21 #include <proto/muimaster.h>
22 #include <proto/utility.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <string.h>
28 const char *version = "$VER: Calculator 1.5 (31.05.2018) © AROS Dev Team";
30 #define ARG_TEMPLATE "PUBSCREEN,TAPE/K"
31 enum {ARG_PUBSCREEN,ARG_TAPE,NUM_ARGS};
33 /* The pattern of the tape name in case we log to a RAW: window */
34 #define RAW_TAPE_NAME "RAW:%d/%d/%d/%d/Calculator Tape/INACTIVE/SCREEN%s"
36 enum
38 BTYPE_0 = 0,
39 BTYPE_1,
40 BTYPE_2,
41 BTYPE_3,
42 BTYPE_4,
43 BTYPE_5,
44 BTYPE_6,
45 BTYPE_7,
46 BTYPE_8,
47 BTYPE_9,
48 BTYPE_COMMA,
49 BTYPE_BS,
50 BTYPE_CA,
51 BTYPE_CE,
52 BTYPE_MUL,
53 BTYPE_DIV,
54 BTYPE_SUB,
55 BTYPE_ADD,
56 BTYPE_SIGN,
57 BTYPE_EQU
60 #define NUM_BUTTONS 20
61 #define DECIMAL_BUTTON_INDEX 16
63 struct CalcButtonInfo
65 const char *label;
66 ULONG btype;
67 char shortcut;
70 struct CalcButtonInfo BUTTONS[] =
72 {"7", BTYPE_7, '7'}, {"8", BTYPE_8, '8'}, {"9", BTYPE_9, '9'}, {"CA", BTYPE_CA, 'A'}, {"CE", BTYPE_CE, 'E'},
73 {"4", BTYPE_4, '4'}, {"5", BTYPE_5, '5'}, {"6", BTYPE_6, '6'}, {"*", BTYPE_MUL, '*'}, {":", BTYPE_DIV, ':'},
74 {"1", BTYPE_1, '1'}, {"2", BTYPE_2, '2'}, {"3", BTYPE_3, '3'}, {"+", BTYPE_ADD, '+'}, {"-", BTYPE_SUB, '-'},
75 {"0", BTYPE_0, '0'}, {".", BTYPE_COMMA, '.'}, {"<<", BTYPE_BS, 8}, {"+/-", BTYPE_SIGN, 's'}, {"=", BTYPE_EQU, '='}
79 * Most of the application state is local or in BOOPSI objects.
80 * The only global state is to communicate the command line arguments
82 #define CALC_TAPENAME_MAX 320
83 static char pubscrname[256];
84 static char tapename[CALC_TAPENAME_MAX];
85 static BOOL use_tape;
87 /**********************************************************************
88 Tape BOOPSI class
89 **********************************************************************/
91 #define TAPEA_FILEHANDLE (TAG_USER + 20)
92 #define TAPEM_NEWLINE (TAG_USER + 21)
93 #define TAPEM_PRINT_LVAL (TAG_USER + 22)
94 #define TAPEM_PRINT_RVAL (TAG_USER + 23)
95 #define TAPEM_PRINT_RESULT (TAG_USER + 24)
97 struct TapeData
99 BPTR tapefh;
102 struct MUIMP_PrintLval
104 STACKED ULONG MethodID;
105 STACKED const char *str;
108 struct MUIMP_PrintRval
110 STACKED ULONG MethodID;
111 STACKED char operator;
112 STACKED const char *str;
115 struct MUIMP_PrintResult
117 STACKED ULONG MethodID;
118 STACKED const char *str;
121 IPTR mNewTape(struct IClass *cl, Object *obj, struct opSet *msg)
123 struct TagItem *tagListState = msg->ops_AttrList, *tag;
124 Object *instance = (Object *) DoSuperMethodA(cl, obj, (APTR) msg);
125 struct TapeData *data = INST_DATA(cl, instance);
126 data->tapefh = BNULL;
128 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
130 switch (tag->ti_Tag)
132 case TAPEA_FILEHANDLE:
133 data->tapefh = (BPTR) tag->ti_Data;
134 break;
135 default:
136 break;
139 return (IPTR) instance;
142 IPTR mDisposeTape(struct IClass *cl, Object *obj, struct opSet *msg)
144 struct TapeData *data = INST_DATA(cl, obj);
145 if (data->tapefh) Close(data->tapefh);
146 return DoSuperMethodA(cl, obj, (APTR) msg);
149 IPTR mTapeNewline(struct IClass *cl, Object *obj, APTR msg)
151 struct TapeData *data = INST_DATA(cl, obj);
152 if (data->tapefh) FPutC(data->tapefh, '\n');
153 return (IPTR) obj;
156 IPTR mTapePrintLval(struct IClass *cl, Object *obj, struct MUIMP_PrintLval *msg)
158 struct TapeData *data = INST_DATA(cl, obj);
159 if (data->tapefh)
161 FPutC(data->tapefh, '\t');
162 FPuts(data->tapefh, msg->str);
163 FPutC(data->tapefh, '\n');
164 Flush(data->tapefh);
166 return (IPTR) obj;
169 IPTR mTapePrintRval(struct IClass *cl, Object *obj, struct MUIMP_PrintRval *msg)
171 struct TapeData *data = INST_DATA(cl, obj);
172 if (data->tapefh)
174 FPutC(data->tapefh, msg->operator);
175 FPutC(data->tapefh, '\t');
176 FPuts(data->tapefh, msg->str);
177 FPutC(data->tapefh, '\n');
178 Flush(data->tapefh);
180 return (IPTR) obj;
183 IPTR mTapePrintResult(struct IClass *cl, Object *obj, struct MUIMP_PrintResult *msg)
185 struct TapeData *data = INST_DATA(cl, obj);
186 if (data->tapefh)
188 FPuts(data->tapefh, "=\t");
189 FPuts(data->tapefh, msg->str);
190 FPutC(data->tapefh, '\n');
191 Flush(data->tapefh);
193 return (IPTR) obj;
196 ULONG mSet(struct IClass *cl, Object *obj, struct opSet *msg)
198 struct TagItem *tagListState = msg->ops_AttrList, *tag;
199 struct TapeData *data = INST_DATA(cl, obj);
201 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
203 switch (tag->ti_Tag)
205 case TAPEA_FILEHANDLE:
206 data->tapefh = (BPTR) tag->ti_Data;
207 break;
208 default:
209 break;
212 return (IPTR) obj;
215 BOOPSI_DISPATCHER(IPTR, TapeDispatcher, cl, obj, msg)
217 switch (msg->MethodID)
219 case OM_NEW: return mNewTape(cl, obj, (APTR) msg);
220 case OM_DISPOSE: return mDisposeTape(cl, obj, (APTR) msg);
221 case OM_SET: return mSet(cl, obj, (APTR) msg);
223 case TAPEM_NEWLINE: return mTapeNewline(cl, obj, (APTR) msg);
224 case TAPEM_PRINT_LVAL: return mTapePrintLval(cl, obj, (struct MUIMP_PrintLval *) msg);
225 case TAPEM_PRINT_RVAL: return mTapePrintRval(cl, obj, (struct MUIMP_PrintRval *) msg);
226 case TAPEM_PRINT_RESULT: return mTapePrintResult(cl, obj, (struct MUIMP_PrintResult *) msg);
228 return DoSuperMethodA(cl, obj, msg);
230 BOOPSI_DISPATCHER_END
232 static Class *make_tape_class(void)
234 Class *cl;
235 cl = MakeClass(NULL, ROOTCLASS, NULL, sizeof(struct TapeData), 0);
236 if (cl) cl->cl_Dispatcher.h_Entry = TapeDispatcher;
237 return cl;
240 /**********************************************************************
241 Calculator BOOPSI class
242 **********************************************************************/
244 #define MAX_DIGITS 13
245 #define OM_ADD_KEY (TAG_USER + 30)
246 #define CALCA_DISPLAY (TAG_USER + 31)
247 #define CALCA_TAPE (TAG_USER + 32)
248 #define CALCA_DECIMAL_POINT (TAG_USER + 33)
250 #define EDIT_BUFFER_SIZE MAX_DIGITS + 2 /* space for '-' sign and terminator byte */
251 const char *INITIAL_DISPLAY = "\033r0";
252 enum { STATE_LEFTVAL, STATE_OP, STATE_RIGHTVAL, STATE_EQU };
254 struct CalculatorData
256 char edit_buffer[EDIT_BUFFER_SIZE];
257 int num_digits;
258 int state;
259 char decimal_point;
261 double lvalue, rvalue;
262 int op;
263 Object *display, *tape;
266 struct MUIMP_CalcKey
268 STACKED ULONG MethodID;
269 STACKED ULONG btype;
272 static char op2char(int op)
274 switch (op) {
275 case BTYPE_MUL: return '*';
276 case BTYPE_DIV: return '*';
277 case BTYPE_SUB: return '-';
278 case BTYPE_ADD: return '+';
279 default: return '?';
283 static void clear_edit_buffer(struct CalculatorData *data)
285 memset(data->edit_buffer, 0, EDIT_BUFFER_SIZE);
286 data->num_digits = 0;
289 IPTR mNewCalc(struct IClass *cl, Object *obj, struct opSet *msg)
291 struct TagItem *tagListState = msg->ops_AttrList, *tag;
292 Object *instance = (Object *) DoSuperMethodA(cl, obj, (APTR) msg);
293 struct CalculatorData *data = INST_DATA(cl, instance);
294 clear_edit_buffer(data);
295 data->display = NULL;
296 data->tape = NULL;
297 data->state = STATE_LEFTVAL;
298 data->decimal_point = '.';
300 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
302 switch (tag->ti_Tag)
304 case CALCA_DISPLAY:
305 data->display = (Object *) tag->ti_Data;
306 break;
307 case CALCA_TAPE:
308 data->tape = (Object *) tag->ti_Data;
309 break;
310 case CALCA_DECIMAL_POINT:
311 data->decimal_point = (char) tag->ti_Data;
312 break;
313 default:
314 break;
317 return (IPTR) instance;
320 IPTR mDisposeCalc(struct IClass *cl, Object *obj, struct opSet *msg)
322 return DoSuperMethodA(cl, obj, (APTR) msg);
325 static BOOL is_operator(int btype)
327 return btype >= BTYPE_MUL && btype <= BTYPE_ADD;
330 static BOOL can_insert_comma(struct CalculatorData *data)
332 if (data->num_digits == 0) return TRUE;
333 else
335 int i;
336 for (i = 0; i < data->num_digits; i++)
338 if (data->edit_buffer[i] == '.') return FALSE;
340 return TRUE;
344 static double eval_result(double lvalue, double rvalue, int op)
346 switch (op)
348 case BTYPE_MUL: return lvalue * rvalue;
349 case BTYPE_DIV: return lvalue / rvalue;
350 case BTYPE_SUB: return lvalue - rvalue;
351 case BTYPE_ADD: return lvalue + rvalue;
352 default: return 0;
357 static void localize_buffer(char *buffer, char decimal_point, int from, int to)
359 int i;
360 for (i = from; i < to; i ++)
362 if (buffer[i] == '.')
364 buffer[i] = decimal_point;
365 break;
370 * Rendering is centralized in this function, by copying
371 * the edit buffer into and manipulating the display buffer.
372 * MUI/Zune's text field right-justifies text through the inclusion
373 * of the "Esc-r" control sequence.
375 static void display_state(struct CalculatorData *data)
377 /* add 2 extra chars: Esc+'r' */
378 static char display_buffer[EDIT_BUFFER_SIZE + 2];
380 if (data->num_digits == 0)
382 SetAttrs(data->display, MUIA_Text_Contents, INITIAL_DISPLAY, TAG_DONE);
384 else
386 memset(display_buffer, 0, EDIT_BUFFER_SIZE + 2);
387 display_buffer[0] = '\033';
388 display_buffer[1] = 'r';
389 memcpy(display_buffer + 2, data->edit_buffer, data->num_digits);
390 localize_buffer(display_buffer, data->decimal_point, 2, MAX_DIGITS + 3);
391 SetAttrs(data->display, MUIA_Text_Contents, display_buffer, TAG_DONE);
395 static const char *localize_display(struct CalculatorData *data)
397 static char buffer[EDIT_BUFFER_SIZE];
398 memset(buffer, 0, MAX_DIGITS + 1);
399 memcpy(buffer, data->edit_buffer, data->num_digits);
400 localize_buffer(buffer, data->decimal_point, 0, MAX_DIGITS + 1);
401 return buffer;
404 static void toggle_sign(struct CalculatorData *data)
406 BOOL sign_found = FALSE;
407 int i;
408 if (data->state == STATE_LEFTVAL) data->lvalue = -data->lvalue;
409 else if (data->state == STATE_RIGHTVAL) data->rvalue = -data->rvalue;
411 for (i = 0; i < EDIT_BUFFER_SIZE; i++)
413 if (data->edit_buffer[i] == '-')
415 sign_found = TRUE;
416 break;
420 if (sign_found)
422 /* eliminate the sign by shifting to the left */
423 data->num_digits--;
424 memmove(data->edit_buffer, data->edit_buffer + 1, data->num_digits);
425 data->edit_buffer[data->num_digits] = 0;
427 else
429 /* add sign by shifting to the right and inserting - */
430 memmove(data->edit_buffer + 1, data->edit_buffer, data->num_digits);
431 data->num_digits++;
432 data->edit_buffer[0] = '-';
433 data->edit_buffer[data->num_digits] = 0;
435 display_state(data);
439 * This method implements the main logic of the calculator by performing transitions
440 * of a state machine.
442 IPTR mAddCalcKey(struct IClass *cl, Object *obj, struct MUIMP_CalcKey *msg)
444 struct CalculatorData *data = INST_DATA(cl, obj);
445 if (msg->btype <= BTYPE_9 && data->num_digits < MAX_DIGITS)
447 if (data->state == STATE_OP)
449 data->state = STATE_RIGHTVAL;
450 clear_edit_buffer(data);
452 if (data->state == STATE_EQU)
454 data->state = STATE_LEFTVAL;
455 clear_edit_buffer(data);
457 char digit = '0' + msg->btype;
458 data->edit_buffer[data->num_digits++] = digit;
459 display_state(data);
462 else if (msg->btype == BTYPE_COMMA && can_insert_comma(data))
464 data->edit_buffer[data->num_digits++] = '.';
465 display_state(data);
467 else if (is_operator(msg->btype))
469 if (data->state == STATE_LEFTVAL || data->state == STATE_EQU)
471 data->lvalue = strtod(data->edit_buffer, NULL);
472 data->state = STATE_OP;
473 data->op = msg->btype;
474 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_LVAL, localize_display(data));
477 else if (msg->btype == BTYPE_EQU)
479 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_RVAL, op2char(data->op), localize_display(data));
481 data->rvalue = strtod(data->edit_buffer, NULL);
482 data->state = STATE_EQU;
483 data->lvalue = eval_result(data->lvalue, data->rvalue, data->op);
484 snprintf(data->edit_buffer, MAX_DIGITS, "%f", data->lvalue);
485 /* note that there is no strnlen() in AROS !!! */
486 data->num_digits = strlen(data->edit_buffer);
488 display_state(data);
489 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_RESULT, localize_display(data));
491 else if (msg->btype == BTYPE_CA)
493 data->lvalue = 0;
494 data->rvalue = 0;
495 data->op = BTYPE_ADD;
496 data->state = STATE_LEFTVAL;
497 clear_edit_buffer(data);
499 display_state(data);
500 if (data->tape) DoMethod(data->tape, TAPEM_NEWLINE);
502 else if (msg->btype == BTYPE_CE &&
503 (data->state == STATE_LEFTVAL || data->state == STATE_RIGHTVAL))
505 clear_edit_buffer(data);
506 display_state(data);
509 else if (msg->btype == BTYPE_SIGN && data->state != STATE_OP)
511 toggle_sign(data);
513 else if (msg->btype == BTYPE_BS &&
514 (data->state == STATE_LEFTVAL || data->state == STATE_RIGHTVAL) &&
515 data->num_digits > 0)
517 data->edit_buffer[--data->num_digits] = 0;
518 display_state(data);
520 return (IPTR) obj;
523 BOOPSI_DISPATCHER(IPTR, CalculatorDispatcher, cl, obj, msg)
525 switch (msg->MethodID)
527 case OM_NEW: return mNewCalc(cl, obj, (APTR) msg);
528 case OM_DISPOSE: return mDisposeCalc(cl, obj, (APTR) msg);
529 case OM_ADD_KEY: return (IPTR) mAddCalcKey(cl, obj, (struct MUIMP_CalcKey *) msg);
531 return DoSuperMethodA(cl, obj, msg);
533 BOOPSI_DISPATCHER_END
535 static Class *make_calculator_class(void)
537 Class *cl;
538 cl = MakeClass(NULL, ROOTCLASS, NULL, sizeof(struct CalculatorData), 0);
539 if (cl) cl->cl_Dispatcher.h_Entry = CalculatorDispatcher;
540 return cl;
543 /**********************************************************************
544 Main program
545 **********************************************************************/
547 static void cleanup(char *msg)
549 WORD rc;
550 if (msg)
552 fprintf(stderr, "Calculator: %s\n", msg);
553 rc = RETURN_WARN;
555 else
557 rc = RETURN_OK;
559 exit(rc);
562 static void dos_error(void)
564 static char tempstring[256];
565 Fault(IoErr(), 0, tempstring, 255);
566 cleanup(tempstring);
569 static char retrieve_decimal_point(void)
571 struct Locale *loc;
572 char result = '.';
574 if ((loc = OpenLocale(0)))
576 result = loc->loc_DecimalPoint[0];
577 CloseLocale(loc);
579 return result;
582 static void get_arguments(void)
584 struct RDArgs *rdargs;
585 IPTR args[NUM_ARGS];
586 int i;
588 for (i = 0; i < NUM_ARGS; i++) args[i] = (IPTR) NULL;
590 if (!(rdargs = ReadArgs(ARG_TEMPLATE, (IPTR *) args,0))) dos_error();
592 if (args[ARG_PUBSCREEN]) {
593 strncpy(pubscrname, (const char *) args[ARG_PUBSCREEN], 255);
596 if (args[ARG_TAPE])
598 use_tape = TRUE;
599 strncpy(tapename, (const char *) args[ARG_TAPE], CALC_TAPENAME_MAX);
601 if (rdargs) FreeArgs(rdargs);
604 static void open_raw_tape_if_needed(Object *window, Object *obj_tape)
606 if (use_tape && !strlen(tapename))
608 int x, y, w, h;
609 struct Window *win;
610 BPTR tapefh;
612 GetAttr(MUIA_Window_Window, window, (IPTR *) &win);
613 w = win->Width * 5 / 4;
614 h = win->Height;
615 x = win->LeftEdge;
616 y = win->TopEdge;
618 if (x > (win->WScreen->Width - (x + w))) x -= w;
619 else x += win->WScreen->Width;
621 snprintf(tapename, CALC_TAPENAME_MAX, RAW_TAPE_NAME, x, y, w, h, pubscrname);
622 tapefh = Open(tapename, MODE_NEWFILE);
623 SetAttrs(obj_tape, TAPEA_FILEHANDLE, tapefh);
627 int main(void)
629 Class *cl_calc = NULL, *cl_tape = NULL;
630 Object *app = NULL, *window = NULL, *display = NULL, *button[NUM_BUTTONS],
631 *obj_calc, *obj_tape;
632 char decimal_point, decimal_label[2];
633 struct Screen *pub_screen = NULL;
634 BPTR tapefh = BNULL;
635 int i;
637 get_arguments();
638 decimal_point = retrieve_decimal_point();
639 snprintf(decimal_label, 2, "%c", decimal_point);
641 display = TextObject,
642 StringFrame,
643 MUIA_Text_Contents, INITIAL_DISPLAY,
644 MUIA_ShortHelp, "Display",
645 End;
647 cl_tape = make_tape_class();
649 if (use_tape && strlen(tapename)) {
650 tapefh = Open(tapename, MODE_NEWFILE);
653 if (tapefh) {
654 obj_tape = NewObject(cl_tape, NULL, TAPEA_FILEHANDLE, tapefh, TAG_DONE);
656 else
658 obj_tape = NewObject(cl_tape, NULL, TAG_DONE);
661 cl_calc = make_calculator_class();
662 obj_calc = NewObject(cl_calc, NULL,
663 CALCA_DISPLAY, display,
664 CALCA_TAPE, obj_tape,
665 CALCA_DECIMAL_POINT, decimal_point,
666 TAG_DONE);
668 for (i = 0; i < NUM_BUTTONS; i++)
670 button[i] = (i != DECIMAL_BUTTON_INDEX) ?
671 SimpleButton(BUTTONS[i].label) : SimpleButton(decimal_label);
672 if (BUTTONS[i].shortcut)
674 SetAttrs(button[i], MUIA_ControlChar, BUTTONS[i].shortcut, TAG_DONE);
678 if (strlen(pubscrname))
680 pub_screen = LockPubScreen((CONST_STRPTR) pubscrname);
681 if (!pub_screen)
683 printf("Can't lock public screen '%s' -> fallback to Wanderer!\n", pubscrname);
684 memset(pubscrname, 0, 256);
685 strcpy(pubscrname, "Workbench");
686 pub_screen = LockPubScreen((CONST_STRPTR) pubscrname);
690 app = ApplicationObject,
691 MUIA_Application_Title, "Calculator",
692 MUIA_Application_Version, "1.5",
693 MUIA_Application_Copyright, "©2007-2018, AROS Dev Team",
694 MUIA_Application_Author, "AROS Team",
695 MUIA_Application_Description, "Simple desktop calculator",
696 MUIA_Application_Base, "calculator",
697 SubWindow, window = WindowObject,
698 MUIA_Window_Title, "Calculator",
699 MUIA_Window_ID, MAKE_ID('C', 'A', 'L', 'C'),
700 MUIA_Window_AppWindow, TRUE,
701 MUIA_Window_Screen, pub_screen,
702 WindowContents, VGroup,
703 Child, display,
705 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
706 Child, button[0],
707 Child, button[1],
708 Child, button[2],
709 Child, button[3],
710 Child, button[4],
711 End,
713 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
714 Child, button[5],
715 Child, button[6],
716 Child, button[7],
717 Child, button[8],
718 Child, button[9],
719 End,
721 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
722 Child, button[10],
723 Child, button[11],
724 Child, button[12],
725 Child, button[13],
726 Child, button[14],
727 End,
729 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
730 Child, button[15],
731 Child, button[16],
732 Child, button[17],
733 Child, button[18],
734 Child, button[19],
735 End,
737 End,
738 End,
739 End;
741 DoMethod(window, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
742 app, 2, MUIM_Application_ReturnID,
743 MUIV_Application_ReturnID_Quit);
745 for (i = 0; i < NUM_BUTTONS; i++)
747 DoMethod(button[i], MUIM_Notify, MUIA_Pressed, FALSE,
748 obj_calc, 2, OM_ADD_KEY, BUTTONS[i].btype);
751 SetAttrs(window, MUIA_Window_Open, TRUE, TAG_DONE);
752 open_raw_tape_if_needed(window, obj_tape);
754 if (pub_screen) UnlockPubScreen(0, pub_screen);
756 BOOL running = TRUE;
757 ULONG sigs = 0, id;
759 while (running) {
760 id = DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs);
762 switch(id)
764 case MUIV_Application_ReturnID_Quit:
765 running = FALSE;
766 break;
767 default:
768 break;
770 if (running && sigs)
772 sigs = Wait(sigs | SIGBREAKF_CTRL_C);
773 if (sigs & SIGBREAKF_CTRL_C) break;
777 set((APTR) window, MUIA_Window_Open, FALSE);
778 MUI_DisposeObject(app);
780 DisposeObject(obj_calc);
781 DisposeObject(obj_tape);
782 FreeClass(cl_calc);
783 FreeClass(cl_tape);
785 cleanup(NULL);
786 return 0;