NCEPLIBS-bufr 11.7.1
debufr.f
Go to the documentation of this file.
1C> @file
2C> @brief Fortran language code for debufr utility.
3
4C> This module is used within the debufr utility to share
5C> information between subroutine fdebufr() and subroutine
6C> openbt(), since the latter is not called by the former but
7C> rather is called directly from within the BUFRLIB software.
8
10
11C> @var ctbldir
12C> Directory containing DX BUFR tables to be used for
13C> decoding.
14C>
15C> @var ltbd
16C> Length (in characters) of ctbldir.
17C>
18C> @var ludx
19C> Fortran logical unit number to use for referencing
20C> a DX table.
21
22 character*120 ctbldir
23 integer ltbd, ludx
24 END MODULE
25
26C> This subroutine reads, decodes, and generates a verbose output
27C> listing of the contents of every BUFR message from within the
28C> input file that was previously opened via a call to subroutine
29C> cobfl() with io = 'r'.
30C>
31C> @author J. Ator
32C> @date 2009-07-01
33C>
34C> @param[in] ofile -- character*(*): File to contain verbose output
35C> listing of contents of each decoded BUFR message
36C> @param[in] tbldir -- character*(*): Directory containing DX and/or
37C> master BUFR tables to be used for decoding
38C> @param[in] lentd -- integer: length of tbldir string
39C> @param[in] tblfil -- character*(*): File containing DX BUFR table
40C> information to be used for decoding
41C> - 'NULLFILE' = No such file will be used
42C> @param[in] prmstg -- character*(*): String of up to 20 comma-separated
43C> PARAMETER=VALUE pairs to be used to dynamically
44C> allocate memory within the BUFRLIB software,
45C> overriding the default VALUE that would otherwise
46C> be used for each such PARAMETER.
47C> - 'NULLPSTG' = No such pairs will be used
48C> @param[in] basic -- character: Indicator as to whether only "basic"
49C> information in Sections 0-3 should be decoded
50C> from each BUFR message:
51C> - 'Y' = Yes
52C> - 'N' = No
53C> @param[in] forcemt -- character: Indicator as to whether master BUFR
54C> tables should be used for decoding, regardless
55C> of whether the input file contains any embedded
56C> DX BUFR table messages:
57C> - 'Y' = Yes
58C> - 'N' = No
59C> @param[in] cfms -- character: Indicator as to whether code and flag
60C> table meanings should be read from master BUFR
61C> tables and included in the print output:
62C> - 'Y' = Yes
63C> - 'N' = No
64C>
65C> @remarks
66C> - See BUFRLIB function isetprm() for a complete list of parameters
67C> that can be dynamically sized via prmstg.
68C> - Fortran logical unit numbers 51, 90, 91, 92 and 93 are reserved
69C> for use within this subroutine.
70C>
71C> <b>Program history log:</b>
72C> | Date | Programmer | Comments |
73C> | -----|------------|----------|
74C> | 2009-07-01 | J. Ator | Original author |
75C> | 2012-06-18 | J. Ator | Added tblfil argument and options to decode files according to DX dictionary information |
76C> | 2012-12-07 | J. Ator | Added forcemt and lentd arguments |
77C> | 2013-10-07 | J. Ator | Print Section 1 tank receipt time information for NCEP/NCO BUFR messages if available |
78C> | 2013-11-15 | J. Ator | Added check for missing or unreadable tblfil |
79C> | 2014-09-15 | J. Ator | Confirm BUFR file was opened (i.e. at least one good return from crbmg() before calling dxdump() |
80C> | 2018-01-19 | J. Ator | Added print of code and flag table meanings |
81C> | 2018-03-01 | J. Ator | Added print of data types and subtypes from code and flag tables |
82C> | 2018-09-05 | J. Ator | Added prmstg argument |
83C> | 2019-02-01 | J. Ator | Remove limit on length of prmstg |
84C> | 2021-02-24 | J. Ator | Use all formatted writes, for consistent output between builds using 4-byte vs. 8-byte integers |
85C>
86 SUBROUTINE fdebufr ( ofile, tbldir, lentd, tblfil, prmstg,
87 + basic, forcemt, cfms )
88
90
91 parameter( mxbf = 2500000 )
92 parameter( mxbfd4 = mxbf/4 )
93 parameter( mxds3 = 500 )
94 parameter( mxprms = 20 )
95
96 character*(*) ofile, tbldir, tblfil, prmstg
97
98 logical exists
99
100 character*120 cmorgc, cmgses, cmmtyp, cmmsbt, cmmsbti
101 character*20 ptag( mxprms ), pvtag(2), cprmnm
102 character*8 cmgtag
103 character*6 cds3( mxds3 )
104 character*1 basic, forcemt, opened, usemt, cfms,
105 + bfmg( mxbf )
106
107 integer ibfmg( mxbfd4 )
108
109 equivalence( bfmg(1), ibfmg(1) )
110
111C-----------------------------------------------------------------------
112C-----------------------------------------------------------------------
113
114C Open the output file.
115
116 OPEN ( unit = 51, file = ofile )
117
118C Note that in the below OPEN statement we just need to specify
119C a dummy placeholder file.
120
121 lunit = 92
122 OPEN ( unit = lunit, file = '/dev/null' )
123
124 CALL datelen ( 10 )
125
126C Initialize the values in the Share_Table_Info module.
127
128 ludx = 93
129 ltbd = lentd
130 ctbldir = tbldir(1:lentd)
131
132C Initialize some other values.
133
134 nmsg = 0
135 nsubt = 0
136
137 opened = 'N'
138 usemt = 'N'
139
140 DO WHILE ( .true. )
141
142C Get the next message from the input BUFR file.
143
144 CALL crbmg ( bfmg, mxbf, nbyt, ierr )
145
146 IF ( ierr .ne. 0 ) THEN
147
148 IF ( ierr .eq. -1 ) THEN
149 WRITE ( unit = 51, fmt = '( /, 2A, I7, A, I9, A )')
150 + 'Reached end of BUFR file; it contained a total ',
151 + 'of', nmsg, ' messages and', nsubt, ' subsets'
152 ELSE
153 WRITE ( unit = 51, fmt = '( /, 2A, I4 )' )
154 + 'Error while reading BUFR file; the return code ',
155 + 'from CRBMG = ', ierr
156 ENDIF
157
158 IF ( ( basic .eq. 'N' ) .and. ( opened .eq. 'Y' ) ) THEN
159 WRITE (51, fmt = '( /, A, / )' )
160 + 'Here is the DX table that was generated:'
161 CALL dxdump ( lunit, 51 )
162 ENDIF
163
164C Close the output file and return.
165
166 CLOSE ( 51 )
167 RETURN
168 ENDIF
169
170 IF ( opened .eq. 'N' ) THEN
171
172 CALL isetprm ( 'MAXCD', mxds3 )
173 CALL isetprm ( 'MXMSGL', mxbf )
174 CALL isetprm ( 'MAXSS', 300000 )
175 CALL isetprm ( 'NFILES', 2 )
176
177C Process any dynamic allocation parameters that were
178C passed in on the command line.
179
180 IF ( prmstg(1:8) .ne. 'NULLPSTG' ) THEN
181 CALL parstr ( prmstg, ptag, mxprms, nptag, ',',
182 + .false. )
183 IF ( nptag .gt. 0 ) THEN
184 DO ii = 1, nptag
185 CALL parstr ( ptag(ii), pvtag, 2, npvtag, '=',
186 + .false. )
187 IF ( npvtag .eq. 2 ) THEN
188 CALL strsuc ( pvtag(1), cprmnm, lcprmnm )
189 CALL strnum ( pvtag(2), ipval )
190 IF ( ( lcprmnm .gt. 0 ) .and.
191 + ( ipval .ne. -1 ) )
192 + CALL isetprm ( cprmnm(1:lcprmnm), ipval )
193 ENDIF
194 ENDDO
195 ENDIF
196 ENDIF
197
198C Decide how to process the file.
199
200 IF ( ( idxmsg( ibfmg ) .eq. 1 ) .and.
201 + ( forcemt .eq. 'N' ) ) THEN
202
203C The first message in the file is a DX dictionary
204C message, so assume there's an embedded table at the
205C front of the file and use this table to decode it.
206
207 CALL openbf ( lunit, 'INUL', lunit )
208 ELSE IF ( ( tblfil(1:8) .ne. 'NULLFILE' ) .and.
209 + ( forcemt .eq. 'N' ) ) THEN
210
211C A DX dictionary tables file was specified on the
212C command line, so use it to decode the BUFR file.
213
214 INQUIRE ( file = tblfil, exist = exists )
215 IF ( .not. exists ) THEN
216 print *, 'ERROR: COULD NOT FIND FILE ', tblfil
217 RETURN
218 ENDIF
219 OPEN ( unit = 91, file = tblfil, iostat = ier )
220 IF ( ier .ne. 0 ) THEN
221 print *, 'ERROR: COULD NOT OPEN FILE ', tblfil
222 RETURN
223 ENDIF
224 CALL openbf ( lunit, 'IN', 91 )
225 ELSE
226
227C Decode the file using the master tables in tbldir.
228
229 usemt = 'Y'
230 CALL openbf ( lunit, 'SEC3', lunit )
231 ENDIF
232
233 opened = 'Y'
234
235 CALL mtinfo ( tbldir, 90, 91 )
236 IF ( cfms .eq. 'Y' ) CALL codflg ( 'Y' )
237 ENDIF
238
239 IF ( basic .eq. 'N' ) THEN
240
241C Pass the message to the decoder.
242
243 CALL readerme ( ibfmg, lunit, cmgtag, imgdt, ierme )
244 ENDIF
245
246C If this is a DX dictionary message, then don't generate any
247C output unless master tables are being used for decoding.
248
249 IF ( ( idxmsg( ibfmg ) .ne. 1 ) .or.
250 + ( usemt .eq. 'Y' ) ) THEN
251
252 nmsg = nmsg + 1
253
254 WRITE ( unit = 51, fmt = '( /, A, I7 )' )
255 + 'Found BUFR message #', nmsg
256
257C Decode and output the data from Section 0.
258
259 WRITE ( 51, fmt= '( /, A, I9 )' )
260 + ' Message length: ',
261 + iupbs01( ibfmg, 'LENM' )
262 WRITE ( 51, fmt= '( A, I4 )' )
263 + ' Section 0 length: ',
264 + iupbs01( ibfmg, 'LEN0' )
265 WRITE ( 51, fmt= '( A, I4 )' )
266 + ' BUFR edition: ',
267 + iupbs01( ibfmg, 'BEN' )
268
269C Decode and output the data from Section 1.
270
271 WRITE ( 51, fmt= '( /, A, I4 )' )
272 + ' Section 1 length: ',
273 + iupbs01( ibfmg, 'LEN1' )
274 WRITE ( 51, fmt= '( A, I4 )' )
275 + ' Master table: ',
276 + iupbs01( ibfmg, 'BMT' )
277
278 iogce = iupbs01( ibfmg, 'OGCE' )
279 igses = iupbs01( ibfmg, 'GSES' )
280 IF ( ( basic .eq. 'Y' ) .or.
281 + ( cfms .eq. 'N' ) ) THEN
282 WRITE ( 51, fmt= '( A, I5 )' )
283 + ' Originating center: ', iogce
284 WRITE ( 51, fmt= '( A, I4 )' )
285 + ' Originating subcenter: ', igses
286 ELSE
287 CALL getcfmng ( lunit, 'ORIGC', iogce, ' ', -1,
288 + cmorgc, lcmorgc, ierorgc )
289 IF ( ierorgc .eq. 0 ) THEN
290 WRITE ( 51, fmt= '( A, I5, 3A )' )
291 + ' Originating center: ', iogce,
292 + ' (= ', cmorgc(1:lcmorgc), ')'
293 ELSE
294 WRITE ( 51, fmt= '( A, I5 )' )
295 + ' Originating center: ', iogce
296 ENDIF
297 CALL getcfmng ( lunit, 'GSES', igses,
298 + 'ORIGC', iogce,
299 + cmgses, lcmgses, iergses )
300 IF ( iergses .eq. 0 ) THEN
301 WRITE ( 51, fmt= '( A, I4, 3A )' )
302 + ' Originating subcenter: ', igses,
303 + ' (= ', cmgses(1:lcmgses), ')'
304 ELSE
305 WRITE ( 51, fmt= '( A, I4 )' )
306 + ' Originating subcenter: ', igses
307 ENDIF
308 ENDIF
309
310 WRITE ( 51, fmt= '( A, I4 )' )
311 + ' Update sequence numbr: ',
312 + iupbs01( ibfmg, 'USN' )
313
314 IF ( iupbs01( ibfmg, 'ISC2' ) .eq. 1 ) THEN
315 WRITE ( 51, fmt = '( A )')
316 + ' Section 2 present?: Yes'
317 ELSE
318 WRITE ( 51, fmt = '( A )')
319 + ' Section 2 present?: No'
320 ENDIF
321
322 mtyp = iupbs01( ibfmg, 'MTYP' )
323 msbt = iupbs01( ibfmg, 'MSBT' )
324 msbti = iupbs01( ibfmg, 'MSBTI' )
325 IF ( ( basic .eq. 'Y' ) .or.
326 + ( cfms .eq. 'N' ) ) THEN
327 WRITE ( 51, fmt= '( A, I4 )' )
328 + ' Data category: ', mtyp
329 WRITE ( 51, fmt= '( A, I4 )' )
330 + ' Local subcategory: ', msbt
331 WRITE ( 51, fmt= '( A, I4 )' )
332 + ' Internatl subcategory: ', msbti
333 ELSE
334 CALL getcfmng ( lunit, 'TABLAT', mtyp, ' ', -1,
335 + cmmtyp, lcmmtyp, iermtyp )
336 IF ( iermtyp .eq. 0 ) THEN
337 WRITE ( 51, fmt= '( A, I4, 3A )' )
338 + ' Data category: ', mtyp,
339 + ' (= ', cmmtyp(1:lcmmtyp), ')'
340 ELSE
341 WRITE ( 51, fmt= '( A, I4 )' )
342 + ' Data category: ', mtyp
343 ENDIF
344 CALL getcfmng ( lunit, 'TABLASL', msbt,
345 + 'TABLAT', mtyp,
346 + cmmsbt, lcmmsbt, iermsbt )
347 IF ( ( iermsbt .eq. 0 ) .and.
348 + ( iogce .eq. 7 ) ) THEN
349 WRITE ( 51, fmt= '( A, I4, 3A )' )
350 + ' Local subcategory: ', msbt,
351 + ' (= ', cmmsbt(1:lcmmsbt), ')'
352 ELSE
353 WRITE ( 51, fmt= '( A, I4 )' )
354 + ' Local subcategory: ', msbt
355 ENDIF
356 CALL getcfmng ( lunit, 'TABLASS', msbti,
357 + 'TABLAT', mtyp,
358 + cmmsbti, lcmmsbti, iermsbti )
359 IF ( iermsbti .eq. 0 ) THEN
360 WRITE ( 51, fmt= '( A, I4, 3A )' )
361 + ' Internatl subcategory: ', msbti,
362 + ' (= ', cmmsbti(1:lcmmsbti), ')'
363 ELSE
364 WRITE ( 51, fmt= '( A, I4 )' )
365 + ' Internatl subcategory: ', msbti
366 ENDIF
367 ENDIF
368
369 WRITE ( 51, fmt= '( A, I4 )' )
370 + ' Master table version: ',
371 + iupbs01( ibfmg, 'MTV' )
372 WRITE ( 51, fmt= '( A, I4 )' )
373 + ' Local table version: ',
374 + iupbs01( ibfmg, 'MTVL' )
375 WRITE ( 51, fmt= '( A, I4 )' )
376 + ' Year: ',
377 + iupbs01( ibfmg, 'YEAR' )
378 WRITE ( 51, fmt= '( A, I4 )' )
379 + ' Month: ',
380 + iupbs01( ibfmg, 'MNTH' )
381 WRITE ( 51, fmt= '( A, I4 )' )
382 + ' Day: ',
383 + iupbs01( ibfmg, 'DAYS' )
384 WRITE ( 51, fmt= '( A, I4 )' )
385 + ' Hour: ',
386 + iupbs01( ibfmg, 'HOUR' )
387 WRITE ( 51, fmt= '( A, I4 )' )
388 + ' Minute: ',
389 + iupbs01( ibfmg, 'MINU' )
390 WRITE ( 51, fmt= '( A, I4 )' )
391 + ' Second: ',
392 + iupbs01( ibfmg, 'SECO' )
393 IF ( ( iogce .eq. 7 ) .and. ( igses .eq. 3 ) ) THEN
394 CALL rtrcptb ( ibfmg, iryr, irmo, irdy, irhr,
395 + irmi, irtret )
396 IF ( irtret .eq. 0 ) THEN
397 WRITE ( 51, fmt= '( A, I4 )' )
398 + ' NCEP tank rcpt year: ', iryr
399 WRITE ( 51, fmt= '( A, I4 )' )
400 + ' NCEP tank rcpt month: ', irmo
401 WRITE ( 51, fmt= '( A, I4 )' )
402 + ' NCEP tank rcpt day: ', irdy
403 WRITE ( 51, fmt= '( A, I4 )' )
404 + ' NCEP tank rcpt hour: ', irhr
405 WRITE ( 51, fmt= '( A, I4 )' )
406 + ' NCEP tank rcpt minute: ', irmi
407 END IF
408 END IF
409
410C Decode and output the data from Section 3.
411
412 nsub = iupbs3( ibfmg, 'NSUB' )
413 WRITE ( 51, fmt= '( /, A, I4 )' )
414 + ' Number of data subsets: ', nsub
415 nsubt = nsubt + nsub
416
417 IF ( iupbs3( ibfmg, 'IOBS' ) .eq. 1 ) THEN
418 WRITE ( 51, fmt = '( A )')
419 + ' Data are observed?: Yes'
420 ELSE
421 WRITE ( 51, fmt = '( A )')
422 + ' Data are observed?: No'
423 ENDIF
424
425 IF ( iupbs3( ibfmg, 'ICMP' ) .eq. 1 ) THEN
426 WRITE ( 51, fmt = '( A )')
427 + ' Data are compressed?: Yes'
428 ELSE
429 WRITE ( 51, fmt = '( A )')
430 + ' Data are compressed?: No'
431 ENDIF
432
433 CALL upds3 ( ibfmg, mxds3, cds3, nds3 )
434 WRITE ( 51, fmt= '( A, I5 )' )
435 + ' Number of descriptors: ', nds3
436 DO jj = 1, nds3
437 WRITE ( 51, fmt = '( 5X, I4, A, A6)' )
438 + jj, ": ", cds3( jj )
439 END DO
440
441 IF ( ( basic .eq. 'N' ) .and.
442 + ( ierme .ge. 0 ) ) THEN
443
444C Decode and output the data from Section 4.
445
446 WRITE ( unit = 51,
447 + fmt = '( /, A, I7, 3A, I10, A, I6, A )' )
448 + 'BUFR message #', nmsg, ' of type ', cmgtag,
449 + ' and date ', imgdt, ' contains ', nsub,
450 + ' subsets:'
451 DO WHILE ( ireadsb( lunit ) .eq. 0 )
452 CALL ufdump ( lunit, 51 )
453 ENDDO
454 ENDIF
455
456 WRITE ( unit = 51, fmt = '( /, A, I7 )' )
457 + 'End of BUFR message #', nmsg
458 WRITE ( unit = 51, fmt = '( /, 120("-"))' )
459 ENDIF
460
461 ENDDO
462
463 RETURN
464 END
465
466C> This subroutine overrides the placeholder subroutine of the same
467C> name within the BUFRLIB distribution package.
468C>
469C> <p>Given the data category for a BUFR message, it opens the
470C> appropriate DX BUFR tables file to use in reading/decoding
471C> the message.
472C>
473C> @author J. Ator
474C> @date 2012-12-07
475C>
476C> @param[in] mtyp -- integer: Data category of BUFR message
477C> @param[out] lundx -- integer: Fortran logical unit number for
478C> DX BUFR tables file to use in
479C> reading/decoding the message
480C> - 0 = No such file is available
481C>
482C> <b>Program history log:</b>
483C> - 2012-12-07 J. Ator -- Original author
484C>
485 SUBROUTINE openbt ( lundx, mtyp )
486
488
489 character*11 bftab
490
491 character*240 bftabfil
492
493 logical exists
494
495C-----------------------------------------------------------------------
496C-----------------------------------------------------------------------
497
498 WRITE ( bftab, '("bufrtab.",i3.3)' ) mtyp
499 bftabfil = ctbldir(1:ltbd) // '/' // bftab
500
501 INQUIRE ( file = bftabfil, exist = exists )
502 IF ( exists ) THEN
503 lundx = ludx
504 CLOSE ( lundx )
505 OPEN ( unit = lundx, file = bftabfil )
506 ELSE
507 lundx = 0
508 END IF
509
510 RETURN
511 END
void crbmg(char *, f77int *, f77int *, f77int *)
This subroutine reads the next BUFR message from the system file that was opened via the most recent ...
Definition: crbmg.c:48
subroutine codflg(CF)
This subroutine is used to specify whether or not code and flag table information should be included ...
Definition: codflg.f:46
subroutine datelen(LEN)
This subroutine is used to specify the format of Section 1 date-time values that will be output by fu...
Definition: datelen.f:36
subroutine fdebufr(ofile, tbldir, lentd, tblfil, prmstg, basic, forcemt, cfms)
This subroutine reads, decodes, and generates a verbose output listing of the contents of every BUFR ...
Definition: debufr.f:88
subroutine dxdump(LUNIT, LDXOT)
This subroutine prints a copy of the DX BUFR table associated with a specified Fortran logical unit.
Definition: dxdump.f:46
subroutine getcfmng(LUNIT, NEMOI, IVALI, NEMOD, IVALD, CMEANG, LNMNG, IRET)
This subroutine searches for a specified Table B mnemonic and associated value (code figure or bit nu...
Definition: getcfmng.f:111
function idxmsg(MESG)
This function determines whether a given BUFR message contains DX BUFR tables information that was ge...
Definition: idxmsg.f:24
function ireadsb(LUNIT)
This function calls BUFRLIB subroutine readsb() and passes back its return code as the function value...
Definition: ireadsb.f:31
integer function isetprm(CPRMNM, IPVAL)
This function sets a specified parameter to a specified value for use in dynamically allocating one o...
Definition: isetprm.f:100
function iupbs01(MBAY, S01MNEM)
This function returns a specified value from within Section 0 or Section 1 of a BUFR message.
Definition: iupbs01.f:74
function iupbs3(MBAY, S3MNEM)
This function returns a specified value from within Section 3 of a BUFR message.
Definition: iupbs3.f:35
subroutine mtinfo(CMTDIR, LUNMT1, LUNMT2)
This subroutine allows the specification of the directory location and Fortran logical unit numbers t...
Definition: mtinfo.f:47
This module is used within the debufr utility to share information between subroutine fdebufr() and s...
Definition: debufr.f:9
subroutine openbf(LUNIT, IO, LUNDX)
This subroutine connects a new file to the BUFRLIB software for input or output operations.
Definition: openbf.f:139
subroutine openbt(LUNDX, MTYP)
This subroutine is called as a last resort from within subroutine cktaba(), in the event the latter s...
Definition: openbt.f:42
subroutine parstr(STR, TAGS, MTAG, NTAG, SEP, LIMIT80)
THIS SUBROUTINE PARSES A STRING CONTAINING ONE OR MORE SUBSTRINGS INTO AN ARRAY OF SUBSTRINGS.
Definition: parstr.f:38
subroutine readerme(MESG, LUNIT, SUBSET, JDATE, IRET)
This subroutine is similar to subroutine readmg(), except that it reads a BUFR message from an array ...
Definition: readerme.f:75
subroutine rtrcptb(MBAY, IYR, IMO, IDY, IHR, IMI, IRET)
This subroutine reads the tank receipt time (if one exists) from Section 1 of a BUFR message.
Definition: rtrcptb.f:32
subroutine strnum(STR, NUM)
This subroutine decodes an integer from a character string.
Definition: strnum.f:24
subroutine strsuc(STR1, STR2, LENS)
This subroutine removes leading and trailing blanks from a character string.
Definition: strsuc.f:24
subroutine ufdump(LUNIT, LUPRT)
This subroutine prints a verbose listing of the contents of a data subset, including all data values ...
Definition: ufdump.f:64
subroutine upds3(MBAY, LCDS3, CDS3, NDS3)
This subroutine returns the sequence of data descriptors contained within Section 3 of a BUFR message...
Definition: upds3.f:35