Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
NextTrainFile.cpp
00001 /////////////////////////////////////////////////////////////////////////////// 00002 // NextTrainFile: NextTrain file parser by rinos 2010 00003 /////////////////////////////////////////////////////////////////////////////// 00004 00005 #include "NextTrainFile.h" 00006 #include <time.h> 00007 #include <stdlib.h> 00008 00009 //////////////////////////////////////////////////////////////////////////////// 00010 // defines 00011 const int MAX_LINE_BUF = 256; 00012 00013 //////////////////////////////////////////////////////////////////////////////// 00014 // NextTrainFile 00015 00016 NextTrainFile::NextTrainFile(const char* ntFile) : m_fp(0), m_shortopt(false), m_delim(' ') { 00017 if(ntFile) open(ntFile); 00018 } 00019 00020 NextTrainFile::~NextTrainFile(){ 00021 close(); 00022 } 00023 00024 //////////////////////////////////////////////////////////////////////////////// 00025 // internal funcs 00026 00027 int getLineType(char ch){ 00028 if(ch == '#') return NextTrainFile::LINE_TITLE; 00029 if(ch < '0') return NextTrainFile::LINE_COMMENT; 00030 if(ch <= '9') return NextTrainFile::LINE_TIME; 00031 if(ch < 'A') return NextTrainFile::LINE_COMMENT; 00032 if(ch <= 'Z') return NextTrainFile::LINE_OPTION; 00033 if(ch == '[') return NextTrainFile::LINE_WEEK; 00034 if(ch < 'a') return NextTrainFile::LINE_COMMENT; 00035 if(ch <= 'z') return NextTrainFile::LINE_OPTION; 00036 return NextTrainFile::LINE_COMMENT; 00037 } 00038 00039 int getOptionID(char ch){ 00040 if(ch < 'A') return -1; 00041 if(ch <= 'Z') return ch - 'A'; 00042 if(ch < 'a') return -1; 00043 if(ch <= 'z') return ch - 'a' + 26; 00044 return -1; 00045 } 00046 00047 const char* WEEK_LIST[] = { // week + holiday 00048 "SUN", "MON", "TUE", "WED", "THU", "FRI", "SAT", "HOL" 00049 }; 00050 int getWeekMask(char* str){ 00051 const char WEEK_DELIM[] = " []\t\r\n"; 00052 00053 int ret = 0; 00054 char * p = strtok(str, WEEK_DELIM); 00055 while(p){ 00056 for(int index = 0; index < 8 ; ++index){ // week7 + holiday 00057 if(strcmp(p, WEEK_LIST[index]) == 0){ // stricmp? 00058 ret |= 1 << index; 00059 break; 00060 } 00061 } 00062 p = strtok(0, WEEK_DELIM); 00063 } 00064 return ret; 00065 } 00066 00067 //////////////////////////////////////////////////////////////////////////////// 00068 // Open NextTrain format file and read option data 00069 NextTrainFile::Status NextTrainFile::open(const char* ntFile){ 00070 Status ret = S_SUCCESS; 00071 00072 // open check 00073 if(m_fp) return S_ALREADY_OPEN; 00074 m_fp = fopen(ntFile, "r"); 00075 if(!m_fp) return S_OPEN_ERROR; 00076 00077 // Read option info 00078 memset(m_index, 0xff, sizeof(m_index)); 00079 int pos = 0; 00080 int left = MAX_OPTBUF - 1; 00081 char line[MAX_LINE_BUF]; 00082 while(fgets(line, sizeof(line), m_fp)){ 00083 switch(getLineType(*line)){ 00084 case LINE_TITLE: 00085 case LINE_TIME: 00086 case LINE_WEEK: 00087 // Don't cache (for saving the memory) 00088 break; 00089 00090 case LINE_OPTION: 00091 { 00092 // Decode option / e.g. "a:Express;EX" 00093 int optID = getOptionID(line[0]); // 0..51 00094 if(optID < 0 || line[1] != ':') continue; // assert? 00095 00096 const char OPTION_DELIM[] = " \t\r\n"; 00097 char* p = strtok(line + 2, OPTION_DELIM); 00098 if(!p) continue; // skip empty option 00099 00100 int len = strlen(p) + 1; 00101 if(len > left){ 00102 ret = S_OPTION_OVERFLOW; // MAX_OPTBUF is too small... 00103 continue; 00104 } 00105 m_index[optID] = (unsigned char)pos; 00106 memcpy(m_optbuf + pos, p, len); 00107 pos += len; 00108 left -= len; 00109 } 00110 break; 00111 } 00112 } 00113 printf("NextTrainFile::open return %d, read %d bytes\n", ret, pos); 00114 return ret; 00115 } 00116 00117 NextTrainFile::Status NextTrainFile::close(){ 00118 if(m_fp){ 00119 fclose(m_fp); // no error check... 00120 m_fp = 0; 00121 } 00122 return S_SUCCESS; 00123 } 00124 00125 NextTrainFile::Status NextTrainFile::search(time_t dt, int offset){ 00126 if(!m_fp) return S_OPEN_ERROR; // Closed 00127 00128 // Set target time/week 00129 if(!dt) dt = time(0); // get current time 00130 struct tm* st = localtime(&dt); 00131 int week_flag = 1 << st->tm_wday; // TODO HOLIDAY! 00132 unsigned int target = st->tm_hour; 00133 if(target < HOUR_DIV) target += 24; 00134 target = target * 60 + st->tm_min; 00135 00136 // Scan from head of file 00137 rewind(m_fp); 00138 int week_mask = -1; // default: all 00139 char line[MAX_LINE_BUF]; 00140 const char TIME_LINE_DELIM[] = " \t\r\n"; 00141 00142 while(fgets(line, sizeof(line), m_fp)){ 00143 switch(getLineType(*line)){ 00144 case LINE_TITLE: 00145 if(week_mask & week_flag) { 00146 char* p1 = line + 1; 00147 while(*p1 && strchr(TIME_LINE_DELIM, *p1)) ++p1; 00148 char* p2 = p1 + strlen(p1); 00149 while(p1 < p2 && strchr(TIME_LINE_DELIM, *p2)) --p2; 00150 int len = p2 - p1; 00151 if(*p1 && ++len > sizeof(m_ni.m_title) - 1){ 00152 len = sizeof(m_ni.m_title) - 1; 00153 } 00154 memcpy(m_ni.m_title, p1, len); 00155 m_ni.m_title[len] = 0; 00156 } 00157 break; 00158 00159 case LINE_TIME: 00160 // Decode option / e.g. "5: ic14 ie19 hc33 ie39 ie54" 00161 if(week_mask & week_flag){ 00162 // hour format check 00163 char* p = strtok(line, ":"); 00164 if(!p) break; // Invalid hour line! (return error?) 00165 int hour = atoi(p); 00166 if(hour > 23 + HOUR_DIV) break; // Invalid time! (return error?) 00167 00168 // check hour 00169 m_ni.m_hour = hour; 00170 if(hour < HOUR_DIV) hour += 24; 00171 unsigned int hm = hour * 60; 00172 if(hm + 60 < target) break; // passed 00173 00174 // search target min 00175 while((p = strtok(0, TIME_LINE_DELIM)) != 0){ 00176 // min format check 00177 char* opt = p; 00178 while(*p && !strchr("0123456789", *p)) ++p; 00179 if(!*p) continue; // Invalid min format! (return error?) 00180 m_ni.m_min = atoi(p); 00181 if(m_ni.m_min >= 60) continue; // Invalid min format! (return error?) 00182 00183 // check min 00184 if(hm + m_ni.m_min <= target) continue; // passed 00185 00186 if(offset-- > 0) continue; // view next 00187 00188 // Found NextTrain 00189 //m_ni.m_hour = hour; // use 24:00 instead of 00:00 00190 m_ni.m_diff = (hm + m_ni.m_min - target) * 60 - st->tm_sec; // leap seconds (max 61)? 00191 char* dst = m_ni.m_option; 00192 int left = MAX_OPTION - 1; 00193 for(; opt < p ; ++opt){ 00194 // check option format 00195 int optID = getOptionID(*opt); 00196 if(optID < 0 || m_index[optID] == 0xff){ 00197 printf("NextTrainFile::search S_INVALID_OPTION_ID %x\n", (optID < 0)? -1 : m_index[optID]); 00198 return S_INVALID_OPTION_ID; 00199 } 00200 00201 // append option string 00202 char* src = m_optbuf + m_index[optID]; 00203 char* sep = strchr(src, ';'); 00204 int len; 00205 if(sep){ 00206 if(m_shortopt){ 00207 // abbreviation 00208 src = sep + 1; 00209 len = strlen(src); 00210 } else { 00211 // long description 00212 len = sep - src; 00213 } 00214 } else { 00215 // no separator 00216 len = strlen(src); 00217 } 00218 00219 if(len + 1 > left){ 00220 printf("NextTrainFile::search S_OPTION_OVERFLOW\n"); 00221 return S_OPTION_OVERFLOW; // MAX_OPTION is too small... 00222 } 00223 if(dst != m_ni.m_option && m_delim){ 00224 *dst++ = m_delim; 00225 left--; 00226 } 00227 memcpy(dst, src, len); 00228 dst += len; 00229 left -= len; 00230 } 00231 *dst = 0; 00232 printf("NextTrainFile::search %02d:%02d:%02d(%s) hit train %d:%02d\n", st->tm_hour, st->tm_min, st->tm_sec, WEEK_LIST[st->tm_wday], m_ni.m_hour, m_ni.m_min); 00233 return S_SUCCESS; 00234 } 00235 } 00236 break; 00237 00238 case LINE_WEEK: 00239 week_mask = getWeekMask(line); 00240 break; 00241 00242 case LINE_OPTION: 00243 // skip (use cache) 00244 break; 00245 } 00246 } 00247 00248 printf("NextTrainFile::search %02d:%02d:%02d(%s) NoTrain\n", st->tm_hour, st->tm_min, st->tm_sec, WEEK_LIST[st->tm_wday]); 00249 00250 return S_NO_TRAIN; // failed 00251 } 00252
Generated on Sat Jul 16 2022 14:19:22 by
1.7.2