mirror of
https://github.com/Unidata/netcdf-c.git
synced 2024-12-03 08:01:25 +08:00
374 lines
7.3 KiB
C
374 lines
7.3 KiB
C
|
/*
|
||
|
* Copyright 1995, University Corporation for Atmospheric Research
|
||
|
* See top level COPYRIGHT file for copying and redistribution conditions.
|
||
|
*/
|
||
|
/* $Id: t_ncio.c,v 1.10 2010/05/26 11:11:26 ed Exp $ */
|
||
|
|
||
|
#include <config.h>
|
||
|
#include <stdio.h>
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
#include <ctype.h>
|
||
|
#include <assert.h>
|
||
|
#include "ncio.h"
|
||
|
#ifndef ENOERR
|
||
|
#define ENOERR 0
|
||
|
#endif
|
||
|
|
||
|
|
||
|
static void
|
||
|
usage(const char *av0)
|
||
|
{
|
||
|
(void)fprintf(stderr,
|
||
|
"Usage: %s [options] fname\t\nOptions:\n", av0);
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-v Verbose\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-w Open Read/Write, default is read only\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-c Create, clobber existing\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-n Create, error if it already exists\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-L Use locking if available\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-S Share updates (turn off caching)\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-U Delete (unlink) on close\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-o igeto Initial get offset\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-i igetsz Initial get size\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-I initialsz Initial file size for create\n") ;
|
||
|
(void)fprintf(stderr,
|
||
|
"\t-s sizehint Buffer size\n") ;
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
|
||
|
static long
|
||
|
argscale(const char *arg, const char *tag)
|
||
|
{
|
||
|
long value = 0;
|
||
|
/* last character */
|
||
|
const char *cp = arg + strlen(arg) -1;
|
||
|
value = atol(arg);
|
||
|
if(isalpha(*cp))
|
||
|
{
|
||
|
switch(*cp) {
|
||
|
case 'k':
|
||
|
case 'K':
|
||
|
value *= 1024;
|
||
|
break;
|
||
|
case 'm':
|
||
|
case 'M':
|
||
|
value *= (1024*1024);
|
||
|
break;
|
||
|
default:
|
||
|
value = 0; /* trigger error below */
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
if(value == 0)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"Illegal %s \"%s\", ignored\n", tag, arg);
|
||
|
}
|
||
|
return value;
|
||
|
}
|
||
|
|
||
|
|
||
|
static void
|
||
|
modify_ex(off_t offset, size_t extent, void *vp)
|
||
|
{
|
||
|
unsigned char *obuf = vp;
|
||
|
const unsigned char *const end = &obuf[extent];
|
||
|
unsigned char *cp = obuf;
|
||
|
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)( offset >> 24);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)((offset & 0x00ff0000) >> 16);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)((offset & 0x0000ff00) >> 8);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)( offset & 0x000000ff);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)( extent >> 24);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)((extent & 0x00ff0000) >> 16);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)((extent & 0x0000ff00) >> 8);
|
||
|
if(cp >= end) return;
|
||
|
*cp++ = (unsigned char)( extent & 0x000000ff);
|
||
|
|
||
|
while(cp < end)
|
||
|
{
|
||
|
*cp++ = (unsigned char) (cp - obuf);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
typedef struct riu {
|
||
|
struct riu *next;
|
||
|
struct riu *prev;
|
||
|
off_t offset;
|
||
|
size_t extent;
|
||
|
void *vp;
|
||
|
} riu;
|
||
|
|
||
|
static void
|
||
|
free_riu(riu *riup)
|
||
|
{
|
||
|
if(riup == NULL)
|
||
|
return;
|
||
|
free(riup);
|
||
|
}
|
||
|
|
||
|
static riu *
|
||
|
new_riu(off_t offset, size_t extent, void *vp)
|
||
|
{
|
||
|
riu *riup = (riu *)malloc(sizeof(riu));
|
||
|
if(riup == NULL)
|
||
|
{
|
||
|
fprintf(stderr,
|
||
|
"new_riu: malloc failed\n");
|
||
|
exit(EXIT_FAILURE);
|
||
|
}
|
||
|
riup->next = NULL;
|
||
|
riup->prev = NULL;
|
||
|
riup->offset = offset;
|
||
|
riup->extent = extent;
|
||
|
riup->vp = vp;
|
||
|
return riup;
|
||
|
}
|
||
|
|
||
|
static riu *stack = NULL;
|
||
|
|
||
|
static void
|
||
|
riu_push(off_t offset, size_t extent, void *vp)
|
||
|
{
|
||
|
riu *riup = new_riu(offset, extent, vp);
|
||
|
/* assert(riup != NULL); */
|
||
|
riup->next = stack;
|
||
|
if(stack != NULL)
|
||
|
stack->prev = riup;
|
||
|
stack = riup;
|
||
|
}
|
||
|
|
||
|
static int
|
||
|
riu_pop(off_t offset, int modify)
|
||
|
{
|
||
|
riu *riup = stack;
|
||
|
while(riup != NULL)
|
||
|
{
|
||
|
if(riup->offset == offset)
|
||
|
{
|
||
|
if(modify)
|
||
|
{
|
||
|
modify_ex(riup->offset, riup->extent, riup->vp);
|
||
|
}
|
||
|
if(riup->next != NULL)
|
||
|
{
|
||
|
riup->next->prev = riup->prev;
|
||
|
}
|
||
|
if(riup == stack)
|
||
|
{
|
||
|
stack = riup->next;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
assert(riup->prev != NULL);
|
||
|
riup->prev->next = riup->next;
|
||
|
}
|
||
|
free_riu(riup);
|
||
|
return 1;
|
||
|
}
|
||
|
riup = riup->next;
|
||
|
}
|
||
|
/* else, not found */
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
main(int ac, char *av[])
|
||
|
{
|
||
|
char *path = "";
|
||
|
ncio *nciop;
|
||
|
char linebuf[128];
|
||
|
off_t offset;
|
||
|
size_t extent;
|
||
|
void *vp;
|
||
|
int status = ENOERR;
|
||
|
int verbose = 0;
|
||
|
int flags = 0;
|
||
|
int create = 0;
|
||
|
off_t igeto = 0;
|
||
|
size_t igetsz = 0;
|
||
|
size_t initialsz = 0;
|
||
|
int doUnlink = 0;
|
||
|
size_t sizehint = NC_SIZEHINT_DEFAULT;
|
||
|
|
||
|
{
|
||
|
extern int optind;
|
||
|
extern int opterr;
|
||
|
extern char *optarg;
|
||
|
int ch;
|
||
|
|
||
|
opterr = 1;
|
||
|
|
||
|
while ((ch = getopt(ac, av, "vwcnLSUo:i:I:s:")) != EOF)
|
||
|
switch (ch) {
|
||
|
case 'v':
|
||
|
verbose = 1;
|
||
|
break;
|
||
|
case 'w':
|
||
|
flags |= NC_WRITE;
|
||
|
break;
|
||
|
case 'c':
|
||
|
create = 1;
|
||
|
break;
|
||
|
case 'n':
|
||
|
create = 1;
|
||
|
flags |= NC_NOCLOBBER;
|
||
|
break;
|
||
|
case 'L':
|
||
|
flags |= NC_LOCK;
|
||
|
break;
|
||
|
case 'S':
|
||
|
flags |= NC_SHARE;
|
||
|
break;
|
||
|
case 'U':
|
||
|
doUnlink = 1;
|
||
|
break;
|
||
|
case 'o':
|
||
|
igeto = argscale(optarg, "igeto");
|
||
|
break;
|
||
|
case 'i':
|
||
|
igetsz = argscale(optarg, "igetsz");
|
||
|
break;
|
||
|
case 'I':
|
||
|
initialsz = argscale(optarg, "initialsz");
|
||
|
break;
|
||
|
case 's':
|
||
|
sizehint = argscale(optarg, "sizehint");
|
||
|
break;
|
||
|
case '?':
|
||
|
usage(av[0]);
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
/* last arg, the file name, is required */
|
||
|
if(ac - optind <= 0)
|
||
|
usage(av[0]) ;
|
||
|
path = av[optind];
|
||
|
|
||
|
|
||
|
}
|
||
|
|
||
|
if(!create)
|
||
|
{
|
||
|
status = ncio_open(path, flags,
|
||
|
igeto, igetsz, &sizehint,
|
||
|
&nciop, &vp);
|
||
|
if(status != ENOERR)
|
||
|
{
|
||
|
fprintf(stderr, "ncio_open: %s: %s\n",
|
||
|
path, strerror(status));
|
||
|
return(EXIT_FAILURE);
|
||
|
}
|
||
|
} else {
|
||
|
status = ncio_create(path, flags, initialsz,
|
||
|
igeto, igetsz, &sizehint,
|
||
|
&nciop, &vp);
|
||
|
if(status != ENOERR)
|
||
|
{
|
||
|
fprintf(stderr, "ncio_create: %s: %s\n",
|
||
|
path, strerror(status));
|
||
|
return(EXIT_FAILURE);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
while(fgets(linebuf, sizeof(linebuf), stdin) != NULL)
|
||
|
{
|
||
|
offset = 0;
|
||
|
extent = 0;
|
||
|
|
||
|
if(*linebuf == '#')
|
||
|
continue; /* comment */
|
||
|
if(sscanf(linebuf, "rel 0x%lx", &offset) == 1
|
||
|
|| sscanf(linebuf, "rel %ld", &offset) == 1)
|
||
|
{
|
||
|
if(verbose)
|
||
|
printf("- rel %8ld\n", offset);
|
||
|
if(!riu_pop(offset, 0))
|
||
|
continue;
|
||
|
status = nciop->rel(nciop, offset, 0);
|
||
|
if(status)
|
||
|
{
|
||
|
fprintf(stderr, "- rel error: %s\n",
|
||
|
strerror(status));
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if(sscanf(linebuf, "relm 0x%lx", &offset) == 1
|
||
|
|| sscanf(linebuf, "relm %ld", &offset) == 1)
|
||
|
{
|
||
|
if(verbose)
|
||
|
printf("- relm %8ld\n", offset);
|
||
|
if(!riu_pop(offset, 1))
|
||
|
continue;
|
||
|
status = nciop->rel(nciop, offset, RGN_MODIFIED);
|
||
|
if(status)
|
||
|
{
|
||
|
fprintf(stderr, "- relm %8ld error: %s\n",
|
||
|
offset, strerror(status));
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
else if(sscanf(linebuf, "get 0x%lx %ld", &offset, &extent) == 2
|
||
|
|| sscanf(linebuf, "get %ld %ld", &offset, &extent) == 2)
|
||
|
{
|
||
|
if(verbose)
|
||
|
printf("- get %10ld %8ld\n", offset, extent);
|
||
|
status = nciop->get(nciop, offset, extent, 0, &vp);
|
||
|
if(status)
|
||
|
{
|
||
|
fprintf(stderr, "- get error: %s\n",
|
||
|
strerror(status));
|
||
|
continue;
|
||
|
}
|
||
|
riu_push(offset, extent, vp);
|
||
|
}
|
||
|
else if(sscanf(linebuf, "getw 0x%lx %ld", &offset, &extent) == 2
|
||
|
|| sscanf(linebuf, "getw %ld %ld", &offset, &extent) == 2)
|
||
|
{
|
||
|
if(verbose)
|
||
|
printf("- getw %10ld %8ld\n", offset, extent);
|
||
|
status = nciop->get(nciop, offset, extent, RGN_WRITE, &vp);
|
||
|
if(status)
|
||
|
{
|
||
|
fprintf(stderr, "- getw error: %s\n",
|
||
|
strerror(status));
|
||
|
continue;
|
||
|
}
|
||
|
riu_push(offset, extent, vp);
|
||
|
}
|
||
|
else if(strchr(linebuf, 'q') != NULL)
|
||
|
break;
|
||
|
else
|
||
|
printf("???\n");
|
||
|
}
|
||
|
|
||
|
status = ncio_close(nciop, doUnlink);
|
||
|
if(status != ENOERR)
|
||
|
{
|
||
|
fprintf(stderr, "ncio_close(%s): %s: %s\n",
|
||
|
doUnlink ? "doUnlink" : "",
|
||
|
path, strerror(status));
|
||
|
return(EXIT_FAILURE);
|
||
|
}
|
||
|
|
||
|
return(EXIT_SUCCESS);
|
||
|
}
|