Fixed AutoDoc indentation, spelling, grammar.
[AROS.git] / workbench / tools / Calculator.c
blobf573cda04274911280acc474e721c45515181d6d
1 /*
2 Copyright © 1995-2011, 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 #ifndef __MORPHOS__
118 struct LocaleBase *LocaleBase;
119 #else
120 struct Library *LocaleBase;
121 #endif
123 static struct Screen *scr;
124 static struct DrawInfo *dri;
125 static struct Gadget *gadlist, *gad[NUM_BUTTONS + 2];
126 static struct Window *win;
127 static struct RDArgs *MyArgs;
128 static APTR vi;
129 static BPTR tapefh;
131 static WORD win_borderleft,win_bordertop;
132 static WORD buttonwidth,buttonheight,ledheight;
133 static WORD inner_winwidth,inner_winheight;
134 static WORD vallen,state,operation;
136 static BOOL dotape;
138 static double leftval,rightval;
140 static char comma,*pubscrname;
141 static char ledstring[256],visledstring[256],
142 tempstring[256],tapename[256];
144 static char *deftapename = "RAW:%ld/%ld/%ld/%ld/Calculator Tape/INACTIVE/SCREEN%s";
146 UBYTE version[] = "$VER: Calculator 1.3 (07.10.2007) © AROS Dev Team";
148 static IPTR Args[NUM_ARGS];
150 static void Cleanup(char *msg)
152 WORD rc;
154 if (msg)
156 printf("Calculator: %s\n",msg);
157 rc = RETURN_WARN;
158 } else {
159 rc = RETURN_OK;
162 if (tapefh) Close(tapefh);
164 if (win) CloseWindow(win);
166 if (gadlist) FreeGadgets(gadlist);
168 if (vi) FreeVisualInfo(vi);
169 if (dri) FreeScreenDrawInfo(scr,dri);
170 if (scr) UnlockPubScreen(0,scr);
172 if (MyArgs) FreeArgs(MyArgs);
174 if (LocaleBase) CloseLibrary((struct Library *)LocaleBase);
175 if (GadToolsBase) CloseLibrary(GadToolsBase);
176 if (GfxBase) CloseLibrary((struct Library *)GfxBase);
177 if (IntuitionBase) CloseLibrary((struct Library *)IntuitionBase);
179 exit (rc);
182 static void DosError(void)
184 Fault(IoErr(),0,tempstring,255);
185 Cleanup(tempstring);
188 static void OpenLibs(void)
190 if (!(IntuitionBase = (struct IntuitionBase *)OpenLibrary("intuition.library",39)))
192 Cleanup("Can't open intuition.library V39!");
195 if (!(GfxBase = (struct GfxBase *)OpenLibrary("graphics.library",39)))
197 Cleanup("Can't open graphics.library V39!");
200 if (!(GadToolsBase = OpenLibrary("gadtools.library",39)))
202 Cleanup("Can't open gadtools.library V39!");
205 LocaleBase = (struct LocaleBase *)OpenLibrary("locale.library",39);
208 static void GetArguments(void)
210 if (!(MyArgs = ReadArgs(ARG_TEMPLATE,(IPTR *)Args,0)))
212 DosError();
215 pubscrname = (char *)Args[ARG_PUBSCREEN];
217 if (Args[ARG_TAPE])
219 strcpy(tapename,(char *)Args[ARG_TAPE]);
220 dotape = TRUE;
224 static void DoLocale(void)
226 struct Locale *loc;
228 comma = '.';
230 if ((loc = OpenLocale(0)))
232 comma = loc->loc_DecimalPoint[0];
233 CloseLocale(loc);
236 bi[16].text[0] = comma;
239 static void GetVisual(void)
241 if (pubscrname) scr = LockPubScreen(pubscrname);
243 if (!scr)
245 if (!(scr = LockPubScreen(0)))
247 Cleanup("Can't lock screen!");
251 if (!(dri = GetScreenDrawInfo(scr)))
253 Cleanup("Can't get drawinfo!");
256 if (!(vi = GetVisualInfo(scr,0)))
258 Cleanup("Can't get visual info!");
261 win_borderleft = scr->WBorLeft;
263 /* SDuvan: was scr->WBorTop + scr->Font->ta_YSize + 1 */
264 win_bordertop = scr->WBorTop + dri->dri_Font->tf_YSize + 1;
268 static void InitGUI(void)
270 static struct RastPort temprp;
272 WORD i,len;
274 InitRastPort(&temprp);
275 SetFont(&temprp,dri->dri_Font);
277 buttonheight = dri->dri_Font->tf_YSize + BUTTON_EXTRA_HEIGHT;
279 for(i = 0;i < NUM_BUTTONS;i++)
281 len = TextLength(&temprp,bi[i].text,strlen(bi[i].text));
282 if (len > buttonwidth) buttonwidth = len;
285 buttonwidth += BUTTON_EXTRA_WIDTH;
287 ledheight = dri->dri_Font->tf_YSize + LED_EXTRA_HEIGHT;
289 inner_winwidth = buttonwidth * NUM_BUTTON_COLS +
290 BUTTON_SPACING_X * (NUM_BUTTON_COLS - 1) +
291 INNER_SPACING_X * 2;
293 inner_winheight = buttonheight * NUM_BUTTON_ROWS +
294 BUTTON_SPACING_Y * (NUM_BUTTON_ROWS - 1) +
295 BUTTON_LED_SPACING +
296 ledheight +
297 INNER_SPACING_Y * 2;
299 strcpy(ledstring,"0");
302 static void MakeGadgets(void)
304 struct Gadget *mygad = 0;
305 struct NewGadget ng = {0};
306 WORD col,row,i;
308 ng.ng_VisualInfo = vi;
310 mygad = CreateContext(&gadlist);
312 ng.ng_GadgetID = BTYPE_LED;
314 ng.ng_LeftEdge = win_borderleft + INNER_SPACING_X;
315 ng.ng_TopEdge = win_bordertop + INNER_SPACING_Y;
316 ng.ng_Width = inner_winwidth - INNER_SPACING_X * 2;
317 ng.ng_Height = ledheight;
319 mygad = gad[BTYPE_LED] = CreateGadget(TEXT_KIND,
320 mygad,
321 &ng,
322 GTTX_Text, (IPTR) ledstring,
323 GTTX_CopyText,TRUE,
324 GTTX_Border,TRUE,
325 GTTX_Justification,GTJ_RIGHT,
326 TAG_DONE);
328 i = 0;
330 ng.ng_TopEdge = win_bordertop +
331 INNER_SPACING_Y +
332 ledheight +
333 BUTTON_LED_SPACING;
335 ng.ng_Width = buttonwidth;
336 ng.ng_Height = buttonheight;
338 for(row = 0; row < NUM_BUTTON_ROWS; row++)
340 for(col = 0; col < NUM_BUTTON_COLS; col++, i++)
342 ng.ng_GadgetID = bi[i].type;
344 ng.ng_LeftEdge = win_borderleft +
345 INNER_SPACING_X +
346 col * (buttonwidth + BUTTON_SPACING_X);
348 ng.ng_GadgetText = bi[i].text;
350 mygad = gad[bi[i].type] = CreateGadgetA(BUTTON_KIND,
351 mygad,
352 &ng,
355 } /* for(col = 0;col < NUM_BUTTON_COLS; col++) */
357 ng.ng_TopEdge += buttonheight + BUTTON_SPACING_Y;
359 } /* for(row = 0; row < NUM_BUTTON_ROWS; row++) */
361 if (!mygad)
363 Cleanup("Can't create gadgets!");
368 static void MakeWin(void)
370 win = OpenWindowTags(0,WA_PubScreen,(IPTR)scr,
371 WA_Left,scr->MouseX,
372 WA_Top,scr->MouseY,
373 WA_InnerWidth,inner_winwidth,
374 WA_InnerHeight,inner_winheight,
375 WA_AutoAdjust,TRUE,
376 WA_Title,(IPTR)"Calculator",
377 WA_CloseGadget,TRUE,
378 WA_DepthGadget,TRUE,
379 WA_DragBar,TRUE,
380 WA_Activate,TRUE,
381 WA_SimpleRefresh,TRUE,
382 WA_IDCMP,IDCMP_CLOSEWINDOW |
383 IDCMP_GADGETUP |
384 IDCMP_VANILLAKEY |
385 IDCMP_RAWKEY |
386 IDCMP_REFRESHWINDOW,
387 WA_Gadgets,(IPTR)gadlist,
388 TAG_DONE);
390 if (!win) Cleanup("Can't open window!");
392 GT_RefreshWindow(win,0);
394 ScreenToFront(win->WScreen);
397 static void OpenTape(void)
399 struct List *l;
400 struct PubScreenNode *psn;
401 char *scrname = "";
402 WORD x,y,w,h;
404 if (!(tapename[0]))
406 l = LockPubScreenList();
408 psn = (struct PubScreenNode *)l->lh_Head;
410 while (psn->psn_Node.ln_Succ)
412 if (psn->psn_Screen == scr)
414 if (psn->psn_Node.ln_Name)
416 scrname = psn->psn_Node.ln_Name;
418 break;
420 psn = (struct PubScreenNode *)psn->psn_Node.ln_Succ;
423 UnlockPubScreenList();
425 w = win->Width * 5 / 4;
426 h = win->Height;
428 x = win->LeftEdge;
429 y = win->TopEdge;
431 if (x > (scr->Width - (x + w)))
433 x -= w;
434 } else {
435 x += win->Width;
437 sprintf(tapename,deftapename,x,y,w,h,scrname);
440 if (!(tapefh = Open(tapename,MODE_NEWFILE)))
442 DisplayBeep(scr);
446 static double GetValue(void)
448 double val;
449 char c = 0,*sp;
451 sp = strchr(ledstring,comma);
452 if (sp)
454 c = *sp;
455 *sp = '.';
458 val = strtod(ledstring,0);
460 if (sp) *sp = c;
462 return val;
465 static void GetLeftValue(void)
467 leftval = GetValue();
470 static void GetRightValue(void)
472 rightval = GetValue();
475 static void LeftValToLED(void)
477 char *sp;
479 sprintf(ledstring,"%f",leftval);
481 sp = strchr(ledstring,'.');
482 if (!sp) sp = strchr(ledstring,',');
483 if (sp) *sp = comma;
486 static char *DoOperation(void)
488 char *matherr = 0;
490 switch (operation)
492 case BTYPE_ADD:
493 leftval += rightval;
494 break;
496 case BTYPE_SUB:
497 leftval -= rightval;
498 break;
500 case BTYPE_MUL:
501 leftval *= rightval;
502 break;
504 case BTYPE_DIV:
505 if (rightval == 0.0)
507 matherr = "Division by zero!";
508 } else {
509 leftval /= rightval;
511 break;
514 if (leftval > 9999999999999.0) // because of MAX_VAL_LEN
516 matherr = "Buffer overflow!";
519 if (!matherr) LeftValToLED();
521 return matherr;
524 static void RefreshLED(void)
526 strcpy(visledstring,ledstring);
528 if ((ledstring[0] == ',') ||
529 (ledstring[0] == '\0') ||
530 ((ledstring[0] >= '0') && (ledstring[0] <= '9')))
532 visledstring[0] = '\0';
534 if ((ledstring[0] == ',') ||
535 (ledstring[0] == '.') ||
536 (ledstring[0] == '\0'))
538 strcpy(visledstring,"0");
540 strcat(visledstring,ledstring);
543 GT_SetGadgetAttrs(gad[BTYPE_LED],
544 win,
546 GTTX_Text,(IPTR)visledstring,
547 TAG_DONE);
550 static void HandleButton(WORD type)
552 char *matherr = 0;
553 WORD checklen;
554 BOOL refresh_led = FALSE;
556 switch(type)
558 case BTYPE_0:
559 case BTYPE_1:
560 case BTYPE_2:
561 case BTYPE_3:
562 case BTYPE_4:
563 case BTYPE_5:
564 case BTYPE_6:
565 case BTYPE_7:
566 case BTYPE_8:
567 case BTYPE_9:
568 checklen = vallen;
569 if ((strchr(ledstring,comma))) checklen--;
570 if ((strchr(ledstring,'-'))) checklen--;
572 if (checklen < MAX_VAL_LEN)
574 if (state == STATE_OP)
576 state = STATE_RIGHTVAL;
577 } else if (state == STATE_EQU)
579 state = STATE_LEFTVAL;
582 if ((vallen > 0) || (type != BTYPE_0))
584 ledstring[vallen++] = type + '0';
586 ledstring[vallen] = '\0';
588 refresh_led = TRUE;
590 } /* if (vallen < MAX_VAL_LEN) */
591 break;
593 case BTYPE_COMMA:
594 if (!strchr(ledstring,comma))
596 if (state == STATE_OP)
598 state = STATE_RIGHTVAL;
599 } else if (state == STATE_EQU)
601 state = STATE_LEFTVAL;
604 ledstring[vallen++] = comma;
605 ledstring[vallen] = '\0';
607 refresh_led = TRUE;
609 } /* if (!strchr(ledstring,comma)) */
610 break;
612 case BTYPE_CA:
613 vallen = 0;
614 leftval = 0.0;
615 rightval = 0.0;
616 operation = BTYPE_ADD;
618 state = STATE_LEFTVAL;
620 strcpy(ledstring,"0");
621 refresh_led = TRUE;
623 if (tapefh) FPutC(tapefh, '\n');
624 break;
626 case BTYPE_CE:
627 vallen = 0;
628 strcpy(ledstring,"0");
629 refresh_led = TRUE;
631 switch (state)
633 case STATE_LEFTVAL:
634 leftval = 0.0;
635 break;
637 case STATE_OP:
638 case STATE_RIGHTVAL:
639 rightval = 0.0;
640 break;
642 break;
644 case BTYPE_BS:
645 if (vallen)
647 ledstring[--vallen] = '\0';
648 if (vallen == 0) strcpy(ledstring,"0");
649 refresh_led = TRUE;
651 break;
653 case BTYPE_SIGN:
654 switch(state)
656 case STATE_LEFTVAL:
657 case STATE_RIGHTVAL:
658 if (ledstring[0] == '-')
660 strcpy(ledstring,&ledstring[1]);
661 } else {
662 strcpy(tempstring,ledstring);
663 strcpy(ledstring,"-");
664 strcat(ledstring,tempstring);
666 refresh_led = TRUE;
667 break;
669 case STATE_EQU:
670 leftval = -leftval;
671 LeftValToLED();
672 refresh_led = TRUE;
673 break;
675 break;
677 case BTYPE_ADD:
678 case BTYPE_SUB:
679 case BTYPE_MUL:
680 case BTYPE_DIV:
681 switch(state)
683 case STATE_LEFTVAL:
684 case STATE_EQU:
685 GetLeftValue();
686 rightval = leftval;
688 state = STATE_OP;
689 vallen = 0;
690 strcpy(ledstring,"0");
692 if (tapefh)
694 FPutC(tapefh, '\t');
695 FPuts(tapefh, visledstring);
696 FPutC(tapefh, '\n');
697 Flush(tapefh);
699 break;
701 case STATE_OP:
702 break;
704 case STATE_RIGHTVAL:
705 GetRightValue();
706 matherr = DoOperation();
707 state = STATE_OP;
708 vallen = 0;
709 refresh_led = TRUE;
711 if (tapefh)
713 FPuts(tapefh,
714 (operation == BTYPE_ADD) ? "+" :
715 (operation == BTYPE_SUB) ? "-" :
716 (operation == BTYPE_DIV) ? ":" :
717 "×");
718 FPutC(tapefh, '\t');
719 FPuts(tapefh, visledstring);
720 FPutC(tapefh, '\n');
721 Flush(tapefh);
723 break;
725 } /* switch(state) */
727 operation = type;
728 break;
730 case BTYPE_EQU:
731 if (state == STATE_LEFTVAL)
733 GetLeftValue();
734 if (tapefh)
736 FPutC(tapefh, '\t');
737 FPuts(tapefh, visledstring);
738 FPutC(tapefh, '\n');
739 Flush(tapefh);
742 else if (state == STATE_RIGHTVAL)
744 GetRightValue();
745 if (tapefh)
747 FPuts(tapefh,
748 (operation == BTYPE_ADD) ? "+" :
749 (operation == BTYPE_SUB) ? "-" :
750 (operation == BTYPE_DIV) ? ":" :
751 "×");
752 FPutC(tapefh, '\t');
753 FPuts(tapefh, visledstring);
754 FPutC(tapefh, '\n');
755 Flush(tapefh);
759 matherr = DoOperation();
760 state = STATE_EQU;
762 vallen = 0;
764 if (!matherr)
766 RefreshLED();
767 if (tapefh)
769 FPuts(tapefh, "=\t");
770 FPuts(tapefh, visledstring);
771 FPutC(tapefh, '\n');
772 Flush(tapefh);
774 } else {
775 refresh_led = TRUE;
777 break;
779 } /* switch(type) */
781 if (matherr)
783 leftval = rightval = 0.0;
784 state = STATE_LEFTVAL;
785 operation = BTYPE_ADD;
786 vallen = 0;
787 strcpy(ledstring,matherr);
788 refresh_led = TRUE;
791 if (refresh_led) RefreshLED();
795 static void HandleAll(void)
797 struct IntuiMessage *msg;
798 WORD icode,i;
799 ULONG signals;
801 BOOL quitme = FALSE;
803 if (dotape) OpenTape();
805 while(!quitme)
807 signals = Wait(1L << win->UserPort->mp_SigBit | SIGBREAKF_CTRL_C);
809 if (signals & (1L << win->UserPort->mp_SigBit))
811 while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort)))
813 switch(msg->Class)
815 case IDCMP_CLOSEWINDOW:
816 quitme = TRUE;
817 break;
819 case IDCMP_REFRESHWINDOW:
820 GT_BeginRefresh(win);
821 GT_EndRefresh(win,TRUE);
822 break;
824 case IDCMP_GADGETUP:
825 HandleButton(((struct Gadget *)msg->IAddress)->GadgetID);
826 break;
828 case IDCMP_VANILLAKEY:
829 icode = toupper(msg->Code);
831 for(i = 0;i < NUM_BUTTONS;i++)
833 if ((icode == bi[i].key1) ||
834 (icode == bi[i].key2))
836 icode = bi[i].type;
837 break;
840 if (i < NUM_BUTTONS)
842 HandleButton(icode);
843 } else if (icode == 27)
845 quitme = TRUE;
847 break;
849 } /* switch(msg->Class) */
851 ReplyMsg((struct Message *)msg);
852 } /* while ((msg = (struct IntuiMessage *)GetMsg(win->UserPort))) */
853 } /* if(signals & (1L << win->UserPort->mp_SigBit)) */
854 if (signals & SIGBREAKF_CTRL_C)
855 quitme = TRUE;
857 } /* while(!quitme) */
860 int main(void)
862 OpenLibs();
863 GetArguments();
864 DoLocale();
865 GetVisual();
866 InitGUI();
867 MakeGadgets();
868 MakeWin();
869 HandleAll();
870 Cleanup(0);
871 return 0;