1: /*
2: * $Id: views.c,v 1.9 2026/01/07 19:51:33 snw Exp $
3: * implementation of VIEW command and $VIEW intrinsic function
4: *
5: *
6: * Author: Serena Willis <snw@coherent-logic.com>
7: * Copyright (C) 1998 MUG Deutschland
8: * Copyright (C) 2020, 2025 Coherent Logic Development LLC
9: *
10: *
11: * This file is part of FreeM.
12: *
13: * FreeM is free software: you can redistribute it and/or modify
14: * it under the terms of the GNU Affero Public License as published by
15: * the Free Software Foundation, either version 3 of the License, or
16: * (at your option) any later version.
17: *
18: * FreeM is distributed in the hope that it will be useful,
19: * but WITHOUT ANY WARRANTY; without even the implied warranty of
20: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21: * GNU Affero Public License for more details.
22: *
23: * You should have received a copy of the GNU Affero Public License
24: * along with FreeM. If not, see <https://www.gnu.org/licenses/>.
25: *
26: * $Log: views.c,v $
27: * Revision 1.9 2026/01/07 19:51:33 snw
28: * Fix segfault in reverse $QUERY
29: *
30: * Revision 1.8 2025/04/09 19:52:02 snw
31: * Eliminate as many warnings as possible while building with -Wall
32: *
33: * Revision 1.7 2025/04/02 03:02:42 snw
34: * Stop requiring users to pass -e to fmadm when -u or -g are passed
35: *
36: * Revision 1.6 2025/03/09 19:50:47 snw
37: * Second phase of REUSE compliance and header reformat
38: *
39: *
40: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
41: * SPDX-License-Identifier: AGPL-3.0-or-later
42: **/
43:
44: #include <stdlib.h>
45:
46: #include "mpsdef.h"
47: #include "mwapi_window.h"
48:
49: #define LOCK 'l'
50:
51: /* system services */
52:
53: #include <signal.h>
54:
55: #if defined(__NetBSD__) || defined(__OpenBSD__) || defined(__linux__)
56: #include <sys/ioctl.h>
57: #endif
58:
59:
60: #if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(EMSCRIPTEN)
61: # if defined(__FreeBSD__) || defined(__NetBSD__) || defined(__OpenBSD__) || defined(__AMIGA)
62: # include <termios.h>
63: # if !defined(__AMIGA)
64: # define TCGETA TIOCGETA
65: # define TCSETA TIOCSETA
66: # endif
67: # define termio termios
68: # else
69: # if !defined(MSDOS) && !defined(__linux__)
70: # include <termio.h>
71: # else
72: # include <termios.h>
73: # define termio termios
74: # endif
75: # endif
76: #else
77: # include <termios.h>
78: #endif
79:
80:
81: #ifdef __CYGWIN__
82: #include <errno.h>
83: #endif /* __CYGWIN__ */
84: #include <errno.h> /* snw */
85:
86:
87: #include <fcntl.h>
88: #include <unistd.h>
89: #include <time.h>
90: #include <string.h>
91: #include <stdio.h>
92: #include "shmmgr.h"
93:
94: /* 01/18/99 rlf Apparently, tell disappeared with libc-6 */
95: #if defined(LINUX_GLIBC) || defined(__APPLE__)
96:
97: long int tell (int fd)
98: {
99: return lseek (fd, 0, SEEK_CUR);
100: }
101:
102: #else
103: long int tell ();
104: #endif /* LINUX_GLIBC */
105:
106:
107: #if defined(MWAPI_GTK)
108: void destroy(GtkWidget* widget, gpointer data)
109: {
110: gtk_main_quit();
111: }
112: #endif
113:
114:
115: void view_com (void)
116: {
117: /* process VIEW command */
118:
119: int arg1;
120: register long int i;
121: register long int j;
122: register long int ch;
123:
124: if (*codptr == SP || *codptr == EOL) { /* no argument form of VIEW */
125: merr_raise (ARGER);
126: return;
127: }
128:
129: expr (STRING);
130:
131: arg1 = intexpr (argptr);
132:
133: if (merr () > OK) return;
134:
135: if (*codptr == ':') {
136:
137: codptr++;
138:
139: expr (STRING);
140:
141: if (merr () > OK) return;
142:
143: switch (arg1) {
144:
145:
146: /* VIEW 52: G0 input translation table */
147: case 52:
148:
149: stcpy0 (G0I[io], argptr, 256L);
150:
151: for (i = 0; i < 256; i++) {
152:
153: if (G0I[io][i] == EOL) {
154:
155: while (i < 256) {
156: G0I[io][i] = (char) i;
157: i++;
158: }
159:
160: break;
161: }
162:
163: }
164:
165: break;
166:
167:
168: /* VIEW 53: G0 output translation table */
169: case 53:
170:
171: stcpy0 (G0O[io], argptr, 256L);
172:
173: for (i = 0; i < 256; i++) {
174:
175: if (G0O[io][i] == EOL) {
176:
177: while (i < 256) {
178: G0O[io][i] = (char) i;
179: i++;
180: }
181:
182: break;
183: }
184:
185: }
186:
187: break;
188:
189:
190: /* VIEW 54: G1 input translation table */
191: case 54:
192:
193: stcpy0 (G1I[io], argptr, 256L);
194:
195: for (i = 0; i < 256; i++) {
196:
197: if (G1I[io][i] == EOL) {
198:
199: while (i < 256) {
200: G1I[io][i] = (char) i;
201: i++;
202: }
203:
204: break;
205:
206: }
207:
208: }
209:
210: break;
211:
212:
213: /* VIEW 55: G1 output translation table */
214: case 55:
215:
216: stcpy0 (G1O[io], argptr, 256L);
217:
218: for (i = 0; i < 256; i++) {
219:
220: if (G1O[io][i] == EOL) {
221:
222: while (i < 256) {
223: G1O[io][i] = (char) i;
224: i++;
225: }
226:
227: break;
228:
229: }
230:
231: }
232:
233: break;
234:
235:
236: /* VIEW 62: random: seed number */
237: case 62:
238:
239: i = intexpr (argptr);
240:
241: if (merr () == MXNUM) return;
242:
243: if (i < 0) {
244: merr_raise (ARGER);
245: }
246: else {
247: nrandom = i;
248: }
249:
250: break;
251:
252:
253: /* VIEW 63: random: parameter a */
254: case 63:
255:
256: i = intexpr (argptr);
257:
258: if (merr () == MXNUM) return;
259:
260: if (i <= 0) {
261: merr_raise (ARGER);
262: }
263: else {
264: ran_a = i;
265: }
266:
267: break;
268:
269:
270: /* VIEW 64: random: parameter b */
271: case 64:
272:
273: i = intexpr (argptr);
274:
275: if (merr () == MXNUM) return;
276:
277: if (i < 0) {
278: merr_raise (ARGER);
279: }
280: else {
281: ran_b = i;
282: }
283:
284: break;
285:
286:
287: /* VIEW 65: random: parameter c */
288: case 65:
289:
290: i = intexpr (argptr);
291:
292: if (merr () == MXNUM) return;
293:
294: if (i <= 0) {
295: merr_raise (ARGER);
296: }
297: else {
298: ran_c = i;
299: }
300:
301: break;
302:
303:
304: /* VIEW 66: SIGTERM handling flag */
305: case 66:
306:
307: killerflag = tvexpr (argptr);
308:
309: break;
310:
311:
312: /* VIEW 67: SIGHUP handling flag */
313: case 67:
314:
315: huperflag = tvexpr (argptr);
316:
317: break;
318:
319:
320: /* ... reserved ... */
321:
322: /* VIEW 70: ZSORT/ZSYNTAX flag */
323: case 70:
324:
325: s_fun_flag = tvexpr (argptr);
326:
327: break;
328:
329:
330: /* VIEW 71: ZNEXT/ZNAME flag */
331: case 71:
332:
333: n_fun_flag = tvexpr (argptr);
334:
335: break;
336:
337:
338: /* VIEW 72: ZPREVIOUS/ZPIECE flag */
339: case 72:
340:
341: p_fun_flag = tvexpr (argptr);
342:
343: break;
344:
345:
346: /* VIEW 73: ZDATA/ZDATE flag */
347: case 73:
348:
349: d_fun_flag = tvexpr (argptr);
350:
351: break;
352:
353:
354: /* VIEW 79: old ZJOB vs. new ZJOB flag */
355: case 79:
356:
357: zjobflag = tvexpr (argptr);
358:
359: break;
360:
361:
362: /* VIEW 80: 7 vs. 8 bit flag */
363: case 80:
364:
365: eightbit = tvexpr (argptr);
366:
367: break;
368:
369:
370: /* VIEW 81: PF1 flag */
371: case 81:
372:
373: PF1flag = tvexpr (argptr);
374:
375: break;
376:
377:
378: /* VIEW 82: not used */
379: /* VIEW 83: text in $ZE flag */
380: case 83:
381:
382: etxtflag = tvexpr (argptr);
383:
384: break;
385:
386:
387: /* VIEW 84: not used */
388: /* VIEW 85: not used */
389: /* VIEW 86: not used */
390:
391: case 87: /* VIEW 87: date type definition */
392:
393: i = intexpr (argptr);
394:
395: if (i < 0 || i >= NO_DATETYPE) {
396: merr_raise (ARGER);
397: return;
398: }
399:
400: if (*codptr != ':') {
401: datetype = i;
402: break;
403: }
404:
405: if (i == 0) {
406: merr_raise (ARGER);
407: return;
408: }
409:
410: codptr++;
411:
412: expr (STRING);
413:
414: j = intexpr (argptr);
415:
416: if (*codptr != ':') {
417: merr_raise (ARGER);
418: return;
419: }
420:
421: codptr++;
422:
423: expr (STRING);
424:
425: if (j > 0 && j < 15 && stlen (argptr) > MONTH_LEN) {
426: merr_raise (M75);
427: }
428: else if (j > 0 && j < 13) {
429: stcpy (month[i][j - 1], argptr);
430: }
431: else if (j == 13) {
432: stcpy (dat1char[i], argptr);
433: }
434: else if (j == 14) {
435: stcpy (dat2char[i], argptr);
436: }
437: else if (j == 15) {
438: dat3char[i] = (*argptr);
439: }
440: else if (j == 16) {
441:
442: if ((j = intexpr (argptr)) < 0 || j > 2) {
443: merr_raise (ARGER);
444: return;
445: }
446:
447: dat4flag[i] = j;
448:
449: }
450: else if (j == 17) {
451: dat5flag[i] = tvexpr (argptr);
452: }
453: else if (j == 18) {
454: if ((j = intexpr (argptr) + 672411L) <= 0L) {
455: merr_raise (ARGER);
456: return;
457: }
458: datGRbeg[i] = j;
459: }
460: else {
461: merr_raise (ARGER);
462: }
463:
464: if (merr () > OK) return;
465:
466: break;
467:
468:
469: case 88: /* VIEW 88: time type definition */
470:
471: i = intexpr (argptr);
472:
473: if (i < 0 || i >= NO_TIMETYPE) {
474: merr_raise (ARGER);
475: return;
476: }
477:
478: if (*codptr != ':') {
479: timetype = i;
480: break;
481: }
482:
483: codptr++;
484:
485: expr (STRING);
486:
487: j = intexpr (argptr);
488:
489: if (*codptr != ':') {
490: merr_raise (ARGER);
491: return;
492: }
493:
494: codptr++;
495:
496: expr (STRING);
497:
498: if (j == 1) {
499: tim1char[i] = (*argptr);
500: }
501: else if (j == 2) {
502: tim2char[i] = (*argptr);
503: }
504: else if (j == 3) {
505: tim3char[i] = (*argptr);
506: }
507: else if (j == 4) {
508: tim4flag[i] = tvexpr (argptr);
509: }
510: else if (j == 5) {
511: tim5flag[i] = tvexpr (argptr);
512: }
513: else {
514: merr_raise (ARGER);
515: }
516:
517: if (merr () > OK) return;
518:
519: break;
520:
521:
522: case 91: /* VIEW 91: missing QUIT expr default expression */
523:
524: stcpy (exfdefault, argptr);
525:
526: break;
527:
528:
529: case 92: /* VIEW 92: EUR2DEM: type mismatch error */
530:
531: typemmflag = tvexpr (argptr);
532:
533: break;
534:
535:
536: case 93: /* VIEW 93: zkey production rule definition */
537:
538: i = intexpr (argptr);
539:
540: if (i < 1 || i > NO_V93) {
541: merr_raise (ARGER);
542: return;
543: }
544:
545: if (*codptr != ':') {
546: v93 = i;
547: break;
548: }
549:
550: codptr++;
551:
552: expr (STRING);
553:
554: stcpy (v93a[i - 1], argptr);
555:
556: break;
557:
558:
559: case 96: /* VIEW 96: global prefix */
560:
561: if (stlen (argptr) > MONTH_LEN) {
562: merr_raise (M75);
563: }
564: else {
565: stcpy (glo_prefix, argptr);
566: }
567:
568: break;
569:
570:
571: case 97: /* VIEW 97: global postfix */
572:
573: if (stlen (argptr) > MONTH_LEN) {
574: merr_raise (M75);
575: }
576: else {
577: stcpy (glo_ext, argptr);
578: }
579:
580: break;
581:
582:
583: case 98: /* VIEW 98: routine extension */
584:
585: if (stlen (argptr) > MONTH_LEN) {
586: merr_raise (M75);
587: }
588: else {
589: stcpy (rou_ext, argptr);
590: }
591:
592: break;
593:
594:
595: case 101: /* VIEW 101: set ierr */
596:
597: merr_raise (intexpr (argptr));
598:
599: break;
600:
601: case 102: /* VIEW 102 set deferred_ierr */
602:
603: deferred_ierr = intexpr (argptr);
604:
605: break;
606:
607:
608: case 103: /* MERGE to ^$WINDOW complete. Parameter is empty (for all windows) or string for window name in subscript 1 */
609: #if defined(MWAPI_GTK)
610: mwapi_on_merge_complete (argptr);
611: #endif
612: break;
613:
614:
615:
616: #if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(__AMIGA) && !defined(EMSCRIPTEN) && !defined(MSDOS)
617:
618: case 113: /* VIEW 113: set termio infos */
619: {
620:
621: struct termio tpara;
622:
623: i = intexpr (argptr);
624:
625: if (i < 1 || i > MAXDEV) {
626: merr_raise (NODEVICE);
627: }
628: else if (devopen[i] == 0) {
629: merr_raise (NOPEN);
630: }
631: else if (*codptr != ':') {
632: merr_raise (ARGER);
633: }
634: else {
635:
636: codptr++;
637:
638: expr (STRING);
639:
640: j = intexpr (argptr);
641:
642: }
643:
644: if (merr () > OK) return;
645:
646: ioctl (fileno (opnfile[i]), TCGETA, &tpara);
647:
648: j = 0;
649:
650: tpara.c_iflag = intexpr (argptr);
651:
652: while ((ch = argptr[j]) != EOL) {
653:
654: j++;
655:
656: if (ch == ':') break;
657:
658: }
659:
660: tpara.c_oflag = intexpr (&argptr[j]);
661:
662: while ((ch = argptr[j]) != EOL) {
663:
664: j++;
665:
666: if (ch == ':') break;
667:
668: }
669:
670: tpara.c_cflag = intexpr (&argptr[j]);
671:
672: while ((ch = argptr[j]) != EOL) {
673:
674: j++;
675:
676: if (ch == ':') break;
677:
678: }
679:
680: tpara.c_lflag = intexpr (&argptr[j]);
681:
682: ioctl (fileno (opnfile[i]), TCSETA, &tpara);
683:
684: return;
685:
686: }
687:
688: #endif /* __APPLE__ */
689:
690:
691: /* VIEW 133: remember ZLOAD directory on ZSAVE */
692: case 133:
693:
694: zsavestrategy = tvexpr (argptr);
695:
696: return;
697:
698:
699: default:
700:
701: merr_raise (ARGER);
702: return;
703:
704: } /* end switch one parameter VIEWs */
705: }
706: else { /* no parameters VIEWs */
707:
708: switch (arg1) {
709:
710:
711: /* VIEW 21: close all globals */
712: case 21:
713:
714: close_all_globals ();
715:
716: return;
717:
718:
719:
720: /* VIEW 29: symtab copy */
721: case 29: /* get space if needed */
722:
723: if (apartition == NULL) apartition = calloc ((unsigned) (PSIZE + 1), 1);
724:
725: for (i = 0; i <= PSIZE; i++) apartition[i] = partition[i];
726:
727: asymlen = symlen;
728:
729: for (i = 0; i < 128; i++) aalphptr[i] = alphptr[i];
730:
731: return;
732:
733: }
734:
735: merr_raise (ARGER);
736: return;
737:
738: }
739:
740: return;
741: } /* end view_com() */
742:
743: /*
744: * f = number of arguments
745: * a = the arguments
746: */
747: void view_fun (int f, char *a) /* process VIEW function */
748: {
749: int i;
750:
751: if (standard) {
752: merr_raise (NOSTAND);
753: return;
754: } /* non_standard */
755:
756: if (f == 1) {
757:
758: f = intexpr (a);
759:
760: switch (f) {
761:
762: /* $V(21) returns size of last global */
763: case 21:
764:
765: if (oldfil[inuse][0] != NUL) {
766:
767: lseek (olddes[inuse], 0L, 2);
768: lintstr (a, (long) tell (olddes[inuse]));
769:
770: }
771: else {
772: *a = EOL;
773: }
774:
775: break;
776:
777:
778: /* $V(22): number of v22_aliases */
779: case 22:
780:
781: i = 0;
782: f = 0;
783:
784: while (f < v22ptr) {
785: i++;
786: f += UNSIGN (v22ali[f]) + 1;
787: }
788:
789: intstr (a, i);
790:
791: break;
792:
793:
794: /* $V(23): contents of 'input buffer' */
795: case 23:
796:
797: stcpy (a, ug_buf[io]);
798: break;
799:
800:
801: /* $V(24)/$V(25) number of screen lines */
802: case 24:
803: case 25:
804:
805: intstr (a, N_LINES);
806: break;
807:
808:
809: /* $V(26): DO-FOR-XEC stack pointer */
810: case 26:
811:
812: intstr (a, nstx);
813: break;
814:
815:
816: /* $V(27): DO-FOR-XEC stack pointer (copy on error) */
817: case 27:
818:
819: intstr (a, nesterr);
820: break;
821:
822:
823: /* $V(30): number of mumps arguments */
824: case 30:
825:
826: intstr (a, m_argc);
827: break;
828:
829:
830: /* $V(31): environment variables */
831: case 31:
832:
833: f = 0;
834:
835: while (m_envp[f] && m_envp[f][0] != NUL) f++;
836:
837: intstr (a, f);
838: break;
839:
840:
841: /* $V(52): G0 input translation table */
842: case 52:
843:
844: stcpy0 (a, G0I[io], 257L);
845: a[255] = EOL;
846: break;
847:
848:
849: /* $V(53): G0 output translation table */
850: case 53:
851:
852: stcpy0 (a, G0O[io], 257L);
853: a[255] = EOL;
854:
855: break;
856:
857:
858: /* $V(54): G1 input translation table */
859: case 54:
860:
861: stcpy0 (a, G1I[io], 257L);
862: a[255] = EOL;
863:
864: break;
865:
866:
867: /* $V(55): G1 output translation table */
868: case 55:
869:
870: stcpy0 (a, G1O[io], 257L);
871: a[255] = EOL;
872:
873: break;
874:
875:
876: /* $V(60): partial pattern match flag */
877: case 60:
878:
879: intstr (a, pattrnflag);
880: break;
881:
882:
883: /* $V(61): partial pattern supplement character */
884: case 61:
885:
886: a[0] = pattrnchar;
887: a[1] = EOL;
888:
889: break;
890:
891:
892: /* $V(62): random: seed number */
893: case 62:
894:
895: lintstr (a, nrandom);
896: break;
897:
898:
899: /* $V(63): random: parameter a */
900: case 63:
901:
902: lintstr (a, ran_a);
903: break;
904:
905:
906: /* $V(64): random: parameter b */
907: case 64:
908:
909: lintstr (a, ran_b);
910: break;
911:
912:
913: /* $V(65): random: parameter c */
914: case 65:
915:
916: lintstr (a, ran_c);
917: break;
918:
919:
920: /* $V(66): SIGTERM handling flag */
921: case 66:
922:
923: intstr (a, killerflag);
924: break;
925:
926:
927: /* $V(67): SIGHUP handling flag */
928: case 67:
929:
930: intstr (a, huperflag);
931: break;
932:
933:
934: /* ... reserved ... */
935:
936:
937: /* $V(70): ZSORT/ZSYNTAX flag */
938: case 70:
939:
940: intstr (a, s_fun_flag);
941: break;
942:
943:
944: /* $V(71): ZNEXT/ZNAME flag */
945: case 71:
946:
947: intstr (a, n_fun_flag);
948: break;
949:
950:
951: /* $V(72): ZPREVIOUS/ZPIECE flag */
952: case 72:
953:
954: intstr (a, p_fun_flag);
955: break;
956:
957:
958: /* $V(73): ZDATA/ZDATE flag */
959: case 73:
960:
961: intstr (a, d_fun_flag);
962: break;
963:
964:
965: /* ... reserved ... */
966:
967:
968: /* $V(79): old ZJOB vs. new ZJOB flag */
969: case 79:
970:
971: intstr (a, zjobflag);
972: break;
973:
974:
975: /* $V(80): 7 vs. 8 bit flag */
976: case 80:
977:
978: intstr (a, eightbit);
979: break;
980:
981:
982: /* $V(81): PF1 flag */
983: case 81:
984:
985: intstr (a, PF1flag);
986: break;
987:
988:
989: /* $V(82): order counter */
990: case 82:
991:
992: intstr (a, ordercounter);
993: break;
994:
995:
996: /* $V(83): text in $ZE flag */
997: case 83:
998:
999: intstr (a, etxtflag);
1000: break;
1001:
1002:
1003: /* $V(84): path of current routine */
1004: case 84: /* look whether we know where the routine came from */
1005:
1006: for (i = 0; i < NO_OF_RBUF; i++) {
1007:
1008: int j;
1009:
1010: if (pgms[i][0] == 0) {
1011: *a = EOL;
1012: return;
1013: } /* buffer empty */
1014:
1015: j = 0;
1016:
1017: while (rou_name[j] == pgms[i][j]) {
1018:
1019: if (rou_name[j++] == EOL) {
1020:
1021: stcpy (a, path[i]);
1022: i = stlen (a);
1023:
1024: if (i > 0) a[i - 1] = EOL;
1025:
1026: return;
1027:
1028: }
1029:
1030: }
1031:
1032: }
1033:
1034: *a = EOL;
1035:
1036: break; /* not found */
1037:
1038:
1039: /* $V(85): path of last global */
1040: case 85:
1041:
1042: if (oldfil[inuse][0]) {
1043: stcpy (a, oldfil[inuse]);
1044: }
1045: else {
1046: *a = EOL;
1047: }
1048:
1049: i = 0;
1050:
1051: while (a[i] != EOL) {
1052:
1053: if (a[i] == '^') {
1054:
1055: if (i > 0) {
1056: i--;
1057: }
1058:
1059: a[i] = EOL;
1060:
1061: break;
1062:
1063: }
1064:
1065: i++;
1066:
1067: }
1068:
1069: break;
1070:
1071:
1072: /* $V(86): path of current device */
1073: case 86:
1074:
1075: stcpy (a, act_oucpath[io]);
1076: break;
1077:
1078:
1079: /* $V(87): date type definitions */
1080: case 87:
1081:
1082: intstr (a, datetype);
1083: break;
1084:
1085:
1086: /* $V(88): date type definitions */
1087: case 88:
1088:
1089: intstr (a, timetype);
1090: break;
1091:
1092:
1093: /* $V(91): missig QUIT expr default expression */
1094: case 91:
1095:
1096: stcpy (a, exfdefault);
1097: break;
1098:
1099:
1100: /* $V(92): type mismatch error */
1101: case 92:
1102:
1103: intstr (a, typemmflag);
1104: break;
1105:
1106:
1107: /* $V(93): zkey production default rule definition */
1108: case 93:
1109:
1110: lintstr (a, v93);
1111: break;
1112:
1113:
1114: /* $V(98): routine extention */
1115: case 98:
1116:
1117: stcpy (a, rou_ext);
1118: break;
1119:
1120: /* $V(100): exit status of last kill */
1121: case 100:
1122:
1123: intstr (a, v100);
1124: break;
1125:
1126: /* $V(114): Number of rows in terminal */
1127: case 114:
1128:
1129: intstr (a, n_lines);
1130: break;
1131:
1132:
1133: /* $V(115): Number of columns in terminal */
1134: case 115:
1135:
1136: intstr (a, n_columns);
1137: break;
1138:
1139:
1140: /* $V(133): remember ZLOAD directory on ZSAVE */
1141: case 133:
1142:
1143: intstr (a, zsavestrategy);
1144: break;
1145:
1146:
1147: default:
1148:
1149: merr_raise (ARGER);
1150: return;
1151:
1152: }
1153:
1154: return;
1155: }
1156:
1157: if (f == 2) {
1158:
1159: char tmp[256];
1160:
1161: stcpy (tmp, argstck[arg + 1]);
1162:
1163: i = intexpr (argstck[arg + 1]);
1164: f = intexpr (a);
1165:
1166: if (merr () == MXNUM) return;
1167:
1168: if (f == 16) {
1169:
1170: if (i <= OK || i >= MAXERR) {
1171: merr_raise (ARGER);
1172: return;
1173: }
1174: else {
1175: stcpy (a, errmes[i]);
1176: }
1177:
1178: }
1179: else if (f == 22) { /* return v22_alias entry */
1180:
1181: if (i) { /* give one of the names which are aliases */
1182:
1183: f = 0;
1184:
1185: while (f < v22ptr) {
1186:
1187: i--;
1188:
1189: if (i == 0) {
1190: stcpy (a, &v22ali[f + 1]);
1191: return;
1192: }
1193:
1194: f += UNSIGN (v22ali[f]) + 1;
1195:
1196: }
1197:
1198: a[0] = EOL;
1199:
1200: return; /* that number had no entry in the table */
1201:
1202: }
1203:
1204: if (tstglvn (tmp) == FALSE) {
1205: merr_raise (INVREF);
1206: return;
1207: }
1208:
1209: if (v22ptr) { /* there are aliases */
1210:
1211: int k, j;
1212:
1213: i = 0;
1214:
1215: while (i < v22ptr) {
1216:
1217: k = i + UNSIGN (v22ali[i]) + 1;
1218: j = 0; /* is current reference an alias ??? */
1219:
1220: while (v22ali[++i] == tmp[j]) {
1221:
1222: if (v22ali[i] == EOL) break;
1223:
1224: j++;
1225:
1226: }
1227:
1228: /* yes, it is, return it */
1229: if (v22ali[i] == EOL && tmp[j] == EOL) {
1230: stcpy (a, &v22ali[i + 1]);
1231: return;
1232: }
1233:
1234: i = k;
1235:
1236: }
1237:
1238: }
1239:
1240: a[0] = EOL; /* entry was not in the table */
1241:
1242: return;
1243:
1244: }
1245: else if (f == 24) { /* return screen line */
1246:
1247: if (i < -N_LINES || i > N_LINES || i == 0) {
1248: *a = EOL;
1249: }
1250: else if (i < 0) {
1251:
1252: stcpy0 (a, (*screen).screena[(unsigned int) (*screen).sclines[-i - 1]], (long) N_COLUMNS);
1253: a[80] = EOL;
1254:
1255: return;
1256:
1257: }
1258: else {
1259:
1260: stcpy0 (a, (*screen).screenx[(unsigned int) (*screen).sclines[i - 1]], (long) N_COLUMNS);
1261: a[80] = EOL;
1262:
1263: return;
1264:
1265: }
1266: }
1267: else if (f == 25) { /* return screen line with attribute */
1268:
1269: i--;
1270:
1271: if (i < 0 || i >= N_LINES) {
1272: *a = EOL;
1273: }
1274: else {
1275: v25 (a, i);
1276: }
1277:
1278: return;
1279:
1280: }
1281: else if (f == 26) { /* $V(26) returns DO-FOR-XEC stack pointer */
1282:
1283: if (i < 1 || i > nstx) {
1284: merr_raise (ARGER);
1285: return;
1286: }
1287:
1288: getraddress (a, i);
1289:
1290: return;
1291:
1292: } /* $V(27) returns DO-FOR-XEC stack pointer(error state) */
1293: else if (f == 27) {
1294:
1295: if (i < 1 || i > nesterr) {
1296: merr_raise (ARGER);
1297: return;
1298: }
1299:
1300: stcpy (a, callerr[i]);
1301:
1302: return;
1303:
1304: }
1305: else if (f == 30) { /* $V(30): arguments of mumps */
1306:
1307: if (i < 1 || i > m_argc) {
1308: merr_raise (ARGER);
1309: return;
1310: }
1311:
1312: strcpy (a, m_argv[i - 1]);
1313: a[strlen (a)] = EOL;
1314:
1315: return;
1316:
1317: /* guard against very long environment name=value entries */
1318: }
1319: else if (f == 31) { /* $V(31): environment variables */
1320:
1321: f = 0;
1322:
1323: while (m_envp[f] && m_envp[f++][0] != NUL) {
1324:
1325: if (f != i) continue;
1326:
1327: if ((f = strlen (m_envp[i - 1])) > STRLEN) {
1328: merr_raise (M75);
1329: return;
1330: }
1331:
1332: strcpy (a, m_envp[i - 1]);
1333: a[f] = EOL;
1334:
1335: return;
1336:
1337: }
1338:
1339: merr_raise (ARGER);
1340: return;
1341:
1342: }
1343: else if (f == 93) { /* $V(93): zkey production rule definition */
1344:
1345: if (i <= 0 || i > NO_V93) {
1346: merr_raise (ARGER);
1347: }
1348: else {
1349: strcpy (a, v93a[i - 1]);
1350: }
1351:
1352: return;
1353:
1354: }
1355: #if !defined(__APPLE__) && !defined(__gnu_hurd__) && !defined(__AMIGA) && !defined(EMSCRIPTEN) && !defined(MSDOS)
1356: else if (f == 113) { /* $V(113): get termio infos */
1357:
1358: struct termio tpara;
1359:
1360: if (i < 1 || i > MAXDEV) {
1361: merr_raise (NODEVICE);
1362: return;
1363: }
1364:
1365: if (devopen[i] == 0) {
1366: merr_raise (NOPEN);
1367: return;
1368: }
1369:
1370: ioctl (fileno (opnfile[i]), TCGETA, &tpara);
1371:
1372: intstr (a, tpara.c_iflag);
1373: i = stlen (a);
1374: a[i++] = ':';
1375:
1376: intstr (&a[i], tpara.c_oflag);
1377: i = stlen (a);
1378: a[i++] = ':';
1379:
1380: intstr (&a[i], tpara.c_cflag);
1381: i = stlen (a);
1382: a[i++] = ':';
1383:
1384: intstr (&a[i], tpara.c_lflag);
1385:
1386: return;
1387:
1388: }
1389: #endif
1390: else {
1391: merr_raise (ARGER);
1392: return;
1393: }
1394:
1395: }
1396: else if (f == 3) {
1397:
1398: char tmp[256];
1399:
1400: stcpy (tmp, argstck[arg + 2]);
1401: i = intexpr (argstck[arg + 1]);
1402: f = intexpr (a);
1403:
1404: if (merr () == MXNUM) return;
1405:
1406: if (f == 87) { /* $V(87): date type definitions */
1407:
1408: if (i < 0 || i >= NO_DATETYPE) {
1409: merr_raise (ARGER);
1410: return;
1411: }
1412:
1413: f = intexpr (tmp);
1414:
1415: if (f > 0 && f < 13) {
1416: stcpy (a, month[i][f - 1]);
1417: return;
1418: }
1419:
1420: switch (f) {
1421:
1422:
1423: case 13:
1424:
1425: {
1426: stcpy (a, dat1char[i]);
1427: return;
1428: }
1429:
1430:
1431: case 14:
1432:
1433: {
1434: stcpy (a, dat2char[i]);
1435: return;
1436: }
1437:
1438:
1439: case 15:
1440:
1441: {
1442: a[0] = dat3char[i];
1443: a[1] = EOL;
1444:
1445: return;
1446: }
1447:
1448:
1449: case 16:
1450:
1451: {
1452: a[0] = dat4flag[i] + '0';
1453: a[1] = EOL;
1454:
1455: return;
1456: }
1457:
1458:
1459: case 17:
1460:
1461: {
1462: a[0] = dat5flag[i] + '0';
1463: a[1] = EOL;
1464:
1465: return;
1466: }
1467:
1468:
1469: case 18:
1470:
1471: {
1472: lintstr (a, datGRbeg[i] - 672411L);
1473: return;
1474: }
1475:
1476:
1477: }
1478: }
1479: else if (f == 88) { /* $V(88): time type definitions */
1480:
1481: if (i < 0 || i >= NO_TIMETYPE) {
1482: merr_raise (ARGER);
1483: return;
1484: }
1485:
1486: f = intexpr (tmp);
1487:
1488: switch (f) {
1489: case 1:
1490:
1491: {
1492: a[0] = tim1char[i];
1493: a[1] = EOL;
1494:
1495: return;
1496: }
1497:
1498:
1499: case 2:
1500:
1501: {
1502: a[0] = tim2char[i];
1503: a[1] = EOL;
1504:
1505: return;
1506: }
1507:
1508:
1509: case 3:
1510:
1511: {
1512: a[0] = tim3char[i];
1513: a[1] = EOL;
1514:
1515: return;
1516: }
1517:
1518:
1519: case 4:
1520:
1521: {
1522: a[0] = tim4flag[i] + '0';
1523: a[1] = EOL;
1524:
1525: return;
1526: }
1527:
1528:
1529: case 5:
1530:
1531: {
1532: a[0] = tim5flag[i] + '0';
1533: a[1] = EOL;
1534:
1535: return;
1536: }
1537:
1538:
1539: }
1540:
1541: }
1542:
1543: merr_raise (ARGER);
1544: return;
1545:
1546: }
1547: else {
1548: merr_raise (FUNARG);
1549: return;
1550: }
1551:
1552: return;
1553: } /* end view_fun() */
1554:
1555:
1556: void m_tolower (char *str)
1557: {
1558: int ch;
1559:
1560: while ((ch = *str) != EOL) {
1561:
1562: ch = *str;
1563:
1564: if (ch <= 'Z' && ch >= 'A') {
1565: ch += 32;
1566: *str = ch;
1567: }
1568:
1569: str++;
1570:
1571: }
1572:
1573: return;
1574:
1575: } /* end tolower() */
1576:
1577:
1578: /*
1579: * size = desired size for 'partition'
1580: */
1581: short int newpsize (long size)
1582: {
1583: char *newpart = NULL;
1584: char *anewpart = NULL;
1585: long dif, j;
1586:
1587: if (size == PSIZE) return 0; /* nothing changes */
1588: if (size <= (PSIZE - symlen + 512)) return 0; /* cannot decrease it now */
1589: if (apartition && size <= (PSIZE - asymlen + 512)) return 0; /* cannot decrease it now */
1590:
1591: if (writing_mb) {
1592: newpart = shm_alloc ((size_t) (size+1));
1593: }
1594: else {
1595: newpart = calloc ((unsigned) (size + 1), 1);
1596: }
1597:
1598: if (newpart == NULL) return 1; /* could not allocate stuff */
1599:
1600: if (apartition) {
1601:
1602: anewpart = calloc ((unsigned) (size + 1), 1);
1603:
1604: if (anewpart == NULL) {
1605: free (newpart);
1606: return 1;
1607: }
1608: /* no more space */
1609:
1610: }
1611:
1612: dif = argptr - partition + 256;
1613:
1614: if (dif > PSIZE) dif = PSIZE;
1615:
1616: stcpy0 (newpart, partition, dif); /* intermediate results */
1617: dif = size - PSIZE;
1618: stcpy0 (&newpart[symlen + dif], &partition[symlen], PSIZE - symlen);
1619:
1620: if (apartition) stcpy0 (&anewpart[asymlen + dif], &apartition[asymlen], PSIZE - asymlen);
1621:
1622: for (j = '%'; j <= 'z'; j++) { /* update alphpointers */
1623:
1624: if (alphptr[j]) alphptr[j] += dif;
1625: if (aalphptr[j]) aalphptr[j] += dif;
1626:
1627: }
1628:
1629: PSIZE = size;
1630: symlen += dif;
1631: asymlen += dif;
1632:
1633: if (writing_mb) {
1634: shm_free (partition);
1635: }
1636: else {
1637: free (partition); /* free previously allocated space */
1638: }
1639:
1640: if (apartition) free (apartition); /* free previously allocated space */
1641:
1642: dif = newpart - partition;
1643: partition = newpart;
1644:
1645: if (apartition) apartition = anewpart;
1646:
1647: s = &partition[symlen] - 256; /* pointer to symlen_offset */
1648: argptr += dif; /* pointer to beg of tmp-storage */
1649:
1650: for (j = 0; j <= PARDEPTH; j++) {
1651:
1652: if (argstck[j]) argstck[j] += dif;
1653:
1654: }
1655:
1656: return 0;
1657:
1658: } /* end newpsize() */
1659:
1660: /* change size of svn_table to 'size' */
1661: short int newusize (long size)
1662: {
1663:
1664: char *newsvn;
1665: long dif, j;
1666:
1667: if (size <= (UDFSVSIZ - svnlen)) return 0; /* cannot decrease it now */
1668: if (size == UDFSVSIZ) return 0; /* nothing changes */
1669:
1670: newsvn = calloc ((unsigned) (size + 1), 1);
1671:
1672: if (newsvn == NULL) return 1; /* could not allocate stuff */
1673:
1674: stcpy0 (newsvn, svntable, svnlen); /* intermediate results */
1675: dif = size - UDFSVSIZ;
1676: stcpy0 (&newsvn[svnlen + dif], &svntable[svnlen], UDFSVSIZ - svnlen);
1677:
1678: for (j = '%'; j <= 'z'; j++) { /* update svn_alphpointers */
1679: if (svnaptr[j]) svnaptr[j] += dif;
1680: }
1681:
1682: UDFSVSIZ = size;
1683: svnlen += dif;
1684:
1685: free (svntable); /* free previously allocated space */
1686:
1687: svntable = newsvn;
1688:
1689: return 0;
1690:
1691: } /* end newusize() */
1692:
1693: /*
1694: * allocate 'nbrbuf' routine buffers
1695: * of 'size' bytes
1696: */
1697: short int newrsize (long size, long nbrbuf)
1698: {
1699:
1700: char *newrbuf;
1701: int i;
1702: long dif;
1703: unsigned long total;
1704:
1705: if (size <= (rouend - rouptr + 1)) return 0; /* making it smaller would be a mistake */
1706:
1707: if (nbrbuf > MAXNO_OF_RBUF) nbrbuf = MAXNO_OF_RBUF;
1708:
1709: total = (unsigned) nbrbuf *(unsigned) size;
1710:
1711: /* some overflow ??? */
1712: if ((total / (unsigned) size) != (unsigned) nbrbuf) {
1713: merr_raise (ARGER);
1714: return 1;
1715: }
1716:
1717: newrbuf = calloc (total, 1); /* routine buffer pool */
1718:
1719: while (newrbuf == NULL) { /* could not allocate stuff... */
1720:
1721: if (--nbrbuf < 2) return 1; /* ...so try with less buffers */
1722:
1723: total = (unsigned) nbrbuf *(unsigned) size;
1724:
1725: newrbuf = calloc (total, 1);
1726:
1727: }
1728:
1729: /* clear all routine buffers but one */
1730: for (i = 0; i < MAXNO_OF_RBUF; i++) { /* empty routine buffers */
1731: pgms[i][0] = 0;
1732: ages[i] = 0L;
1733: }
1734:
1735: /* transfer to new buffer */
1736: stcpy0 (newrbuf, rouptr, (long) (rouend - rouptr + 1));
1737:
1738: dif = newrbuf - rouptr;
1739: rouend += dif;
1740: ends[0] = rouend;
1741:
1742: stcpy (pgms[0], rou_name);
1743:
1744: rouins += dif;
1745:
1746: if (roucur == (buff + (NO_OF_RBUF * PSIZE0 + 1))) {
1747: roucur = newrbuf + (nbrbuf * size + 1);
1748: }
1749: else {
1750: roucur += dif;
1751: }
1752:
1753: rouptr = newrbuf;
1754:
1755: free (buff); /* free previously allocated space */
1756:
1757: buff = newrbuf;
1758: NO_OF_RBUF = nbrbuf;
1759: PSIZE0 = size;
1760:
1761: return 0;
1762:
1763: } /* end newrsize() */
1764:
1765:
1766: void zreplace (char *a, char *b, char *c)
1767: {
1768: long int ch, f, l, m, n;
1769: char d[256];
1770:
1771: if (b[0] == EOL) return; /* 2nd argument was empty */
1772:
1773: l = stlen (c); /* length of 3rd argument */
1774: n = 0;
1775: f = 0;
1776:
1777: for (;;) {
1778:
1779: m = 0;
1780:
1781: while ((ch = a[f + m]) == b[m] && ch != EOL) m++;
1782:
1783: if (b[m] == EOL) {
1784:
1785: if (n + l > STRLEN) {
1786: merr_raise (M75);
1787: return;
1788: }
1789:
1790: stcpy0 (&d[n], c, l);
1791:
1792: n += l;
1793: f += m;
1794:
1795: }
1796: else {
1797:
1798: m = 1;
1799:
1800: if (n + 1 > STRLEN) {
1801: merr_raise (M75);
1802: return;
1803: }
1804:
1805: d[n++] = a[f++];
1806:
1807: }
1808:
1809: if (a[f] == EOL) break;
1810:
1811: }
1812:
1813: d[n] = EOL;
1814: stcpy (a, d);
1815:
1816: return;
1817:
1818: } /* end zreplace() */
1819:
1820: short int tstglvn (char *a) /* tests whether 'a' is a proper unsubscripted glvn */
1821: {
1822: int i, ch;
1823:
1824: i = 0;
1825:
1826: if (a[0] == '^') {
1827:
1828: while (((ch = a[++i]) >= 'A' && ch <= 'Z') ||
1829: (ch >= 'a' && ch <= 'z') ||
1830: (ch >= '0' && ch <= '9') ||
1831: ((ch == '%' && i == 1) ||
1832: (standard == 0 &&
1833: (((ch == '.' || ch == '/') && i == 1) ||
1834: (((ch == '/' && a[i - 1] != '/') ||
1835: (ch == '%' && a[i - 1] == '/')) &&
1836: (a[1] == '.' || a[1] == '/'))))));
1837:
1838: return a[i] == EOL;
1839:
1840: }
1841:
1842: if ((ch = a[i++]) != '%' && (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) return FALSE;
1843:
1844: while ((ch = a[i++]) != EOL) {
1845:
1846: if ((ch < '0' || ch > '9') && (ch < 'A' || ch > 'Z') && (ch < 'a' || ch > 'z')) {
1847: return FALSE;
1848: }
1849:
1850: }
1851:
1852: return TRUE;
1853:
1854: } /* end tstnam() */
1855:
1856: void zname (char *a, char *b)
1857: {
1858: int i, j, f, n;
1859:
1860: i = 0;
1861: j = 0;
1862: f = FALSE; /* we are in name section (vs.subscr.) */
1863: n = FALSE; /* part is numeric (vs.alphabetic) */
1864:
1865: while ((a[i] = b[j++]) != EOL) {
1866:
1867: if (a[i] == '"') a[++i] = '"';
1868:
1869: if (a[i] == DELIM) {
1870:
1871: if (f) {
1872:
1873: if (n == FALSE) a[i++] = '"';
1874:
1875: if (i >= (STRLEN-2)/*was 253*/) {
1876: a[i] = EOL;
1877: merr_raise (M75);
1878:
1879: return;
1880: }
1881:
1882: a[i] = ',';
1883:
1884: if ((n = znamenumeric (&b[j])) == FALSE) a[++i] = '"';
1885:
1886: }
1887: else {
1888:
1889: a[i] = '(';
1890: f = TRUE;
1891:
1892: if ((n = znamenumeric (&b[j])) == FALSE) a[++i] = '"';
1893:
1894: }
1895:
1896: }
1897:
1898: if (++i >= STRLEN) {
1899:
1900: a[STRLEN] = EOL;
1901:
1902: if (b[j] != EOL) {
1903: merr_raise (M75);
1904: return;
1905: }
1906:
1907: }
1908:
1909: }
1910:
1911: if (f) {
1912:
1913: if (i > (STRLEN-2) /* was 253 */) {
1914: merr_raise (M75);
1915: return;
1916: }
1917:
1918: if (n == FALSE) a[i++] = '"';
1919:
1920: a[i++] = ')';
1921: a[i] = EOL;
1922:
1923: }
1924:
1925: return;
1926:
1927: } /* end zname() */
1928:
1929: /* boolean function that tests whether str is a canonical numeric */
1930: short int znamenumeric (char *str)
1931: {
1932:
1933: register int ptr = 0;
1934: register int ch;
1935: register int point;
1936:
1937: if (str[0] == '-') ptr = 1;
1938:
1939: if (str[ptr] == EOL) return FALSE;
1940: if (str[ptr] == DELIM) return FALSE;
1941: if (str[ptr] == '0') return str[1] == EOL || str[1] == DELIM; /* leading zero */
1942:
1943: point = FALSE;
1944:
1945: while ((ch = str[ptr++]) != EOL && ch != DELIM) {
1946:
1947: if (ch > '9') return FALSE;
1948:
1949: if (ch < '0') {
1950:
1951: if (ch != '.') return FALSE;
1952: if (point) return FALSE; /* multiple points */
1953:
1954: point = TRUE;
1955:
1956: }
1957:
1958: }
1959:
1960: if (point) {
1961: if ((ch = str[ptr - 2]) == '0') return FALSE; /* trailing zero */
1962: if (ch == '.') return FALSE; /* trailing point */
1963: }
1964:
1965: return TRUE;
1966:
1967: } /* end of znamenumeric() */
1968:
1969: void procv22 (char *key) /* process v22 translation */
1970: {
1971: int i, j, k1;
1972: char tmp1[256];
1973:
1974: if (*key == EOL || *key == 0) return;
1975:
1976: i = 0;
1977: j = 0;
1978:
1979: while (i < v22ptr) {
1980:
1981: k1 = i + UNSIGN (v22ali[i]) + 1;
1982:
1983: /* is current reference an alias ??? */
1984:
1985: j = 0;
1986:
1987: while (v22ali[++i] == key[j]) {
1988:
1989: if (v22ali[i] == EOL) break;
1990:
1991: j++;
1992: }
1993:
1994: /* yes, it is, so resolve it now! */
1995: if (v22ali[i] == EOL && (key[j] == EOL || key[j] == DELIM)) {
1996:
1997: stcpy (tmp1, key);
1998: stcpy (key, &v22ali[i + 1]);
1999: stcat (key, &tmp1[j]);
2000:
2001: i = 0;
2002:
2003: continue; /* try again, it might be a double alias! */
2004:
2005: }
2006:
2007: i = k1;
2008:
2009: }
2010:
2011: return;
2012:
2013: } /* end of procv22() */
2014:
2015: void v25 (char *a, int i)
2016: {
2017: short c, exc, k, l, p;
2018:
2019: k = 0;
2020: exc = ~((*screen).screena[(unsigned int) (*screen).sclines[i]][0]);
2021:
2022: for (l = 0; l < N_COLUMNS; l++) {
2023:
2024: p = exc;
2025: exc = (*screen).screena[(unsigned int) (*screen).sclines[i]][l];
2026: c = (*screen).screenx[(unsigned int) (*screen).sclines[i]][l];
2027:
2028: #ifdef NEVER
2029:
2030: /* this may result in a problem, when in a system */
2031: /* different G0O/G1O sets are in use !!! */
2032: if (((exc == 1 && (p == 0)) || ((exc == 0) && (p == 1))) && (G0O[HOME][c] == G1O[HOME][c])) {
2033: exc = p; /* if char looks same in SI/SO, delay SI/SO */
2034: }
2035:
2036: #endif /* NEVER */
2037:
2038: if (exc != p) { /* set attribute */
2039:
2040: #ifdef SCO
2041:
2042: p = p & ~04; /* suppress SGR(3) */
2043:
2044: if (p & 0200) p = p & 0201; /* no display */
2045: if (p & 0100) p = p & 0101; /* inverse */
2046:
2047: #endif /* SCO */
2048:
2049: if ((p & 01) != (exc & 01)) a[k++] = (exc & 01) ? SO : SI;
2050:
2051: if ((p & ~01) != (exc & ~01)) {
2052:
2053: a[k++] = ESC;
2054: a[k++] = '[';
2055:
2056: for (p = 1; p < 8; p++) {
2057:
2058: if (exc & (1 << p)) {
2059:
2060: #ifdef SCO
2061:
2062: if (p == 1) {
2063: a[k++] = '1';
2064: a[k++] = ';';
2065:
2066: continue;
2067: }
2068:
2069: #endif /* SCO */
2070:
2071: a[k++] = '1' + p;
2072: a[k++] = ';';
2073:
2074: }
2075:
2076: }
2077:
2078: if (a[k - 1] == ';') k--;
2079:
2080: a[k++] = 'm';
2081: }
2082:
2083: }
2084:
2085: a[k++] = c;
2086:
2087: }
2088:
2089: if (exc & 01) a[k++] = SI;
2090:
2091: a[k] = EOL;
2092:
2093: return;
2094:
2095: } /* end of v25() */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>