Reworked the rule_copy_multi, rule_ref_multi, rule_compile_multi to avoid
[AROS.git] / workbench / tools / calculator.c
blob19da524d315267f35cc92f9aa02b82b420d7d75f
1 /*
2 Copyright © 1995-2003, The AROS Development Team. All rights reserved.
3 $Id$
4 */
6 #include <intuition/intuition.h>
7 #include <libraries/gadtools.h>
8 #include <libraries/locale.h>
10 #include <proto/exec.h>
11 #include <proto/dos.h>
12 #include <proto/intuition.h>
13 #include <proto/graphics.h>
14 #include <proto/gadtools.h>
15 #include <proto/locale.h>
16 #include <proto/alib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <ctype.h>
21 #include <stdlib.h>
22 #include <math.h>
24 #define ARG_TEMPLATE "PUBSCREEN,TAPE/K"
26 enum {ARG_PUBSCREEN,ARG_TAPE,NUM_ARGS};
28 #define MAX_VAL_LEN 13
30 #define INNER_SPACING_X 4
31 #define INNER_SPACING_Y 4
33 #define BUTTON_SPACING_X 4
34 #define BUTTON_SPACING_Y 4
36 #define BUTTON_LED_SPACING 4
38 #define NUM_BUTTONS 20
39 #define NUM_BUTTON_COLS 5
40 #define NUM_BUTTON_ROWS 4
42 #define BUTTON_EXTRA_WIDTH 8
43 #define BUTTON_EXTRA_HEIGHT 4
45 #define LED_EXTRA_HEIGHT 4
47 enum
49 STATE_LEFTVAL, STATE_OP, STATE_RIGHTVAL, STATE_EQU
52 enum
54 BTYPE_0,
55 BTYPE_1,
56 BTYPE_2,
57 BTYPE_3,
58 BTYPE_4,
59 BTYPE_5,
60 BTYPE_6,
61 BTYPE_7,
62 BTYPE_8,
63 BTYPE_9,
64 BTYPE_COMMA,
65 BTYPE_BS,
66 BTYPE_CA,
67 BTYPE_CE,
68 BTYPE_MUL,
69 BTYPE_DIV,
70 BTYPE_SUB,
71 BTYPE_ADD,
72 BTYPE_SIGN,
73 BTYPE_EQU,
75 BTYPE_LED
78 struct ButtonInfo
80 char *text;
81 WORD type;
82 char key1;
83 char key2;
86 static struct ButtonInfo bi[NUM_BUTTONS] =
88 {"7" ,BTYPE_7 , '7' , 0 },
89 {"8" ,BTYPE_8 , '8' , 0 },
90 {"9" ,BTYPE_9 , '9' , 0 },
91 {"CA" ,BTYPE_CA , 'A' , 127 },
92 {"CE" ,BTYPE_CE , 'E' , 0 },
94 {"4" ,BTYPE_4 , '4' , 0 },
95 {"5" ,BTYPE_5 , '5' , 0 },
96 {"6" ,BTYPE_6 , '6' , 0 },
97 {"×" ,BTYPE_MUL , '*' , 'X' },
98 {":" ,BTYPE_DIV , '/' , ':' },
100 {"1" ,BTYPE_1 , '1' , 0 },
101 {"2" ,BTYPE_2 , '2' , 0 },
102 {"3" ,BTYPE_3 , '3' , 0 },
103 {"+" ,BTYPE_ADD , '+' , 0 },
104 {"-" ,BTYPE_SUB , '-' , 0 },
106 {"0" ,BTYPE_0 , '0' , 0 },
107 {"." ,BTYPE_COMMA , '.' , ',' },
108 {"«" ,BTYPE_BS , 8 , 0 },
109 {"±" ,BTYPE_SIGN , 'S' , 0 },
110 {"=" ,BTYPE_EQU , '=' , 13 }
114 struct IntuitionBase *IntuitionBase;
115 struct GfxBase *GfxBase;
116 struct Library *GadToolsBase;
117 struct LocaleBase *LocaleBase;
119 static struct Screen *scr;
120 static struct DrawInfo *dri;
121 static struct Gadget *gadlist, *gad[NUM_BUTTONS + 2];
122 static struct Window *win;
123 static struct RDArgs *MyArgs;
124 static APTR vi;
125 static FILE *tapefh;
127 static WORD win_borderleft,win_bordertop;
128 static WORD buttonwidth,buttonheight,ledheight;
129 static WORD inner_winwidth,inner_winheight;
130 static WORD vallen,state,operation;
132 static BOOL dotape;
134 static double leftval,rightval;
136 static char comma,*pubscrname;
137 static char ledstring[256],visledstring[256],
138 tempstring[256],tapename[256];
140 static char *deftapename = "RAW:%ld/%ld/%ld/%ld/Calculator Tape/INACTIVE/SCREEN%s";
142 UBYTE version[] = "$VER: Calculator 1.1 (1.5.2001)";
144 static LONG Args[NUM_ARGS];
146 static void Cleanup(char *msg)
148 WORD rc;
150 if (msg)
152 printf("Calculator: %s\n",msg);
153 rc = RETURN_WARN;
154 } else {
155 rc = RETURN_OK;
158 if (tapefh) fclose(tapefh);
160 if (win) CloseWindow(win);
162 if (gadlist) FreeGadgets(gadlist);
164 if (vi) FreeVisualInfo(vi);
165 if (dri) FreeScreenDrawInfo(scr,dri);
166 if (scr) UnlockPubScreen(0,scr);
168 if (MyArgs) FreeArgs(MyArgs);
170 if (LocaleBase) CloseLibrary((struct Library *)LocaleBase);
171 if (GadToolsBase) CloseLibrary(GadToolsBase);
172 if (GfxBase) CloseLibrary((struct Library *)GfxBase);
173 if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
175 exit (rc);
178 static void DosError(void)
180 Fault(IoErr(),0,tempstring,255);
181 Cleanup(tempstring);
184 static void OpenLibs(void)
186 if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
188 Cleanup("Can't open intuition.library V39!");
191 if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
193 Cleanup("Can't open graphics.library V39!");
196 if (!(GadToolsBase = OpenLibrary("gadtools.library",39)))
198 Cleanup("Can't open gadtools.library V39!");
201 LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",39);
204 static void GetArguments(void)
206 if (!(MyArgs = ReadArgs(ARG_TEMPLATE,(LONG *)Args,0)))
208 DosError();
211 pubscrname = (char *)Args[ARG_PUBSCREEN];
213 if (Args[ARG_TAPE])
215 strcpy(tapename,(char *)Args[ARG_TAPE]);
216 dotape = TRUE;
220 static void DoLocale(void)
222 //struct Locale *loc;
224 comma = '.';
226 /* SDuvan: removed Locale code as it seemed to cause segfaults
227 when running calculator several times */
228 // if ((loc = OpenLocale(0)))
229 // {
230 // comma = loc->loc_DecimalPoint[0];
231 // CloseLocale(loc);
232 // }
234 bi[16].text[0] = comma;
237 static void GetVisual(void)
239 if (pubscrname) scr = LockPubScreen(pubscrname);
241 if (!scr)
243 if (!(scr = LockPubScreen(0)))
245 Cleanup("Can't lock screen!");
249 if (!(dri = GetScreenDrawInfo(scr)))
251 Cleanup("Can't get drawinfo!");
254 if (!(vi = GetVisualInfo(scr,0)))
256 Cleanup("Can't get visual info!");
259 win_borderleft = scr->WBorLeft;
261 /* SDuvan: was scr->WBorTop + scr->Font->ta_YSize + 1 */
262 win_bordertop = scr->WBorTop + dri->dri_Font->tf_YSize + 1;
266 static void InitGUI(void)
268 static struct RastPort temprp;
270 WORD i,len;
272 InitRastPort(&temprp);
273 SetFont(&temprp,dri->dri_Font);
275 buttonheight = dri->dri_Font->tf_YSize + BUTTON_EXTRA_HEIGHT;
277 for(i = 0;i < NUM_BUTTONS;i++)
279 len = TextLength(&temprp,bi[i].text,strlen(bi[i].text));
280 if (len > buttonwidth) buttonwidth = len;
283 buttonwidth += BUTTON_EXTRA_WIDTH;
285 ledheight = dri->dri_Font->tf_YSize + LED_EXTRA_HEIGHT;
287 inner_winwidth = buttonwidth * NUM_BUTTON_COLS +
288 BUTTON_SPACING_X * (NUM_BUTTON_COLS - 1) +
289 INNER_SPACING_X * 2;
291 inner_winheight = buttonheight * NUM_BUTTON_ROWS +
292 BUTTON_SPACING_Y * (NUM_BUTTON_ROWS - 1) +
293 BUTTON_LED_SPACING +
294 ledheight +
295 INNER_SPACING_Y * 2;
297 DeinitRastPort(&temprp);
298 strcpy(ledstring,"0");
301 static void MakeGadgets(void)
303 struct Gadget *mygad = 0;
304 struct NewGadget ng = {0};
305 WORD col,row,i;
307 ng.ng_VisualInfo = vi;
309 mygad = CreateContext(&gadlist);
311 ng.ng_GadgetID = BTYPE_LED;
313 ng.ng_LeftEdge = win_borderleft + INNER_SPACING_X;
314 ng.ng_TopEdge = win_bordertop + INNER_SPACING_Y;
315 ng.ng_Width = inner_winwidth - INNER_SPACING_X * 2;
316 ng.ng_Height = ledheight;
318 mygad = gad[BTYPE_LED] = CreateGadget(TEXT_KIND,
319 mygad,
320 &ng,
321 GTTX_Text, (IPTR) ledstring,
322 GTTX_CopyText,TRUE,
323 GTTX_Border,TRUE,
324 GTTX_Justification,GTJ_RIGHT,
325 TAG_DONE);
327 i = 0;
329 ng.ng_TopEdge = win_bordertop +
330 INNER_SPACING_Y +
331 ledheight +
332 BUTTON_LED_SPACING;
334 ng.ng_Width = buttonwidth;
335 ng.ng_Height = buttonheight;
337 for(row = 0; row < NUM_BUTTON_ROWS; row++)
339 for(col = 0; col < NUM_BUTTON_COLS; col++, i++)
341 ng.ng_GadgetID = bi[i].type;
343 ng.ng_LeftEdge = win_borderleft +
344 INNER_SPACING_X +
345 col * (buttonwidth + BUTTON_SPACING_X);
347 ng.ng_GadgetText = bi[i].text;
349 mygad = gad[bi[i].type] = CreateGadgetA(BUTTON_KIND,
350 mygad,
351 &ng,
354 } /* for(col = 0;col < NUM_BUTTON_COLS; col++) */
356 ng.ng_TopEdge += buttonheight + BUTTON_SPACING_Y;
358 } /* for(row = 0; row < NUM_BUTTON_ROWS; row++) */
360 if (!mygad)
362 Cleanup("Can't create gadgets!");
367 static void MakeWin(void)
369 win = OpenWindowTags(0,WA_PubScreen,(IPTR)scr,
370 WA_Left,scr->MouseX,
371 WA_Top,scr->MouseY,
372 WA_InnerWidth,inner_winwidth,
373 WA_InnerHeight,inner_winheight,
374 WA_AutoAdjust,TRUE,
375 WA_Title,(IPTR)"Calculator",
376 WA_CloseGadget,TRUE,
377 WA_DepthGadget,TRUE,
378 WA_DragBar,TRUE,
379 WA_Activate,TRUE,
380 WA_SimpleRefresh,TRUE,
381 WA_IDCMP,IDCMP_CLOSEWINDOW |
382 IDCMP_GADGETUP |
383 IDCMP_VANILLAKEY |
384 IDCMP_RAWKEY |
385 IDCMP_REFRESHWINDOW,
386 WA_Gadgets,(IPTR)gadlist,
387 TAG_DONE);
389 if (!win) Cleanup("Can't open window!");
391 GT_RefreshWindow(win,0);
393 ScreenToFront(win->WScreen);
396 static void OpenTape(void)
398 struct List *l;
399 struct PubScreenNode *psn;
400 char *scrname = "";
401 WORD x,y,w,h;
403 if (!(tapename[0]))
405 l = LockPubScreenList();
407 psn = (struct PubScreenNode *)l->lh_Head;
409 while (psn->psn_Node.ln_Succ)
411 if (psn->psn_Screen == scr)
413 if (psn->psn_Node.ln_Name)
415 scrname = psn->psn_Node.ln_Name;
417 break;
419 psn = (struct PubScreenNode *)psn->psn_Node.ln_Succ;
422 UnlockPubScreenList();
424 w = win->Width * 5 / 4;
425 h = win->Height;
427 x = win->LeftEdge;
428 y = win->TopEdge;
430 if (x > (scr->Width - (x + w)))
432 x -= w;
433 } else {
434 x += win->Width;
436 sprintf(tapename,deftapename,x,y,w,h,scrname);
439 if (!(tapefh = fopen(tapename,"w")))
441 DisplayBeep(scr);
445 static double GetValue(void)
447 double val;
448 char c = 0,*sp;
450 sp = strchr(ledstring,comma);
451 if (sp)
453 c = *sp;
454 *sp = '.';
457 val = strtod(ledstring,0);
459 if (sp) *sp = c;
461 return val;
464 static void GetLeftValue(void)
466 leftval = GetValue();
469 static void GetRightValue(void)
471 rightval = GetValue();
474 static void LeftValToLED(void)
476 char *sp;
478 sprintf(ledstring,"%f",leftval);
480 sp = strchr(ledstring,'.');
481 if (!sp) sp = strchr(ledstring,',');
482 if (sp) *sp = comma;
485 static char *DoOperation(void)
487 char *matherr = 0;
489 switch (operation)
491 case BTYPE_ADD:
492 leftval += rightval;
493 break;
495 case BTYPE_SUB:
496 leftval -= rightval;
497 break;
499 case BTYPE_MUL:
500 leftval *= rightval;
501 break;
503 case BTYPE_DIV:
504 if (rightval == 0.0)
506 matherr = "Division by zero!";
507 } else {
508 leftval /= rightval;
510 break;
513 if (!matherr) LeftValToLED();
515 return matherr;
518 static void RefreshLED(void)
520 strcpy(visledstring,ledstring);
522 if ((ledstring[0] == ',') ||
523 (ledstring[0] == '\0') ||
524 ((ledstring[0] >= '0') && (ledstring[0] <= '9')))
526 visledstring[0] = '\0';
528 if ((ledstring[0] == ',') ||
529 (ledstring[0] == '.') ||
530 (ledstring[0] == '\0'))
532 strcpy(visledstring,"0");
534 strcat(visledstring,ledstring);
537 GT_SetGadgetAttrs(gad[BTYPE_LED],
538 win,
540 GTTX_Text,(IPTR)visledstring,
541 TAG_DONE);
544 static void HandleButton(WORD type)
546 char *matherr = 0;
547 WORD checklen;
548 BOOL refresh_led = FALSE;
550 switch(type)
552 case BTYPE_0:
553 case BTYPE_1:
554 case BTYPE_2:
555 case BTYPE_3:
556 case BTYPE_4:
557 case BTYPE_5:
558 case BTYPE_6:
559 case BTYPE_7:
560 case BTYPE_8:
561 case BTYPE_9:
562 checklen = vallen;
563 if ((strchr(ledstring,comma))) checklen--;
564 if ((strchr(ledstring,'-'))) checklen--;
566 if (checklen < MAX_VAL_LEN)
568 if (state == STATE_OP)
570 state = STATE_RIGHTVAL;
571 } else if (state == STATE_EQU)
573 state = STATE_LEFTVAL;
576 if ((vallen > 0) || (type != BTYPE_0))
578 ledstring[vallen++] = type + '0';
580 ledstring[vallen] = '\0';
582 refresh_led = TRUE;
584 } /* if (vallen < MAX_VAL_LEN) */
585 break;
587 case BTYPE_COMMA:
588 if (!strchr(ledstring,comma))
590 if (state == STATE_OP)
592 state = STATE_RIGHTVAL;
593 } else if (state == STATE_EQU)
595 state = STATE_LEFTVAL;
598 ledstring[vallen++] = comma;
599 ledstring[vallen] = '\0';
601 refresh_led = TRUE;
603 } /* if (!strchr(ledstring,comma)) */
604 break;
606 case BTYPE_CA:
607 vallen = 0;
608 leftval = 0.0;
609 rightval = 0.0;
610 operation = BTYPE_ADD;
612 state = STATE_LEFTVAL;
614 strcpy(ledstring,"0");
615 refresh_led = TRUE;
617 if (tapefh) fputs("\n",tapefh);
618 break;
620 case BTYPE_CE:
621 vallen = 0;
622 strcpy(ledstring,"0");
623 refresh_led = TRUE;
625 switch (state)
627 case STATE_LEFTVAL:
628 leftval = 0.0;
629 break;
631 case STATE_OP:
632 case STATE_RIGHTVAL:
633 rightval = 0.0;
634 break;
636 break;
638 case BTYPE_BS:
639 if (vallen)
641 ledstring[--vallen] = '\0';
642 if (vallen == 0) strcpy(ledstring,"0");
643 refresh_led = TRUE;
645 break;
647 case BTYPE_SIGN:
648 switch(state)
650 case STATE_LEFTVAL:
651 case STATE_RIGHTVAL:
652 if (ledstring[0] == '-')
654 strcpy(ledstring,&ledstring[1]);
655 } else {
656 strcpy(tempstring,ledstring);
657 strcpy(ledstring,"-");
658 strcat(ledstring,tempstring);
660 refresh_led = TRUE;
661 break;
663 case STATE_EQU:
664 leftval = -leftval;
665 LeftValToLED();
666 refresh_led = TRUE;
667 break;
669 break;
671 case BTYPE_ADD:
672 case BTYPE_SUB:
673 case BTYPE_MUL:
674 case BTYPE_DIV:
675 switch(state)
677 case STATE_LEFTVAL:
678 case STATE_EQU:
679 GetLeftValue();
680 rightval = leftval;
682 state = STATE_OP;
683 vallen = 0;
684 strcpy(ledstring,"0");
686 if (tapefh)
688 fprintf(tapefh,"\t%s\n",visledstring);
689 fflush(tapefh);
691 break;
693 case STATE_OP:
694 break;
696 case STATE_RIGHTVAL:
697 GetRightValue();
698 matherr = DoOperation();
699 state = STATE_OP;
700 vallen = 0;
701 refresh_led = TRUE;
703 if (tapefh)
705 fprintf(tapefh,"%s\t%s\n",(operation == BTYPE_ADD) ? "+" :
706 (operation == BTYPE_SUB) ? "-" :
707 (operation == BTYPE_DIV) ? ":" :
708 "×" ,visledstring);
709 fflush(tapefh);
711 break;
713 } /* switch(state) */
715 operation = type;
716 break;
718 case BTYPE_EQU:
719 if (state == STATE_LEFTVAL)
721 GetLeftValue();
722 if (tapefh)
724 fprintf(tapefh,"\t%s\n",visledstring);
725 fflush(tapefh);
728 else if (state == STATE_RIGHTVAL)
730 GetRightValue();
731 if (tapefh)
733 fprintf(tapefh,"%s\t%s\n",(operation == BTYPE_ADD) ? "+" :
734 (operation == BTYPE_SUB) ? "-" :
735 (operation == BTYPE_DIV) ? ":" :
736 "×" ,visledstring);
737 fflush(tapefh);
741 matherr = DoOperation();
742 state = STATE_EQU;
744 vallen = 0;
746 if (!matherr)
748 RefreshLED();
749 if (tapefh)
751 fprintf(tapefh,"=\t%s\n",visledstring);
752 fflush(tapefh);
754 } else {
755 refresh_led = TRUE;
757 break;
759 } /* switch(type) */
761 if (matherr)
763 leftval = rightval = 0.0;
764 state = STATE_LEFTVAL;
765 operation = BTYPE_ADD;
766 vallen = 0;
767 strcpy(ledstring,matherr);
768 refresh_led = TRUE;
771 if (refresh_led) RefreshLED();
775 static void HandleAll(void)
777 struct IntuiMessage *msg;
778 WORD icode,i;
779 ULONG signals;
781 BOOL quitme = FALSE;
783 if (dotape) OpenTape();
785 while(!quitme)
787 signals = Wait(1L << win->UserPort->mp_SigBit | SIGBREAKF_CTRL_C);
789 if (signals & (1L << win->UserPort->mp_SigBit))
791 while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
793 switch(msg->Class)
795 case IDCMP_CLOSEWINDOW:
796 quitme = TRUE;
797 break;
799 case IDCMP_REFRESHWINDOW:
800 GT_BeginRefresh(win);
801 GT_EndRefresh(win,TRUE);
802 break;
804 case IDCMP_GADGETUP:
805 HandleButton(((struct Gadget *)msg->IAddress)->GadgetID);
806 break;
808 case IDCMP_VANILLAKEY:
809 icode = toupper(msg->Code);
811 for(i = 0;i < NUM_BUTTONS;i++)
813 if ((icode == bi[i].key1) ||
814 (icode == bi[i].key2))
816 icode = bi[i].type;
817 break;
820 if (i < NUM_BUTTONS)
822 HandleButton(icode);
823 } else if (icode == 27)
825 quitme = TRUE;
827 break;
829 } /* switch(msg->Class) */
831 ReplyMsg((struct Message *)msg);
832 } /* while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort))) */
833 } /* if(signals & (1L << win->UserPort->mp_SigBit)) */
834 if (signals & SIGBREAKF_CTRL_C)
835 quitme = TRUE;
837 } /* while(!quitme) */
840 int main(void)
842 OpenLibs();
843 GetArguments();
844 DoLocale();
845 GetVisual();
846 InitGUI();
847 MakeGadgets();
848 MakeWin();
849 HandleAll();
850 Cleanup(0);
851 return 0;