NCEPLIBS-bufr  12.1.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 "bufr_interface.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[2];
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 the xbfmg utility, 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  ** Locate each BUFR message within the input file and write each one to a separate output file.
197  **
198  ** Note that we can't use the intrinsic C strstr function to locate the "BUFR" and "7777"
199  ** strings within the file, because the file could contain embedded NULL characters.
200  */
201  noutfile = 0;
202  pmsg = psb = pc;
203  while ( 1 ) {
204  while ( ( ( pmsg - pc + 4 ) < filesize ) &&
205  ( ( *(pmsg) != 'B' ) ||
206  ( *(pmsg + 1) != 'U' ) ||
207  ( *(pmsg + 2) != 'F' ) ||
208  ( *(pmsg + 3) != 'R' ) ) ) {
209  if ( *pmsg == '\x01' ) psb = pmsg;
210  pmsg++;
211  }
212  if ( ( pmsg - pc + 4 ) >= filesize ) {
213  free( pc );
214  free( outfile_temp );
215  free( outfile );
216  return 0;
217  }
218 
219  /*
220  ** Open a new output file for this message.
221  */
222  sprintf( outfile, "%s.%06lu", outfile_temp, ++noutfile );
223  if ( ( fp = fopen( outfile, "wb" ) ) == NULL ) {
224  printf( "\nERROR: Could not open output file %s!\n", outfile );
225  return -1;
226  }
227 
228  /*
229  ** If requested, write the preceding GTS bulletin information to the output file.
230  */
231  if ( save_GTSbull ) {
232  while ( psb < pmsg ) {
233  fputc( *psb++, fp );
234  }
235  }
236 
237  /*
238  ** Read the BUFR message length from Section 0.
239  */
240  memcpy( wkint, pmsg, 8 );
241  msglen = iupbs01_f( wkint, "LENM" );
242 
243  /*
244  ** Write the BUFR message to the output file.
245  */
246  if ( ( pmsg + msglen - pc - 1 ) <= filesize ) {
247  for ( i = 1; i <= msglen; i++ ) {
248  fputc( *pmsg++, fp );
249  }
250  }
251 
252  /*
253  ** Make sure that the "7777" indicator is in the expected place.
254  */
255  if ( ( *(pmsg - 4) != '7' ) || ( *(pmsg - 3) != '7' ) ||
256  ( *(pmsg - 2) != '7' ) || ( *(pmsg - 1) != '7' ) ) {
257  printf( "\nERROR: Could not find 7777 indicator in output file %s!\n",
258  outfile );
259  }
260 
261  /*
262  ** If requested, append GTS bulletin tail markers to the output file.
263  */
264  if ( save_GTSbull ) {
265  fputc( '\x0d', fp );
266  fputc( '\x0d', fp );
267  fputc( '\x0a', fp );
268  fputc( '\x03', fp );
269  }
270 
271  fclose( fp );
272  }
273 }
Enable a number of NCEPLIBS-bufr subprograms to be called from within C and C++ application programs.
#define VERS_STR_LEN
Size of a character string needed to store a library version number.
int iupbs01_f(int *bufr, char *mnemonic)
Read a data value from Section 0 or Section 1 of a BUFR message.
void bvers_f(char *cverstr, int cverstr_len)
Get the version number of the NCEPLIBS-bufr software.
integer, dimension(:), allocatable msglen
Length (in integers) of BUFR message most recently written to each output file ID.
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