aboutsummaryrefslogtreecommitdiff
path: root/pkg/dataio/mtexamine/t_mtexamine.x
blob: 26f7b2fd0b9bfd66bc0f9a499a82d62ec84584f2 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.

include <error.h>
include <fset.h>
include <printf.h>
include <mach.h>

define	MAX_RANGES	100
define	LEN_LINE	80
define	TAPE_BYTE	8
define	TWO_TO_EIGHT	256
define	FIELD_INDEX	5
define	NFORMATS	5


# MTEXAMINE -- Examine one or more magtape files, counting the number and size
# of the records in a file, and the number of files on the tape.

procedure t_mtexamine()

int	nfiles, file_number, ndumps, nrecords
int	file_range[2*MAX_RANGES+1], rec_range[2*MAX_RANGES+1]
pointer	sp, tape_name, tape_file, file_list, rec_list

bool	clgetb()
char	clgetc()
int	fstati(), mtfile(), mtneedfileno(), decode_ranges(), get_next_number()
int	mt_examine(), mt_get_format(), clgeti(), btoi()
include "mtexamine.com"

begin
	# Allocate working space.
	call smark (sp)
	call salloc (tape_name, SZ_FNAME, TY_CHAR)
	call salloc (tape_file, SZ_FNAME, TY_CHAR)
	call salloc (file_list, SZ_LINE, TY_CHAR)
	call salloc (rec_list,  SZ_LINE, TY_CHAR)

	# Flush STDOUT on a newline only if output is not redirected.
	if (fstati (STDOUT, F_REDIR) == NO)
	    call fseti (STDOUT, F_FLUSHNL, YES)

        # Get input file(s).
        call clgstr ("tape_file", Memc[tape_file], SZ_FNAME)
        if (mtfile (Memc[tape_file]) == NO)
	    call strcpy ("1", Memc[file_list], SZ_LINE)
	else if (mtneedfileno (Memc[tape_file]) == NO)
	    call strcpy ("1", Memc[file_list], SZ_LINE)
        else
	    call clgstr ("file_list", Memc[file_list], SZ_LINE)
        if (decode_ranges (Memc[file_list],file_range,MAX_RANGES,nfiles) == ERR)
	    call error (0, "Illegal file number list.")

        # Get dump parameters
        dump_records = btoi (clgetb ("dump_records"))
        if (dump_records == YES) {
	    call clgstr ("rec_list", Memc[rec_list], SZ_LINE)
	    if (decode_ranges (Memc[rec_list], rec_range, MAX_RANGES,
		ndumps) == ERR)
	        call error (0, "Illegal record list.")
	    byteswap = btoi (clgetb ("swapbytes"))
	    byte_chunk = clgeti ("byte_chunk")
	    if (byte_chunk < 1 || byte_chunk > (SZ_LONG * SZB_CHAR))
		call error (0, "Illegal byte chunk size.")
	    output_format = mt_get_format (clgetc ("output_format"))
	    if (output_format == ERR)
		call error (0, "Illegal format.")
	    if (byte_chunk != 1 && output_format == FMT_CHAR)
		call error (0, "Cannot output integers as chars.")
        }

        # Loop over files
	file_number = 0
        while (get_next_number (file_range, file_number) != EOF) {

	    if (mtfile (Memc[tape_file]) == YES &&
		mtneedfileno (Memc[tape_file]) == YES)
		call mtfname (Memc[tape_file], file_number, Memc[tape_name],
		    SZ_FNAME)
	    else
	        call strcpy (Memc[tape_file], Memc[tape_name], SZ_FNAME)

	    iferr {
	        nrecords = mt_examine (Memc[tape_name], rec_range)
	    } then {
		call eprintf ("Error reading file: %s\n")
		    call pargstr (Memc[tape_name])
		call erract (EA_WARN)
		break
	    } else if (nrecords == 0) {
	        call printf ("Tape at EOT\n")
		break
	    }

        }

	call sfree (sp)
end


# MT_EXAMINE -- Procedure to examine a tape file. If dump_record is
# no mtexamine gives a summary of the record structure of the file,
# otherwise the specified records are dumped.

int procedure mt_examine (tape_file, dump_range)

char	tape_file[ARB]		# input file name
int	dump_range[ARB]		# range of records to be dumped

pointer	sp, inbuf, pchar, junk
int	in, bufsize, totrecords, nrecords, totbytes, last_recsize, nbadrec
int	stat, rec_number, next_dump, recsize, nelems, vals_per_line, field_len
long	maxval, max_plusint, twice_max_plusint

int	mtopen(), fstati(), get_next_number(), read(), gltoc()
errchk	mtopen, malloc, read, mfree, close
include "mtexamine.com"

begin
	call smark (sp)
	call salloc (junk, SZ_FNAME, TY_CHAR)

	in = mtopen (tape_file, READ_ONLY, 0)
	bufsize = fstati (in, F_BUFSIZE)
	call salloc (pchar, bufsize, TY_CHAR)

	call printf ("File %s:\n")
	    call pargstr (tape_file)

	totrecords = 0
	nrecords = 0
	totbytes = 0
	nbadrec  = 0
	last_recsize = 0

	# Prepare formatting parameters for dumping records.
	if (dump_records == YES) {
	    call salloc (inbuf, bufsize * SZB_CHAR, TY_LONG)
	    rec_number = 0
	    next_dump = get_next_number (dump_range, rec_number)
	    maxval = 2 ** (byte_chunk * TAPE_BYTE - 1) - 1
	    field_len = gltoc (maxval, Memc[junk], SZ_FNAME, TAPE_BYTE) + 1
	    vals_per_line = (LEN_LINE - FIELD_INDEX) / (field_len + 1)
	    if (output_format == FMT_DECIMAL && byte_chunk > 1 &&
	    		byte_chunk < (SZ_LONG * SZB_CHAR)) {
	        max_plusint = maxval + 1
	        twice_max_plusint = 2 * max_plusint
	    }
	}

	# Loop through the records.
	repeat {
	    iferr (stat = read (in, Memc[pchar], bufsize)) {
		call fseti (in, F_VALIDATE, last_recsize / SZB_CHAR)
		nbadrec = nbadrec + 1
	        call printf ("\tRead error on record: %d\n")
		    call pargi (totrecords + 1)
		stat = read (in, Memc[pchar], bufsize)
	    }
	    if (stat == EOF)
		break

	    recsize = fstati (in, F_SZBBLK)
	    if (dump_records == NO) {
	        if (nrecords == 0) {
		    nrecords = 1
		    last_recsize = recsize
		} else if (recsize == last_recsize) {
		    nrecords = nrecords + 1
		} else {
		    call printf ("\t%d %d-byte records\n")
		        call pargi (nrecords)
		        call pargi (last_recsize)
		    nrecords = 1
		    last_recsize = recsize
		}
	    } else if (next_dump != EOF && rec_number == totrecords + 1) {
	        call printf ("    Record %d,")
		    call pargi (totrecords + 1)
		call printf (" %d bytes,")
		    call pargi (recsize)
		nelems = recsize / byte_chunk
		call printf (" %d elements")
		    call pargi (nelems)
		call mt_bytupkl (Memc[pchar], Meml[inbuf], recsize, byte_chunk,
		    byteswap)
		call mt_dump (Meml[inbuf], nelems, field_len, vals_per_line,
		    max_plusint, twice_max_plusint)
		next_dump = get_next_number (dump_range, rec_number)
	    }

	    totrecords = totrecords + 1
	    totbytes = totbytes + recsize
	 }

	if (nrecords > 0 && dump_records == NO) {
	    call printf ("\t%d %d-byte records\n")
	        call pargi (nrecords)
	        call pargi (last_recsize)
 	}

	# Print total number of records and bytes
	if (dump_records == YES) {
	    call printf ("    Total %d records, %d bytes\n")
	        call pargi (totrecords)
	        call pargi (totbytes)
	} else { 
	    call printf ("\tTotal %d records, %d bytes")
	        call pargi (totrecords)
	        call pargi (totbytes)
	    if (nbadrec > 0) {
		call printf (" [%d bad records]")
		    call pargi (nbadrec)
	    }
	    call printf ("\n")
	}

	call close (in)

	call sfree (sp)
	return (totrecords)
end


# MT_DUMP -- Procedure to format and dump a tape record in chars, shorts or
# longs in char, decimal, octal, unsigned decimal or hexadecimal format.

procedure mt_dump (buffer, nelems, field_len, vals_per_line, max_plusint,
	twice_max_plusint)

int	nelems, field_len, vals_per_line
long	buffer[ARB], max_plusint, twice_max_plusint

int	i, nchars
char	ch, outstr[SZ_FNAME]
int	ctocc()
include "mtexamine.com"

begin
	for (i = 1; i <= nelems; i = i + 1) {
	    if (mod (i, vals_per_line) == 1) {
		call printf ("\n%*d:")
		    call pargi (FIELD_INDEX)
		    call pargi (i)
	    }
	    if (output_format == FMT_CHAR) {
		ch = buffer[i]
		nchars = ctocc (ch, outstr, SZ_FNAME)
		call printf ("%*s")
		    call pargi (field_len)
		    call pargstr (outstr)
	    } else {
		if (output_format == FMT_DECIMAL && byte_chunk > 1
			        && byte_chunk < (SZ_LONG * SZB_CHAR))
		    call mt_sign_convert (buffer[i], 1, max_plusint,
		    		    twice_max_plusint)
		call printf ("%**")
		    call pargi (field_len)
		    call pargc (output_format)
		    call pargl (buffer[i])
	    }
	}

	call printf ("\n")
end


# MT_GET_FORMAT -- Procedure to return the appropriate output format.

int procedure mt_get_format (c)

char	c
int	i, format_code[NFORMATS]
int	stridx()
string	formats "cdoxu"
data	format_code /FMT_CHAR, FMT_DECIMAL, FMT_OCTAL, FMT_HEX, FMT_UNSIGNED/

begin
	i = stridx (c, formats)
	if ( i == 0)
	    return (ERR)
	else
	    return (format_code[i])
end


# MT_BYTUPKL -- Procedure to unpack an  array in chunks byte_chunk bytes long
# into a long array with optional byteswapping.

procedure mt_bytupkl (a, b, nbytes, byte_chunk, byteswap)

char	a[ARB]		# input buffer
long	b[ARB]		# output array
int	nbytes		# number of bytes
int	byte_chunk	# number of bytes to be formatted, swapped etc.
int	byteswap	# swap bytes

int	op, i, j, rem
long	sum

begin
	op = 1

	# Unpack unsigned bytes into a long integer array
	call achtbl (a, b, nbytes)

	# Flip bytes if necessary
	if (byteswap == YES && byte_chunk > 1) {
	    for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk)
		call mt_aflipl (b[i], byte_chunk)
	}

	# Convert the bytes into unsigned integers
	for (i = 1; i <= nbytes - byte_chunk + 1; i = i + byte_chunk) {
	    sum = 0
	    for (j = 1; j <= byte_chunk; j = j + 1) {
		sum = sum + TWO_TO_EIGHT ** (byte_chunk - j) *
			b[i + j - 1]
	    }
	    b[op] = sum
	    op = op + 1
	}

	# Convert remaining bytes
	rem = nbytes -  i + 1
	if (rem > 0) {
	    if (byteswap == YES && byte_chunk > 1)
	        call mt_aflipl (b[i], rem)
	    sum = 0
	    for (j = 1; j <= rem; j = j + 1)
	        sum = sum + TWO_TO_EIGHT ** (rem - j) *
			b[i + j - 1]
	    b[op] = sum
	}
end


# MT_AFLIPL -- Procedure to flip a long integer array in place.

procedure mt_aflipl (buf, npix)

long	buf[npix]	# array to be flipped
int	npix		# number of elements in array

int	n_total, n_half, i, j

begin
	n_half = npix / 2
	n_total = npix + 1
	for (i = 1; i <= n_half; i = i + 1) {
	    j = buf[i]
	    buf[i] = buf[n_total - i]
	    buf[n_total - i] = j
	}
end


# MT_SIGN_CONVERT -- Procedure to convert unsigned long integers in the range
# 0 to twice_max_plusint - 1 to integers in the range  - max_plusint
# to max_plusint - 1.

procedure mt_sign_convert (b, nelems, max_plusint, twice_max_plusint)

long	b[nelems]		# array of long integers to be converted
int	nelems			# number of elements in the array
long	max_plusint		# 0 <= b[i] <= max_plusint - 1
long	twice_max_plusint	# twice max_plusint

int	i

begin
	for (i = 1; i <= nelems; i = i + 1) {
	    if (b[i] >= max_plusint)
		b[i] = b[i] - twice_max_plusint
	}
end