alsa.audio: add debug logs
[AROS.git] / workbench / tools / Calculator.c
blobb65f6c223fed4ae37d403e6f743004c2e7d3f759
1 /*
2 Copyright © 1995-2013, 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.4 (08.08.2013) © 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 static char pubscrname[256];
83 static char tapename[256];
84 static BOOL use_tape;
86 /**********************************************************************
87 Tape BOOPSI class
88 **********************************************************************/
90 #define TAPEA_FILEHANDLE (TAG_USER + 20)
91 #define TAPEM_NEWLINE (TAG_USER + 21)
92 #define TAPEM_PRINT_LVAL (TAG_USER + 22)
93 #define TAPEM_PRINT_RVAL (TAG_USER + 23)
94 #define TAPEM_PRINT_RESULT (TAG_USER + 24)
96 struct TapeData
98 BPTR tapefh;
101 struct MUIMP_PrintLval
103 STACKED ULONG MethodID;
104 STACKED const char *str;
107 struct MUIMP_PrintRval
109 STACKED ULONG MethodID;
110 STACKED char operator;
111 STACKED const char *str;
114 struct MUIMP_PrintResult
116 STACKED ULONG MethodID;
117 STACKED const char *str;
120 IPTR mNewTape(struct IClass *cl, Object *obj, struct opSet *msg)
122 struct TagItem *tagListState = msg->ops_AttrList, *tag;
123 Object *instance = (Object *) DoSuperMethodA(cl, obj, (APTR) msg);
124 struct TapeData *data = INST_DATA(cl, instance);
125 data->tapefh = BNULL;
127 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
129 switch (tag->ti_Tag)
131 case TAPEA_FILEHANDLE:
132 data->tapefh = (BPTR) tag->ti_Data;
133 break;
134 default:
135 break;
138 return (IPTR) instance;
141 IPTR mDisposeTape(struct IClass *cl, Object *obj, struct opSet *msg)
143 struct TapeData *data = INST_DATA(cl, obj);
144 if (data->tapefh) Close(data->tapefh);
145 return DoSuperMethodA(cl, obj, (APTR) msg);
148 IPTR mTapeNewline(struct IClass *cl, Object *obj, APTR msg)
150 struct TapeData *data = INST_DATA(cl, obj);
151 if (data->tapefh) FPutC(data->tapefh, '\n');
152 return (IPTR) obj;
155 IPTR mTapePrintLval(struct IClass *cl, Object *obj, struct MUIMP_PrintLval *msg)
157 struct TapeData *data = INST_DATA(cl, obj);
158 if (data->tapefh)
160 FPutC(data->tapefh, '\t');
161 FPuts(data->tapefh, msg->str);
162 FPutC(data->tapefh, '\n');
163 Flush(data->tapefh);
165 return (IPTR) obj;
168 IPTR mTapePrintRval(struct IClass *cl, Object *obj, struct MUIMP_PrintRval *msg)
170 struct TapeData *data = INST_DATA(cl, obj);
171 if (data->tapefh)
173 FPutC(data->tapefh, msg->operator);
174 FPutC(data->tapefh, '\t');
175 FPuts(data->tapefh, msg->str);
176 FPutC(data->tapefh, '\n');
177 Flush(data->tapefh);
179 return (IPTR) obj;
182 IPTR mTapePrintResult(struct IClass *cl, Object *obj, struct MUIMP_PrintResult *msg)
184 struct TapeData *data = INST_DATA(cl, obj);
185 if (data->tapefh)
187 FPuts(data->tapefh, "=\t");
188 FPuts(data->tapefh, msg->str);
189 FPutC(data->tapefh, '\n');
190 Flush(data->tapefh);
192 return (IPTR) obj;
195 ULONG mSet(struct IClass *cl, Object *obj, struct opSet *msg)
197 struct TagItem *tagListState = msg->ops_AttrList, *tag;
198 struct TapeData *data = INST_DATA(cl, obj);
200 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
202 switch (tag->ti_Tag)
204 case TAPEA_FILEHANDLE:
205 data->tapefh = (BPTR) tag->ti_Data;
206 break;
207 default:
208 break;
211 return (IPTR) obj;
214 IPTR TapeDispatcher(struct IClass *cl, Object *obj, Msg msg)
216 switch (msg->MethodID)
218 case OM_NEW: return mNewTape(cl, obj, (APTR) msg);
219 case OM_DISPOSE: return mDisposeTape(cl, obj, (APTR) msg);
220 case OM_SET: return mSet(cl, obj, (APTR) msg);
222 case TAPEM_NEWLINE: return mTapeNewline(cl, obj, (APTR) msg);
223 case TAPEM_PRINT_LVAL: return mTapePrintLval(cl, obj, (struct MUIMP_PrintLval *) msg);
224 case TAPEM_PRINT_RVAL: return mTapePrintRval(cl, obj, (struct MUIMP_PrintRval *) msg);
225 case TAPEM_PRINT_RESULT: return mTapePrintResult(cl, obj, (struct MUIMP_PrintResult *) msg);
227 return DoSuperMethodA(cl, obj, msg);
230 static Class *make_tape_class(void)
232 Class *cl;
233 cl = MakeClass(NULL, ROOTCLASS, NULL, sizeof(struct TapeData), 0);
234 if (cl) cl->cl_Dispatcher.h_Entry = TapeDispatcher;
235 return cl;
238 /**********************************************************************
239 Calculator BOOPSI class
240 **********************************************************************/
242 #define MAX_DIGITS 13
243 #define OM_ADD_KEY (TAG_USER + 30)
244 #define CALCA_DISPLAY (TAG_USER + 31)
245 #define CALCA_TAPE (TAG_USER + 32)
246 #define CALCA_DECIMAL_POINT (TAG_USER + 33)
248 #define EDIT_BUFFER_SIZE MAX_DIGITS + 2 /* space for '-' sign and terminator byte */
249 const char *INITIAL_DISPLAY = "\033r0";
250 enum { STATE_LEFTVAL, STATE_OP, STATE_RIGHTVAL, STATE_EQU };
252 struct CalculatorData
254 char edit_buffer[EDIT_BUFFER_SIZE];
255 int num_digits;
256 int state;
257 char decimal_point;
259 double lvalue, rvalue;
260 int op;
261 Object *display, *tape;
264 struct MUIMP_CalcKey
266 STACKED ULONG MethodID;
267 STACKED ULONG btype;
270 static char op2char(int op)
272 switch (op) {
273 case BTYPE_MUL: return '*';
274 case BTYPE_DIV: return '*';
275 case BTYPE_SUB: return '-';
276 case BTYPE_ADD: return '+';
277 default: return '?';
281 static void clear_edit_buffer(struct CalculatorData *data)
283 memset(data->edit_buffer, 0, EDIT_BUFFER_SIZE);
284 data->num_digits = 0;
287 IPTR mNewCalc(struct IClass *cl, Object *obj, struct opSet *msg)
289 struct TagItem *tagListState = msg->ops_AttrList, *tag;
290 Object *instance = (Object *) DoSuperMethodA(cl, obj, (APTR) msg);
291 struct CalculatorData *data = INST_DATA(cl, instance);
292 clear_edit_buffer(data);
293 data->display = NULL;
294 data->tape = NULL;
295 data->state = STATE_LEFTVAL;
296 data->decimal_point = '.';
298 while ((tag = (struct TagItem *) NextTagItem(&tagListState)))
300 switch (tag->ti_Tag)
302 case CALCA_DISPLAY:
303 data->display = (Object *) tag->ti_Data;
304 break;
305 case CALCA_TAPE:
306 data->tape = (Object *) tag->ti_Data;
307 break;
308 case CALCA_DECIMAL_POINT:
309 data->decimal_point = (char) tag->ti_Data;
310 break;
311 default:
312 break;
315 return (IPTR) instance;
318 IPTR mDisposeCalc(struct IClass *cl, Object *obj, struct opSet *msg)
320 return DoSuperMethodA(cl, obj, (APTR) msg);
323 static BOOL is_operator(int btype)
325 return btype >= BTYPE_MUL && btype <= BTYPE_ADD;
328 static BOOL can_insert_comma(struct CalculatorData *data)
330 if (data->num_digits == 0) return TRUE;
331 else
333 int i;
334 for (i = 0; i < data->num_digits; i++)
336 if (data->edit_buffer[i] == '.') return FALSE;
338 return TRUE;
342 static double eval_result(double lvalue, double rvalue, int op)
344 switch (op)
346 case BTYPE_MUL: return lvalue * rvalue;
347 case BTYPE_DIV: return lvalue / rvalue;
348 case BTYPE_SUB: return lvalue - rvalue;
349 case BTYPE_ADD: return lvalue + rvalue;
350 default: return 0;
355 static void localize_buffer(char *buffer, char decimal_point, int from, int to)
357 int i;
358 for (i = from; i < to; i ++)
360 if (buffer[i] == '.')
362 buffer[i] = decimal_point;
363 break;
368 * Rendering is centralized in this function, by copying
369 * the edit buffer into and manipulating the display buffer.
370 * MUI/Zune's text field right-justifies text through the inclusion
371 * of the "Esc-r" control sequence.
373 static void display_state(struct CalculatorData *data)
375 /* add 2 extra chars: Esc+'r' */
376 static char display_buffer[EDIT_BUFFER_SIZE + 2];
378 if (data->num_digits == 0)
380 SetAttrs(data->display, MUIA_Text_Contents, INITIAL_DISPLAY, TAG_DONE);
382 else
384 memset(display_buffer, 0, EDIT_BUFFER_SIZE + 2);
385 display_buffer[0] = '\033';
386 display_buffer[1] = 'r';
387 memcpy(display_buffer + 2, data->edit_buffer, data->num_digits);
388 localize_buffer(display_buffer, data->decimal_point, 2, MAX_DIGITS + 3);
389 SetAttrs(data->display, MUIA_Text_Contents, display_buffer, TAG_DONE);
393 static const char *localize_display(struct CalculatorData *data)
395 static char buffer[EDIT_BUFFER_SIZE];
396 memset(buffer, 0, MAX_DIGITS + 1);
397 memcpy(buffer, data->edit_buffer, data->num_digits);
398 localize_buffer(buffer, data->decimal_point, 0, MAX_DIGITS + 1);
399 return buffer;
402 static void toggle_sign(struct CalculatorData *data)
404 BOOL sign_found = FALSE;
405 int i;
406 if (data->state == STATE_LEFTVAL) data->lvalue = -data->lvalue;
407 else if (data->state == STATE_RIGHTVAL) data->rvalue = -data->rvalue;
409 for (i = 0; i < EDIT_BUFFER_SIZE; i++)
411 if (data->edit_buffer[i] == '-')
413 sign_found = TRUE;
414 break;
418 if (sign_found)
420 /* eliminate the sign by shifting to the left */
421 data->num_digits--;
422 memmove(data->edit_buffer, data->edit_buffer + 1, data->num_digits);
423 data->edit_buffer[data->num_digits] = 0;
425 else
427 /* add sign by shifting to the right and inserting - */
428 memmove(data->edit_buffer + 1, data->edit_buffer, data->num_digits);
429 data->num_digits++;
430 data->edit_buffer[0] = '-';
431 data->edit_buffer[data->num_digits] = 0;
433 display_state(data);
437 * This method implements the main logic of the calculator by performing transitions
438 * of a state machine.
440 IPTR mAddCalcKey(struct IClass *cl, Object *obj, struct MUIMP_CalcKey *msg)
442 struct CalculatorData *data = INST_DATA(cl, obj);
443 if (msg->btype <= BTYPE_9 && data->num_digits < MAX_DIGITS)
445 if (data->state == STATE_OP)
447 data->state = STATE_RIGHTVAL;
448 clear_edit_buffer(data);
450 if (data->state == STATE_EQU)
452 data->state = STATE_LEFTVAL;
453 clear_edit_buffer(data);
455 char digit = '0' + msg->btype;
456 data->edit_buffer[data->num_digits++] = digit;
457 display_state(data);
460 else if (msg->btype == BTYPE_COMMA && can_insert_comma(data))
462 data->edit_buffer[data->num_digits++] = '.';
463 display_state(data);
465 else if (is_operator(msg->btype))
467 if (data->state == STATE_LEFTVAL || data->state == STATE_EQU)
469 data->lvalue = strtod(data->edit_buffer, NULL);
470 data->state = STATE_OP;
471 data->op = msg->btype;
472 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_LVAL, localize_display(data));
475 else if (msg->btype == BTYPE_EQU)
477 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_RVAL, op2char(data->op), localize_display(data));
479 data->rvalue = strtod(data->edit_buffer, NULL);
480 data->state = STATE_EQU;
481 data->lvalue = eval_result(data->lvalue, data->rvalue, data->op);
482 snprintf(data->edit_buffer, MAX_DIGITS, "%f", data->lvalue);
483 /* note that there is no strnlen() in AROS !!! */
484 data->num_digits = strlen(data->edit_buffer);
486 display_state(data);
487 if (data->tape) DoMethod(data->tape, TAPEM_PRINT_RESULT, localize_display(data));
489 else if (msg->btype == BTYPE_CA)
491 data->lvalue = 0;
492 data->rvalue = 0;
493 data->op = BTYPE_ADD;
494 data->state = STATE_LEFTVAL;
495 clear_edit_buffer(data);
497 display_state(data);
498 if (data->tape) DoMethod(data->tape, TAPEM_NEWLINE);
500 else if (msg->btype == BTYPE_CE &&
501 (data->state == STATE_LEFTVAL || data->state == STATE_RIGHTVAL))
503 clear_edit_buffer(data);
504 display_state(data);
507 else if (msg->btype == BTYPE_SIGN && data->state != STATE_OP)
509 toggle_sign(data);
511 else if (msg->btype == BTYPE_BS &&
512 (data->state == STATE_LEFTVAL || data->state == STATE_RIGHTVAL) &&
513 data->num_digits > 0)
515 data->edit_buffer[--data->num_digits] = 0;
516 display_state(data);
518 return (IPTR) obj;
521 IPTR CalculatorDispatcher(struct IClass *cl, Object *obj, Msg msg)
523 switch (msg->MethodID)
525 case OM_NEW: return mNewCalc(cl, obj, (APTR) msg);
526 case OM_DISPOSE: return mDisposeCalc(cl, obj, (APTR) msg);
527 case OM_ADD_KEY: return (IPTR) mAddCalcKey(cl, obj, (struct MUIMP_CalcKey *) msg);
529 return DoSuperMethodA(cl, obj, msg);
532 static Class *make_calculator_class(void)
534 Class *cl;
535 cl = MakeClass(NULL, ROOTCLASS, NULL, sizeof(struct CalculatorData), 0);
536 if (cl) cl->cl_Dispatcher.h_Entry = CalculatorDispatcher;
537 return cl;
540 /**********************************************************************
541 Main program
542 **********************************************************************/
544 static void cleanup(char *msg)
546 WORD rc;
547 if (msg)
549 fprintf(stderr, "Calculator: %s\n", msg);
550 rc = RETURN_WARN;
552 else
554 rc = RETURN_OK;
556 exit(rc);
559 static void dos_error(void)
561 static char tempstring[256];
562 Fault(IoErr(), 0, tempstring, 255);
563 cleanup(tempstring);
566 static char retrieve_decimal_point(void)
568 struct Locale *loc;
569 char result = '.';
571 if ((loc = OpenLocale(0)))
573 result = loc->loc_DecimalPoint[0];
574 CloseLocale(loc);
576 return result;
579 static void get_arguments(void)
581 struct RDArgs *rdargs;
582 IPTR args[NUM_ARGS];
583 int i;
585 for (i = 0; i < NUM_ARGS; i++) args[i] = (IPTR) NULL;
587 if (!(rdargs = ReadArgs(ARG_TEMPLATE, (IPTR *) args,0))) dos_error();
589 if (args[ARG_PUBSCREEN]) {
590 strncpy(pubscrname, (const char *) args[ARG_PUBSCREEN], 255);
593 if (args[ARG_TAPE])
595 use_tape = TRUE;
596 strncpy(tapename, (const char *) args[ARG_TAPE], 255);
598 if (rdargs) FreeArgs(rdargs);
601 static void open_raw_tape_if_needed(Object *window, Object *obj_tape)
603 if (use_tape && !strlen(tapename))
605 int x, y, w, h;
606 struct Window *win;
607 BPTR tapefh;
609 GetAttr(MUIA_Window_Window, window, (IPTR *) &win);
610 w = win->Width * 5 / 4;
611 h = win->Height;
612 x = win->LeftEdge;
613 y = win->TopEdge;
615 if (x > (win->WScreen->Width - (x + w))) x -= w;
616 else x += win->WScreen->Width;
618 snprintf(tapename, 255, RAW_TAPE_NAME, x, y, w, h, pubscrname);
619 tapefh = Open(tapename, MODE_NEWFILE);
620 SetAttrs(obj_tape, TAPEA_FILEHANDLE, tapefh);
624 int main(void)
626 Class *cl_calc = NULL, *cl_tape = NULL;
627 Object *app = NULL, *window = NULL, *display = NULL, *button[NUM_BUTTONS],
628 *obj_calc, *obj_tape;
629 char decimal_point, decimal_label[2];
630 struct Screen *pub_screen = NULL;
631 BPTR tapefh = BNULL;
632 int i;
634 get_arguments();
635 decimal_point = retrieve_decimal_point();
636 snprintf(decimal_label, 2, "%c", decimal_point);
638 display = TextObject,
639 StringFrame,
640 MUIA_Text_Contents, INITIAL_DISPLAY,
641 MUIA_ShortHelp, "Display",
642 End;
644 cl_tape = make_tape_class();
646 if (use_tape && strlen(tapename)) {
647 tapefh = Open(tapename, MODE_NEWFILE);
650 if (tapefh) {
651 obj_tape = NewObject(cl_tape, NULL, TAPEA_FILEHANDLE, tapefh, TAG_DONE);
653 else
655 obj_tape = NewObject(cl_tape, NULL, TAG_DONE);
658 cl_calc = make_calculator_class();
659 obj_calc = NewObject(cl_calc, NULL,
660 CALCA_DISPLAY, display,
661 CALCA_TAPE, obj_tape,
662 CALCA_DECIMAL_POINT, decimal_point,
663 TAG_DONE);
665 for (i = 0; i < NUM_BUTTONS; i++)
667 button[i] = (i != DECIMAL_BUTTON_INDEX) ?
668 SimpleButton(BUTTONS[i].label) : SimpleButton(decimal_label);
669 if (BUTTONS[i].shortcut)
671 SetAttrs(button[i], MUIA_ControlChar, BUTTONS[i].shortcut, TAG_DONE);
675 if (strlen(pubscrname))
677 pub_screen = LockPubScreen((CONST_STRPTR) pubscrname);
678 if (!pub_screen)
680 printf("Can't lock public screen '%s' -> fallback to Wanderer!\n", pubscrname);
681 memset(pubscrname, 0, 256);
682 strcpy(pubscrname, "Workbench");
683 pub_screen = LockPubScreen((CONST_STRPTR) pubscrname);
687 app = ApplicationObject,
688 MUIA_Application_Title, "Calculator",
689 MUIA_Application_Version, "1.4",
690 MUIA_Application_Copyright, "©2007-2013, AROS Dev Team",
691 MUIA_Application_Author, "AROS Team",
692 MUIA_Application_Description, "Simple desktop calculator",
693 MUIA_Application_Base, "calculator",
694 SubWindow, window = WindowObject,
695 MUIA_Window_Title, "Calculator",
696 MUIA_Window_ID, MAKE_ID('C', 'A', 'L', 'C'),
697 MUIA_Window_AppWindow, TRUE,
698 MUIA_Window_Screen, pub_screen,
699 WindowContents, VGroup,
700 Child, display,
702 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
703 Child, button[0],
704 Child, button[1],
705 Child, button[2],
706 Child, button[3],
707 Child, button[4],
708 End,
710 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
711 Child, button[5],
712 Child, button[6],
713 Child, button[7],
714 Child, button[8],
715 Child, button[9],
716 End,
718 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
719 Child, button[10],
720 Child, button[11],
721 Child, button[12],
722 Child, button[13],
723 Child, button[14],
724 End,
726 Child, HGroup, GroupSpacing(5), MUIA_Group_SameWidth, TRUE,
727 Child, button[15],
728 Child, button[16],
729 Child, button[17],
730 Child, button[18],
731 Child, button[19],
732 End,
734 End,
735 End,
736 End;
738 DoMethod(window, MUIM_Notify, MUIA_Window_CloseRequest, TRUE,
739 app, 2, MUIM_Application_ReturnID,
740 MUIV_Application_ReturnID_Quit);
742 for (i = 0; i < NUM_BUTTONS; i++)
744 DoMethod(button[i], MUIM_Notify, MUIA_Pressed, FALSE,
745 obj_calc, 2, OM_ADD_KEY, BUTTONS[i].btype);
748 SetAttrs(window, MUIA_Window_Open, TRUE, TAG_DONE);
749 open_raw_tape_if_needed(window, obj_tape);
751 if (pub_screen) UnlockPubScreen(0, pub_screen);
753 BOOL running = TRUE;
754 ULONG sigs = 0, id;
756 while (running) {
757 id = DoMethod(app, MUIM_Application_NewInput, (IPTR) &sigs);
759 switch(id)
761 case MUIV_Application_ReturnID_Quit:
762 running = FALSE;
763 break;
764 default:
765 break;
767 if (running && sigs)
769 sigs = Wait(sigs | SIGBREAKF_CTRL_C);
770 if (sigs & SIGBREAKF_CTRL_C) break;
774 set((APTR) window, MUIA_Window_Open, FALSE);
775 MUI_DisposeObject(app);
777 DisposeObject(obj_calc);
778 DisposeObject(obj_tape);
779 FreeClass(cl_calc);
780 FreeClass(cl_tape);
782 cleanup(NULL);
783 return 0;