예제 #1
0
파일: rtkgps.c 프로젝트: DuQiFa/rtkgps-1
/*****************************************************************************
 Read a single log file.
 *****************************************************************************/
void file_read(int fd, short int flnm, char *fnam, FILE *strm,
	       const geoid_height_t *gdhtp, const status_t* status,
	       const cmdlnopts_t *cmdopt) {
  logfile_t lgfl;
#if !defined(FILENAME_DATE_PTR)
  date_time_t dt;
#endif
  gps_fix_t *gfxp = NULL;
  float *gcrp = NULL;
  char *pstr = "";
  int fn;

  if (cmdopt->vflg)
    printf("Requesting metadata for file %4d\n", flnm);

  /* Read metadata for file number flnm */
  if (get_file_info(fd, flnm, &lgfl) < 0) {
    fprintf(stderr,"rtkgps: Error reading information for file %d [%s]\n",
	    flnm, gcstrerror(rcerrno));
    free(fnam);
    outlog_enable(fd, status->gpsms, cmdopt);
    coms_close(fd, cmdopt);
    exit(5);
  }

  /* If memory is allocated for the file name, the output path is a
      destination directory. Construct a standard file path with the
      directory as a base, and open the file for writing */
  if (fnam != NULL) {

#if !defined(FILENAME_DATE_PTR)
    if (get_file_start_time(fd, &lgfl, &dt) != 1) {
      fprintf(stderr,"rtkgps: Error reading initial time for file %d [%s]\n",
	      flnm, gcstrerror(rcerrno));
      free(fnam);
      outlog_enable(fd, status->gpsms, cmdopt);
      coms_close(fd, cmdopt);
      exit(5);
    }
#endif

    /* Add filename postfix to indicate file is not complete (data
       still being captured). */
    if (flnm == status->nfile-1)
      pstr = "_part";
    /* Construct file name */
#if defined(FILENAME_DATE_PTR)
    sprintf(fnam, "%s/%8.8s_%06x%s.%s", cmdopt->dsts, lgfl.date, 
	    lgfl.memp, pstr, (cmdopt->nflg)?"rngl":"nmea");
#else
    sprintf(fnam, "%s/%8.8sT%6.6sZ%s.%s", cmdopt->dsts, lgfl.date, 
	    dt.time, pstr, (cmdopt->nflg)?"rngl":"nmea");
#endif
    /* Skip existing files if requested */
    if (cmdopt->uflg && is_nzsregfile(fnam) && flnm != status->nfile-1) {
      if (cmdopt->vflg)
	printf("Skipping download for file %4d\n", flnm);
      return;
    }

    /* Create backup of output file if it already exists */
    if (file_backup(fnam) != 0) {
      fprintf(stderr,"rtkgps: Error creating backup of file %s\n", fnam);
      free(fnam);
      outlog_enable(fd, status->gpsms, cmdopt);
      coms_close(fd, cmdopt);
      exit(3);
    }
    /* Attempt to open file */
    if ((strm = fopen(fnam, "w")) == NULL) {
      fprintf(stderr,"rtkgps: Error opening output file %s [%s]\n",
	      fnam, gcstrerror(rcerrno));
      free(fnam);
      outlog_enable(fd, status->gpsms, cmdopt);
      coms_close(fd, cmdopt);
      exit(3);
    }
  }

  /* Allocate memory for the log file data */
  if ((gfxp = malloc(lgfl.nfix*sizeof(gps_fix_t))) == NULL) {
    fprintf(stderr,"rtkgps: Error allocating memory\n");
    free(fnam);
    if (fnam != NULL)
      fclose(strm);
    outlog_enable(fd, status->gpsms, cmdopt);
    coms_close(fd, cmdopt);
    exit(2);
  }

#ifdef GEOIDCOR
  /* If necessary, allocate memory for geoid correction values */
  if (lgfl.fxtyp > 0 && gdhtp->filep != NULL) {
    if ((gcrp = malloc(lgfl.nfix*sizeof(float))) == NULL) {
      fprintf(stderr,"rtkgps: Error allocating memory\n");
      free(fnam);
      if (fnam != NULL)
	fclose(strm);
      outlog_enable(fd, status->gpsms, cmdopt);
      coms_close(fd, cmdopt);
      exit(2);
    }
  }
#endif

  if (cmdopt->vflg)
    printf("Requesting content of file   %4d\n", flnm);

  /* Read the log file data */
  fn = get_file_data(fd, &lgfl, gfxp);
  if (fn < 0) {
    fprintf(stderr,"rtkgps: Error reading file %d [%s]\n",
	    flnm, gcstrerror(rcerrno));
    /* Remove empty file so that it isn't skipped (with -u flag) on
       read restart */
    if (fnam != NULL)
      remove(fnam);
    free(gcrp);
    free(gfxp);
    free(fnam);
    if (fnam != NULL)
      fclose(strm);
    outlog_enable(fd, status->gpsms, cmdopt);
    coms_close(fd, cmdopt);
    exit(5);
  }

#ifdef GEOIDCOR
  if (gcrp != NULL) {
    const double dgrd = 360.0/(2*M_PI);
    unsigned short n;

    if (cmdopt->vflg)
      printf("Computing geoid altitude corrections\n");
    for (n = 0; n < lgfl.nfix; n++) {
      gcrp[n] = geoid_calc_correction(gdhtp, dgrd*gfxp[n].lat,
				      dgrd*gfxp[n].lng);
    }
  }
#endif

  /* Print the log file data to the output stream */
  if (cmdopt->nflg) {
    if (fnam != NULL)
      print_hdr_native(strm);
    print_log_native(strm, &lgfl, gfxp, gcrp);
  }
  else {
    if (fnam != NULL)
      print_hdr_nmea(strm, cmdopt->btas);
    print_log_nmea(strm, &lgfl, gfxp, gcrp);
  }

  /* Free memory for geoid correction values */
  free(gcrp);
  /* Free memory for the log file data */
  free(gfxp);

  /* If memory is allocated for the file name, the output path is a
     directory and the output stream was opened in this function, so
     the stream should be closed here */
  if (fnam != NULL)
    fclose(strm);
}
예제 #2
0
파일: rtkgps.c 프로젝트: DuQiFa/rtkgps-1
/*****************************************************************************
 Perform rtkgps read command.
 *****************************************************************************/
void cmd_read(cmdlnopts_t *cmdopt) {
  int fd;
  status_t status;
  geoid_height_t gdht = {0,0,0.0,0.0,0.0,0.0,0.0,0.0,0.0,NULL,NULL};
  FILE *strm = NULL;
  char *fnam = NULL;
  short int n;

#ifdef GEOIDCOR
  /* Set up geoid correction data structure */
  if (geoid_calc_open(GGRDPATH, &gdht) == -1) {
    fprintf(stderr, "rtkgps: Warning: could not access geoid correction "
	    "data\n");
  }
#endif

  /* Open communication with logger */
  fd = coms_open(cmdopt);

  /* Set up progress bar if requested */
  if (cmdopt->pflg) {
#ifdef HAVE_TIOCGWINSZ
     struct winsize ws;
     if (ioctl(1, TIOCGWINSZ, (void *)&ws) == 0)
       prgbrfp = 1;
     else if (ioctl(2, TIOCGWINSZ, (void *)&ws) == 0)
       prgbrfp = 2;
#else
     prgbrfp = 1;
#endif
     if (prgbrfp)
       gdpfp = get_data_progress;
  }

  if (cmdopt->vflg)
    printf("Requesting logger status information\n");

  /* Read logger status */
  status_read(fd, &status, cmdopt);

 /* Handle unspecified ends of file number range */
  if (cmdopt->fnmn == -1)
    cmdopt->fnmn = 0;
  if (cmdopt->fnmx == -1)
    cmdopt->fnmx = status.nfile-1;

  /* Check for minimum file number out of range */
  if (cmdopt->fnmn >= status.nfile) {
    fprintf(stderr,"rtkgps: Requested file number(s) all invalid\n");
    coms_close(fd, cmdopt);
    exit(1);
  }

  /* Check for maximum file number out of range */
  if (cmdopt->fnmx >= status.nfile) {
    cmdopt->fnmx = status.nfile-1;
    fprintf(stderr, "rtkgps:  Warning: reduced maximum requested file "
	    "number to valid range\n");
  }

  outlog_disable(fd, cmdopt);

  /* The complicated handling of output files, split between this function 
     and file_read, is due to the following output policy:
     • If no output file is specified, selected logfiles are written 
       to stdout
     • If the specified output file is a regular file, all selected logfiles
       are written to that file
     • If the specified output file is a directory, each selected logfile is
       written to a unique file within that directory  
  */
  if (cmdopt->dsts == NULL)
    strm = stdout; /* If output flag not specified, output stream is stdout */
  else {
    /* If output flag is specified, determine whether it is a directory */
    if (is_directory(cmdopt->dsts)) {
      /* If specified output path is a directory, allocate memory for
	 constructing the full output filename */
      if ((fnam = malloc(strlen(cmdopt->dsts) + 32)) == NULL) {
	fprintf(stderr,"rtkgps: Error allocating memory\n");
	outlog_enable(fd, status.gpsms, cmdopt);
	coms_close(fd, cmdopt);
	exit(2);
      }
    } else {
      /* If specified output path is not a directory, open the file
	 for writing after creating a backup if the file already exists. */
      if (file_backup(cmdopt->dsts) != 0) {
	fprintf(stderr,"rtkgps: Error creating backup of file %s\n",
		cmdopt->dsts);
	outlog_enable(fd, status.gpsms, cmdopt);
	coms_close(fd, cmdopt);
	exit(3);
      }
      if ((strm = fopen(cmdopt->dsts, "w")) == NULL) {
	fprintf(stderr,"rtkgps: Error opening output file %s [%s]\n",
		cmdopt->dsts, gcstrerror(rcerrno));
	outlog_enable(fd, status.gpsms, cmdopt);
	coms_close(fd, cmdopt);
	exit(3);
      }
    }
  }

  if (strm != NULL) {
    /* Write output file header */
    if (cmdopt->nflg)
      print_hdr_native(strm);
    else
      print_hdr_nmea(strm, cmdopt->btas);
  }

  /* Reset warning function message records */
  warning(NULL, 0, NULL);

  /* Read requested range of log files */
  for (n = cmdopt->fnmn; n <= cmdopt->fnmx; n++) {
    char nstr[8];

    /* If progress bar requested and verbose output not enabled, set
       up prefix displaying file number */
    if (cmdopt->pflg && !cmdopt->vflg) {
      sprintf(nstr, "%4d ", n);
      text_progress_bar(0.0, nstr);
    }
    file_read(fd, n, fnam, strm, &gdht, &status, cmdopt);

    /* Reset warning function message records */
    warning(NULL, 0, NULL);
  }

  /* Free memory allocated for file name */
  free(fnam);

  outlog_enable(fd, status.gpsms, cmdopt);

  /* Close ommunication with logger */
  coms_close(fd, cmdopt);

#ifdef GEOIDCOR
   /* Destroy geoid correction data structure */
  geoid_calc_close(&gdht);
#endif
}
예제 #3
0
파일: exf.c 프로젝트: fishman/nvi
/*
 * file_write --
 *	Write the file to disk.  Historic vi had fairly convoluted
 *	semantics for whether or not writes would happen.  That's
 *	why all the flags.
 *
 * PUBLIC: int file_write __P((SCR *, MARK *, MARK *, char *, int));
 */
int
file_write(SCR *sp, MARK *fm, MARK *tm, char *name, int flags)
{
    enum { NEWFILE, OLDFILE } mtype;
    struct stat sb;
    EXF *ep;
    FILE *fp;
    FREF *frp;
    MARK from, to;
    size_t len;
    u_long nlno, nch;
    int fd, nf, noname, oflags, rval;
    char *p, *s, *t, buf[MAXPATHLEN + 64];
    const char *msgstr;

    ep = sp->ep;
    frp = sp->frp;

    /*
     * Writing '%', or naming the current file explicitly, has the
     * same semantics as writing without a name.
     */
    if (name == NULL || !strcmp(name, frp->name)) {
        noname = 1;
        name = frp->name;
    } else
        noname = 0;

    /* Can't write files marked read-only, unless forced. */
    if (!LF_ISSET(FS_FORCE) && noname && O_ISSET(sp, O_READONLY)) {
        msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ?
             "244|Read-only file, not written; use ! to override" :
             "245|Read-only file, not written");
        return (1);
    }

    /* If not forced, not appending, and "writeany" not set ... */
    if (!LF_ISSET(FS_FORCE | FS_APPEND) && !O_ISSET(sp, O_WRITEANY)) {
        /* Don't overwrite anything but the original file. */
        if ((!noname || F_ISSET(frp, FR_NAMECHANGE)) &&
                !stat(name, &sb)) {
            msgq_str(sp, M_ERR, name,
                     LF_ISSET(FS_POSSIBLE) ?
                     "246|%s exists, not written; use ! to override" :
                     "247|%s exists, not written");
            return (1);
        }

        /*
         * Don't write part of any existing file.  Only test for the
         * original file, the previous test catches anything else.
         */
        if (!LF_ISSET(FS_ALL) && noname && !stat(name, &sb)) {
            msgq(sp, M_ERR, LF_ISSET(FS_POSSIBLE) ?
                 "248|Partial file, not written; use ! to override" :
                 "249|Partial file, not written");
            return (1);
        }
    }

    /*
     * Figure out if the file already exists -- if it doesn't, we display
     * the "new file" message.  The stat might not be necessary, but we
     * just repeat it because it's easier than hacking the previous tests.
     * The information is only used for the user message and modification
     * time test, so we can ignore the obvious race condition.
     *
     * One final test.  If we're not forcing or appending the current file,
     * and we have a saved modification time, object if the file changed
     * since we last edited or wrote it, and make them force it.
     */
    if (stat(name, &sb))
        mtype = NEWFILE;
    else {
        if (noname && !LF_ISSET(FS_FORCE | FS_APPEND) &&
                ((F_ISSET(ep, F_DEVSET) &&
                  (sb.st_dev != ep->mdev || sb.st_ino != ep->minode)) ||
                 sb.st_mtime != ep->mtime)) {
            msgq_str(sp, M_ERR, name, LF_ISSET(FS_POSSIBLE) ?
                     "250|%s: file modified more recently than this copy; use ! to override" :
                     "251|%s: file modified more recently than this copy");
            return (1);
        }

        mtype = OLDFILE;
    }

    /* Set flags to create, write, and either append or truncate. */
    oflags = O_CREAT | O_WRONLY |
             (LF_ISSET(FS_APPEND) ? O_APPEND : O_TRUNC);

    /* Backup the file if requested. */
    if (!opts_empty(sp, O_BACKUP, 1) &&
            file_backup(sp, name, O_STR(sp, O_BACKUP)) && !LF_ISSET(FS_FORCE))
        return (1);

    /* Open the file. */
    SIGBLOCK;
    if ((fd = open(name, oflags,
                   S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH)) < 0) {
        msgq_str(sp, M_SYSERR, name, "%s");
        SIGUNBLOCK;
        return (1);
    }
    SIGUNBLOCK;

    /* Try and get a lock. */
    if (!noname && file_lock(sp, NULL, NULL, fd, 0) == LOCK_UNAVAIL)
        msgq_str(sp, M_ERR, name,
                 "252|%s: write lock was unavailable");

#if __linux__
    /*
     * XXX
     * In libc 4.5.x, fdopen(fd, "w") clears the O_APPEND flag (if set).
     * This bug is fixed in libc 4.6.x.
     *
     * This code works around this problem for libc 4.5.x users.
     * Note that this code is harmless if you're using libc 4.6.x.
     */
    if (LF_ISSET(FS_APPEND) && lseek(fd, (off_t)0, SEEK_END) < 0) {
        msgq(sp, M_SYSERR, name);
        return (1);
    }
#endif

    /*
     * Use stdio for buffering.
     *
     * XXX
     * SVR4.2 requires the fdopen mode exactly match the original open
     * mode, i.e. you have to open with "a" if appending.
     */
    if ((fp = fdopen(fd, LF_ISSET(FS_APPEND) ? "a" : "w")) == NULL) {
        msgq_str(sp, M_SYSERR, name, "%s");
        (void)close(fd);
        return (1);
    }

    /* Build fake addresses, if necessary. */
    if (fm == NULL) {
        from.lno = 1;
        from.cno = 0;
        fm = &from;
        if (db_last(sp, &to.lno))
            return (1);
        to.cno = 0;
        tm = &to;
    }

    rval = ex_writefp(sp, name, fp, fm, tm, &nlno, &nch, 0);

    /*
     * Save the new last modification time -- even if the write fails
     * we re-init the time.  That way the user can clean up the disk
     * and rewrite without having to force it.
     */
    if (noname) {
        if (stat(name, &sb))
            time(&ep->mtime);
        else {
            F_SET(ep, F_DEVSET);
            ep->mdev = sb.st_dev;
            ep->minode = sb.st_ino;

            ep->mtime = sb.st_mtime;
        }
    }

    /*
     * If the write failed, complain loudly.  ex_writefp() has already
     * complained about the actual error, reinforce it if data was lost.
     */
    if (rval) {
        if (!LF_ISSET(FS_APPEND))
            msgq_str(sp, M_ERR, name,
                     "254|%s: WARNING: FILE TRUNCATED");
        return (1);
    }

    /*
     * Once we've actually written the file, it doesn't matter that the
     * file name was changed -- if it was, we've already whacked it.
     */
    F_CLR(frp, FR_NAMECHANGE);

    /*
     * If wrote the entire file, and it wasn't by appending it to a file,
     * clear the modified bit.  If the file was written to the original
     * file name and the file is a temporary, set the "no exit" bit.  This
     * permits the user to write the file and use it in the context of the
     * filesystem, but still keeps them from discarding their changes by
     * exiting.
     */
    if (LF_ISSET(FS_ALL) && !LF_ISSET(FS_APPEND)) {
        F_CLR(ep, F_MODIFIED);
        if (F_ISSET(frp, FR_TMPFILE)) {
            if (noname)
                F_SET(frp, FR_TMPEXIT);
            else
                F_CLR(frp, FR_TMPEXIT);
        }
    }

    p = msg_print(sp, name, &nf);
    switch (mtype) {
    case NEWFILE:
        msgstr = msg_cat(sp,
                         "256|%s: new file: %lu lines, %lu characters", NULL);
        len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch);
        break;
    case OLDFILE:
        msgstr = msg_cat(sp, LF_ISSET(FS_APPEND) ?
                         "315|%s: appended: %lu lines, %lu characters" :
                         "257|%s: %lu lines, %lu characters", NULL);
        len = snprintf(buf, sizeof(buf), msgstr, p, nlno, nch);
        break;
    default:
        abort();
    }

    /*
     * There's a nasty problem with long path names.  Cscope and tags files
     * can result in long paths and vi will request a continuation key from
     * the user.  Unfortunately, the user has typed ahead, and chaos will
     * result.  If we assume that the characters in the filenames only take
     * a single screen column each, we can trim the filename.
     */
    s = buf;
    if (len >= sp->cols) {
        for (s = buf, t = buf + strlen(p); s < t &&
                (*s != '/' || len >= sp->cols - 3); ++s, --len);
        if (s == t)
            s = buf;
        else {
            *--s = '.';		/* Leading ellipses. */
            *--s = '.';
            *--s = '.';
        }
    }
    msgq(sp, M_INFO, s);
    if (nf)
        FREE_SPACE(sp, p, 0);
    return (0);
}