ATimeControl::ATimeControl(AComponent* pOwner):base_class(pOwner),m_pFocusEdit(NULL)
{
	m_iBorderWidth = 1;
	m_pEditHour = new AEdit(this);
	m_pEditMinute =new AEdit(this);
	m_pEditSecond = new AEdit(this);
	m_pLabel1 = new ALabel(this);
	m_pLabel2 = new ALabel(this);
	m_pSpin = new ASpinControl(this);
	m_pSpin->SetAutoSpin(false);
	m_pSpin->SetWidth(11);
	m_pSpin->SetAlign( alRight );
	EVENT_CONNECT(m_pSpin,OnSpin,OnSpin);

	m_pEditHour->SetBorderWidth(0);
	m_pEditMinute->SetBorderWidth(0);
	m_pEditSecond->SetBorderWidth(0);
	m_pLabel1->SetText(L":");
	m_pLabel2->SetText(L":");

	ADateTime now = ADateTime::GetCurrentTime();
	m_pEditHour->SetText( AString().Format(L"%02d",now.GetHour()));
	m_pEditMinute->SetText( AString().Format(L"%02d",now.GetMinute()));
	m_pEditSecond->SetText( AString().Format(L"%02d",now.GetSecond()));

	EVENT_CONNECT(m_pEditHour,OnFocus,OnEditFocus);
	EVENT_CONNECT(m_pEditMinute,OnFocus,OnEditFocus);
	EVENT_CONNECT(m_pEditSecond,OnFocus,OnEditFocus);

	EVENT_CONNECT(m_pEditHour,OnKillFocus,OnEditKillFocus);
	EVENT_CONNECT(m_pEditMinute,OnKillFocus,OnEditKillFocus);
	EVENT_CONNECT(m_pEditSecond,OnKillFocus,OnEditKillFocus);
}
Example #2
0
void ADVBConfig::writetorecordlog(const char *fmt, ...) const
{
	ADateTime dt;
	AStdFile fp;

	if (fp.open(GetRecordLog(dt.GetDays()), "a")) {
		va_list ap;

		fp.printf("%s: ", dt.DateFormat("%Y-%M-%D %h:%m:%s.%S").str());

		va_start(ap, fmt);
		fp.vprintf(fmt, ap);
		va_end(ap);

		fp.printf("\n");

		fp.close();
	}
}
Example #3
0
/*--------------------------------------------------------------------------------*/
bool PostgresDatabase::PostgresQuery::Fetch(AString& results)
{
	bool success = false;

	if (res && nfields && (row < nrows)) {
		uint_t i;

		results.Delete();

		for (i = 0; i < nfields; i++) {
			if (i) results.printf(",");

			const char *p = PQgetvalue(res, row, i);
			switch (PQftype(res, i)) {
				case TIMESTAMPOID: {
					ADateTime dt;
					dt.FromTimeStamp(p, true);
					results += AString((uint64_t)dt);
					//debug("%s->%llu->%s (%s)\n", p, (uint64)dt, dt.DateFormat("%Y-%M-%D %h:%m:%s.%S").str(), dt.UTCToLocal().DateFormat("%Y-%M-%D %h:%m:%s.%S").str());
					break;
				}

				case TEXTOID:
				case CHAROID:
				case VARCHAROID:
					results.printf("'%s'", AString(p).Escapify().str());
					break;

				default:
					results.printf("%s", p);
					break;
			}
		}

		//debug("Row %u/%u: %s\n", row, nrows, results.str());
		row++;
		success = true;
	}

	return success;
}
Example #4
0
void ADVBConfig::vlogit(const char *fmt, va_list ap, bool show) const
{
	ADateTime dt;
	AString   filename = GetLogFile(dt.GetDays());
	AString   str;
	AStdFile  fp;

	str.vprintf(fmt, ap);

	if (fp.open(filename, "a")) {
		uint_t i, n = str.CountLines("\n", 0);

		for (i = 0; i < n; i++) {
			fp.printf("%s [%05u]: %s\n", dt.DateFormat("%Y-%M-%D %h:%m:%s.%S").str(), (uint_t)getpid(), str.Line(i, "\n", 0).str());
		}

		fp.close();
	}

	if (show && !webresponse) {
		Stdout->printf("%s\n", str.str());
	}
}
Example #5
0
bool ADVBConfig::ExtractLogData(const ADateTime& start, const ADateTime& end, const AString& filename) const
{
	AStdFile dst;
	bool success = false;

	if (dst.open(filename, "w")) {
		ADateTime dt;
		uint32_t day1 = start.GetDays();
		uint32_t day2 = end.GetDays();
		uint32_t day;
		bool     valid = false;

		for (day = day1; day <= day2; day++) {
			AStdFile src;

			if (src.open(GetLogFile(day))) {
				AString line;

				while (line.ReadLn(src) >= 0) {
					valid |= dt.FromTimeStamp(line.Words(0, 2));

					if (valid) {
						if ((dt >= start) && (dt <= end)) dst.printf("%s\n", line.str());
						if (dt >= end) break;
					}
				}

				src.close();
			}
		}

		dst.close();
	}

	return success;
}
void ATimeControl::SetTime(const ADateTime& dt)
{
	m_pEditHour->SetText( AString().Format(L"%02d",dt.GetHour()));
	m_pEditMinute->SetText( AString().Format(L"%02d",dt.GetMinute()));
	m_pEditSecond->SetText( AString().Format(L"%02d",dt.GetSecond()));
}
Example #7
0
void AFramework::MTempMaster::commandExec(const AString &cmd){
    
    AStringList *   list;
    AString         str;
    ADateTime       time;
    bool            flag = false;
    uint8           index = 0;
    uint8           index1 = 0;
    
    list = cmd.split(_MTEMP_SEP);
    
    if(list && cmd.good()){
        
        if(list->at(0) == m_username && list->at(1) == m_password){
            
            str = list->at(list->size() - 1);
            
            if(str == _MTEMP_TIMESET){
                //*  (CLIENT)        username*password*AA*MM*GG*WD*HH*MM*SS*[TIMESET]
                if(time.setYear(list->at(2).toInt32(flag)) && flag){
                    
                    if(time.setMonth(static_cast<ADateTime::Months>(list->at(3).toInt32(flag))) && flag){
                        
                        if(time.setDayOfMonth(list->at(4).toInt32(flag)) && flag){
                            
                            if(time.setWeekday(static_cast<ADateTime::Weekdays>(list->at(5).toInt32(flag))) && flag){
                                
                                if(time.setHours(list->at(6).toInt32(flag)) && flag){
                                    
                                    if(time.setMinutes(list->at(7).toInt32(flag)) && flag){
                                        
                                        if(time.setSeconds(list->at(8).toInt32(flag)) && flag){
                                            
                                            if(m_clk->setTime(time)){
                                                
                                                if(m_wifi->send(_MTEMP_BOARD_OK)){
                                                    
                                                    str.clear();
                                                    str = m_clk->currentTime().timeToString();
                                                    str.prepend("Ora settata\n");
                                                    msg(str, 0);
                                                    delete list;
                                                    return;
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                    }
                }

            }else if(str == _MTEMP_TIMEGET){
                
                //*  (CLIENT)        username*password*[TIMEGET]
                //*  (SERVER)        (AA*MM*GG*WD*HH*MM*SS*[OK] || [FAIL] || [ERROR])
                
                if(m_clk->isGood()){
                    str.clear();
                    time = m_clk->currentTime();
                    str += AString(time.year());
                    str += _MTEMP_SEP;
                    str += AString(static_cast<uint8>(time.month()));
                    str += _MTEMP_SEP;
                    str += AString(time.dayOfMonth());
                    str += _MTEMP_SEP;
                    str += AString(static_cast<uint8>(time.Weekday()));
                    str += _MTEMP_SEP;
                    str += AString(time.hours());
                    str += _MTEMP_SEP;
                    str += AString(time.minutes());
                    str += _MTEMP_SEP;
                    str += AString(time.seconds());
                    str += _MTEMP_SEP;
                    str += _MTEMP_BOARD_OK;
                    m_wifi->send(str);
                    delete list;
                    return;
                }else{
                    
                    m_wifi->send(_MTEMP_BOARD_FAIL);
                    msg("Errore...\nOrologio");
                    delete list;
                    return;
                }
                delete list;
                return;
            }else if(str == _MTEMP_TEMPGET){
                
                //(CLIENT)        username*password*R*[TEMPGET]
                //(SERVER)        R*TT*([OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                    
                    str.clear();
                    str += list->at(2);
                    str += _MTEMP_SEP;
                    
                    /////////////////////////////////////////////////////////////////////////////////////////
                    //AString prova = m_rooms[index].sensorAddress();
                    //str += AString(readTemp(prova, 500));
                    
                    str += AString(m_rooms[index].currentTemperature());                ///////////da fare per casa
                    
                    /////////////////////////////////////////////////////////////////////////////////////////////
                    str += _MTEMP_SEP;
                    str += _MTEMP_BOARD_OK;
                    m_wifi->send(str);
                    delete list;
                    return;
                }else{
                    
                    m_wifi->send(_MTEMP_BOARD_FAIL);
                    delete list;
                    return;
                }
                delete list;
                return;
            }else if(str == _MTEMP_ROOMSTAT){
                
                //(CLIENT)    username*password*R*[ROOMSTAT]
                //(SERVER)    (R*NAME*STATE*ISFORCEDON*ISFORCEDOFF*TT*[OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                
                    str.clear();
                    str += list->at(2);         
                    str += _MTEMP_SEP;
                    str += m_rooms[index].roomName();
                    str += _MTEMP_SEP;
                    str += (m_rooms[index].isOn() ? _MTEMP_ENABLED : _MTEMP_DISABLED);
                    str += _MTEMP_SEP;
                    str += (m_rooms[index].isForcedOn() ? _MTEMP_ENABLED : _MTEMP_DISABLED);
                    str += _MTEMP_SEP;
                    str += (m_rooms[index].isForcedOff() ? _MTEMP_ENABLED : _MTEMP_DISABLED);
                    str += _MTEMP_SEP;
                    ///////////////////////////////////////////////////////////////////////////////////////////
                    //AString prova = m_rooms[index].sensorAddress();
                    //str += AString(readTemp(prova, 1000));
                    str += AString(m_rooms[index].currentTemperature());
                    //////////////////////////////////////////////////////////////////////////////////////////
                    
                    str += _MTEMP_SEP;
                    str += _MTEMP_BOARD_OK;
                    m_wifi->send(str);
                }else{
                    
                    m_wifi->send(_MTEMP_BOARD_FAIL);
                }
                delete list;
                return;
            }else if(str == _MTEMP_ROOMSET){
                
                //username*password*R*NAME*FORCEON*FORCEOFF*AUTO*[ROOMSET]
                //([OK] || [FAIL] || [ERROR])
                
                index = list->at(2).toInt32(flag);          //numero stanza                 
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                
                    if(m_rooms[index].setRoomName(list->at(3))){

                        if(m_rooms[index].forceOn(list->at(4) == _MTEMP_ENABLED)){

                            if(m_rooms[index].forceOff(list->at(5) == _MTEMP_ENABLED)){

                                if(m_rooms[index].setAuto(list->at(6) == _MTEMP_ENABLED)){

                                    if(m_rooms[index].saveRoom()){

                                        m_wifi->send(_MTEMP_BOARD_OK);
                                        delete list;
                                        return;
                                    }
                                }
                            }
                        }
                    }
                }
                m_wifi->send(_MTEMP_BOARD_FAIL);
                delete list;
                return;
            }else if(str == _MTEMP_PROGGET){
                
                //(CLIENT)    username*password*R*D*[PROGGET]                           
                //(SERVER)    (R*D*HS*MS*HE*ME*TT*E*[OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);          //numero stanza                 
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                    
                    index1 = list->at(3).toInt32(flag);      //numero programma   
                    if(flag && index1 > 0 && index1 <= _MTEMP_WEEKPROGRAM_VEC_SIZE){
                        
                        str.clear();
                        str += list->at(2);
                        str += _MTEMP_SEP;
                        str += m_rooms[index].program(static_cast<ADateTime::Weekdays>(index1)).toString();
                        str += _MTEMP_SEP;
                        str += _MTEMP_BOARD_OK;
                        m_wifi->send(str);
                        delete list;
                        return;
                    }
                }
                m_wifi->send(_MTEMP_BOARD_FAIL);
                delete list;
                return;
            }else if(str == _MTEMP_PROGSET){
                
                //(CLIENT)    username*password*R*D*HS*MS*HE*ME*TT*E*[PROGSET]
                //(SERVER)    ([OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);          //numero stanza
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                    
                    index1 = list->at(3).toInt32(flag);      //numero programma   
                    if(flag && index1 > 0 && index1 <= _MTEMP_WEEKPROGRAM_VEC_SIZE){                
                        
                        str.clear();
                        for(uint8 i = 3; i < 9; i++){
                            
                            str += list->at(i);
                            str += _MTEMP_SEP;   
                        }
                        str += list->at(9);
                        if(m_rooms[index].setProgram((static_cast<ADateTime::Weekdays>(index1)), str)){
                            
                            if(m_rooms[index].saveProgram(static_cast<ADateTime::Weekdays>(index1))){
                                
                                m_wifi->send(_MTEMP_BOARD_OK);
                                delete list;
                                return;
                            }
                        }
                    }
                }
                m_wifi->send(_MTEMP_BOARD_FAIL);
                delete list;
                return;
            }else if(str == _MTEMP_FORCEON){
                
                //(CLIENT)    username*password*R*[FORCEON]
                //(SERVER)    ([OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                    
                    m_rooms[index].forceOn(true);
                    m_wifi->send(_MTEMP_BOARD_OK);
                }else{
                    
                    m_wifi->send(_MTEMP_BOARD_FAIL);
                }
                delete list;
                return;
            }else if(str == _MTEMP_FORCEOFF){
                
                //(CLIENT)    username*password*R*[FORCEOFF]
                //(SERVER)    ([OK] || [FAIL] || [ERROR])
                index = list->at(2).toInt32(flag);
                if(flag && index < _MTEMP_ROOM_VEC_SIZE){
                    
                    m_rooms[index].forceOff(true);
                    m_wifi->send(_MTEMP_BOARD_OK);
                }else{
                    
                    m_wifi->send(_MTEMP_BOARD_FAIL);
                }
                delete list;
                return;    
            }else{      //altro comando 
                
                m_wifi->send(_MTEMP_BOARD_FAIL);
                delete list;
                return;
            }
        }else{              //login fallito
            
            m_wifi->send(_MTEMP_BOARD_ERROR);
            delete list;
            return;
        }
    }       //split fallita
    
    if(list){
        
        delete list;
        msg("Errore\nCmd Handler");
        m_wifi->send(_MTEMP_BOARD_ERROR);
    }
    return;
}
Example #8
0
bool AFramework::MTempMaster::programsManager(const bool read){                                                //da fare
    
    ADateTime currentClk;
    Program prg;
    AString str;
    
    if(!m_flag){
        
        return false;
    }
    
    if(read){
        for(uint8 i = 0; i < _MTEMP_ROOM_VEC_SIZE; i++){
            
            if(m_rooms[i].currentTemperature() != 0){           //se il sensore è vivo
                
                str.clear();
                str = m_rooms[i].sensorAddress();
                m_rooms[i].setTemperature(readTemp(str, 1000));      //aggiorno la temperatura
            }
        }
    }
    if(m_clk->isGood()){
        
        currentClk = m_clk->currentTime();

        for(uint8 i=0; i < _MTEMP_ROOM_VEC_SIZE; i++){

            prg = m_rooms[i].program(currentClk.Weekday());
            
            if(m_rooms[i].isAuto()){
                
                if(prg.isEnabled()){
                    
                    if( ((prg.startHours() == currentClk.hours() && prg.startMinutes() <= currentClk.minutes())
                                                             ||
                                           (prg.startHours() < currentClk.hours()))    
                                                             &&
                    ((prg.endHours() == currentClk.hours() && prg.endMinutes() >= currentClk.minutes())
                                                             ||
                                            (prg.endHours() > currentClk.hours()))) {
                        
                        if(m_rooms[i].currentTemperature() <= prg.targetTemperature()){
                           
                            m_rooms[i].on();
                        }else{
                            
                            m_rooms[i].off();
                        }    
                    }else{
                    
                        m_rooms[i].off();
                    }   
                }else{
                
                    m_rooms[i].off();
                }
            }
            
            if(m_rooms[i].isForcedOff()){           //se lo spegnimento è forzato

                m_rooms[i].off();               //metto off la porta
            }
            
            if(m_rooms[i].isForcedOn()){            

                m_rooms[i].on();                //metto on la porta

            }
        }
    }else{
        
        m_lcd->clear();
        m_lcd->write("Errore ora");
        System::delay(1000);
    }
    return false;
}
Example #9
0
void MotionDetector::ProcessImage(const ADateTime& dt, const AImage& image)
{
    AString datestr = dt.DateFormat("%Y-%M-%D %h:%m:%s.%S");

    images[imgindex] = image;

    AImage& image1 = images[(imgindex + images.size() - 1) % images.size()];
    AImage& image2 = images[imgindex];
    imgindex = (imgindex + 1) % images.size();

    if ((image1.GetRect() == image2.GetRect()) && (image2 != image1)) {
        const AImage::PIXEL *pix1 = image1.GetPixelData();
        const AImage::PIXEL *pix2 = image2.GetPixelData();
        const ARect& rect = image1.GetRect();
        std::vector<float> data;
        float *ptr, *p;
        double avg[3];
        uint_t x, y, w = rect.w, h = rect.h, w3 = w * 3, len = w * h, len3 = w3 * h;

        data.resize(len3);
        ptr = &data[0];

        memset(avg, 0, sizeof(avg));

        for (y = 0, p = ptr; y < h; y++) {
            double yavg[3];

            memset(yavg, 0, sizeof(yavg));

            for (x = 0; x < w; x++, p += 3, pix1++, pix2++) {
                p[0] 	 = ((float)pix1->r - (float)pix2->r) * redscale;
                p[1] 	 = ((float)pix1->g - (float)pix2->g) * grnscale;
                p[2] 	 = ((float)pix1->b - (float)pix2->b) * bluscale;

                yavg[0] += p[0];
                yavg[1] += p[1];
                yavg[2] += p[2];
            }

            yavg[0] /= (double)w;
            yavg[1] /= (double)w;
            yavg[2] /= (double)w;

            p -= 3 * w;

            for (x = 0; x < w; x++, p += 3) {
                p[0] -= yavg[0];
                avg[0] += p[0];
                p[1] -= yavg[1];
                avg[1] += p[1];
                p[2] -= yavg[2];
                avg[2] += p[2];
            }
        }

        avg[0] /= (double)len;
        avg[1] /= (double)len;
        avg[2] /= (double)len;

        float *p2;
        for (y = 0, p = ptr, p2 = ptr; y < h; y++) {
            for (x = 0; x < w; x++, p += 3, p2++) {
                p[0] -= avg[0];
                p[1] -= avg[1];
                p[2] -= avg[2];
                p2[0] = sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]);
            }
        }

        double avg2 = 0.0, sd2 = 0.0;
        uint_t mx, my, cx = (matwid - 1) >> 1, cy = (mathgt - 1) >> 1;
        for (x = 0; x < w; x++) {
            for (y = 0; y < h; y++) {
                float val = 0.f;

                if (matwid && mathgt) {
                    for (my = 0; my < mathgt; my++) {
                        if (((y + my) >= cy) && ((y + my) < (h + cy))) {
                            for (mx = 0; mx < matwid; mx++) {
                                if (((x + mx) >= cx) && ((x + mx) < (h + cx))) {
                                    val += matrix[mx + my * matwid] * ptr[(x + mx - cx) + (y + my - cy) * w];
                                }
                            }
                        }
                    }

                    val *= matmul;
                }
                else val = ptr[x + y * w];

                ptr[w * h + x + y * w] = (float)val;
                avg2 += val;
                sd2  += val * val;
            }
        }

        avg2 /= (double)len;
        sd2   = sqrt(sd2 / (double)len - avg2 * avg2);

        Interpolate(diffavg, avg2, coeff);
        Interpolate(diffsd,  sd2,  coeff);

        stats.Set(AString("avg%").Arg(index), AString("%0.16e").Arg(diffavg));
        stats.Set(AString("sd%").Arg(index),  AString("%0.16e").Arg(diffsd));

        double diff = avgfactor * diffavg + sdfactor * diffsd, total = 0.0;
        for (x = 0; x < len; x++) {
            ptr[x] = MAX(ptr[w * h + x] - diff, 0.0);
            total += ptr[x];
        }

        total = total * 1000.0 / ((double)w * (double)h);

        if (verbose) {
            log.printf("%s[%u]: Level = %0.1lf (diff = %0.6lf)\n",
                       datestr.str(), index, total, diff);
        }

        stats.Set(AString("level%").Arg(index), AString("%0.4").Arg(total));

        if (total >= threshold) {
            static const TAG tags[] = {
                {AImage::TAG_JPEG_QUALITY, 95},
                {TAG_DONE, 0},
            };

            if (detimgdir.Valid()) {
                AImage img;
                if (img.Create(rect.w, rect.h)) {
                    const AImage::PIXEL *pixel1 = image1.GetPixelData();
                    const AImage::PIXEL *pixel2 = image2.GetPixelData();
                    AImage::PIXEL       *pixel  = img.GetPixelData();

                    for (x = 0; x < len; x++, pixel++, pixel1++, pixel2++) {
                        pixel->r = (uint8_t)LIMIT((double)MAX(pixel1->r, pixel2->r) * ptr[x] / 255.0, 0.0, 255.0);
                        pixel->g = (uint8_t)LIMIT((double)MAX(pixel1->g, pixel2->g) * ptr[x] / 255.0, 0.0, 255.0);
                        pixel->b = (uint8_t)LIMIT((double)MAX(pixel1->b, pixel2->b) * ptr[x] / 255.0, 0.0, 255.0);
                    }

                    AString filename = detimgdir.CatPath(dt.DateFormat(detimgfmt) + ".jpg");
                    CreateDirectory(filename.PathPart());
                    img.SaveJPEG(filename, tags);
                }
            }

            AString filename = imagedir.CatPath(dt.DateFormat(imagefmt) + ".jpg");
            CreateDirectory(filename.PathPart());
            log.printf("%s[%u]: Saving detection image in '%s'\n", datestr.str(), index, filename.str());
            image2.SaveJPEG(filename, tags);

            if (detcmd.Valid()) {
                AString cmd = detcmd.SearchAndReplace("{level}", AString("%0.4").Arg(total));
                if (system(cmd) != 0) {
                    log.printf("%s[%u]: Detection command '%s' failed\n", datestr.str(), index, cmd.str());
                }
            }
        }
        else if (nodetcmd.Valid()) {
            AString cmd = nodetcmd.SearchAndReplace("{level}", AString("%0.4").Arg(total));
            if (system(cmd) != 0) {
                log.printf("%s[%u]: No-detection command '%s' failed\n", datestr.str(), index, cmd.str());
            }
        }
    }
    //else debug("Images are different sizes or identical\n");
}
Example #10
0
AString ADVBPatterns::ParsePattern(const AString& _line, PATTERN& pattern, const AString& user)
{
	const ADVBConfig& config = ADVBConfig::Get();
	ADataList& list   = pattern.list;
	AString&   errors = pattern.errors;
	AString    line   = config.ReplaceTerms(user, _line);
	TERM   *term;
	uint_t i;

	pattern.exclude    = false;
	pattern.enabled    = true;
	pattern.scorebased = false;
	pattern.pri        = 0;
	pattern.user       = user;
	pattern.pattern    = line;

	if (pattern.user.Valid()) {
		pattern.pri = (int)config.GetUserConfigItem(pattern.user, "pri");
	}

	list.DeleteList();
	list.SetDestructor(&__DeleteTerm);

	i = 0;
	while (IsWhiteSpace(line[i])) i++;
	if (line[i] == '#') {
		pattern.enabled = false;
		i++;
	}
	else if (line[i] == ';') {
		return errors;
	}

	while (IsWhiteSpace(line[i])) i++;

	if (line[i]) {
		while (line[i] && errors.Empty()) {
			if (!IsSymbolStart(line[i])) {
				errors.printf("Character '%c' (at %u) is not a legal field start character (term %u)", line[i], i, list.Count() + 1);
				break;
			}

			uint_t fieldstart = i++;
			while (IsSymbolChar(line[i])) i++;
			AString field = line.Mid(fieldstart, i - fieldstart).ToLower();

			while (IsWhiteSpace(line[i])) i++;

			if (field == "exclude") {
				pattern.exclude = true;
				continue;
			}

			const FIELD *fieldptr = (const FIELD *)ADVBProg::fieldhash.Read(field);
			if (!fieldptr) {
				uint_t nfields;
				const FIELD *fields = ADVBProg::GetFields(nfields);

				errors.printf("'%s' (at %u) is not a valid search field (term %u), valid search fields are: ", field.str(), fieldstart, list.Count() + 1);
				for (i = 0; i < nfields; i++) {
					const FIELD& field = fields[i];

					if (i) errors.printf(", ");
					errors.printf("'%s'", field.name);
				}
				break;
			}

			uint_t opstart = i;

			const char *str = line.str() + i;
			bool isassign = fieldptr->assignable;
			uint_t j;
			uint_t opindex = 0, opcode = Operator_EQ;
			for (j = 0; j < NUMBEROF(operators); j++) {
				if (((isassign == operators[j].assign) ||
					 (isassign && !operators[j].assign)) &&
					(operators[j].fieldtypes & (1U << fieldptr->type)) &&
					(strncmp(str, operators[j].str, operators[j].len) == 0)) {
					i      += operators[j].len;
					opindex = j;
					opcode  = operators[j].opcode;
					break;
				}
			}

			while (IsWhiteSpace(line[i])) i++;

			AString value;
			bool    implicitvalue = false;
			if (j == NUMBEROF(operators)) {
				if (!line[i] || IsSymbolStart(line[i])) {
					if (fieldptr->assignable) {
						switch (fieldptr->type) {
							case FieldType_string:
								break;

							case FieldType_date:
								value = "now";
								break;

							default:
								value = "1";
								break;
						}

						opcode = Operator_Assign;
					}
					else opcode = Operator_NE;

					for (j = 0; j < NUMBEROF(operators); j++) {
						if ((opcode == operators[j].opcode) &&
							((isassign == operators[j].assign) ||
							 (isassign && !operators[j].assign)) &&
							(operators[j].fieldtypes & (1U << fieldptr->type))) {
							opindex = j;
							break;
						}
					}

					implicitvalue = true;
				}
				else {
					errors.printf("Symbols at %u do not represent a legal operator (term %u), legal operators for the field '%s' are: ", opstart, list.Count() + 1, field.str());

					bool flag = false;
					for (j = 0; j < NUMBEROF(operators); j++) {
						if (((isassign == operators[j].assign) ||
							 (isassign && !operators[j].assign)) &&
							(operators[j].fieldtypes & (1U << fieldptr->type))) {
							if (flag) errors.printf(", ");
							errors.printf("'%s'", operators[j].str);
							flag = true;
						}
					}
					break;
				}
			}

			if (!implicitvalue) {
				char quote = 0;
				if (IsQuoteChar(line[i])) quote = line[i++];

				uint_t valuestart = i;
				while (line[i] && ((!quote && !IsWhiteSpace(line[i])) || (quote && (line[i] != quote)))) {
					if (line[i] == '\\') i++;
					i++;
				}

				value = line.Mid(valuestart, i - valuestart).DeEscapify();

				if (quote && (line[i] == quote)) i++;

				while (IsWhiteSpace(line[i])) i++;
			}

			bool orflag = false;
			if ((line.Mid(i, 2).ToLower() == "or") && IsWhiteSpace(line[i + 2])) {
				orflag = true;
				i += 2;

				while (IsWhiteSpace(line[i])) i++;
			}
			else if ((line[i] == '|') && IsWhiteSpace(line[i + 1])) {
				orflag = true;
				i += 1;

				while (IsWhiteSpace(line[i])) i++;
			}

			if ((term = new TERM) != NULL) {
				term->data.start   = fieldstart;
				term->data.length  = i - fieldstart;
				term->data.field   = fieldptr - ADVBProg::fields;
				term->data.opcode  = opcode;
				term->data.opindex = opindex;
				term->data.value   = value;
				term->data.orflag  = (orflag && !RANGE(opcode, Operator_First_Assignable, Operator_Last_Assignable));
				term->field    	   = fieldptr;
				term->datetype 	   = DateType_none;

				switch (term->field->type) {
					case FieldType_string:
#if DVBDATVERSION > 1
						if (fieldptr->offset == ADVBProg::GetTagsDataOffset()) {
							value = "|" + value + "|";
						}
#endif
						
						if ((opcode & ~Operator_Inverted) == Operator_Regex) {
							AString regexerrors;
							AString rvalue;

							rvalue = ParseRegex(value, regexerrors);
							if (regexerrors.Valid()) {
								errors.printf("Regex error in value '%s' (term %u): %s", value.str(), list.Count() + 1, regexerrors.str());
							}

							value = rvalue;
						}
						term->value.str = value.Steal();
						break;

					case FieldType_date: {
						ADateTime dt;
						uint_t specified;

						dt.StrToDate(value, ADateTime::Time_Relative_Local, &specified);

						//debug("Value '%s', specified %u\n", value.str(), specified);

						if (!specified) {
							errors.printf("Failed to parse date '%s' (term %u)", value.str(), list.Count() + 1);
							break;
						}
						else if (((specified == ADateTime::Specified_Day) && (stricmp(term->field->name, "on") == 0)) ||
								 (stricmp(term->field->name, "day") == 0)) {
							//debug("Date from '%s' is '%s' (week day only)\n", value.str(), dt.DateToStr().str());
							term->value.u64 = dt.GetWeekDay();
							term->datetype  = DateType_weekday;
						}
						else if (specified & ADateTime::Specified_Day) {
							specified |= ADateTime::Specified_Date;
						}

						if (term->datetype == DateType_none) {
							specified &= ADateTime::Specified_Date | ADateTime::Specified_Time;

							if (specified == (ADateTime::Specified_Date | ADateTime::Specified_Time)) {
								//debug("Date from '%s' is '%s' (full date and time)\n", value.str(), dt.DateToStr().str());
								term->value.u64 = (uint64_t)dt;
								term->datetype  = DateType_fulldate;
							}
							else if (specified == ADateTime::Specified_Date) {
								//debug("Date from '%s' is '%s' (date only)\n", value.str(), dt.DateToStr().str());
								term->value.u64 = dt.GetDays();
								term->datetype  = DateType_date;
							}
							else if (specified == ADateTime::Specified_Time) {
								//debug("Date from '%s' is '%s' (time only)\n", value.str(), dt.DateToStr().str());
								term->value.u64 = dt.GetMS();
								term->datetype  = DateType_time;
							}
							else {
								errors.printf("Unknown date specifier '%s' (term %u)", value.str(), list.Count() + 1);
							}
						}
						break;
					}

					case FieldType_span:
					case FieldType_age: {
						ADateTime dt;
						//ADateTime::EnableDebugStrToDate(true);
						term->value.u64 = (uint64_t)ADateTime(value, ADateTime::Time_Absolute);
						//ADateTime::EnableDebugStrToDate(false);
						break;
					}

					case FieldType_uint32_t:
					case FieldType_external_uint32_t:
						term->value.u32 = (uint32_t)value;
						break;

					case FieldType_sint32_t:
					case FieldType_external_sint32_t:
						term->value.s32 = (sint32_t)value;
						break;

					case FieldType_uint16_t:
						term->value.u16 = (uint16_t)value;
						break;

					case FieldType_sint16_t:
						term->value.s16 = (sint16_t)value;
						break;

					case FieldType_uint8_t:
						term->value.u8 = (uint8_t)(uint16_t)value;
						break;

					case FieldType_sint8_t:
						term->value.s8 = (sint8_t)(sint16_t)value;
						break;

					case FieldType_flag...FieldType_lastflag:
						term->value.u8 = ((uint32_t)value != 0);
						//debug("Setting test of flag to %u\n", (uint_t)term->value.u8);
						break;

					case FieldType_prog: {
						ADVBProg *prog;

						if ((prog = new ADVBProg) != NULL) {
							if (prog->Base64Decode(value)) {
								term->value.prog = prog;
							}
							else {
								errors.printf("Failed to decode base64 programme ('%s') for %s at %u (term %u)", value.str(), field.str(), fieldstart, list.Count() + 1);
								delete prog;
							}
						}
						else {
							errors.printf("Failed to allocate memory for base64 programme ('%s') for %s at %u (term %u)", value.str(), field.str(), fieldstart, list.Count() + 1);
						}
						break;
					}

					default:
						errors.printf("Unknown field '%s' type (%u) (term %u)", field.str(), (uint_t)term->field->type, list.Count() + 1);
						break;
				}

				//debug("term: field {name '%s', type %u, assignable %u, offset %u} type %u dateflags %u value '%s'\n", term->field->name, (uint_t)term->field->type, (uint_t)term->field->assignable, term->field->offset, (uint_t)term->data.opcode, (uint_t)term->dateflags, term->value.str);

				if (errors.Empty()) {
					pattern.scorebased |= (term->field->offset == ADVBProg::GetScoreDataOffset());
					list.Add((uptr_t)term);
				}
				else {
					__DeleteTerm((uptr_t)term, NULL);
					break;
				}
			}
		}
	}