NCEPLIBS-bufr  12.0.0
xbfmg.c
Go to the documentation of this file.
1 
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <string.h>
10 #include <libgen.h>
11 #include <unistd.h>
12 #include <sys/stat.h>
13 
14 #include "bufrlib.h"
15 
23 void prtusage( char *prgnam ) {
24  printf( "\nUSAGE: %s [-v] [-h] [-g] bufrfile\n\n", prgnam );
25  printf( "WHERE:\n" );
26  printf( " -v prints program version information and exits\n" );
27  printf( " -h prints program help and usage information and exits\n" );
28  printf( " -g preserves within each output file any GTS bulletin header and\n" );
29  printf( " control characters associated with the corresponding BUFR message\n" );
30  printf( " from the input file\n" );
31  printf( " bufrfile [path/]name of input file containing one or more BUFR messages\n" );
32  printf( " to be extracted into separate output files within the current\n" );
33  printf( " working directory\n\n" );
34  printf( "The output will be stored within the current working directory using the\n" );
35  printf( "following filenames:\n\n" );
36  printf( " (basename).xbfmg.out.000001\n" );
37  printf( " (basename).xbfmg.out.000002\n" );
38  printf( " (basename).xbfmg.out.000003\n" );
39  printf( " .\n" );
40  printf( " .\n" );
41  printf( " (basename).xbfmg.out.(last#)\n\n" );
42  printf( "where:\n\n" );
43  printf( " (basename) = basename of bufrfile\n" );
44  printf( " (last#) = total number of BUFR messages in bufrfile\n\n" );
45 }
46 
95 int main( int argc, char *argv[] ) {
96 
97  struct stat fileinfo;
98 
99  char *pc, *pmsg, *psb;
100 
101  int save_GTSbull = 0;
102 
103  char *outfile, *outfile_temp;
104 
105  char bvstr[VERS_STR_LEN+1];
106 
107  int ch;
108 
109  FILE *fp;
110 
111  int msglen, wkint;
112 
113  unsigned long i, filesize, noutfile;
114 
115  /*
116  ** Get the valid options from the command line:
117  */
118  while ( ( ch = getopt ( argc, argv, "vgh" ) ) != EOF ) {
119  switch ( ch ) {
120  case 'v':
121  bvers_f( bvstr, VERS_STR_LEN+1 );
122  printf( "This is xbfmg v4.0.0, built with NCEPLIBS-bufr v%s\n", bvstr );
123  return 0;
124  case 'g':
125  save_GTSbull = 1;
126  break;
127  case 'h':
128  printf( "\nPROGRAM %s\n", argv[0] );
129  printf( "\nABSTRACT: This program reads an input file containing one or more\n" );
130  printf( " BUFR messages as given by the first argument. It then extracts each\n" );
131  printf( " each individual BUFR message into its own separate output file within\n" );
132  printf( " the current working directory.\n" );
133  prtusage( argv[0] );
134  return 0;
135  break;
136  }
137  }
138 
139  /*
140  ** There should be one remaining command line argument specifying the input file.
141  */
142  if ( (optind+1) != argc ) {
143  printf( "\nERROR: You must specify an input BUFR file of BUFR messages!\n" );
144  prtusage( argv[0] );
145  return -1;
146  }
147 
148  /*
149  ** Get the filesize of the input file.
150  */
151  if ( stat( argv[optind], &fileinfo ) != 0 ) {
152  printf( "\nERROR: Could not stat the file %s!\n", argv[optind] );
153  return -1;
154  }
155  filesize = fileinfo.st_size;
156 
157  /*
158  ** Dynamically allocate memory in order to read in the input file.
159  */
160  if ( ( pc = malloc( filesize + 1 ) ) == NULL ) {
161  printf( "\nERROR: Could not allocate memory for file %s!\n", argv[optind] );
162  return -1;
163  }
164 
165  /*
166  ** Read the input file into memory.
167  */
168  if ( ( fp = fopen( argv[optind], "rb" ) ) == NULL ) {
169  printf( "\nERROR: Could not open input file %s!\n", argv[optind] );
170  free(pc);
171  return -1;
172  }
173  for ( i = 0; i < filesize; i++ ) {
174  pc[i] = (char) fgetc( fp );
175  }
176  pc[i] = '\0';
177  fclose( fp );
178 
179  /*
180  ** Create an output file name template.
181  */
182  if ( ( outfile_temp = malloc( strlen( argv[optind] ) + 26 ) ) == NULL ) {
183  // allow for up to 25 extra chars so that we can strcat an additional filename qualifier below
184  printf( "\nERROR: Could not allocate memory for output file name template!\n" );
185  return -1;
186  }
187  strcpy( outfile_temp, basename( argv[optind] ) );
188  strcat( outfile_temp, ".xbfmg.out" );
189  if ( ( outfile = malloc( strlen( outfile_temp ) + 26 ) ) == NULL ) {
190  // allow for up to 25 extra chars so that we can sprintf an additional filename qualifier below
191  printf( "\nERROR: Could not allocate memory for output file names!\n" );
192  return -1;
193  }
194 
195  /*
196  ** Call wrdlen function to initialize NCEPLIBS-bufr and determine machine endianness.
197  */
198  wrdlen_f( );
199 
200  /*
201  ** Locate each BUFR message within the input file and write each one to a separate output file.
202  **
203  ** Note that we can't use the intrinsic C strstr function to locate the "BUFR" and "7777"
204  ** strings within the file, because the file could contain embedded NULL characters.
205  */
206  noutfile = 0;
207  pmsg = psb = pc;
208  while ( 1 ) {
209  while ( ( ( pmsg - pc + 4 ) < filesize ) &&
210  ( ( *(pmsg) != 'B' ) ||
211  ( *(pmsg + 1) != 'U' ) ||
212  ( *(pmsg + 2) != 'F' ) ||
213  ( *(pmsg + 3) != 'R' ) ) ) {
214  if ( *pmsg == '\x01' ) psb = pmsg;
215  pmsg++;
216  }
217  if ( ( pmsg - pc + 4 ) >= filesize ) {
218  free( pc );
219  free( outfile_temp );
220  free( outfile );
221  return 0;
222  }
223 
224  /*
225  ** Open a new output file for this message.
226  */
227  sprintf( outfile, "%s.%06lu", outfile_temp, ++noutfile );
228  if ( ( fp = fopen( outfile, "wb" ) ) == NULL ) {
229  printf( "\nERROR: Could not open output file %s!\n", outfile );
230  return -1;
231  }
232 
233  /*
234  ** If requested, write the preceding GTS bulletin information to the output file.
235  */
236  if ( save_GTSbull ) {
237  while ( psb < pmsg ) {
238  fputc( *psb++, fp );
239  }
240  }
241 
242  /*
243  ** Read the BUFR message length from Section 0.
244  */
245  memcpy( &wkint, ( pmsg + 4 ), 3 );
246  msglen = iupb_f( &wkint, 1, 24 );
247 
248  /*
249  ** Write the BUFR message to the output file.
250  */
251  if ( ( pmsg + msglen - pc - 1 ) <= filesize ) {
252  for ( i = 1; i <= msglen; i++ ) {
253  fputc( *pmsg++, fp );
254  }
255  }
256 
257  /*
258  ** Make sure that the "7777" indicator is in the expected place.
259  */
260  if ( ( *(pmsg - 4) != '7' ) || ( *(pmsg - 3) != '7' ) ||
261  ( *(pmsg - 2) != '7' ) || ( *(pmsg - 1) != '7' ) ) {
262  printf( "\nERROR: Could not find 7777 indicator in output file %s!\n",
263  outfile );
264  }
265 
266  /*
267  ** If requested, append GTS bulletin tail markers to the output file.
268  */
269  if ( save_GTSbull ) {
270  fputc( '\x0d', fp );
271  fputc( '\x0d', fp );
272  fputc( '\x0a', fp );
273  fputc( '\x03', fp );
274  }
275 
276  fclose( fp );
277  }
278 }
void bvers_f(char *cverstr, int cverstr_len)
Get the version number of the NCEPLIBS-bufr software.
Enable a number of NCEPLIBS-bufr subprograms to be called from within the C part of the library.
#define VERS_STR_LEN
Size of a character string needed to store a library version number.
Definition: bufrlib.h:72
void wrdlen_f(void)
Determine important information about the local machine.
int iupb_f(int *mbay, int nbyt, int nbit)
Decode an integer value from an integer array.
integer, dimension(:), allocatable msglen
Length (in integers) of BUFR message most recently written to each output I/O stream.
int main(int argc, char *argv[])
This program splits a single file containing one or more BUFR messages into one or more BUFR files ea...
Definition: xbfmg.c:95
void prtusage(char *prgnam)
This function prints program usage information to standard output.
Definition: xbfmg.c:23