NextTrain format file library

Committer:
rinosh2
Date:
Wed Nov 17 16:21:38 2010 +0000
Revision:
1:f89f955130c7
Parent:
0:1e951aba6a7e
Child:
2:0aa41f709144
delete implement of protected method

Who changed what in which revision?

UserRevisionLine numberNew contents of line
rinosh2 0:1e951aba6a7e 1 ///////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 2 // NextTrainFile: NextTrain file parser by rinos 2010
rinosh2 0:1e951aba6a7e 3 ///////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 4
rinosh2 0:1e951aba6a7e 5 #include "NextTrainFile.h"
rinosh2 0:1e951aba6a7e 6 #include <time.h>
rinosh2 0:1e951aba6a7e 7 #include <stdlib.h>
rinosh2 0:1e951aba6a7e 8
rinosh2 0:1e951aba6a7e 9 ////////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 10 // defines
rinosh2 0:1e951aba6a7e 11 const int MAX_LINE_BUF = 256;
rinosh2 0:1e951aba6a7e 12
rinosh2 0:1e951aba6a7e 13 ////////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 14 // NextTrainFile
rinosh2 0:1e951aba6a7e 15
rinosh2 0:1e951aba6a7e 16 NextTrainFile::NextTrainFile(const char* ntFile) : m_fp(0), m_shortopt(false) {
rinosh2 0:1e951aba6a7e 17 if(ntFile) open(ntFile);
rinosh2 0:1e951aba6a7e 18 }
rinosh2 0:1e951aba6a7e 19
rinosh2 0:1e951aba6a7e 20 NextTrainFile::~NextTrainFile(){
rinosh2 0:1e951aba6a7e 21 close();
rinosh2 0:1e951aba6a7e 22 }
rinosh2 0:1e951aba6a7e 23
rinosh2 0:1e951aba6a7e 24 ////////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 25 // internal funcs
rinosh2 0:1e951aba6a7e 26
rinosh2 0:1e951aba6a7e 27 int getLineType(char ch){
rinosh2 0:1e951aba6a7e 28 if(ch == '#') return NextTrainFile::LINE_TITLE;
rinosh2 0:1e951aba6a7e 29 if(ch < '0') return NextTrainFile::LINE_COMMENT;
rinosh2 0:1e951aba6a7e 30 if(ch <= '9') return NextTrainFile::LINE_TIME;
rinosh2 0:1e951aba6a7e 31 if(ch < 'A') return NextTrainFile::LINE_COMMENT;
rinosh2 0:1e951aba6a7e 32 if(ch <= 'Z') return NextTrainFile::LINE_OPTION;
rinosh2 0:1e951aba6a7e 33 if(ch == '[') return NextTrainFile::LINE_WEEK;
rinosh2 0:1e951aba6a7e 34 if(ch < 'a') return NextTrainFile::LINE_COMMENT;
rinosh2 0:1e951aba6a7e 35 if(ch <= 'z') return NextTrainFile::LINE_OPTION;
rinosh2 0:1e951aba6a7e 36 return NextTrainFile::LINE_COMMENT;
rinosh2 0:1e951aba6a7e 37 }
rinosh2 0:1e951aba6a7e 38 int getOptionID(char ch){
rinosh2 0:1e951aba6a7e 39 if(ch < 'A') return -1;
rinosh2 0:1e951aba6a7e 40 if(ch <= 'Z') return ch - 'A';
rinosh2 0:1e951aba6a7e 41 if(ch < 'a') return -1;
rinosh2 0:1e951aba6a7e 42 if(ch <= 'z') return ch - 'a' + 26;
rinosh2 0:1e951aba6a7e 43 return -1;
rinosh2 0:1e951aba6a7e 44 }
rinosh2 0:1e951aba6a7e 45
rinosh2 0:1e951aba6a7e 46 int getWeekMask(char* str){
rinosh2 0:1e951aba6a7e 47 const char WEEK_DELIM[] = " []\t\r\n";
rinosh2 0:1e951aba6a7e 48 const char* WEEK_LIST[] = { // week + holiday
rinosh2 0:1e951aba6a7e 49 "MON", "TUE", "WED", "THU", "FRI", "SAT", "SUN", "HOL"
rinosh2 0:1e951aba6a7e 50 };
rinosh2 0:1e951aba6a7e 51
rinosh2 0:1e951aba6a7e 52 int ret = 0;
rinosh2 0:1e951aba6a7e 53 char * p = strtok(str, WEEK_DELIM);
rinosh2 0:1e951aba6a7e 54 while(p){
rinosh2 0:1e951aba6a7e 55 for(int index = 0; index < 8 ; ++index){ // week7 + holiday
rinosh2 0:1e951aba6a7e 56 // if(stricmp(p, WEEK_LIST[index]) == 0){
rinosh2 0:1e951aba6a7e 57 if(strcmp(p, WEEK_LIST[index]) == 0){
rinosh2 0:1e951aba6a7e 58 ret |= 1 << index;
rinosh2 0:1e951aba6a7e 59 break;
rinosh2 0:1e951aba6a7e 60 }
rinosh2 0:1e951aba6a7e 61 }
rinosh2 0:1e951aba6a7e 62 p = strtok(0, WEEK_DELIM);
rinosh2 0:1e951aba6a7e 63 }
rinosh2 0:1e951aba6a7e 64 return ret;
rinosh2 1:f89f955130c7 65 }
rinosh2 0:1e951aba6a7e 66
rinosh2 0:1e951aba6a7e 67 ////////////////////////////////////////////////////////////////////////////////
rinosh2 0:1e951aba6a7e 68 // Open NextTrain format file and read option data
rinosh2 0:1e951aba6a7e 69 NextTrainFile::Status NextTrainFile::open(const char* ntFile){
rinosh2 0:1e951aba6a7e 70 Status ret = S_SUCCESS;
rinosh2 0:1e951aba6a7e 71
rinosh2 0:1e951aba6a7e 72 // open check
rinosh2 0:1e951aba6a7e 73 if(m_fp) return S_ALREADY_OPEN;
rinosh2 0:1e951aba6a7e 74 m_fp = fopen(ntFile, "r");
rinosh2 0:1e951aba6a7e 75 if(!m_fp) return S_OPEN_ERROR;
rinosh2 0:1e951aba6a7e 76
rinosh2 0:1e951aba6a7e 77 // Read option info
rinosh2 0:1e951aba6a7e 78 memset(m_index, 0xff, sizeof(m_index));
rinosh2 0:1e951aba6a7e 79 int pos = 0;
rinosh2 0:1e951aba6a7e 80 int left = MAX_OPTBUF - 1;
rinosh2 0:1e951aba6a7e 81 char line[MAX_LINE_BUF];
rinosh2 0:1e951aba6a7e 82 while(fgets(line, sizeof(line), m_fp)){
rinosh2 0:1e951aba6a7e 83 switch(getLineType(*line)){
rinosh2 0:1e951aba6a7e 84 case LINE_TITLE:
rinosh2 0:1e951aba6a7e 85 case LINE_TIME:
rinosh2 0:1e951aba6a7e 86 case LINE_WEEK:
rinosh2 0:1e951aba6a7e 87 // Don't cache (for saving the memory)
rinosh2 0:1e951aba6a7e 88 break;
rinosh2 0:1e951aba6a7e 89
rinosh2 0:1e951aba6a7e 90 case LINE_OPTION:
rinosh2 0:1e951aba6a7e 91 {
rinosh2 0:1e951aba6a7e 92 // Decode option / e.g. "a:Express;EX"
rinosh2 0:1e951aba6a7e 93 int optID = getOptionID(line[0]); // 0..51
rinosh2 0:1e951aba6a7e 94 if(optID < 0 || line[1] != ':') continue; // assert?
rinosh2 0:1e951aba6a7e 95
rinosh2 0:1e951aba6a7e 96 const char OPTION_DELIM[] = " \t\r\n";
rinosh2 0:1e951aba6a7e 97 char* p = strtok(line + 2, OPTION_DELIM);
rinosh2 0:1e951aba6a7e 98 if(!p) continue; // skip empty option
rinosh2 0:1e951aba6a7e 99
rinosh2 0:1e951aba6a7e 100 int len = strlen(p) + 1;
rinosh2 0:1e951aba6a7e 101 if(len > left){
rinosh2 0:1e951aba6a7e 102 ret = S_OPTION_OVERFLOW; // MAX_OPTBUF is too small...
rinosh2 0:1e951aba6a7e 103 continue;
rinosh2 0:1e951aba6a7e 104 }
rinosh2 0:1e951aba6a7e 105 m_index[optID] = (unsigned char)pos;
rinosh2 0:1e951aba6a7e 106 memcpy(m_optbuf + pos, p, len);
rinosh2 0:1e951aba6a7e 107 pos += len;
rinosh2 0:1e951aba6a7e 108 left -= len;
rinosh2 0:1e951aba6a7e 109 }
rinosh2 0:1e951aba6a7e 110 break;
rinosh2 0:1e951aba6a7e 111 }
rinosh2 0:1e951aba6a7e 112 }
rinosh2 0:1e951aba6a7e 113 return ret;
rinosh2 0:1e951aba6a7e 114 }
rinosh2 0:1e951aba6a7e 115 NextTrainFile::Status NextTrainFile::close(){
rinosh2 0:1e951aba6a7e 116 if(m_fp){
rinosh2 0:1e951aba6a7e 117 fclose(m_fp); // no error check...
rinosh2 0:1e951aba6a7e 118 m_fp = 0;
rinosh2 0:1e951aba6a7e 119 }
rinosh2 0:1e951aba6a7e 120 return S_SUCCESS;
rinosh2 0:1e951aba6a7e 121 }
rinosh2 0:1e951aba6a7e 122
rinosh2 0:1e951aba6a7e 123 NextTrainFile::Status NextTrainFile::search(time_t dt, int offset){
rinosh2 0:1e951aba6a7e 124 if(!m_fp) return S_OPEN_ERROR; // Closed
rinosh2 0:1e951aba6a7e 125
rinosh2 0:1e951aba6a7e 126 // Set target time/week
rinosh2 0:1e951aba6a7e 127 if(!dt) dt = time(0); // get current time
rinosh2 0:1e951aba6a7e 128 struct tm* st = localtime(&dt);
rinosh2 0:1e951aba6a7e 129 int week_flag = 1 << st->tm_wday; // TODO HOLIDAY!
rinosh2 0:1e951aba6a7e 130 unsigned int target = st->tm_hour;
rinosh2 0:1e951aba6a7e 131 if(target < HOUR_DIV) target += 24;
rinosh2 0:1e951aba6a7e 132 target = target * 60 + st->tm_min;
rinosh2 0:1e951aba6a7e 133
rinosh2 0:1e951aba6a7e 134 // Scan from head of file
rinosh2 0:1e951aba6a7e 135 rewind(m_fp);
rinosh2 0:1e951aba6a7e 136 int week_mask = -1; // default: all
rinosh2 0:1e951aba6a7e 137 char line[MAX_LINE_BUF];
rinosh2 0:1e951aba6a7e 138 const char TIME_LINE_DELIM[] = " \t\r\n";
rinosh2 0:1e951aba6a7e 139
rinosh2 0:1e951aba6a7e 140 while(fgets(line, sizeof(line), m_fp)){
rinosh2 0:1e951aba6a7e 141 switch(getLineType(*line)){
rinosh2 0:1e951aba6a7e 142 case LINE_TITLE:
rinosh2 0:1e951aba6a7e 143 if(week_mask & week_flag) {
rinosh2 0:1e951aba6a7e 144 char* p1 = line + 1;
rinosh2 0:1e951aba6a7e 145 while(*p1 && strchr(TIME_LINE_DELIM, *p1)) ++p1;
rinosh2 0:1e951aba6a7e 146 char* p2 = p1 + strlen(p1);
rinosh2 0:1e951aba6a7e 147 while(p1 < p2 && strchr(TIME_LINE_DELIM, *p2)) --p2;
rinosh2 0:1e951aba6a7e 148 int len = p2 - p1;
rinosh2 0:1e951aba6a7e 149 if(*p1 && ++len > sizeof(m_ni.m_title) - 1){
rinosh2 0:1e951aba6a7e 150 len = sizeof(m_ni.m_title) - 1;
rinosh2 0:1e951aba6a7e 151 }
rinosh2 0:1e951aba6a7e 152 memcpy(m_ni.m_title, p1, len);
rinosh2 0:1e951aba6a7e 153 m_ni.m_title[len] = 0;
rinosh2 0:1e951aba6a7e 154 }
rinosh2 0:1e951aba6a7e 155 break;
rinosh2 0:1e951aba6a7e 156
rinosh2 0:1e951aba6a7e 157 case LINE_TIME:
rinosh2 0:1e951aba6a7e 158 // Decode option / e.g. "5: ic14 ie19 hc33 ie39 ie54"
rinosh2 0:1e951aba6a7e 159 if(week_mask & week_flag){
rinosh2 0:1e951aba6a7e 160 // hour format check
rinosh2 0:1e951aba6a7e 161 char* p = strtok(line, ":");
rinosh2 0:1e951aba6a7e 162 if(!p) break; // Invalid hour line! (return error?)
rinosh2 0:1e951aba6a7e 163 int hour = atoi(p);
rinosh2 0:1e951aba6a7e 164 if(hour > 23 + HOUR_DIV) break; // Invalid time! (return error?)
rinosh2 0:1e951aba6a7e 165
rinosh2 0:1e951aba6a7e 166 // check hour
rinosh2 0:1e951aba6a7e 167 m_ni.m_hour = hour;
rinosh2 0:1e951aba6a7e 168 if(hour < HOUR_DIV) hour += 24;
rinosh2 0:1e951aba6a7e 169 unsigned int hm = hour * 60;
rinosh2 0:1e951aba6a7e 170 if(hm + 60 < target) break; // passed
rinosh2 0:1e951aba6a7e 171
rinosh2 0:1e951aba6a7e 172 // search target min
rinosh2 0:1e951aba6a7e 173 while((p = strtok(0, TIME_LINE_DELIM)) != 0){
rinosh2 0:1e951aba6a7e 174 // min format check
rinosh2 0:1e951aba6a7e 175 char* opt = p;
rinosh2 0:1e951aba6a7e 176 while(*p && !strchr("0123456789", *p)) ++p;
rinosh2 0:1e951aba6a7e 177 if(!*p) continue; // Invalid min format! (return error?)
rinosh2 0:1e951aba6a7e 178 m_ni.m_min = atoi(p);
rinosh2 0:1e951aba6a7e 179 if(m_ni.m_min >= 60) continue; // Invalid min format! (return error?)
rinosh2 0:1e951aba6a7e 180
rinosh2 0:1e951aba6a7e 181 // check min
rinosh2 0:1e951aba6a7e 182 if(hm + m_ni.m_min <= target) continue; // passed
rinosh2 0:1e951aba6a7e 183
rinosh2 0:1e951aba6a7e 184 if(offset-- > 0) continue; // view next
rinosh2 0:1e951aba6a7e 185
rinosh2 0:1e951aba6a7e 186 // Found NextTrain
rinosh2 0:1e951aba6a7e 187 //m_ni.m_hour = hour; // use 24:00 instead of 00:00
rinosh2 0:1e951aba6a7e 188 m_ni.m_diff = (hm + m_ni.m_min - target) * 60 - st->tm_sec; // leap seconds (max 61)?
rinosh2 0:1e951aba6a7e 189 char* dst = m_ni.m_option;
rinosh2 0:1e951aba6a7e 190 int left = MAX_OPTION - 1;
rinosh2 0:1e951aba6a7e 191 for(; opt < p ; ++opt){
rinosh2 0:1e951aba6a7e 192 // check option format
rinosh2 0:1e951aba6a7e 193 int optID = getOptionID(*opt);
rinosh2 0:1e951aba6a7e 194 if(optID < 0 || m_index[optID] == 0xff) return S_INVALID_OPTION_ID;
rinosh2 0:1e951aba6a7e 195
rinosh2 0:1e951aba6a7e 196 // append option string
rinosh2 0:1e951aba6a7e 197 char* src = m_optbuf + m_index[optID];
rinosh2 0:1e951aba6a7e 198 char* sep = strchr(src, ';');
rinosh2 0:1e951aba6a7e 199 int len;
rinosh2 0:1e951aba6a7e 200 if(sep){
rinosh2 0:1e951aba6a7e 201 if(m_shortopt){
rinosh2 0:1e951aba6a7e 202 // abbreviation
rinosh2 0:1e951aba6a7e 203 src = sep + 1;
rinosh2 0:1e951aba6a7e 204 len = strlen(src);
rinosh2 0:1e951aba6a7e 205 } else {
rinosh2 0:1e951aba6a7e 206 // long description
rinosh2 0:1e951aba6a7e 207 len = sep - src;
rinosh2 0:1e951aba6a7e 208 }
rinosh2 0:1e951aba6a7e 209 } else {
rinosh2 0:1e951aba6a7e 210 // no separator
rinosh2 0:1e951aba6a7e 211 len = strlen(src);
rinosh2 0:1e951aba6a7e 212 }
rinosh2 0:1e951aba6a7e 213
rinosh2 0:1e951aba6a7e 214 if(len > left) return S_OPTION_OVERFLOW; // MAX_OPTION is too small...
rinosh2 0:1e951aba6a7e 215 memcpy(dst, src, len);
rinosh2 0:1e951aba6a7e 216 dst += len;
rinosh2 0:1e951aba6a7e 217 left -= len;
rinosh2 0:1e951aba6a7e 218 }
rinosh2 0:1e951aba6a7e 219 *dst = 0;
rinosh2 0:1e951aba6a7e 220 return S_SUCCESS;
rinosh2 0:1e951aba6a7e 221 }
rinosh2 0:1e951aba6a7e 222 }
rinosh2 0:1e951aba6a7e 223 break;
rinosh2 0:1e951aba6a7e 224
rinosh2 0:1e951aba6a7e 225 case LINE_WEEK:
rinosh2 0:1e951aba6a7e 226 week_mask = getWeekMask(line);
rinosh2 0:1e951aba6a7e 227 break;
rinosh2 0:1e951aba6a7e 228
rinosh2 0:1e951aba6a7e 229 case LINE_OPTION:
rinosh2 0:1e951aba6a7e 230 // skip (use cache)
rinosh2 0:1e951aba6a7e 231 break;
rinosh2 0:1e951aba6a7e 232 }
rinosh2 0:1e951aba6a7e 233 }
rinosh2 0:1e951aba6a7e 234
rinosh2 0:1e951aba6a7e 235 return S_NO_TRAIN; // failed
rinosh2 0:1e951aba6a7e 236 }
rinosh2 0:1e951aba6a7e 237
rinosh2 0:1e951aba6a7e 238