// read zone file, allowing for zones with or without end dates bool Zones::read(QFile &file) { defaults_from_user = false; scheme.zone_default.clear(); scheme.zone_default_is_pct.clear(); scheme.zone_default_name.clear(); scheme.zone_default_desc.clear(); scheme.nzones_default = 0; ranges.clear(); // set up possible warning dialog warning = QString(); int warning_lines = 0; const int max_warning_lines = 100; int defaultwprime = 20000; // default to 20kJ int defaultpmax = 1000; // macro to append lines to the warning #define append_to_warning(s) \ if (warning_lines < max_warning_lines) { \ warning.append(s); } \ else if (warning_lines == max_warning_lines) { \ warning.append("...\n"); } \ warning_lines++; // read using text mode takes care of end-lines if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { err = "can't open file"; return false; } QTextStream fileStream(&file); QRegExp commentrx("\\s*#.*$"); QRegExp blankrx("^[ \t]*$"); QRegExp rangerx[] = { QRegExp("^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s*([,:]?\\s*(FTP|CP)\\s*=\\s*(\\d+))?" // optional {CP/FTP = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive), QRegExp("^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s+(?:until|to|-)\\s+" // until "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|END)?" // end date "\\s*:?,?\\s*((FTP|CP)\\s*=\\s*(\\d+))?" // optional {CP/FTP = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive) }; QRegExp ftpx("^FTP=(\\d+)$"); QRegExp wprimerx("^W'=(\\d+)$"); QRegExp pmaxx("^Pmax=(\\d+)$"); QRegExp zonerx("^\\s*([^ ,][^,]*),\\s*([^ ,][^,]*),\\s*" "(\\d+)\\s*(%?)\\s*(?:,\\s*(\\d+|MAX)\\s*(%?)\\s*)?$", Qt::CaseInsensitive); QRegExp zonedefaultsx("^\\s*(?:zone)?\\s*defaults?\\s*:?\\s*$", Qt::CaseInsensitive); int lineno = 0; // the current range in the file // ZoneRange *range = NULL; bool in_range = false; QDate begin = date_zero, end = date_infinity; int cp=0; int ftp=0; int wprime=0; int pmax=0; QList<ZoneInfo> zoneInfos; // true if zone defaults are found in the file (then we need to write them) bool zones_are_defaults = false; while (!fileStream.atEnd() ) { ++lineno; QString line = fileStream.readLine(); int pos = commentrx.indexIn(line, 0); if (pos != -1) line = line.left(pos); if (blankrx.indexIn(line, 0) == 0) goto next_line; // check for default zone range definition (may be followed by zone definitions) if (zonedefaultsx.indexIn(line, 0) != -1) { zones_are_defaults = true; // defaults are allowed only at the beginning of the file if (ranges.size()) { err = "Zone defaults must be specified at head of power.zones file"; return false; } // only one set of defaults is allowed if (scheme.nzones_default) { err = "Only one set of zone defaults may be specified in power.zones file"; return false; } goto next_line; } // check for range specification (may be followed by zone definitions) for (int r=0; r<2; r++) { if (rangerx[r].indexIn(line, 0) != -1) { if (in_range) { // if zones are empty, then generate them ZoneRange range(begin, end, cp, ftp ? ftp : cp, wprime ? wprime : defaultwprime, pmax ? pmax : defaultpmax); range.zones = zoneInfos; if (range.zones.empty()) { if (range.cp > 0) { setZonesFromCP(range); } else { err = tr("line %1: read new range without reading " "any zones for previous one").arg(lineno); file.close(); return false; } } else { qSort(range.zones); } ranges.append(range); } in_range = true; zones_are_defaults = false; zoneInfos.clear(); // process the beginning date if (rangerx[r].cap(1) == "BEGIN") { begin = date_zero; } else { begin = QDate(rangerx[r].cap(2).toInt(), rangerx[r].cap(3).toInt(), rangerx[r].cap(4).toInt()); } // process an end date, if any, else it is null if (rangerx[r].cap(5) == "END") { end = date_infinity; } else if (rangerx[r].cap(6).toInt() || rangerx[r].cap(7).toInt() || rangerx[r].cap(8).toInt()) { end = QDate(rangerx[r].cap(6).toInt(), rangerx[r].cap(7).toInt(), rangerx[r].cap(8).toInt()); } else { end = QDate(); } // set up the range, capturing CP if it's specified // range = new ZoneRange(begin, end); int nCP = (r ? 11 : 7); if (rangerx[r].captureCount() == (nCP)) cp = rangerx[r].cap(nCP).toInt(); else cp = 0; // bleck goto next_line; } } // check for FTP if (ftpx.indexIn(line, 0) != -1) { if (!in_range) qDebug()<<"ignoring errant FTP= in power.zones"; else { ftp = ftpx.cap(1).toInt(); // ok its stored, so if it is in kJ upscale // if it is zero as never set, then use default if (!ftp) { ftp = cp; } } } // check for w' if (wprimerx.indexIn(line, 0) != -1) { if (!in_range) qDebug()<<"ignoring errant W'= in power.zones"; else { wprime = wprimerx.cap(1).toInt(); // ok its stored, so if it is in kJ upscale // if it is zero as never set, then use default if (wprime) { if (wprime < 1000) wprime *= 1000; // JOULES not kJ defaultwprime = wprime; } else { wprime = defaultwprime; } } } // check for Pmax if (pmaxx.indexIn(line, 0) != -1) { if (!in_range) qDebug()<<"ignoring errant Pmax= in power.zones"; else { pmax = pmaxx.cap(1).toInt(); } } // check for zone definition if (zonerx.indexIn(line, 0) != -1) { if (!(in_range || zones_are_defaults)) { err = tr("line %1: read zone without " "preceding date range").arg(lineno); file.close(); return false; } int lo = zonerx.cap(3).toInt(); // allow for zone specified as % of CP bool lo_is_pct = false; if (zonerx.cap(4) == "%") { if (zones_are_defaults) { lo_is_pct = true; } else if (cp > 0) { lo = int(lo * cp / 100); } else { err = tr("attempt to set zone based on % of " "CP without setting CP in line number %1.\n").arg(lineno); file.close(); return false; } } int hi; // if this is not a zone defaults specification, process possible hi end of zones if (zones_are_defaults || zonerx.cap(5).isEmpty()) { hi = -1; // signal an undefined number } else if (zonerx.cap(5) == "MAX") { hi = INT_MAX; } else { hi = zonerx.cap(5).toInt(); // allow for zone specified as % of CP if (zonerx.cap(5) == "%") { if (cp > 0) { hi = int(hi * cp / 100); } else { err = tr("attempt to set zone based on % of CP " "without setting CP in line number %1.\n"). arg(lineno); file.close(); return false; } } } if (zones_are_defaults) { scheme.nzones_default++; scheme.zone_default_is_pct.append(lo_is_pct); scheme.zone_default.append(lo); scheme.zone_default_name.append(zonerx.cap(1)); scheme.zone_default_desc.append(zonerx.cap(2)); defaults_from_user = true; } else { ZoneInfo zone(zonerx.cap(1), zonerx.cap(2), lo, hi); zoneInfos.append(zone); } } next_line: {} } if (in_range) { ZoneRange range(begin, end, cp, ftp ? ftp : cp, wprime ? wprime : defaultwprime, pmax ? pmax : defaultpmax); range.zones = zoneInfos; if (range.zones.empty()) { if (range.cp > 0) { setZonesFromCP(range); } else { err = tr("file ended without reading any zones for last range"); file.close(); return false; } } else { qSort(range.zones); } ranges.append(range); } file.close(); // sort the ranges qSort(ranges); // set the default zones if not in file if (!scheme.nzones_default) { // do we have a zone which is explicitly set? for (int i=0; i<ranges.count(); i++) { if (ranges[i].zonesSetFromCP == false) { // set the defaults using this one! scheme.nzones_default = ranges[i].zones.count(); for (int j=0; j<scheme.nzones_default; j++) { scheme.zone_default.append(((double)ranges[i].zones[j].lo / (double)ranges[i].cp) * 100.00); scheme.zone_default_is_pct.append(true); scheme.zone_default_name.append(ranges[i].zones[j].name); scheme.zone_default_desc.append(ranges[i].zones[j].desc); } } } // still not set then reset to defaults as usual if (!scheme.nzones_default) initializeZoneParameters(); } // resolve undefined endpoints in ranges and zones for (int nr = 0; nr < ranges.size(); nr++) { // clean up gaps or overlaps in zone ranges if (ranges[nr].end.isNull()) { ranges[nr].end = (nr < ranges.size() - 1) ? ranges[nr + 1].begin : date_infinity; } else if ((nr < ranges.size() - 1) && (ranges[nr + 1].begin != ranges[nr].end)) { append_to_warning(tr("Setting end date of range %1 " "to start date of range %2.\n"). arg(nr + 1). arg(nr + 2) ); ranges[nr].end = ranges[nr + 1].begin; } else if ((nr == ranges.size() - 1) && (ranges[nr].end < QDate::currentDate())) { append_to_warning(tr("Extending final range %1 to infinite " "to include present date.\n").arg(nr + 1)); ranges[nr].end = date_infinity; } if (ranges[nr].cp <= 0) { err = tr("CP must be greater than zero in zone " "range %1 of power.zones").arg(nr + 1); return false; } if (ranges[nr].zones.size()) { // check that the first zone starts with zero // ranges[nr].zones[0].lo = 0; // there is no reason we should enforce this // resolve zone end powers for (int nz = 0; nz < ranges[nr].zones.size(); nz++) { if (ranges[nr].zones[nz].hi == -1) { ranges[nr].zones[nz].hi = (nz < ranges[nr].zones.size() - 1) ? ranges[nr].zones[nz + 1].lo : INT_MAX; } else if ((nz < ranges[nr].zones.size() - 1) && (ranges[nr].zones[nz].hi != ranges[nr].zones[nz + 1].lo)) { if (abs(ranges[nr].zones[nz].hi - ranges[nr].zones[nz + 1].lo) > 4) { append_to_warning(tr("Range %1: matching top of zone %2 " "(%3) to bottom of zone %4 (%5).\n"). arg(nr + 1). arg(ranges[nr].zones[nz].name). arg(ranges[nr].zones[nz].hi). arg(ranges[nr].zones[nz + 1].name). arg(ranges[nr].zones[nz + 1].lo) ); } ranges[nr].zones[nz].hi = ranges[nr].zones[nz + 1].lo; } else if ((nz == ranges[nr].zones.size() - 1) && (ranges[nr].zones[nz].hi < INT_MAX)) { append_to_warning(tr("Range %1: setting top of zone %2 from %3 to MAX.\n"). arg(nr + 1). arg(ranges[nr].zones[nz].name). arg(ranges[nr].zones[nz].hi) ); ranges[nr].zones[nz].hi = INT_MAX; } } } } // mark zones as modified so pages which depend on zones can be updated modificationTime = QDateTime::currentDateTime(); return true; }
// read zone file, allowing for zones with or without end dates bool HrZones::read(QFile &file) { defaults_from_user = false; scheme.zone_default.clear(); scheme.zone_default_is_pct.clear(); scheme.zone_default_name.clear(); scheme.zone_default_desc.clear(); scheme.zone_default_trimp.clear(); scheme.nzones_default = 0; ranges.clear(); // set up possible warning dialog warning = QString(); int warning_lines = 0; const int max_warning_lines = 100; // macro to append lines to the warning #define append_to_warning(s) \ if (warning_lines < max_warning_lines) \ warning.append(s); \ else if (warning_lines == max_warning_lines) \ warning.append("...\n"); \ warning_lines ++; // read using text mode takes care of end-lines if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { err = "can't open file"; return false; } QTextStream fileStream(&file); QRegExp commentrx("\\s*#.*$"); QRegExp blankrx("^[ \t]*$"); QRegExp rangerx[] = { QRegExp("^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s*([,:]?\\s*(LT)\\s*=\\s*(\\d+))?" // optional {LT = integer (optional %)} "\\s*([,:]?\\s*(RestHr)\\s*=\\s*(\\d+))?" // optional {RestHr = integer (optional %)} "\\s*([,:]?\\s*(MaxHr)\\s*=\\s*(\\d+))?" // optional {MaxHr = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive), QRegExp("^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s+(?:until|to|-)\\s+" // until "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|END)?" // end date "\\s*:?,?\\s*((LT)\\s*=\\s*(\\d+))?" // optional {LT = integer (optional %)} "\\s*:?,?\\s*((RestHr)\\s*=\\s*(\\d+))?" // optional {RestHr = integer (optional %)} "\\s*:?,?\\s*((MaxHr)\\s*=\\s*(\\d+))?" // optional {MaxHr = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive) }; QRegExp zonerx("^\\s*([^ ,][^,]*),\\s*([^ ,][^,]*),\\s*" "(\\d+)\\s*(%?)\\s*(?:,\\s*(\\d+(\\.\\d+)?)\\s*)?$", Qt::CaseInsensitive);// QRegExp zonedefaultsx("^\\s*(?:zone)?\\s*defaults?\\s*:?\\s*$", Qt::CaseInsensitive); int lineno = 0; // the current range in the file // ZoneRange *range = NULL; bool in_range = false; QDate begin = date_zero, end = date_infinity; int lt = 0; int restHr = 0; int maxHr = 0; QList<HrZoneInfo> zoneInfos; // true if zone defaults are found in the file (then we need to write them) bool zones_are_defaults = false; while (! fileStream.atEnd() ) { ++lineno; QString line = fileStream.readLine(); int pos = commentrx.indexIn(line, 0); if (pos != -1) line = line.left(pos); if (blankrx.indexIn(line, 0) == 0) goto next_line; // check for default zone range definition (may be followed by hr zone definitions) if (zonedefaultsx.indexIn(line, 0) != -1) { zones_are_defaults = true; // defaults are allowed only at the beginning of the file if (ranges.size()) { err = "HR Zone defaults must be specified at head of hr.zones file"; return false; } // only one set of defaults is allowed if (scheme.nzones_default) { err = "Only one set of zone defaults may be specified in hr.zones file"; return false; } goto next_line; } // check for range specification (may be followed by zone definitions) for (int r=0; r<2; r++) { if (rangerx[r].indexIn(line, 0) != -1) { if (in_range) { // if zones are empty, then generate them HrZoneRange range(begin, end, lt, restHr, maxHr); range.zones = zoneInfos; if (range.zones.empty()) { if (range.lt > 0) setHrZonesFromLT(range); else { err = tr("line %1: read new range without reading " "any zones for previous one").arg(lineno); file.close(); return false; } } else { qSort(range.zones); } ranges.append(range); } in_range = true; zones_are_defaults = false; zoneInfos.clear(); // process the beginning date if (rangerx[r].cap(1) == "BEGIN") begin = date_zero; else { begin = QDate(rangerx[r].cap(2).toInt(), rangerx[r].cap(3).toInt(), rangerx[r].cap(4).toInt()); } // process an end date, if any, else it is null if (rangerx[r].cap(5) == "END") end = date_infinity; else if (rangerx[r].cap(6).toInt() || rangerx[r].cap(7).toInt() || rangerx[r].cap(8).toInt()) { end = QDate(rangerx[r].cap(6).toInt(), rangerx[r].cap(7).toInt(), rangerx[r].cap(8).toInt()); } else { end = QDate(); } // set up the range, capturing LT if it's specified // range = new ZoneRange(begin, end); int nLT = (r ? 11 : 7); if (rangerx[r].numCaptures() >= (nLT)) lt = rangerx[r].cap(nLT).toInt(); else lt = 0; int nRestHr = (r ? 14 : 10); if (rangerx[r].numCaptures() >= (nRestHr)) restHr = rangerx[r].cap(nRestHr).toInt(); else restHr = 0; int nMaxHr = (r ? 17 : 13); if (rangerx[r].numCaptures() >= (nRestHr)) maxHr = rangerx[r].cap(nMaxHr).toInt(); else maxHr = 0; // bleck goto next_line; } } // check for zone definition if (zonerx.indexIn(line, 0) != -1) { if (! (in_range || zones_are_defaults)) { err = tr("line %1: read zone without " "preceeding date range").arg(lineno); file.close(); return false; } int lo = zonerx.cap(3).toInt(); double trimp = zonerx.cap(5).toDouble(); // allow for zone specified as % of LT bool lo_is_pct = false; if (zonerx.cap(4) == "%") { if (zones_are_defaults) lo_is_pct = true; else if (lt > 0) lo = int(lo * lt / 100); else { err = tr("attempt to set zone based on % of " "LT without setting LT in line number %1.\n"). arg(lineno); file.close(); return false; } } int hi = -1; // signal an undefined number double tr = zonerx.cap(5).toDouble(); if (zones_are_defaults) { scheme.nzones_default ++; scheme.zone_default_is_pct.append(lo_is_pct); scheme.zone_default.append(lo); scheme.zone_default_name.append(zonerx.cap(1)); scheme.zone_default_desc.append(zonerx.cap(2)); scheme.zone_default_trimp.append(trimp); defaults_from_user = true; } else { HrZoneInfo zone(zonerx.cap(1), zonerx.cap(2), lo, hi, tr); zoneInfos.append(zone); } } next_line: {} } if (in_range) { HrZoneRange range(begin, end, lt, restHr, maxHr); range.zones = zoneInfos; if (range.zones.empty()) { if (range.lt > 0) setHrZonesFromLT(range); else { err = tr("file ended without reading any zones for last range"); file.close(); return false; } } else { qSort(range.zones); } ranges.append(range); } file.close(); // sort the ranges qSort(ranges); // set the default zones if not in file if (!scheme.nzones_default) { // do we have a zone which is explicitly set? for (int i=0; i<ranges.count(); i++) { if (ranges[i].hrZonesSetFromLT == false) { // set the defaults using this one! scheme.nzones_default = ranges[i].zones.count(); for (int j=0; j<scheme.nzones_default; j++) { scheme.zone_default.append(((double)ranges[i].zones[j].lo / (double)ranges[i].lt) * 100.00); scheme.zone_default_is_pct.append(true); scheme.zone_default_name.append(ranges[i].zones[j].name); scheme.zone_default_desc.append(ranges[i].zones[j].desc); scheme.zone_default_trimp.append(ranges[i].zones[j].trimp); } } } // still not set then reset to defaults as usual if (!scheme.nzones_default) initializeZoneParameters(); } // resolve undefined endpoints in ranges and zones for (int nr = 0; nr < ranges.size(); nr ++) { // clean up gaps or overlaps in zone ranges if (ranges[nr].end.isNull()) ranges[nr].end = (nr < ranges.size() - 1) ? ranges[nr + 1].begin : date_infinity; else if ((nr < ranges.size() - 1) && (ranges[nr + 1].begin != ranges[nr].end)) { append_to_warning(tr("Setting end date of range %1 " "to start date of range %2.\n"). arg(nr + 1). arg(nr + 2) ); ranges[nr].end = ranges[nr + 1].begin; } else if ((nr == ranges.size() - 1) && (ranges[nr].end < QDate::currentDate())) { append_to_warning(tr("Extending final range %1 to infinite " "to include present date.\n").arg(nr + 1)); ranges[nr].end = date_infinity; } if (ranges[nr].lt <= 0) { err = tr("LT must be greater than zero in zone " "range %1 of hr.zones").arg(nr + 1); return false; } if (ranges[nr].zones.size()) { // check that the first zone starts with zero ranges[nr].zones[0].lo = 0; // resolve zone end powers for (int nz = 0; nz < ranges[nr].zones.size(); nz ++) { if (ranges[nr].zones[nz].hi == -1) ranges[nr].zones[nz].hi = (nz < ranges[nr].zones.size() - 1) ? ranges[nr].zones[nz + 1].lo : INT_MAX; else if ((nz < ranges[nr].zones.size() - 1) && (ranges[nr].zones[nz].hi != ranges[nr].zones[nz + 1].lo)) { if (abs(ranges[nr].zones[nz].hi - ranges[nr].zones[nz + 1].lo) > 4) { append_to_warning(tr("Range %1: matching top of zone %2 " "(%3) to bottom of zone %4 (%5).\n"). arg(nr + 1). arg(ranges[nr].zones[nz].name). arg(ranges[nr].zones[nz].hi). arg(ranges[nr].zones[nz + 1].name). arg(ranges[nr].zones[nz + 1].lo) ); } ranges[nr].zones[nz].hi = ranges[nr].zones[nz + 1].lo; } else if ((nz == ranges[nr].zones.size() - 1) && (ranges[nr].zones[nz].hi < INT_MAX)) { append_to_warning(tr("Range %1: setting top of zone %2 from %3 to MAX.\n"). arg(nr + 1). arg(ranges[nr].zones[nz].name). arg(ranges[nr].zones[nz].hi) ); ranges[nr].zones[nz].hi = INT_MAX; } } } } // mark zones as modified so pages which depend on zones can be updated modificationTime = QDateTime::currentDateTime(); return true; }
// read zone file, allowing for zones with or without end dates bool Zones::read(QFile &file) { defaults_from_user = false; zone_default.clear(); zone_default_is_pct.clear(); zone_default_name.clear(); zone_default_desc.clear(); nzones_default = 0; // set up possible warning dialog warning = QString(); int warning_lines = 0; const int max_warning_lines = 100; // macro to append lines to the warning #define append_to_warning(s) \ if (warning_lines < max_warning_lines) \ warning.append(s); \ else if (warning_lines == max_warning_lines) \ warning.append("...\n"); \ warning_lines ++; // read using text mode takes care of end-lines if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { err = "can't open file"; return false; } QTextStream fileStream(&file); QRegExp commentrx("\\s*#.*$"); QRegExp blankrx("^[ \t]*$"); QRegExp rangerx[] = { QRegExp( "^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s*([,:]?\\s*(FTP|CP)\\s*=\\s*(\\d+))?" // optional {CP/FTP = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive ), QRegExp( "^\\s*(?:from\\s+)?" // optional "from" "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|BEGIN)" // begin date "\\s+(?:until|to|-)\\s+" // until "((\\d\\d\\d\\d)[-/](\\d{1,2})[-/](\\d{1,2})|END)?" // end date "\\s*:?,?\\s*((FTP|CP)\\s*=\\s*(\\d+))?" // optional {CP/FTP = integer (optional %)} "\\s*:?\\s*$", // optional : Qt::CaseInsensitive ) }; QRegExp zonerx("^\\s*([^ ,][^,]*),\\s*([^ ,][^,]*),\\s*" "(\\d+)\\s*(%?)\\s*(?:,\\s*(\\d+|MAX)\\s*(%?)\\s*)?$", Qt::CaseInsensitive ); QRegExp zonedefaultsx("^\\s*(?:zone)?\\s*defaults?\\s*:?\\s*$", Qt::CaseInsensitive ); int lineno = 0; // the current range in the file ZoneRange *range = NULL; // true if zone defaults are found in the file (then we need to write them) bool zones_are_defaults = false; while (! fileStream.atEnd() ) { ++lineno; QString line = fileStream.readLine(); fprintf(stderr, "line %d: \"%s\"\n", lineno, line.toAscii().constData()); int pos = commentrx.indexIn(line, 0); if (pos != -1) { fprintf(stderr, "line %d: blank\n", lineno); line = line.left(pos); } if (blankrx.indexIn(line, 0) == 0) { goto next_line; } // check for default zone range definition (may be followed by zone definitions) if (zonedefaultsx.indexIn(line, 0) != -1) { fprintf(stderr, "line %d: zone defaults specification identified\n", lineno); zones_are_defaults = true; // defaults are allowed only at the beginning of the file if (ranges.size()) { err = "Zone defaults must be specified at head of power.zones file"; return false; } // only one set of defaults is allowed if (nzones_default) { err = "Only one set of zone defaults may be specified in power.zones file"; return false; } goto next_line; } // check for range specification (may be followed by zone definitions) for (int r = 0; r < 2; r++) { if (rangerx[r].indexIn(line, 0) != -1) { zones_are_defaults = false; fprintf(stderr, "line %d: matched range: %s to %s\n", lineno, rangerx[r].cap(1).toAscii().constData(), rangerx[r].cap(5).toAscii().constData()); QDate begin, end; // process the beginning date if (rangerx[r].cap(1) == "BEGIN") begin = date_zero; else { begin = QDate(rangerx[r].cap(2).toInt(), rangerx[r].cap(3).toInt(), rangerx[r].cap(4).toInt() ); } // process an end date, if any, else it is null if (rangerx[r].cap(5) == "END") end = date_infinity; else if (rangerx[r].cap(6).toInt() || rangerx[r].cap(7).toInt() || rangerx[r].cap(8).toInt()) { end = QDate(rangerx[r].cap(6).toInt(), rangerx[r].cap(7).toInt(), rangerx[r].cap(8).toInt() ); fprintf(stderr, "end date = %s\n", end.toString().toAscii().constData()); } else { end = QDate(); fprintf(stderr, "no end date\n"); } if (range) { // if zones are empty, then generate them if (range->zones.empty()) { fprintf(stderr, "create zones from cp = %d\n", range->cp); if (range->cp > 0) setZonesFromCP(range); else { err = tr("line %1: read new range without reading " "any zones for previous one").arg(lineno); file.close(); return false; } } // else sort them else { fprintf(stderr, "Sorting zones for range %d\n", ranges.size() + 1); qSort(range->zones.begin(), range->zones.end(), zoneptr_lessthan); } ranges.append(range); } // set up the range, capturing CP if it's specified range = new ZoneRange(begin, end); int nCP = (r ? 11 : 7); if (rangerx[r].numCaptures() == (nCP)) { range->cp = rangerx[r].cap(nCP).toInt(); fprintf(stderr, "setting CP = %d\n", range->cp); } goto next_line; } } // check for zone definition if (zonerx.indexIn(line, 0) != -1) { if (! (range || zones_are_defaults)) { err = tr("line %1: read zone without " "preceeding date range").arg(lineno); file.close(); return false; } int lo = zonerx.cap(3).toInt(); // allow for zone specified as % of CP bool lo_is_pct = false; if (zonerx.cap(4) == "%") if (zones_are_defaults) lo_is_pct = true; else if (range->cp > 0) lo = int(lo * range->cp / 100); else { err = tr("attempt to set zone based on % of " "CP without setting CP in line number %1.\n"). arg(lineno); file.close(); return false; } int hi; // if this is not a zone defaults specification, process possible hi end of zones if (zones_are_defaults || zonerx.cap(5).isEmpty()) hi = -1; // signal an undefined number else if (zonerx.cap(5) == "MAX") hi = INT_MAX; else { hi = zonerx.cap(5).toInt(); // allow for zone specified as % of CP if (zonerx.cap(5) == "%") if (range->cp > 0) hi = int(hi * range->cp / 100); else { err = tr("attempt to set zone based on % of CP " "without setting CP in line number %1.\n"). arg(lineno); file.close(); return false; } } if (zones_are_defaults) { nzones_default ++; zone_default_is_pct.append(lo_is_pct); zone_default.append(lo); zone_default_name.append(zonerx.cap(1)); zone_default_desc.append(zonerx.cap(2)); fprintf(stderr, "line %d: zone default #%d found: \"%s\" (%s): %d%s\n", lineno, nzones_default, zone_default_name[nzones_default - 1].toAscii().constData(), zone_default_desc[nzones_default - 1].toAscii().constData(), zone_default[nzones_default - 1], zone_default_is_pct[nzones_default - 1] ? "%" : "" ); defaults_from_user = true; } else { ZoneInfo *zone = new ZoneInfo(zonerx.cap(1), zonerx.cap(2), lo, hi); fprintf(stderr, "line %d: matched zones: " "\"%s\", \"%s\", %s, %s\n", lineno, zonerx.cap(1).toAscii().constData(), zonerx.cap(2).toAscii().constData(), zonerx.cap(3).isEmpty() ? "null" : zonerx.cap(3).toAscii().constData(), zonerx.cap(4).isEmpty() ? "null" : zonerx.cap(4).toAscii().constData() ); range->zones.append(zone); } } next_line: {} } if (range) { if (range->zones.empty()) { fprintf(stderr, "empty zones found: cp = %d\n", range->cp); if (range->cp > 0) setZonesFromCP(range); else { err = tr("file ended without reading any zones for last range"); file.close(); return false; } } else { fprintf(stderr, "Sorting zones for final range %d\n", ranges.size()); qSort(range->zones.begin(), range->zones.end(), zoneptr_lessthan); } ranges.append(range); } file.close(); // sort the ranges qSort(ranges.begin(), ranges.end(), rangeptr_lessthan); // sort the zone defaults, as best we can (may not be right if there's // a mix of % and absolute ranges) if (nzones_default) { fprintf(stderr, "Sorting zone defaults...\n"); QVector <int> zone_default_index(nzones_default); for (int i = 0; i < nzones_default; i++) zone_default_index[i] = i; qSort(zone_default_index.begin(), zone_default_index.end(), zone_default_index_lessthan); QVector <int> zone_default_new(nzones_default); QVector <bool> zone_default_is_pct_new(nzones_default); QVector <QString> zone_default_name_new(nzones_default); QVector <QString> zone_default_desc_new(nzones_default); for (int i = 0; i < nzones_default; i++) { zone_default_new[i] = zone_default[zone_default_index[i]]; zone_default_is_pct_new[i] = zone_default_is_pct[zone_default_index[i]]; zone_default_name_new[i] = zone_default_name[zone_default_index[i]]; zone_default_desc_new[i] = zone_default_desc[zone_default_index[i]]; } for (int i = 0; i < nzones_default; i++) { zone_default[i] = zone_default_new[i]; zone_default_is_pct[i] = zone_default_is_pct_new[i]; zone_default_name[i] = zone_default_name_new[i]; zone_default_desc[i] = zone_default_desc_new[i]; } } // resolve undefined endpoints in ranges and zones for (int nr = 0; nr < ranges.size(); nr ++) { // clean up gaps or overlaps in zone ranges if (ranges[nr]->end.isNull()) ranges[nr]->end = (nr < ranges.size() - 1) ? ranges[nr + 1]->begin : date_infinity; else if ((nr < ranges.size() - 1) && (ranges[nr + 1]->begin != ranges[nr]->end) ) { append_to_warning(tr("Setting end date of range %1 " "to start date of range %2.\n"). arg(nr + 1). arg(nr + 2) ); ranges[nr]->end = ranges[nr + 1]->begin; } else if ((nr == ranges.size() - 1) && (ranges[nr]->end < QDate::currentDate()) ) { append_to_warning(tr("Extending final range %1 to infinite " "to include present date.\n").arg(nr + 1)); ranges[nr]->end = date_infinity; } if (ranges[nr]->zones.size()) { // check that the first zone starts with zero ranges[nr]->zones[0]->lo = 0; // resolve zone end powers for (int nz = 0; nz < ranges[nr]->zones.size(); nz ++) if (ranges[nr]->zones[nz]->hi == -1) ranges[nr]->zones[nz]->hi = (nz < ranges[nr]->zones.size() - 1) ? ranges[nr]->zones[nz + 1]->lo : INT_MAX; else if ((nz < ranges[nr]->zones.size() - 1) && (ranges[nr]->zones[nz]->hi != ranges[nr]->zones[nz + 1]->lo) ) { if (abs(ranges[nr]->zones[nz]->hi - ranges[nr]->zones[nz + 1]->lo) > 4) append_to_warning(tr("Range %1: matching top of zone %2 " "(%3) to bottom of zone %4 (%5).\n"). arg(nr + 1). arg(ranges[nr]->zones[nz]->name). arg(ranges[nr]->zones[nz]->hi). arg(ranges[nr]->zones[nz + 1]->name). arg(ranges[nr]->zones[nz + 1]->lo) ); ranges[nr]->zones[nz]->hi = ranges[nr]->zones[nz + 1]->lo; } else if ((nz == ranges[nr]->zones.size() - 1) && (ranges[nr]->zones[nz]->hi < INT_MAX) ) { append_to_warning(tr("Range %1: setting top of zone %2 from %3 to MAX.\n"). arg(nr + 1). arg(ranges[nr]->zones[nz]->name). arg(ranges[nr]->zones[nz]->hi) ); ranges[nr]->zones[nz]->hi = INT_MAX; } } fprintf(stderr, "sorted range %d: from %s to %s with %s zones\n", nr + 1, ranges[nr]->begin.isNull() ? "BEGIN" : ranges[nr]->begin.toString().toAscii().constData(), ranges[nr]->end.isNull() ? "END" : ranges[nr]->end.toString().toAscii().constData(), ranges[nr]->zonesSetFromCP ? "calculated" : "specified" ); } // mark zones as modified so pages which depend on zones can be updated modificationTime = QDateTime::currentDateTime(); return true; }