mirror of
https://github.com/GoldenCheetah/GoldenCheetah.git
synced 2026-02-13 08:08:42 +00:00
- Download ride dialog now shows progress better.
- cpint added to GUI - cpint now handles interrupt properly, deleting partially-computed files
This commit is contained in:
@@ -27,12 +27,20 @@
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <unistd.h>
|
||||
#include "cpint.h"
|
||||
|
||||
struct cpi_file_info *head;
|
||||
|
||||
static void
|
||||
one_done_cb(const char *longdate)
|
||||
canceled(int unused)
|
||||
{
|
||||
fprintf(stderr, "Compiling data for ride on %s...", longdate);
|
||||
unused = 0;
|
||||
if (head) {
|
||||
fprintf(stderr, "calceled.\n");
|
||||
unlink(head->outname);
|
||||
}
|
||||
exit(1);
|
||||
}
|
||||
|
||||
int
|
||||
@@ -44,7 +52,15 @@ main(int argc, char *argv[])
|
||||
char *dir = ".";
|
||||
if (argc > 1)
|
||||
dir = argv[1];
|
||||
update_cpi_files(dir, one_done_cb);
|
||||
signal(SIGINT, canceled);
|
||||
head = cpi_files_to_update(dir);
|
||||
while (head) {
|
||||
fprintf(stderr, "Processing ride file %s...", head->file);
|
||||
fflush(stderr);
|
||||
update_cpi_file(head, NULL, NULL);
|
||||
fprintf(stderr, "done.\n");
|
||||
head = head->next;
|
||||
}
|
||||
combine_cpi_files(dir, &bests, &bestlen);
|
||||
for (i = 0; i < bestlen; ++i) {
|
||||
if (bests[i] != 0)
|
||||
|
||||
168
src/gui/CpintPlot.cpp
Normal file
168
src/gui/CpintPlot.cpp
Normal file
@@ -0,0 +1,168 @@
|
||||
/*
|
||||
* $Id: CpintPlot.cpp,v 1.2 2006/07/12 02:13:57 srhea Exp $
|
||||
*
|
||||
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#include "CpintPlot.h"
|
||||
|
||||
extern "C" {
|
||||
#include "cpint.h"
|
||||
}
|
||||
|
||||
#include <qwt_data.h>
|
||||
#include <qwt_legend.h>
|
||||
#include <qwt_plot_curve.h>
|
||||
#include <qwt_plot_grid.h>
|
||||
#include <qwt_scale_engine.h>
|
||||
|
||||
CpintPlot::CpintPlot(QString p) : path(p), allCurve(NULL), thisCurve(NULL),
|
||||
grid(NULL)
|
||||
{
|
||||
insertLegend(new QwtLegend(), QwtPlot::BottomLegend);
|
||||
setCanvasBackground(Qt::white);
|
||||
setAxisTitle(yLeft, "Average Power (watts)");
|
||||
setAxisTitle(xBottom, "Interval Length (minutes)");
|
||||
setAxisScaleEngine(xBottom, new QwtLog10ScaleEngine);
|
||||
}
|
||||
|
||||
static int
|
||||
cancel_cb(void *user_data)
|
||||
{
|
||||
CpintPlot *self = (CpintPlot*) user_data;
|
||||
QCoreApplication::processEvents();
|
||||
return self->progress->wasCanceled();
|
||||
}
|
||||
|
||||
void
|
||||
CpintPlot::calculate(QString fileName, QDateTime dateTime)
|
||||
{
|
||||
char *dir = strdup(path.toAscii().constData());
|
||||
char *file = strdup(fileName.toAscii().constData());
|
||||
|
||||
if (grid == NULL) {
|
||||
grid = new QwtPlotGrid();
|
||||
grid->enableX(false);
|
||||
QPen gridPen;
|
||||
gridPen.setStyle(Qt::DotLine);
|
||||
grid->setPen(gridPen);
|
||||
grid->attach(this);
|
||||
}
|
||||
|
||||
if (allCurve == NULL) {
|
||||
bool aborted = false;
|
||||
struct cpi_file_info *head = cpi_files_to_update(dir);
|
||||
int count = 0;
|
||||
struct cpi_file_info *tmp = head;
|
||||
while (tmp) {
|
||||
++count;
|
||||
tmp = tmp->next;
|
||||
}
|
||||
progress = new QProgressDialog(
|
||||
QString(tr("Computing critical power intervals.\n"
|
||||
"This may take a while.\n")),
|
||||
tr("Abort"), 0, count, this);
|
||||
int endingOffset = progress->labelText().size();
|
||||
tmp = head;
|
||||
progress->show();
|
||||
count = 0;
|
||||
while (tmp) {
|
||||
QString existing = progress->labelText();
|
||||
existing.chop(progress->labelText().size() - endingOffset);
|
||||
progress->setLabelText(
|
||||
existing + QString(tr("Processing %1...")).arg(tmp->file));
|
||||
progress->setValue(count++);
|
||||
update_cpi_file(tmp, cancel_cb, this);
|
||||
QCoreApplication::processEvents();
|
||||
if (progress->wasCanceled()) {
|
||||
aborted = true;
|
||||
break;
|
||||
}
|
||||
tmp = tmp->next;
|
||||
}
|
||||
free_cpi_file_info(head);
|
||||
|
||||
if (head && !aborted) {
|
||||
QString existing = progress->labelText();
|
||||
existing.chop(progress->labelText().size() - endingOffset);
|
||||
progress->setValue(count++);
|
||||
progress->setLabelText(existing
|
||||
+ tr("Aggregating over all files."));
|
||||
int i;
|
||||
double *bests;
|
||||
int bestlen;
|
||||
combine_cpi_files(dir, &bests, &bestlen);
|
||||
double *timeArray = new double[bestlen];
|
||||
int maxNonZero = 0;
|
||||
for (i = 0; i < bestlen; ++i) {
|
||||
timeArray[i] = i * 0.021;
|
||||
if (bests[i] > 0) maxNonZero = i;
|
||||
}
|
||||
if (maxNonZero > 1) {
|
||||
allCurve = new QwtPlotCurve("All Rides");
|
||||
allCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
|
||||
allCurve->setPen(QPen(Qt::red));
|
||||
allCurve->setData(timeArray + 1, bests + 1, maxNonZero - 1);
|
||||
setAxisScale(xBottom, 0.021, maxNonZero * 0.021);
|
||||
allCurve->attach(this);
|
||||
}
|
||||
delete [] timeArray;
|
||||
free(bests);
|
||||
}
|
||||
|
||||
delete progress;
|
||||
progress = NULL;
|
||||
}
|
||||
|
||||
if (allCurve) {
|
||||
delete thisCurve;
|
||||
int i;
|
||||
double *bests;
|
||||
int bestlen;
|
||||
read_cpi_file(dir, file, &bests, &bestlen);
|
||||
double *timeArray = new double[bestlen];
|
||||
int maxNonZero = 0;
|
||||
for (i = 0; i < bestlen; ++i) {
|
||||
timeArray[i] = i * 0.021;
|
||||
if (bests[i] > 0) maxNonZero = i;
|
||||
}
|
||||
if (maxNonZero > 1) {
|
||||
thisCurve = new QwtPlotCurve(
|
||||
dateTime.toString("ddd MMM d, yyyy h:mm AP"));
|
||||
thisCurve->setRenderHint(QwtPlotItem::RenderAntialiased);
|
||||
thisCurve->setPen(QPen(Qt::green));
|
||||
thisCurve->attach(this);
|
||||
thisCurve->setData(timeArray + 1, bests + 1, maxNonZero - 1);
|
||||
}
|
||||
delete [] timeArray;
|
||||
free(bests);
|
||||
}
|
||||
|
||||
replot();
|
||||
free(dir);
|
||||
free(file);
|
||||
|
||||
}
|
||||
|
||||
void
|
||||
CpintPlot::showGrid(int state)
|
||||
{
|
||||
assert(state != Qt::PartiallyChecked);
|
||||
grid->setVisible(state == Qt::Checked);
|
||||
replot();
|
||||
}
|
||||
|
||||
53
src/gui/CpintPlot.h
Normal file
53
src/gui/CpintPlot.h
Normal file
@@ -0,0 +1,53 @@
|
||||
/*
|
||||
* $Id: CpintPlot.h,v 1.2 2006/07/12 02:13:57 srhea Exp $
|
||||
*
|
||||
* Copyright (c) 2006 Sean C. Rhea (srhea@srhea.net)
|
||||
*
|
||||
* 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; either version 2 of the License, or (at your option)
|
||||
* any later version.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License along
|
||||
* with this program; if not, write to the Free Software Foundation, Inc., 51
|
||||
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
|
||||
*/
|
||||
|
||||
#ifndef _GC_CpintPlot_h
|
||||
#define _GC_CpintPlot_h 1
|
||||
|
||||
#include <qwt_plot.h>
|
||||
#include <QtGui>
|
||||
|
||||
class QwtPlotCurve;
|
||||
class QwtPlotGrid;
|
||||
|
||||
class CpintPlot : public QwtPlot
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
|
||||
CpintPlot(QString path);
|
||||
QProgressDialog *progress;
|
||||
|
||||
public slots:
|
||||
|
||||
void showGrid(int state);
|
||||
void calculate(QString fileName, QDateTime dateTime);
|
||||
|
||||
protected:
|
||||
|
||||
QString path;
|
||||
QwtPlotCurve *allCurve;
|
||||
QwtPlotCurve *thisCurve;
|
||||
QwtPlotGrid *grid;
|
||||
};
|
||||
|
||||
#endif // _GC_CpintPlot_h
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include <QtGui>
|
||||
#include <errno.h>
|
||||
#include <fcntl.h>
|
||||
#include <math.h>
|
||||
|
||||
#define MAX_DEVICES 10
|
||||
|
||||
@@ -165,7 +166,8 @@ DownloadRideDialog::time_cb(struct tm *time)
|
||||
+ tr(" for writing: ") + strerror(errno));
|
||||
reject();
|
||||
}
|
||||
label->setText(label->text() + tr("\nReading ride data..."));
|
||||
label->setText(label->text() + tr("\nRide data read: "));
|
||||
endingOffset = label->text().size();
|
||||
}
|
||||
timer->start(5000);
|
||||
}
|
||||
@@ -182,7 +184,13 @@ DownloadRideDialog::record_cb(unsigned char *buf)
|
||||
for (int i = 0; i < 6; ++i)
|
||||
fprintf(out, "%02x%s", buf[i], (i == 5) ? "\n" : " ");
|
||||
if ((++blockCount % 256) == 0) {
|
||||
label->setText(label->text() + ".");
|
||||
QString existing = label->text();
|
||||
existing.chop(existing.size() - endingOffset);
|
||||
int minutes = (int) round(blockCount * 0.021);
|
||||
existing.append(QString("%1:%2").arg(minutes / 60)
|
||||
.arg(minutes % 60, 2, 10, QLatin1Char('0')));
|
||||
label->setText(existing);
|
||||
repaint();
|
||||
}
|
||||
timer->start(5000);
|
||||
}
|
||||
@@ -259,7 +267,7 @@ DownloadRideDialog::readData()
|
||||
delete timer;
|
||||
timer = NULL;
|
||||
}
|
||||
label->setText(label->text() + tr("done."));
|
||||
// label->setText(label->text() + tr("done."));
|
||||
QMessageBox::information(this, tr("Success"), tr("Download complete."));
|
||||
fclose(out);
|
||||
out = NULL;
|
||||
|
||||
@@ -55,6 +55,7 @@ class DownloadRideDialog : public QDialog
|
||||
QListWidget *listWidget;
|
||||
QPushButton *downloadButton, *rescanButton, *cancelButton;
|
||||
QLabel *label;
|
||||
int endingOffset;
|
||||
int fd;
|
||||
FILE *out;
|
||||
char outname[24];
|
||||
|
||||
@@ -14,6 +14,7 @@ LIBS += -lz -framework Carbon
|
||||
HEADERS += \
|
||||
AllPlot.h \
|
||||
ChooseCyclistDialog.h \
|
||||
CpintPlot.h \
|
||||
DownloadRideDialog.h \
|
||||
MainWindow.h \
|
||||
RawFile.h \
|
||||
@@ -21,6 +22,7 @@ HEADERS += \
|
||||
SOURCES += \
|
||||
AllPlot.cpp \
|
||||
ChooseCyclistDialog.cpp \
|
||||
CpintPlot.cpp \
|
||||
DownloadRideDialog.cpp \
|
||||
MainWindow.cpp \
|
||||
RawFile.cpp \
|
||||
|
||||
@@ -21,6 +21,7 @@
|
||||
#include "MainWindow.h"
|
||||
#include "AllPlot.h"
|
||||
#include "ChooseCyclistDialog.h"
|
||||
#include "CpintPlot.h"
|
||||
#include "DownloadRideDialog.h"
|
||||
#include "RawFile.h"
|
||||
#include "RideItem.h"
|
||||
@@ -135,7 +136,7 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
window->setLayout(vlayout);
|
||||
window->show();
|
||||
|
||||
tabWidget->addTab(window, "All-in-One Graph");
|
||||
tabWidget->addTab(window, "Ride Plot");
|
||||
splitter->addWidget(tabWidget);
|
||||
|
||||
QVariant splitterSizes = settings.value(GC_SETTINGS_SPLITTER_SIZES);
|
||||
@@ -148,6 +149,9 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
splitter->setSizes(sizes);
|
||||
}
|
||||
|
||||
cpintPlot = new CpintPlot(home.path());
|
||||
tabWidget->addTab(cpintPlot, "Critical Power Plot");
|
||||
|
||||
connect(treeWidget, SIGNAL(itemSelectionChanged()),
|
||||
this, SLOT(rideSelected()));
|
||||
connect(splitter, SIGNAL(splitterMoved(int,int)),
|
||||
@@ -166,6 +170,8 @@ MainWindow::MainWindow(const QDir &home) :
|
||||
this, SLOT(setSmoothingFromSlider()));
|
||||
connect(smoothLineEdit, SIGNAL(returnPressed()),
|
||||
this, SLOT(setSmoothingFromLineEdit()));
|
||||
connect(tabWidget, SIGNAL(currentChanged(int)),
|
||||
this, SLOT(tabChanged(int)));
|
||||
|
||||
QMenu *fileMenu = new QMenu(tr("&File"), this);
|
||||
fileMenu->addAction(tr("&New..."), this,
|
||||
@@ -246,6 +252,8 @@ MainWindow::rideSelected()
|
||||
rideSummary->setHtml(ride->htmlSummary());
|
||||
rideSummary->setAlignment(Qt::AlignCenter);
|
||||
allPlot->setData(ride->raw);
|
||||
if (tabWidget->currentIndex() == 2)
|
||||
cpintPlot->calculate(ride->fileName, ride->dateTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -289,3 +297,18 @@ MainWindow::setSmoothingFromLineEdit()
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
MainWindow::tabChanged(int index)
|
||||
{
|
||||
if (index == 2) {
|
||||
if (treeWidget->selectedItems().size() == 1) {
|
||||
QTreeWidgetItem *which = treeWidget->selectedItems().first();
|
||||
if (which->type() == RIDE_TYPE) {
|
||||
RideItem *ride = (RideItem*) which;
|
||||
cpintPlot->calculate(ride->fileName, ride->dateTime);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <QtGui>
|
||||
|
||||
class AllPlot;
|
||||
class CpintPlot;
|
||||
|
||||
class MainWindow : public QMainWindow
|
||||
{
|
||||
@@ -46,6 +47,7 @@ class MainWindow : public QMainWindow
|
||||
void downloadRide();
|
||||
void setSmoothingFromSlider();
|
||||
void setSmoothingFromLineEdit();
|
||||
void tabChanged(int index);
|
||||
|
||||
private:
|
||||
|
||||
@@ -57,6 +59,7 @@ class MainWindow : public QMainWindow
|
||||
QTabWidget *tabWidget;
|
||||
QTextEdit *rideSummary;
|
||||
AllPlot *allPlot;
|
||||
CpintPlot *cpintPlot;
|
||||
QSlider *smoothSlider;
|
||||
QLineEdit *smoothLineEdit;
|
||||
QTreeWidgetItem *allRides;
|
||||
|
||||
241
src/lib/cpint.c
241
src/lib/cpint.c
@@ -23,10 +23,10 @@
|
||||
#include <assert.h>
|
||||
#include <dirent.h>
|
||||
#include <math.h>
|
||||
#include <regex.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "pt.h"
|
||||
#include "cpint.h"
|
||||
|
||||
struct point
|
||||
{
|
||||
@@ -94,14 +94,78 @@ error_cb(const char *msg, void *context)
|
||||
exit(1);
|
||||
}
|
||||
|
||||
void
|
||||
one_file(FILE *in, FILE *out)
|
||||
struct cpi_file_info *
|
||||
cpi_files_to_update(const char *dir)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
regex_t reg;
|
||||
struct stat sbi, sbo;
|
||||
char *inname, *outname;
|
||||
struct cpi_file_info *head = NULL, *tail = NULL;
|
||||
|
||||
if (regcomp(®, "^([0-9][0-9][0-9][0-9])_([0-9][0-9])_([0-9][0-9])"
|
||||
"_([0-9][0-9])_([0-9][0-9])_([0-9][0-9])\\.raw$", REG_EXTENDED))
|
||||
assert(0);
|
||||
|
||||
dirp = opendir(dir);
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
int nmatch = 7;
|
||||
regmatch_t *pmatch = (regmatch_t*) calloc(nmatch, sizeof(regmatch_t));
|
||||
if (regexec(®, dp->d_name, nmatch, pmatch, 0) == 0) {
|
||||
inname = malloc(strlen(dir) + 25);
|
||||
outname = malloc(strlen(dir) + 25);
|
||||
sprintf(inname, "%s/%s", dir, dp->d_name);
|
||||
if (stat(inname, &sbi))
|
||||
assert(0);
|
||||
sprintf(outname, "%s/%s", dir, dp->d_name);
|
||||
strcpy(outname + strlen(outname) - 4, ".cpi");
|
||||
if ((stat(outname, &sbo)) || (sbo.st_mtime < sbi.st_mtime)) {
|
||||
struct cpi_file_info *info = (struct cpi_file_info*)
|
||||
malloc(sizeof(struct cpi_file_info));
|
||||
info->file = strdup(dp->d_name);
|
||||
info->inname = inname;
|
||||
info->outname = outname;
|
||||
info->pmatch = pmatch;
|
||||
info->next = NULL;
|
||||
if (head == NULL)
|
||||
head = tail = info;
|
||||
else {
|
||||
tail->next = info;
|
||||
tail = info;
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(inname);
|
||||
free(outname);
|
||||
}
|
||||
}
|
||||
else {
|
||||
free(pmatch);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
|
||||
return head;
|
||||
}
|
||||
|
||||
void
|
||||
update_cpi_file(struct cpi_file_info *info,
|
||||
int (*cancel_cb)(void *user_data),
|
||||
void *user_data)
|
||||
{
|
||||
FILE *in, *out;
|
||||
int canceled = 0;
|
||||
double start_secs, prev_secs, dur_secs, avg, sum;
|
||||
int dur_ints, i, total_intervals;
|
||||
double *bests;
|
||||
struct point *p, *q;
|
||||
int progress_count = 0;
|
||||
|
||||
in = fopen(info->inname, "r");
|
||||
assert(in);
|
||||
out = fopen(info->outname, "w");
|
||||
assert(out);
|
||||
if (head) {
|
||||
p = head;
|
||||
while (p) { q = p; p = p->next; free(q); }
|
||||
@@ -120,6 +184,12 @@ one_file(FILE *in, FILE *out)
|
||||
for (p = head; p; p = p->next) {
|
||||
sum = 0.0;
|
||||
for (q = p; q; q = q->next) {
|
||||
if (cancel_cb && (++progress_count % 1000 == 0)) {
|
||||
if (cancel_cb(user_data)) {
|
||||
canceled = 1;
|
||||
goto done;
|
||||
}
|
||||
}
|
||||
sum += (q->secs - prev_secs) * q->watts;
|
||||
dur_secs = q->secs - start_secs;
|
||||
dur_ints = secs_to_interval(dur_secs);
|
||||
@@ -136,78 +206,32 @@ one_file(FILE *in, FILE *out)
|
||||
fprintf(out, "%6.3f %3.0f\n", i * rec_int_ms / 1000.0 / 60.0,
|
||||
round(bests[i]));
|
||||
}
|
||||
|
||||
done:
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
if (canceled)
|
||||
unlink(info->outname);
|
||||
}
|
||||
|
||||
void
|
||||
update_cpi_files(const char *dir, void (*one_done_cb)(const char *date))
|
||||
free_cpi_file_info(struct cpi_file_info *head)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
regex_t reg;
|
||||
struct stat sbi, sbo;
|
||||
FILE *in, *out;
|
||||
char *outname;
|
||||
char year[5], mon[3], day[3], hour[3], min[3], sec[3];
|
||||
char longdate[26];
|
||||
struct tm time;
|
||||
time_t t;
|
||||
|
||||
int nmatch = 7;
|
||||
regmatch_t *pmatch = (regmatch_t*) calloc(nmatch, sizeof(regmatch_t));
|
||||
|
||||
if (regcomp(®, "^([0-9][0-9][0-9][0-9])_([0-9][0-9])_([0-9][0-9])"
|
||||
"_([0-9][0-9])_([0-9][0-9])_([0-9][0-9])\\.raw$", REG_EXTENDED))
|
||||
assert(0);
|
||||
|
||||
outname = malloc(strlen(dir) + 25);
|
||||
dirp = opendir(dir);
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (regexec(®, dp->d_name, nmatch, pmatch, 0) == 0) {
|
||||
if (stat(dp->d_name, &sbi))
|
||||
assert(0);
|
||||
sprintf(outname, "%s/%s", dir, dp->d_name);
|
||||
strcpy(outname + strlen(outname) - 4, ".cpi");
|
||||
if ((stat(outname, &sbo)) || (sbo.st_mtime < sbi.st_mtime)) {
|
||||
strncpy(year, dp->d_name + pmatch[1].rm_so, 4); year[4] = '\0';
|
||||
strncpy(mon, dp->d_name + pmatch[2].rm_so, 2); mon[2] = '\0';
|
||||
strncpy(day, dp->d_name + pmatch[3].rm_so, 2); day[2] = '\0';
|
||||
strncpy(hour, dp->d_name + pmatch[4].rm_so, 2); hour[2] = '\0';
|
||||
strncpy(min, dp->d_name + pmatch[5].rm_so, 2); min[2] = '\0';
|
||||
strncpy(sec, dp->d_name + pmatch[6].rm_so, 2); sec[2] = '\0';
|
||||
memset(&time, 0, sizeof(time));
|
||||
time.tm_year = atoi(year) - 1900;
|
||||
time.tm_mon = atoi(mon) - 1;
|
||||
time.tm_mday = atoi(day);
|
||||
time.tm_hour = atoi(hour);
|
||||
time.tm_min = atoi(min);
|
||||
time.tm_sec = atoi(sec);
|
||||
time.tm_isdst = -1;
|
||||
t = mktime(&time);
|
||||
assert(t != -1);
|
||||
ctime_r(&t, longdate);
|
||||
longdate[24] = '\0'; /* get rid of newline */
|
||||
one_done_cb(longdate);
|
||||
fflush(stderr);
|
||||
in = fopen(dp->d_name, "r");
|
||||
assert(in);
|
||||
out = fopen(outname, "w");
|
||||
assert(out);
|
||||
one_file(in, out);
|
||||
fclose(in);
|
||||
fclose(out);
|
||||
fprintf(stderr, "done.\n");
|
||||
}
|
||||
}
|
||||
struct cpi_file_info *tmp;
|
||||
while (head) {
|
||||
free(head->file);
|
||||
free(head->inname);
|
||||
free(head->outname);
|
||||
free(head->pmatch);
|
||||
tmp = head;
|
||||
head = head->next;
|
||||
free(tmp);
|
||||
}
|
||||
closedir(dirp);
|
||||
free(pmatch);
|
||||
}
|
||||
|
||||
void
|
||||
combine_cpi_files(const char *dir, double *bests[], int *bestlen)
|
||||
static void
|
||||
read_one(const char *inname, double *bests[], int *bestlen)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
FILE *in;
|
||||
char line[40];
|
||||
int lineno;
|
||||
@@ -216,36 +240,63 @@ combine_cpi_files(const char *dir, double *bests[], int *bestlen)
|
||||
double *tmp;
|
||||
int interval;
|
||||
|
||||
*bestlen = 1000;
|
||||
|
||||
*bests = calloc(*bestlen, sizeof(double));
|
||||
dirp = opendir(dir);
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (strcmp(".cpi", dp->d_name + dp->d_namlen - 4) == 0) {
|
||||
in = fopen(dp->d_name, "r");
|
||||
assert(in);
|
||||
lineno = 1;
|
||||
while (fgets(line, sizeof(line), in) != NULL) {
|
||||
if (sscanf(line, "%lf %d\n", &mins, &watts) != 2) {
|
||||
fprintf(stderr, "Bad match on line %d: %s", lineno, line);
|
||||
exit(1);
|
||||
}
|
||||
interval = secs_to_interval(mins * 60.0);
|
||||
while (interval >= *bestlen) {
|
||||
tmp = calloc(*bestlen * 2, sizeof(double));
|
||||
memcpy(tmp, *bests, *bestlen * sizeof(double));
|
||||
free(*bests);
|
||||
*bests = tmp;
|
||||
*bestlen *= 2;
|
||||
}
|
||||
if ((*bests)[interval] < watts)
|
||||
(*bests)[interval] = watts;
|
||||
++lineno;
|
||||
}
|
||||
fclose(in);
|
||||
in = fopen(inname, "r");
|
||||
assert(in);
|
||||
lineno = 1;
|
||||
while (fgets(line, sizeof(line), in) != NULL) {
|
||||
if (sscanf(line, "%lf %d\n", &mins, &watts) != 2) {
|
||||
fprintf(stderr, "Bad match on line %d: %s", lineno, line);
|
||||
exit(1);
|
||||
}
|
||||
interval = secs_to_interval(mins * 60.0);
|
||||
while (interval >= *bestlen) {
|
||||
tmp = calloc(*bestlen * 2, sizeof(double));
|
||||
memcpy(tmp, *bests, *bestlen * sizeof(double));
|
||||
free(*bests);
|
||||
*bests = tmp;
|
||||
*bestlen *= 2;
|
||||
}
|
||||
if ((*bests)[interval] < watts)
|
||||
(*bests)[interval] = watts;
|
||||
++lineno;
|
||||
}
|
||||
closedir(dirp);
|
||||
fclose(in);
|
||||
}
|
||||
|
||||
void
|
||||
read_cpi_file(const char *dir, const char *raw, double *bests[], int *bestlen)
|
||||
{
|
||||
char *inname;
|
||||
|
||||
*bestlen = 1000;
|
||||
*bests = calloc(*bestlen, sizeof(double));
|
||||
inname = malloc(strlen(dir) + 25);
|
||||
sprintf(inname, "%s/%s", dir, raw);
|
||||
strcpy(inname + strlen(inname) - 4, ".cpi");
|
||||
read_one(inname, bests, bestlen);
|
||||
free(inname);
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
combine_cpi_files(const char *dir, double *bests[], int *bestlen)
|
||||
{
|
||||
DIR *dirp;
|
||||
struct dirent *dp;
|
||||
char *inname;
|
||||
|
||||
*bestlen = 1000;
|
||||
*bests = calloc(*bestlen, sizeof(double));
|
||||
inname = malloc(strlen(dir) + 25);
|
||||
dirp = opendir(dir);
|
||||
while ((dp = readdir(dirp)) != NULL) {
|
||||
if (strcmp(".cpi", dp->d_name + dp->d_namlen - 4) == 0) {
|
||||
sprintf(inname, "%s/%s", dir, dp->d_name);
|
||||
read_one(inname, bests, bestlen);
|
||||
}
|
||||
}
|
||||
closedir(dirp);
|
||||
free(inname);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -21,8 +21,25 @@
|
||||
#ifndef __cpint_h
|
||||
#define __cpint_h 1
|
||||
|
||||
extern void update_cpi_files(const char *dir,
|
||||
void (*one_done_cb)(const char *date));
|
||||
#include <regex.h>
|
||||
|
||||
struct cpi_file_info {
|
||||
char *file, *inname, *outname;
|
||||
regmatch_t *pmatch;
|
||||
struct cpi_file_info *next;
|
||||
};
|
||||
|
||||
extern struct cpi_file_info * cpi_files_to_update(const char *dir);
|
||||
|
||||
extern void update_cpi_file(struct cpi_file_info *info,
|
||||
int (*cancel_cb)(void *user_data),
|
||||
void *user_data);
|
||||
|
||||
extern void free_cpi_file_info(struct cpi_file_info *head);
|
||||
|
||||
extern void read_cpi_file(const char *dir, const char *raw,
|
||||
double *bests[], int *bestlen);
|
||||
|
||||
extern void combine_cpi_files(const char *dir, double *bests[], int *bestlen);
|
||||
|
||||
#endif /* __cpint_h */
|
||||
|
||||
Reference in New Issue
Block a user