1: /*
2: * $Id: gfix.c,v 1.4 2025/04/02 03:02:42 snw Exp $
3: * display freem database blocks on-screen
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: gfix.c,v $
27: * Revision 1.4 2025/04/02 03:02:42 snw
28: * Stop requiring users to pass -e to fmadm when -u or -g are passed
29: *
30: * Revision 1.3 2025/03/09 19:14:25 snw
31: * First phase of REUSE compliance and header reformat
32: *
33: *
34: * SPDX-FileCopyrightText: (C) 2025 Coherent Logic Development LLC
35: * SPDX-License-Identifier: AGPL-3.0-or-later
36: **/
37:
38: #include <stdlib.h>
39: #include <setjmp.h>
40: #include <signal.h>
41: #include <stdio.h>
42: #include "mpsdef0.h"
43: #include "errmsg.h"
44: #include <fcntl.h>
45: #include <unistd.h>
46: #include <string.h>
47: #include <sys/types.h>
48: #include <sys/wait.h>
49:
50: /* needed if byte data are to be interpreted as unsigned integer */
51: #define UNSIGN(A) ((A)&0377)
52:
53: #define g_EOL 30
54: #define POINT 28
55: #define MINUS 26
56:
57: #define ROOT 0L
58: /* length of blocks. status bytes defined as offset to blocklength */
59: #define BLOCKLEN 1024
60: #define DATALIM (BLOCKLEN-11)
61: #define LLPTR (BLOCKLEN-10)
62: #define NRBLK LLPTR
63: #define RLPTR (BLOCKLEN- 6)
64: #define FREE RLPTR
65: #define BTYP (BLOCKLEN- 3)
66: #define OFFS (BLOCKLEN- 2)
67:
68: #define PLEN 3
69:
70: #define EMPTY 0
71: #define FBLK 1
72: #define POINTER 2
73: #define BOTTOM 6
74: #define DATA 8
75:
76: #define LF 10
77: #define CR 13
78: #define SPC ' '
79: #define NUL 0
80: #define DEL 127
81:
82: #ifndef SYSFIVE
83: #define FreeM_timezone -3600
84: #else
85:
86: #ifdef __CYGWIN__
87: #define FreeM_timezone _timezone
88: #else
89: extern long FreeM_timezone;
90: #endif /* __CYGWIN__ */
91:
92: #endif /* SYSFIVE */
93:
94: /* mumps commands */
95: #define BREAK 'b'
96: #define CLOSE 'c'
97: #define DO 'd'
98: #define DO_BLOCK 2
99: #define ELSE 'e'
100: #define FOR 'f'
101: #define GOTO 'g'
102: #define HA 'h'
103: #define HALT '0'
104: #define HANG '1'
105: #define IF 'i'
106: #define JOB 'j'
107: #define KILL 'k'
108: #define LOCK 'l'
109: #define NEW 'n'
110: #define OPEN 'o'
111: #define QUIT 'q'
112: #define READ 'r'
113: #define SET 's'
114: #define USE 'u'
115: #define VIEW 'v'
116: #define WRITE 'w'
117: #define XECUTE 'x'
118:
119: #define ZBREAK 'B'
120: #define ZGO 'G'
121: #define ZHALT 'H'
122: #define ZINSERT 'I'
123: #define ZJOB 'J'
124: #define ZLOAD 'L'
125: #define ZNEW 'N'
126: #define ZPRINT 'P'
127: #define ZQUIT 'Q'
128: #define ZREMOVE 'R'
129: #define ZSAVE 'S'
130: #define ZTRAP 'T'
131: #define ZWRITE 'W'
132: #define PRIVATE SP
133:
134:
135:
136: int
137: main (argc, argv)
138: int argc; /* arguments count */
139: char *argv[]; /* arguments string */
140:
141: {
142: static char ASCII[] = "NULSOHSTXETXEOTENQACKBELBS TABLF VT FF CR SO SI DLEDC1DC2DC3DC4NAKSYNETBCANEM SUBESCFS GS RS US ";
143: char filnam[40];
144: short filedes;
145: char block[BLOCKLEN];
146: char key[512];
147: char data[1024];
148: long blknbr;
149: short offset;
150: short type;
151: unsigned long pointer;
152: short length;
153: short koffs;
154:
155: register int i,
156: j,
157: k,
158: ch;
159:
160: filnam[0] = '^';
161: filnam[1] = 0;
162:
163: if (argc > 1) {
164: j = 0;
165: while (--argc > 0) {
166: j++; /* accept it with or without '^' sign */
167: if (**(argv + j) == '-') {
168: fprintf (stderr, "usage is: %s [^]global\012\015", *argv);
169: exit (0);
170: }
171: if (**(argv + j) == '^')
172: strcpy (filnam, *(argv + j));
173: else
174: strcpy (&filnam[1], *(argv + j));
175: }
176: } else {
177: printf ("\012\015display global ^");
178: scanf ("%s", &filnam[1]);
179: }
180: if ((filedes = open (filnam, 0)) == -1) {
181: printf ("cannot open file %s\007\012\015", filnam);
182: exit (0);
183: }
184: again:;
185:
186: printf ("\012\015display block #");
187: scanf ("%ld", &blknbr);
188: if (blknbr < 0) {
189: printf ("\012\015*** done ***\012\015\033[r\033[24H");
190: exit (0);
191: }
192: lseek (filedes, blknbr * 1024L, 0);
193: if (read (filedes, block, BLOCKLEN) == 0) {
194: printf ("block #%ld does not exist\007\012\015-1 will terminate", blknbr);
195: goto again;
196: }
197: printf ("\033[r\033[2Jglobal\033[;20H%s\033[;40Hblock\033[;60H%ld",
198: filnam,
199: blknbr);
200: printf ("\033[2Hblock type\033[2;20H");
201: type = block[BTYP];
202: switch (type) {
203: case DATA:
204: printf ("DATA");
205: break;
206: case POINTER:
207: printf ("POINTER");
208: break;
209: case BOTTOM:
210: printf ("BOTTOM POINTER");
211: break;
212: case EMPTY:
213: printf ("EMPTY");
214: break;
215: case FBLK:
216: printf ("FBLK");
217: break;
218: default:
219: printf ("ILLEGAL TYPE");
220: type = DATA;
221: }
222: if (blknbr == ROOT)
223: printf (", ROOT");
224:
225: offset = UNSIGN (block[OFFS]) * 256 +
226: UNSIGN (block[OFFS + 1]);
227: printf ("\033[2;40Hoffset\033[2;60H%d", offset);
228: if (offset > DATALIM || (type == FBLK && offset % PLEN)) {
229: printf (" ???");
230: offset = DATALIM;
231: }
232: pointer = UNSIGN (block[LLPTR]) * 65536 +
233: UNSIGN (block[LLPTR + 1]) * 256 +
234: UNSIGN (block[LLPTR + 2]);
235: printf ("\033[3H%s\033[3;20H%ld",
236: blknbr != ROOT ? "LEFT LINK POINTER" : "NR_OF_BLKS",
237: pointer);
238:
239: pointer = UNSIGN (block[RLPTR]) * 65536 +
240: UNSIGN (block[RLPTR + 1]) * 256 +
241: UNSIGN (block[RLPTR + 2]);
242: printf ("\033[3;40H%s\033[3;60H%ld",
243: blknbr != ROOT ? "RIGHT LINK POINTER" : "FREE",
244: pointer);
245:
246: printf ("\033[4;24r\033[4H"); /* define scrolling area */
247:
248: if (type == FBLK) {
249: i = 0;
250: while (i < offset) {
251: k = UNSIGN (block[i]) * 65536 +
252: UNSIGN (block[i + 1]) * 256 +
253: UNSIGN (block[i + 2]);
254: i += PLEN;
255: printf ("%8d", k);
256: }
257: goto again;
258: }
259: i = 0;
260: while (i < offset) {
261: printf ("\012\015%3d", i);
262: length = UNSIGN (block[i++]);
263: k = koffs = UNSIGN (block[i++]);
264: if ((i + length) > offset)
265: break;
266: for (j = 0; j < length; j++)
267: key[k++] = block[i++];
268: key[k] = g_EOL;
269: /*----------------------*/
270: {
271: short ch0,
272: i,
273: j,
274: k,
275: typ;
276:
277: j = 0;
278: i = 0;
279: data[j++] = '(';
280: k = 1;
281: while ((ch = UNSIGN (key[i++])) != g_EOL) {
282: if (k) {
283: k = 0;
284: if ((typ = (ch > SPC)))
285: data[j++] = '"';
286: }
287: ch0 = (ch >= SPC ? (ch >> 1) : /* 'string' chars */
288: (ch < 20 ? (ch >> 1) + '0' : /* 0...9 */
289: (ch >> 1) + SPC)); /* '.' or '-' */
290: if (ch0 == DEL) {
291: if (((ch = UNSIGN (key[i++])) >> 1) == DEL) {
292: ch0 += DEL;
293: ch = UNSIGN (key[i++]);
294: }
295: ch0 += (ch >> 1);
296: data[j] = '<';
297: data[++j] = '0' + ch0 / 100;
298: data[++j] = '0' + (ch0 % 100) / 10;
299: data[++j] = '0' + ch0 % 10;
300: data[++j] = '>';
301: } else
302: data[j] = ch0;
303: if (data[j++] == '"')
304: data[j++] = '"';
305: if (ch & 01) {
306: if (typ)
307: data[j++] = '"';
308: data[j++] = ',';
309: k = 1;
310: }
311: }
312: data[j--] = 0;
313: data[j] = ')';
314: if (j == 0)
315: data[0] = 0;
316: while (j >= 0) {
317: if ((ch = data[--j]) < SPC || ch >= DEL)
318: break;
319: }
320: if (j < 0)
321: printf ("[%d][%d] %s ", length, koffs, data);
322: else
323: printf ("[%d][%d] <illegal subscipt>", length, koffs);
324: /*----------------------*/
325: }
326: if (type == DATA) {
327: length = UNSIGN (block[i++]);
328: k = 0;
329: if ((i + length) > offset)
330: break;
331: while (length-- > 0) {
332: ch = UNSIGN (block[i++]);
333: if ((ch >= SPC) && (ch < DEL))
334: data[k++] = ch;
335: else {
336: data[k++] = '<';
337: if ((ch >= NUL) && (ch < SPC)) {
338: ch = ch * 3;
339: data[k++] = ASCII[ch++];
340: data[k++] = ASCII[ch++];
341: if ((data[k++] = ASCII[ch++]) == SPC)
342: k--;
343: } else if (ch == DEL) {
344: data[k++] = 'D';
345: data[k++] = 'E';
346: data[k++] = 'L';
347: } else {
348: if (ch > 99) {
349: data[k++] = '0' + (ch / 100);
350: ch = ch % 100;
351: }
352: if (ch > 9) {
353: data[k++] = '0' + (ch / 10);
354: ch = ch % 10;
355: }
356: data[k++] = '0' + ch;
357: }
358: data[k++] = '>';
359: }
360: }
361: data[k] = 0;
362: printf ("= %s", data);
363: } else {
364: pointer = UNSIGN (block[i]) * 65536 +
365: UNSIGN (block[i + 1]) * 256 +
366: UNSIGN (block[i + 2]);
367: i += PLEN;
368: printf ("-> %ld", pointer);
369: }
370: }
371: if (i != offset)
372: printf ("\012\015wrong offset %d vs. %d\012\015", offset, i);
373: goto again;
374: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>