"Fossies" - the Fresh Open Source Software Archive 
Member "schily-2021-09-18/calc/calc.c" (20 Aug 2021, 9659 Bytes) of package /linux/privat/schily-2021-09-18.tar.bz2:
1 /* @(#)calc.c 1.27 21/08/20 Copyright 1985-2021 J. Schilling */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)calc.c 1.27 21/08/20 Copyright 1985-2021 J. Schilling";
6 #endif
7 /*
8 * Simples Taschenrechnerprogramm
9 *
10 * Copyright (c) 1985-2021 J. Schilling
11 */
12 /*
13 * The contents of this file are subject to the terms of the
14 * Common Development and Distribution License, Version 1.0 only
15 * (the "License"). You may not use this file except in compliance
16 * with the License.
17 *
18 * See the file CDDL.Schily.txt in this distribution for details.
19 * A copy of the CDDL is also available via the Internet at
20 * http://www.opensource.org/licenses/cddl1.txt
21 *
22 * When distributing Covered Code, include this CDDL HEADER in each
23 * file and include the License file CDDL.Schily.txt from this distribution.
24 */
25
26 #include <schily/stdio.h>
27 #include <schily/stdlib.h>
28 #include <schily/utypes.h>
29 #include <schily/standard.h>
30 #define GT_COMERR /* #define comerr gtcomerr */
31 #define GT_ERROR /* #define error gterror */
32 #include <schily/schily.h>
33 #ifdef FERR_DEBUG
34 #include <schily/termios.h>
35 #endif
36 #include <schily/nlsdefs.h>
37
38 #define LLEN 100
39
40 #define LSHIFT 1000
41 #define RSHIFT 1001
42
43 LOCAL void usage __PR((int));
44 EXPORT int main __PR((int, char **));
45 LOCAL void prdig __PR((int));
46 LOCAL void prlldig __PR((Llong));
47 LOCAL void kommentar __PR((void));
48 LOCAL int xbreakline __PR((char *, char *, char **, int));
49
50 LOCAL void
51 usage(exitcode)
52 int exitcode;
53 {
54 error("Usage: calc [options]\n");
55 error("Options:\n");
56 error(" -help Print this help.\n");
57 error(" -version Print version number.\n");
58 kommentar();
59 exit(exitcode);
60 /* NOTREACHED */
61 }
62
63 EXPORT int
64 main(ac, av)
65 int ac;
66 char **av;
67 {
68 int cac;
69 char * const* cav;
70 BOOL help = FALSE;
71 BOOL prversion = FALSE;
72 char eingabe[LLEN+1];
73 char *argumente[8];
74 int i;
75 int op = 0;
76 char *opstr;
77 Llong arg1;
78 Llong arg2;
79 Llong ergebnis;
80 Llong rest = (Llong)0;
81 int iarg1;
82 int iarg2;
83 int iergebnis;
84 int irest = 0;
85
86 save_args(ac, av);
87
88 (void) setlocale(LC_ALL, "");
89
90 #ifdef USE_NLS
91 #if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
92 #define TEXT_DOMAIN "calc" /* Use this only if it weren't */
93 #endif
94 { char *dir;
95 dir = searchfileinpath("share/locale", F_OK,
96 SIP_ANY_FILE|SIP_NO_PATH, NULL);
97 if (dir)
98 (void) bindtextdomain(TEXT_DOMAIN, dir);
99 else
100 #if defined(PROTOTYPES) && defined(INS_BASE)
101 (void) bindtextdomain(TEXT_DOMAIN, INS_BASE "/share/locale");
102 #else
103 (void) bindtextdomain(TEXT_DOMAIN, "/usr/share/locale");
104 #endif
105 (void) textdomain(TEXT_DOMAIN);
106 }
107 #endif /* USE_NLS */
108
109 cac = --ac;
110 cav = ++av;
111 if (getallargs(&cac, &cav, "help,version", &help, &prversion) < 0) {
112 errmsgno(EX_BAD, "Bad Option %s.\n", cav[0]);
113 usage(EX_BAD);
114 }
115 if (help)
116 usage(0);
117 if (prversion) {
118 gtprintf("Calc release %s %s (%s-%s-%s) Copyright (C) 1985, 89-91, 1996, 2000-2021 %s\n",
119 "1.27", "2021/08/20",
120 HOST_CPU, HOST_VENDOR, HOST_OS,
121 _("Jörg Schilling"));
122 exit(0);
123 }
124
125 putchar('?'); flush();
126 while (getline(eingabe, LLEN) >= 0 && !streql(eingabe, "quit")) {
127
128 opstr = eingabe;
129 while (*opstr == ' ' || *opstr == '\t')
130 opstr++;
131
132 /*
133 * optional Kommentarausgabe
134 */
135 if (streql(opstr, "help")) {
136 kommentar();
137 putchar('?'); flush();
138 continue;
139 }
140
141 /*
142 * Test des Formats und der Argumente
143 */
144 i = xbreakline(opstr, " \t", argumente, 5);
145 if (*argumente[i-1] == '\0')
146 i--;
147 switch (i) {
148
149 case 1:
150 if (*astoll(argumente[0], &ergebnis) != '\0') {
151 gtprintf("'%s' ist keine Zahl!\n?", argumente[0]);
152 continue;
153 }
154 iergebnis = (int)ergebnis;
155 goto print;
156 case 2:
157 op = *argumente[0];
158 if (op != '!' && op != '~') {
159 gtprintf("Unzulässiger Operator für: ");
160 gtprintf("'op argument1'\n?");
161 continue;
162 }
163 if (*astoll(argumente[1], &arg1) != '\0') {
164 gtprintf("'%s' ist keine Zahl!\n?", argumente[1]);
165 continue;
166 }
167 break;
168 case 3:
169 if (*astoll(argumente[0], &arg1) != '\0') {
170 gtprintf("'%s' ist keine Zahl!\n?", argumente[0]);
171 continue;
172 }
173 if (*astoll(argumente[2], &arg2) != '\0') {
174 gtprintf("'%s' ist keine Zahl!\n?", argumente[2]);
175 continue;
176 }
177 break;
178
179 default:
180 gtprintf("Die Eingabe hat nicht das richtige Format: ");
181 gtprintf("'argument1 op argument2'\n?");
182 continue;
183 }
184
185 /*
186 * Test der Operationssymbole
187 */
188 op = 0;
189 opstr = argumente[1];
190 if (i == 2)
191 opstr = argumente[0];
192
193 if (streql(opstr, "<<")) {
194 op = LSHIFT;
195 } else if (streql(opstr, ">>")) {
196 op = RSHIFT;
197 } else if (opstr[1] != '\0') {
198 gtprintf("Operationssymbole sind einstellig. Falsche Eingabe!\n?");
199 continue;
200 } else if (!op) {
201 op = *opstr;
202 }
203
204 i = 0;
205 iergebnis = (int)ergebnis;
206 iarg1 = (int)arg1;
207 iarg2 = (int)arg2;
208
209 switch (op) {
210
211 case '+':
212 ergebnis = arg1 + arg2;
213 iergebnis = iarg1 + iarg2;
214 break;
215 case '-':
216 ergebnis = arg1 - arg2;
217 iergebnis = iarg1 - iarg2;
218 break;
219 case '*':
220 ergebnis = arg1 * arg2;
221 iergebnis = iarg1 * iarg2;
222 break;
223 case LSHIFT:
224 ergebnis = (Ullong)arg1 << arg2;
225 iergebnis = (unsigned)iarg1 << iarg2;
226 break;
227 case RSHIFT:
228 ergebnis = (Ullong)arg1 >> arg2;
229 iergebnis = (unsigned)iarg1 >> iarg2;
230 break;
231 case '^':
232 ergebnis = arg1 ^ arg2;
233 iergebnis = iarg1 ^ iarg2;
234 break;
235 case '&':
236 ergebnis = arg1 & arg2;
237 iergebnis = iarg1 & iarg2;
238 break;
239 case '|':
240 ergebnis = arg1 | arg2;
241 iergebnis = iarg1 | iarg2;
242 break;
243 case '!':
244 ergebnis = !arg1;
245 iergebnis = !iarg1;
246 break;
247 case '~':
248 ergebnis = ~arg1;
249 iergebnis = ~iarg1;
250 break;
251 case '%':
252 case '/': if (arg2 == 0) {
253 gtprintf("Division durch Null ist unzulaessig.\n?");
254 i = 1;
255 break;
256 } else {
257 /*
258 * 9223372036854775808 / 322122547200
259 * liefert eine Integer(32) Division durch 0
260 */
261 ergebnis = arg1 / arg2;
262 rest = arg1 % arg2;
263 if (iarg2 == 0) {
264 /*
265 * Alle unteren 32 Bit sind 0
266 * Division durch Null verhindern.
267 */
268 iergebnis = irest = 0;
269 } else {
270 iergebnis = iarg1 / iarg2;
271 irest = iarg1 % iarg2;
272 }
273
274 if (op == '%') {
275 ergebnis = rest;
276 iergebnis = irest;
277 }
278 break;
279 }
280
281 default:
282 gtprintf("Unzulaessiger Operator!\n?");
283 i = 1;
284 break;
285 }
286 if (i == 1)
287 continue;
288
289 print:
290 /*
291 * Ausgabe
292 */
293 prdig(iergebnis);
294 if (op == '/') {
295 gtprintf("\nRest (dezimal): %d\n", irest);
296 prdig(irest);
297 }
298 putchar('\n');
299
300 prlldig(ergebnis);
301 if (op == '/') {
302 gtprintf("\nRest (dezimal): %lld\n", rest);
303 prlldig(rest);
304 }
305 putchar('\n');
306
307 putchar('?'); flush();
308 }
309 if (ferror(stdin)) {
310 #ifdef FERR_DEBUG
311 pid_t pgrp;
312 ioctl(STDIN_FILENO, TIOCGPGRP, (char *)&pgrp);
313 errmsg("Read error on stdin. pid %ld pgrp %ld tty pgrp %ld\n",
314 (long)getpid(), (long)getpgid(0), (long)pgrp);
315 #else
316 errmsg("Read error on stdin.\n");
317 #endif
318 }
319 return (0);
320 }
321
322 LOCAL void
323 prdig(n)
324 int n;
325 {
326 register int i;
327
328 printf(" = %d %u 0%o 0x%x\n = ", n, n, n, n);
329 if (n < 0)
330 putchar('1');
331 else
332 putchar('0');
333 for (i = 1; i <= 31; i++) {
334 /*
335 * New compilers like to make left shifting signed vars illegal
336 */
337 n = (int)(((unsigned int)n) << 1);
338 if (n < 0)
339 putchar('1');
340 else
341 putchar('0');
342 if (i%4 == 3)
343 putchar(' ');
344 }
345 }
346
347 LOCAL void
348 prlldig(n)
349 Llong n;
350 {
351 register int i;
352
353 printf(" = %lld %llu 0%llo 0x%llx\n = ", n, n, n, n);
354 if (n < 0)
355 putchar('1');
356 else
357 putchar('0');
358 for (i = 1; i <= 63; i++) {
359 /*
360 * New compilers like to make left shifting signed vars illegal
361 */
362 n = (Llong)(((ULlong)n) << 1);
363 if (n < 0)
364 putchar('1');
365 else
366 putchar('0');
367 if (i%4 == 3)
368 putchar(' ');
369 }
370 }
371
372 LOCAL void
373 kommentar()
374 {
375 error(" Taschenrechnerprogramm\n");
376 error(" ======================\n");
377 error("Das Programm wird verlassen durch die Eingabe: 'QUIT'\n");
378 error("Es kann jeweils eine binäre Operation aus {+,-,*,/,%%,<<,>>,^,&,|}\n");
379 error("oder eine unäre Operation aus {~,!} ausgeführt werden. Eine einzelne\n");
380 error("Zahl wird wie eine unäre Operation behandelt. Als Eingabe sind nur\n");
381 error("integer-Werte zugelassen, aber es ist egal, ob sie dezimal, oktal\n");
382 error("oder hexadezimal kodiert sind; auch verschiedene Kodierungen in einer\n");
383 error("Rechnung sind zulässig. Die Ausgabe erfolgt dezimal, oktal,\n");
384 error("hexadezimal und binär in zwei Darstellungen: 32 Bit sowie 64 Bit.\n");
385 error("'/' liefert zusätzlich den Rest (dezimal) bei ganzzahliger Division.\n");
386 error("\n");
387 error("***************************************************************\n");
388 error("* Die Eingabe muss folgendes Format haben: *\n");
389 error("* 'argument1 op argument2' oder *\n");
390 error("* 'op argument' oder *\n");
391 error("* 'argument' *\n");
392 error("***************************************************************\n");
393 }
394
395 /*--------------------------------------------------------------------------*/
396 #include <schily/string.h>
397
398 LOCAL int
399 xbreakline(buf, delim, array, len)
400 char *buf;
401 register char *delim;
402 register char *array[];
403 register int len;
404 {
405 register char *bp = buf;
406 register char *dp;
407 register int i;
408 register int found;
409
410 for (i = 0, found = 1; i < len; i++) {
411 for (dp = bp; *dp != '\0' && strchr(delim, *dp) == NULL; dp++)
412 ;
413
414 array[i] = bp;
415 if (*dp != '\0' && strchr(delim, *dp) != NULL) {
416 *dp++ = '\0';
417 found++;
418 }
419 while (*dp != '\0' && strchr(delim, *dp) != NULL)
420 dp++;
421 bp = dp;
422 }
423 if (found > len)
424 found = len;
425 return (found);
426 }