util.c 19.5 KB
Newer Older
Uwe Schulzweida's avatar
Uwe Schulzweida committed
1
2
3
4
/*
  This file is part of CDO. CDO is a collection of Operators to
  manipulate and analyse Climate model Data.

Uwe Schulzweida's avatar
Uwe Schulzweida committed
5
  Copyright (C) 2003-2015 Uwe Schulzweida, <uwe.schulzweida AT mpimet.mpg.de>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
6
7
8
9
10
11
12
13
14
15
16
17
  See COPYING file for copying and redistribution conditions.

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation; version 2 of the License.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.
*/

18
19
20
21
#ifndef _XOPEN_SOURCE
#define _XOPEN_SOURCE 600 /* ftello */
#endif

22
23
24
25
#if defined(HAVE_CONFIG_H)
#  include "config.h"
#endif

26
27
28
29
#if defined(_OPENMP)
#  include <omp.h>
#endif

30
31
32
33
34
#if defined(HAVE_FNMATCH_H)
#include <fnmatch.h>
#endif


Uwe Schulzweida's avatar
Uwe Schulzweida committed
35
36
#include <stdio.h>
#include <string.h>
Uwe Schulzweida's avatar
Uwe Schulzweida committed
37
#include <ctype.h>   /* tolower */
Uwe Schulzweida's avatar
Uwe Schulzweida committed
38

Uwe Schulzweida's avatar
Uwe Schulzweida committed
39
#include "cdi.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
40
#include "cdo.h"
41
#include "cdo_int.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
42
#include "modules.h"
43
#include "util.h"
Uwe Schulzweida's avatar
Uwe Schulzweida committed
44

45
46
47
48

#if ! defined(VERSION)
#  define  VERSION  "0.0.1"
#endif
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
49
50
51
52
53
 

/* refactor: moved here from *.c */

int CDO_opterr = 0;      // refactor: moved here from cdo_getopt.c
54
const char *CDO_optarg = NULL; // refactor: moved here from cdo_getopt.c
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
55
int CDO_optind = 1;      // refactor: moved here from cdo_getopt.c
56

Uwe Schulzweida's avatar
Uwe Schulzweida committed
57

58
/* refactor: moved here from cdo.c */
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
59

60
char *Progname;
61
const char *CDO_Version = "Climate Data Operators version " VERSION" (http://mpimet.mpg.de/cdo)";
62

63
64
int ompNumThreads = 1;

65
66
67
68
int stdin_is_tty  = 0;
int stdout_is_tty = 0;
int stderr_is_tty = 0;

69
char *cdoGridSearchDir   = NULL;
70

71
72
73
74
int cdoDefaultFileType   = CDI_UNDEFID;
int cdoDefaultDataType   = CDI_UNDEFID;
int cdoDefaultByteorder  = CDI_UNDEFID;
int cdoDefaultTableID    = CDI_UNDEFID;
75
int cdoDefaultInstID     = CDI_UNDEFID;     // moved here from institution.c, was UNDEFID
76
77
int cdoDefaultTimeType   = CDI_UNDEFID;

78
79
80
int cdoLockIO            = FALSE;
int cdoCheckDatarange    = FALSE;

81
82
int CDO_Color            = FALSE;
int CDO_Use_FFTW         = TRUE;
83
int CDO_Version_Info     = TRUE;
84
85
int CDO_CMOR_Mode        = FALSE;

86
87
int cdoDiag              = FALSE;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
88
89
int CDO_Memtype          = MEMTYPE_DOUBLE;

90
int CDO_Reduce_Dim       = FALSE;
91
92
int CDO_Append_History   = TRUE;
int CDO_Reset_History    = FALSE;
93

94
95
int cdoCompType          = COMPRESS_NONE;  // compression type
int cdoCompLevel         = 0;              // compression level
96
int cdoDebug             = 0;
97
98
99
100
101
102
103
104
105
106
int cdoChunkType         = CDI_UNDEFID;
int cdoLogOff            = FALSE;
int cdoSilentMode        = FALSE;
int cdoOverwriteMode     = FALSE;
int cdoBenchmark         = FALSE;
int cdoTimer             = FALSE;
int cdoVerbose           = FALSE;
int cdoCompress          = FALSE;
int cdoInteractive       = FALSE;
int cdoParIO             = FALSE;
107
int cdoRegulargrid       = FALSE;
108

109
110
111
112
113
114
int cdoNumVarnames       = 0;
char **cdoVarnames       = NULL;

char CDO_File_Suffix[32];

int cdoExpMode           = -1;
115
const char *cdoExpName         = NULL;
116

117
118
119
int timer_read, timer_write;


Uwe Schulzweida's avatar
Uwe Schulzweida committed
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139

const char *cdoComment(void)
{
  static char comment[256];
  static int init = 0;

  if ( ! init )
    {
      init = 1;

      int size = strlen(CDO_Version);

      strncat(comment, CDO_Version, size);
      comment[size] = 0;
    }

  return comment;
}


140
141
142
#if defined(HAVE_FNMATCH_H)
int wildcardmatch(const char *pattern, const char *string)
{
143
  return fnmatch(pattern, string, 0);
144
145
}
#else
146
147
148
149
150
151
152
153
// The wildcardmatch function checks if two given strings match. 
// The first string may contain wildcard characters
// * --> Matches with 0 or more instances of any character or set of characters.
// ? --> Matches with any one character.
// source code from http://www.geeksforgeeks.org/wildcard-character-matching/
int wildcardmatch(const char *w, const char *s)
{
    // If we reach at the end of both strings, we are done
154
    if ( *w == '\0' && *s == '\0' ) return 0;
155
156
157
 
    // Make sure that the characters after '*' are present in second string.
    // This function assumes that the first string will not contain two consecutive '*'
158
    if ( *w == '*' && *(w+1) != '\0' && *s == '\0' ) return 1;
159
160
 
    // If the first string contains '?', or current characters of both strings match
161
    if ( (*w == '?' && *s != '\0') || *w == *s ) return wildcardmatch(w+1, s+1);
162
163
164
165
166
167
 
    // If there is *, then there are two possibilities
    // a) We consider current character of second string
    // b) We ignore current character of second string.
    if ( *w == '*' ) return wildcardmatch(w+1, s) || wildcardmatch(w, s+1);

168
    return 1;
169
}
170
#endif
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
171

172
173
174
int cdo_omp_get_thread_num(void)
{
#if defined(_OPENMP)
175
176
177
  return omp_get_thread_num();
#else
  return 0;
178
179
180
181
#endif
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
182
183
184
185
char *getProgname(char *string)
{
  char *progname;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
186
#if defined(_WIN32)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
187
188
  /*  progname = strrchr(string, '\\'); */
  progname = " cdo";
Uwe Schulzweida's avatar
Uwe Schulzweida committed
189
#else
Uwe Schulzweida's avatar
Uwe Schulzweida committed
190
  progname = strrchr(string, '/');
Uwe Schulzweida's avatar
Uwe Schulzweida committed
191
#endif
Uwe Schulzweida's avatar
Uwe Schulzweida committed
192
193
194
195
196
197
198
199
200
201
202
203
204
205

  if ( progname == NULL ) progname = string;
  else                    progname++;

  return (progname);
}

char *getOperator(const char *argument)
{
  char *operatorArg = NULL;
  size_t len;

  if ( argument )
    {
206
      len = 1 + strlen(argument);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
207

208
      operatorArg = (char*) Malloc(len);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
209

210
      memcpy(operatorArg, argument, len);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
211
212
213
214
215
    }

  return (operatorArg);
}

216
char *operatorAlias(char *operatorName);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
217

Uwe Schulzweida's avatar
Uwe Schulzweida committed
218
char *getOperatorName(const char *operatorArg)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
219
220
221
222
223
224
225
226
227
{
  char *commapos;
  char *operatorName = NULL;
  size_t len;

  if ( operatorArg )
    {
      if ( operatorArg[0] == '-' ) operatorArg++;

Oliver Heidmann's avatar
Oliver Heidmann committed
228
      commapos = (char *)strchr(operatorArg, ',');
Uwe Schulzweida's avatar
Uwe Schulzweida committed
229
230

      if ( commapos )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
231
        len = commapos - operatorArg;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
232
      else
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
233
        len = strlen(operatorArg);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
234

235
      operatorName = (char*) Malloc(len+1);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
236

237
      memcpy(operatorName, operatorArg, len);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
238
239
240
241
      operatorName[len] = '\0';
    }

  /*  return (operatorName); */
242
243
  char * alias = operatorAlias(operatorName);
  return alias;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
244
245
246
}


247
248
249
250
argument_t *file_argument_new(const char *filename)
{
  argument_t *argument;

251
  argument = (argument_t*) Calloc(1, sizeof(argument_t));
252
253

  argument->argc = 1;
254
  argument->argv = (char **) Calloc(1, sizeof(char *));
255
256
  argument->argv[0] = (char *) filename;
  argument->args = (char *) filename;
257
258
259
260
261
262
263
264
265
266

  return (argument);
}


void file_argument_free(argument_t *argument)
{
  if ( argument )
    {
      if ( argument->argc )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
267
268
        {
          assert(argument->argc == 1);
269
          Free(argument->argv);
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
270
        }
271
      Free(argument);
272
273
274
275
    }
}


276
argument_t *argument_new(size_t argc, size_t len)
Uwe Schulzweida's avatar
Uwe Schulzweida committed
277
{
278
  argument_t *argument;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
279

280
  argument = (argument_t*) Calloc(1, sizeof(argument_t));
Uwe Schulzweida's avatar
cleanup    
Uwe Schulzweida committed
281

282
  if ( argc > 0 )
Uwe Schulzweida's avatar
Uwe Schulzweida committed
283
    {
284
      argument->argc = argc;
285
      argument->argv = (char **) Calloc(argc, sizeof(char *));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
286
287
    }

288
  if ( len > 0 )
289
    argument->args = (char*) Calloc(len, sizeof(char));
Uwe Schulzweida's avatar
Uwe Schulzweida committed
290
291
292
293
294

  return (argument);
}


295
296
297
298
299
void argument_free(argument_t *argument)
{
  if ( argument )
    {
      if ( argument->argc )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
300
301
302
303
304
305
        {
          int argc =  argument->argc;
          for ( int i = 0; i < argc; ++i )
            {
              if ( argument->argv[i] )
                {
306
                  Free(argument->argv[i]);
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
307
308
309
310
                  argument->argv[i] = NULL;
                }
            }

311
          Free(argument->argv);
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
312
313
314
          argument->argv = NULL;
          argument->argc = 0;
        }
315
316

      if ( argument->args )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
317
        {
318
          Free(argument->args);
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
319
320
          argument->args = NULL;
        }
321

322
      Free(argument);
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
    }
}


void argument_fill(argument_t *argument, int argc, char *argv[])
{
  int iarg;

  assert(argument->argc == argc);

  for ( iarg = 0; iarg < argc; ++iarg )
    argument->argv[iarg] = strdup(argv[iarg]);
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
338
339
340
341
342
343
344
345
346
347
348
349
char *getFileArg(char *argument)
{
  char *fileArg = NULL;
  char *parg;
  char *blankpos;
  size_t len;

  if ( argument )
    {
      blankpos = strchr(argument, ' ');

      if ( blankpos )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
350
351
352
        {
          parg = blankpos + 1;
          len = strlen(parg);
353
          fileArg = (char*) Malloc(len+1);
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
354
355
          strcpy(fileArg, parg);
        }
Uwe Schulzweida's avatar
Uwe Schulzweida committed
356
357
358
359
360
    }

  return (fileArg);
}

Uwe Schulzweida's avatar
Uwe Schulzweida committed
361

Uwe Schulzweida's avatar
Uwe Schulzweida committed
362
363
364
365
366
367
368
369
370
371
372
void input_int(char *arg, int intarr[], int maxint, int *nintfound)
{
  int nint = 0;

  intarr[nint++] = atoi(arg);

  while ( (arg = strchr(arg, ',')) && (nint < maxint) )
    intarr[nint++] = atoi(++arg);
    
  *nintfound = nint;
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
373
374
375
376
377
378
379
380
381
382


void strtolower(char *str)
{
  int i, len;

  if ( str )
    {
      len = (int) strlen(str);
      for ( i = 0; i < len; i++ )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
383
        str[i] = tolower((int) str[i]);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
384
385
    }
}
386
387


388
389
390
391
392
393
394
double parameter2double(const char *string)
{
  char *endptr = NULL;

  double fval = strtod(string, &endptr);

  if ( *endptr != 0 )
395
396
    cdoAbort("Float parameter >%s< contains invalid character at position %d!",
	     string, (int)(endptr-string+1));
397
398
399
400
401

  return (fval);
}


402
403
404
405
406
407
408
int parameter2int(const char *string)
{
  char *endptr = NULL;

  int ival = (int) strtol(string, &endptr, 10);

  if ( *endptr != 0 )
409
410
    cdoAbort("Integer parameter >%s< contains invalid character at position %d!",
	     string, (int)(endptr-string+1));
411
412
413
414
415

  return (ival);
}


416
417
418
419
420
421
422
423
424
425
426
427
428
429
int parameter2intlist(const char *string)
{
  char *endptr = NULL;

  int ival = (int) strtol(string, &endptr, 10);

  if ( *endptr != 0 && *endptr != '/' && (endptr - string) == 0 )
    cdoAbort("Integer parameter >%s< contains invalid character at position %d!",
	     string, (int)(endptr-string+1));

  return (ival);
}


430
431
432
const char *seas_name_dec[4] = {"DJF", "MAM", "JJA", "SON"};
const char *seas_name_jan[4] = {"JFM", "AMJ", "JAS", "OND"};

433
434
static int season_start = START_DEC;

435
436
int get_season_start(void)
{
437
  static int lgetenv = TRUE;
438

439
  if ( lgetenv )
440
    {
441
442
443
444
      lgetenv = FALSE;
  
      char *envstr = getenv("CDO_SEASON_START");
      if ( envstr )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
445
        {
446
447
448
449
450
451
452
453
454
455
          if      ( strcmp(envstr, "DEC") == 0 ) season_start = START_DEC;
          else if ( strcmp(envstr, "JAN") == 0 ) season_start = START_JAN;
      
          if ( cdoVerbose )
            {
              if      ( season_start == START_DEC )
                cdoPrint("Set SEASON_START to December");
              else if ( season_start == START_JAN )
                cdoPrint("Set SEASON_START to January");
            }
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
456
        }
457
458
    }

459
  return season_start;
460
461
462
}


Uwe Schulzweida's avatar
Uwe Schulzweida committed
463
void get_season_name(const char *seas_name[])
464
465
466
467
468
469
470
471
472
{
  long i;

  if ( get_season_start() == START_DEC )
    for ( i = 0; i < 4; ++i ) seas_name[i] = seas_name_dec[i];
  else
    for ( i = 0; i < 4; ++i ) seas_name[i] = seas_name_jan[i];
}

473

474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
int month_to_season(int month)
{
  int season_start = get_season_start();
  int seas = -1;

  if ( month < 0 || month > 16 ) cdoAbort("Month %d out of range!", month);

  if ( season_start == START_DEC )
    {
      if ( month <= 12 )
        seas = (month % 12) / 3;
      else
        seas = month - 13;
    }
  else
    {
      if ( month <= 12 )
        seas = (month - 1) / 3;
      else
        seas = month - 13;
    }

  if ( seas < 0 || seas > 3 ) cdoAbort("Season %d out of range!", seas+1);

  return seas;
}

501
502
503
504
//#include <sys/types.h>
#include <sys/stat.h>
//#include <unistd.h>

505
int fileExists(const char *restrict filename)
506
507
508
509
510
511
{
  int status = 0;
  struct stat buf;

  if ( stat(filename, &buf) == 0 )
    {
512
      if ( S_ISREG(buf.st_mode) && buf.st_size > 0 ) status = 1;
513
514
    }

515
  return status;
516
517
518
}


519
int userFileOverwrite(const char *restrict filename)
520
{
521
  int status = 0, len;
522
523
  char line[1024], *pline;

Uwe Schulzweida's avatar
Uwe Schulzweida committed
524
  fprintf(stderr, "File %s already exists, overwrite? (yes/no): ", filename);
525
526
527
  readline(stdin, line, 1024);
  pline = line;
  while ( isspace((int) *pline) ) pline++;
528
529
530
531
  len = strlen(pline);
  if ( len == 3 )
    {
      if ( pline[0] == 'y' && pline[1] == 'e' && pline[2] == 's' )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
532
        status = 1;
533
      else if ( pline[0] == 'Y' && pline[1] == 'E' && pline[2] == 'S' )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
534
        status = 1;
535
536
537
538
539
    }
  else if ( len == 1 )
    {
      if ( pline[0] == 'y' ) status = 1;
    }
540
541
542

  return (status);
}
543
544


545
int ps_lhead = FALSE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
546
547
int ps_nch   = 0;
int ps_cval  = -1;
548
549
550
551

void progressInit(void)
{
  ps_lhead = FALSE;
552
  ps_nch   = 0;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
553
  ps_cval  = -1;
554
555
556
}


557
558
559
560
void progressStatus(double offset, double refval, double curval)
{
  int ival;

561
  if ( cdoSilentMode ) return;
562
563
564
565
566
567
568
569
570
571
572
  if ( !stdout_is_tty ) return;

  offset = offset < 0 ? 0: offset;
  offset = offset > 1 ? 1: offset;
  refval = refval < 0 ? 0: refval;
  refval = refval > 1 ? 1: refval;
  curval = curval < 0 ? 0: curval;
  curval = curval > 1 ? 1: curval;

  ival = (offset + refval*curval)*100;

573
  if ( ps_cval == -1 )
574
    {
575
      ps_nch = fprintf(stdout, "%s: %3d%%", processInqPrompt(), 0);
576
      fflush(stdout);
577
      ps_lhead = TRUE;
578
579
    }

580
  if ( ival != ps_cval )
581
    {
582
583
      ps_cval = ival;
      fprintf(stdout, "\b\b\b\b%3d%%", ps_cval);
584
585
586
      fflush(stdout);
    }

587
  if ( ps_cval == 100 && ps_lhead )
588
    {
589
      ps_lhead = FALSE;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
590
      while ( ps_nch-- ) fprintf(stdout, "\b \b");
591
592
593
      fflush(stdout);
    }
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615


int datatype2str(int datatype, char *datatypestr)
{
  int status = 0;

  if      ( datatype == DATATYPE_PACK   ) strcpy(datatypestr, "P0");
  else if ( datatype > 0 && datatype <= 32  ) sprintf(datatypestr, "P%d", datatype);
  else if ( datatype == DATATYPE_CPX32  ) strcpy(datatypestr, "C32");
  else if ( datatype == DATATYPE_CPX64  ) strcpy(datatypestr, "C64");
  else if ( datatype == DATATYPE_FLT32  ) strcpy(datatypestr, "F32");
  else if ( datatype == DATATYPE_FLT64  ) strcpy(datatypestr, "F64");
  else if ( datatype == DATATYPE_INT8   ) strcpy(datatypestr, "I8");
  else if ( datatype == DATATYPE_INT16  ) strcpy(datatypestr, "I16");
  else if ( datatype == DATATYPE_INT32  ) strcpy(datatypestr, "I32");
  else if ( datatype == DATATYPE_UINT8  ) strcpy(datatypestr, "U8");
  else if ( datatype == DATATYPE_UINT16 ) strcpy(datatypestr, "U16");
  else if ( datatype == DATATYPE_UINT32 ) strcpy(datatypestr, "U32");
  else                                  { strcpy(datatypestr, "-1"); status = -1;}

  return (status);
}
Uwe Schulzweida's avatar
Uwe Schulzweida committed
616
617
618
619
620
621
622
623
624
625
626


int str2datatype(const char *datatypestr)
{
  int datatype = -1;
  size_t len;

  len = strlen(datatypestr);

  if ( len > 1 )
    {
Uwe Schulzweida's avatar
Uwe Schulzweida committed
627
      int ilen = atoi(datatypestr+1);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
628
629
      if      ( strncmp(datatypestr, "P0",  len) == 0 ) datatype = DATATYPE_PACK;
      else if ( strncmp(datatypestr, "P",     1) == 0 &&
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
630
                ilen > 0 && ilen <= 32 )               datatype = atoi(datatypestr+1);
Uwe Schulzweida's avatar
Uwe Schulzweida committed
631
632
633
634
635
636
637
638
639
640
641
642
      else if ( strncmp(datatypestr, "C32", len) == 0 ) datatype = DATATYPE_CPX32;
      else if ( strncmp(datatypestr, "C64", len) == 0 ) datatype = DATATYPE_CPX64;
      else if ( strncmp(datatypestr, "F32", len) == 0 ) datatype = DATATYPE_FLT32;
      else if ( strncmp(datatypestr, "F64", len) == 0 ) datatype = DATATYPE_FLT64;
      else if ( strncmp(datatypestr, "I8",  len) == 0 ) datatype = DATATYPE_INT8;
      else if ( strncmp(datatypestr, "I16", len) == 0 ) datatype = DATATYPE_INT16;
      else if ( strncmp(datatypestr, "I32", len) == 0 ) datatype = DATATYPE_INT32;
      else if ( strncmp(datatypestr, "U8",  len) == 0 ) datatype = DATATYPE_UINT8;
      else if ( strncmp(datatypestr, "U16", len) == 0 ) datatype = DATATYPE_UINT16;
      else if ( strncmp(datatypestr, "U32", len) == 0 ) datatype = DATATYPE_UINT32;
      else if ( strncmp(datatypestr, "real",   len) == 0 ) datatype = DATATYPE_FLT32;
      else if ( strncmp(datatypestr, "double", len) == 0 ) datatype = DATATYPE_FLT64;
Uwe Schulzweida's avatar
Uwe Schulzweida committed
643
644
645
646
    }

  return (datatype);
}
647
648


649
off_t fileSize(const char *restrict filename)
650
{
651
  off_t filesize = 0;
652
653
654
655
656
657

  if ( filename[0] == '(' && filename[1] == 'p' )
    {
    }
  else
    {
658
659
      struct stat buf;
      if ( stat(filename, &buf) == 0 ) filesize = buf.st_size;
660
661
    }
  
662
  return filesize;
663
}
664
665
666
667
668


/* 
 * Return the filetype extension (const char)
 * for a given filetype (int)
669
 * TODO: handle lists of extensions i.e. grb and grb2 for GRIB2-format
670
671
672
673
674
 */
const char *filetypeext(int filetype)
{
  switch ( filetype )
    {
675
676
    case FILETYPE_GRB:
    case FILETYPE_GRB2: return (".grb");   break;
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
    case FILETYPE_NC:
    case FILETYPE_NC2:
    case FILETYPE_NC4:
    case FILETYPE_NC4C: return (".nc");    break;
    case FILETYPE_SRV:  return (".srv");   break;
    case FILETYPE_EXT:  return (".ext");   break;
    case FILETYPE_IEG:  return (".ieg");   break;
    default:            return ("");
    }
}


/*
 * Remove file extension:
 * -------------------------------------------------
 * Remove file extension if it is the expected one
 * Do nothing otherwise
 */
void rm_filetypeext(char *file, const char *ext)
{
  // length of filename
  int namelen = (int) strlen(file);
  // length of the original file extension
  int extlen =  (int) strlen(ext);

  // delete original extension if it is the expected one
  if ( strcmp(&file[namelen-extlen], ext) == 0 )
      file[namelen-extlen] = 0;
}


/*
 * Replace or just add file extension:
 * -------------------------------------------------
 * Replace file extension with new one
 * or just add the new file extension 
 * if the original extension is not the expected one
 */
void repl_filetypeext(char file[], const char *oldext, const char *newext)
{
  // delete original extension if it is the expected one
  rm_filetypeext(file, oldext);

  // add new file extension
  strcat(file, newext);
}
723
724
725
726
727
728
729


void cdoGenFileSuffix(char *filesuffix, size_t maxlen, int filetype, int vlistID, const char *refname)
{
  if ( strncmp(CDO_File_Suffix, "NULL", 4) != 0 )
    {
      if ( CDO_File_Suffix[0] != 0 )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
730
731
732
        {
          strncat(filesuffix, CDO_File_Suffix, maxlen-1);
        }
733
      else
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
734
735
736
737
738
739
740
741
742
743
744
        {
          int lready = FALSE;
          int lcompsz = FALSE;
          
          if ( filetype == cdoDefaultFileType && cdoDefaultDataType == -1 && cdoDefaultByteorder == -1 )
            {
              size_t len = 0;
              if ( refname != NULL && *refname != 0 && *refname != '-' && *refname != '.' ) len = strlen(refname);

              if ( len > 2 )
                {
Oliver Heidmann's avatar
Oliver Heidmann committed
745
                  char *result = (char *)strrchr(refname, '.');
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
                  if ( result != NULL && result[1] != 0 )
                    {
                      int firstchar = tolower(result[1]);
                      switch (firstchar)
                        {
                        case 'g':
                          if ( cdoDefaultFileType == FILETYPE_GRB || cdoDefaultFileType == FILETYPE_GRB2 ) lready = TRUE;
                          break;
                        case 'n':
                          if ( cdoDefaultFileType == FILETYPE_NC || cdoDefaultFileType == FILETYPE_NC2 ||
                               cdoDefaultFileType == FILETYPE_NC4 || cdoDefaultFileType == FILETYPE_NC4C ) lready = TRUE;
                          break;
                        case 's':
                          if ( cdoDefaultFileType == FILETYPE_SRV ) lready = TRUE;
                          break;
                        case 'e':
                          if ( cdoDefaultFileType == FILETYPE_EXT ) lready = TRUE;
                          break;
                        case 'i':
                          if ( cdoDefaultFileType == FILETYPE_IEG ) lready = TRUE;
                          break;
                        }
                    }
769
770
771
772
773
774
775
776
777
778
779

                  //if ( lready )  strncat(filesuffix, result, maxlen-1);
		  if ( lready && ((len=strlen(result)) < (maxlen-1)) )
		    {
		      while ( len-- )
			{
			  if ( *result == '.' || isalnum(*result) ) 
			    strncat(filesuffix, result, 1);
			  result++;
			}
		    }
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
780
781
782
783
784
785
786
787
788
789
790
791
                }
            }

          if ( !lready )
            {
              strncat(filesuffix, streamFilesuffix(cdoDefaultFileType), maxlen-1);
              if ( cdoDefaultFileType == FILETYPE_GRB && vlistIsSzipped(vlistID) ) lcompsz = TRUE;
            }

          if ( cdoDefaultFileType == FILETYPE_GRB && cdoCompType == COMPRESS_SZIP ) lcompsz = TRUE;
          if ( lcompsz ) strncat(filesuffix, ".sz", maxlen-1);
        }
792
793
794
795
796
797
798
799
800
801
    }
}


int cdoFiletype(void)
{
  if ( cdoDefaultFileType == CDI_UNDEFID )
    {
      cdoDefaultFileType = FILETYPE_GRB;
      if ( ! cdoSilentMode )
Yvonne Kuestermann's avatar
Yvonne Kuestermann committed
802
        cdoPrint("Set default filetype to GRIB");
803
804
805
806
807
    }

  return (cdoDefaultFileType);
}