// ------------------------------------------------------------------ // GoldED+ // Copyright (C) 1990-1999 Odinn Sorensen // Copyright (C) 1999-2000 Alexander S. Aganichev // ------------------------------------------------------------------ // 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., 59 Temple Place, Suite 330, Boston, // MA 02111-1307 USA // ------------------------------------------------------------------ // $Id$ // ------------------------------------------------------------------ // Global utility functions (not overlayed in 16-bit DOS). // ------------------------------------------------------------------ #include #include #define UPDATE_STATUSLINE_ERROR " ERROR! Please look a log file and make a report to developers! " // ------------------------------------------------------------------ extern bool in_arealist; extern GPickArealist* PickArealist; // ------------------------------------------------------------------ void update_statuslines() { char buf[200]; /* FIXME: it is need to use dynamic arrays in this fuction to prevent buffer overflow or screen garbage */ char * const buf_end = buf+199; static char old_status_line[200] = ""; char * const old_status_line_end = old_status_line+199; static int called = NO; const int WIDE= sizeof(buf)>MAXCOL? MAXCOL : sizeof(buf)-1; HandleGEvent(EVTT_REMOVEVOCBUF); if(CFG->switches.get(dispstatusline) or not called) // FIXME: Strange, status line displayed always in first call. May be need to change? { called = YES; vchar sep = _box_table(W_BSTAT, 3); char help[200], clkinfo[200]; *clkinfo = NUL; *help = NUL; if(CFG->switches.get(statuslineclock)) { time32_t t = gtime(NULL); struct tm tm; glocaltime(&tm, &t); if( strftimei(help, 40, LNG->StatusLineTimeFmt, &tm) ) gsprintf(PRINTF_DECLARE_BUFFER(clkinfo), " %s", help); } if(CFG->statuslinehelp == -1) *help = NUL; else if(CFG->statuslinehelp) gsprintf(PRINTF_DECLARE_BUFFER(help), "%s ", LNG->StatusLineHelp); else gsprintf(PRINTF_DECLARE_BUFFER(help), "%s%s%s%s %s%i.%i.%i%s ", __gver_prename__, __gver_name__, __gver_postname__, __gver_platform__, __gver_preversion__, __gver_major__, __gver_minor__, __gver_release__, __gver_postversion__ ); int help_len = strlen(help); int clk_len = strlen(clkinfo); int len = WIDE-help_len-clk_len-2; // LOG.printf("! --- %i bytes help=\"%s\"", help_len, help?help:"NULL"); // LOG.printf("! --- %i bytes information=\"%s\"", len, information?information:"NULL"); // LOG.printf("! --- %i bytes clkinfo=\"%s\"", clk_len, clkinfo?clkinfo:"NULL"); gsprintf(PRINTF_DECLARE_BUFFER(buf), "%c%s%-*.*s%s ", goldmark, help, len, len, information, clkinfo); char *begin = buf; char *obegin = old_status_line; char *end = buf + WIDE; char *oend = old_status_line + WIDE; while((*begin != NUL) and (*begin == *obegin) and (begin (help_len-1))) wwprintc(W_STAT, 0,help_len-1, C_STATW, sep); if(((begin - buf) < (WIDE-clk_len)) and ((end - buf) > (WIDE-clk_len))) wwprintc(W_STAT, 0,WIDE-clk_len, C_STATW, sep); vposset(row, col); #ifdef GOLD_MOUSE if(gmou.Row() == MAXROW-1) gmou.ShowCursor(); #endif } } /* update_statuslines() */ // ------------------------------------------------------------------ void update_statusline(const char* info) { if ( !(info) ) { LOG.errpointer(__FILE__, __LINE__); LOG.printf( "! Parameter is NULL pointer: update_statusline(NULL)."); strxcpy(information, UPDATE_STATUSLINE_ERROR, sizeof(information)); } else { strxcpy(information, info, sizeof(information)); } update_statuslines(); } // ------------------------------------------------------------------ void update_statuslinef(const char *format, const char *token, ...) { if ( !(format && *format && token) ) { LOG.errpointer(__FILE__, __LINE__); LOG.printf( "! Parameter is NULL pointer or empty string: update_statuslinef(\"%s\",\"%s\",...).", (format?(*format)?format:"":"(NULL)"), (token?token:"(NULL)") ); update_statusline(UPDATE_STATUSLINE_ERROR); return; } bool error = false; char winfobuf[350]; va_list argptr; va_start(argptr, token); try { vsprintf(winfobuf, format, argptr); } catch(...) { if (*token) sprintf(winfobuf, "ERROR: Update %s in your GOLDLANG.CFG or report to author.", token); else sprintf(winfobuf, "ERROR: \"%s\". Report to author.", format); error = true; } va_end(argptr); update_statusline(winfobuf); if (error) { SayBibi(); waitkeyt(1000); } } // ------------------------------------------------------------------ void w_shadow() { if(CFG->switches.get(screenshadows)) wshadow(C_SHADOW); } // ------------------------------------------------------------------ void w_info(const char* info) { static int wh=-1; static int srow; static int scol; static int erow; static int ecol; static int len; static char buf[150] = { "" }; char* buf2 = NULL; int prev_wh = whandle(); if(wh != -1) wactiv_(wh); if(info) { int tmp = strlen(info); if(tmp > MAXCOL-5) { buf2 = (char *)throw_malloc(MAXCOL-5); strxcpy(buf2, info, MAXCOL-5); info = buf2; tmp = MAXCOL-6; } if(wh == -1) { len = tmp; srow = inforow; erow = srow+3-1; scol = ((MAXCOL-len)/2)-1; ecol = scol+len+1; wh = wopen(srow, scol, erow, ecol, W_BINFO, C_INFOB, C_INFOW); w_shadow(); } else { if(len != tmp) { len = tmp; scol = ((MAXCOL-len)/2)-1; ecol = scol+len+1; wclose(); wh = wopen(srow, scol, erow, ecol, W_BINFO, C_INFOB, C_INFOW); w_shadow(); } } if(not streql(buf, info)) { strcpy(buf, info); wprints(0, 0, C_INFOW, buf); } } else { if(wh != -1) { *buf = NUL; wclose(); wh = -1; } } wactiv_(prev_wh); if(buf2) throw_free(buf2); } // ------------------------------------------------------------------ void w_infof(const char* format, ...) { char winfobuf[350]; va_list argptr; va_start(argptr, format); vsprintf(winfobuf, format, argptr); va_end(argptr); w_info(winfobuf); } // ------------------------------------------------------------------ void w_progress(int mode, vattr attr, long pos, long size, const char* title) { static int wh = -1; static long prev_pos = 0; int prev_wh = whandle(); if(wh != -1) wactiv_(wh); switch(mode) { case MODE_NEW: oops: if(wh == -1) { wh = wopen_(inforow, ((MAXCOL-63)/2)-1, 3, 63, W_BINFO, C_INFOB, C_INFOW); set_title(title, TCENTER, C_INFOT); title_shadow(); goto force_update; } case MODE_UPDATE: if(wh == -1) goto oops; // Oops, someone forgot to open the window.. if((pos*58/size) != (prev_pos*58/size)) { force_update: wpropbar(1, 0, 59, attr, pos, size); } prev_pos = pos; break; case MODE_QUIT: if(wh != -1) { wclose(); wunlink(wh); wh = -1; prev_pos = 0; } break; } wactiv_(prev_wh); } // ------------------------------------------------------------------ void maketitle() { wtitle(m_title, m_titlepos, m_titleattr); } // ------------------------------------------------------------------ int maketitle_and_status(char *dir) { maketitle(); update_statuslinef(LNG->ImportStatus, "ST_IMPORTSTATUS", dir); return 0; } // ------------------------------------------------------------------ void set_title(const char* t, int p, vattr a) { strcpy(m_title, t); m_titlepos = p; m_titleattr = a; } // ------------------------------------------------------------------ void title_shadow() { maketitle(); w_shadow(); } // ------------------------------------------------------------------ int IsQuoteChar(const char* s) { if(*s) { if(*s == '>') return true; if(*AA->Quotechars()) if(strchr(AA->Quotechars(), *s)) return true; } return false; } // ------------------------------------------------------------------ int is_quote(const char* ptr) { const char* endptr = ptr + 11; // Skip leading whitespace while((*ptr == ' ') or (*ptr == LF) or issoftcr(*ptr)) ptr++; // Check for empty string if((*ptr == NUL) or (ptr >= endptr)) return false; // Check for userdefined quotechars after first whitespace if(IsQuoteChar(ptr)) return true; endptr = ptr + 11; // match 10 chars after whitespaces while (*ptr && !IsQuoteChar(ptr) && !iscntrl(*ptr) && !strchr(AA->Quotestops(), *ptr) && !isspace(*ptr)) ptr++; if ((ptr < endptr) && IsQuoteChar(ptr)) return true; /* int spaces = 0; while((ptr < endptr) and *ptr) { if(*ptr == LF or issoftcr(*ptr)) { // Ignore LF's and SOFTCR's and extend check zone if found endptr++; } else if(*ptr == '>') { // Found true quote char return true; } else if(*ptr == ' ') { spaces++; if(spaces > 1) return false; } else if(iscntrl(*ptr) or strchr(AA->Quotestops(), *ptr)) { // Found a char that cannot occur in a quotestring return false; } ptr++; } */ return false; } // ------------------------------------------------------------------ bool is_quote2(Line* line, const char* ptr) { if (!CFG->quoteusenewai) return true; char *head = (char *)ptr; // search first '>' before CR, NUL or any other quote character for (bool found = false; !found; ptr++) { if (*ptr == '>') found = true; else { if (IsQuoteChar(ptr) || (*ptr == CR) || !*ptr) return true; } } // line is double quoted? if (is_quote(ptr)) return true; // if "SPACE*[a-zA-Z]{0, 3}>" for (ptr--; isspace(*head); head++); int nr = 0; for (char *tmp = head; tmp < ptr; tmp++) { char ch = g_toupper(*tmp); if ((ch >= 'A') && (ch <= 'Z')) nr++; } if ((nr < 4) && (nr == (ptr-head))) return true; // take a look at previous lines Line *paragraph = NULL; for (Line *ln = line->prev; ln; ln = ln->prev) { // previous line is quoted? if (ln->isquote()) return true; // or begin of paragraph? if ((ln->txt.length() == 0) || (ln->txt[0] == LF) || (ln->txt[0] == CR)) { if (paragraph) return true; else { paragraph = ln; continue; } } // or kludge? if (ln->txt[0] == CTRL_A) return true; // found begin of citation? const char *begin = strrchr(ln->txt.c_str(), '<'); if (begin) { // found both '<' and '>'? if (strchr(begin, '>')) return true; for (Line *ln2 = ln->next; ln2 != line; ln2 = ln2->next) { // found both '<' and '>'? if (strchr(ln2->txt.c_str(), '>')) return true; } // hide false paragraph if (paragraph) paragraph->type |= GLINE_TXTH; return false; // don't quote current line } } return true; } // ------------------------------------------------------------------ vattr quotecolor(const char* line) { char buf[MAXQUOTELEN]; uint len; GetQuotestr(line, buf, &len); uint qc = 0; for(uint i=0; ixxxx>" and ">xxxx:" lp++; while(isspace(*lp) or issoftcr(*lp)) lp++; if(is_quote(lp)) continue; if(not (IsQuoteChar(lp-1) or (*(lp-1) == ':'))) { while(not IsQuoteChar(lp)) lp--; lp++; } } else { // Type 2: "xxxx>" while(not (IsQuoteChar(lp) and not IsQuoteChar(lp+1)) and (*lp != CR) and (*lp != NUL)) ++lp; if(is_quote(lp)) continue; if(*lp) lp++; } break; } */ while (isspace(*lp) or issoftcr(*lp)) lp++; while (!IsQuoteChar(lp)) lp++; while (IsQuoteChar(lp)) lp++; // lp now points to the character after the quotestring x = lp - ptr; if((*lp != NUL) and (isspace(*lp) or issoftcr(*lp))) x++; for(*qlen = n = 0; (n < x) and ((*qlen) < MAXQUOTELEN-1); n++, ptr++) { if((*ptr != LF) and not issoftcr(*ptr)) { *qbuf++ = *ptr; (*qlen)++; } } *qbuf = NUL; } else { *qbuf = NUL; *qlen = 0; } return *qlen; } // ------------------------------------------------------------------ static int KeyCmp(const gkey* a, const gkey* b) { return CmpV(*a, *b); } // ------------------------------------------------------------------ gkey SearchKey(gkey key, std::list::iterator keys, int totkeys) { std::list::iterator kmin; int again = 0; do { kmin = keys; int tkeys=totkeys; while(tkeys > 0) { int j = KeyCmp(&key, &(kmin->key)); if(j == 0) return(kmin->cmd); else if(j < 0) break; else { kmin++; tkeys--; } } // Key not found. Try again, this time without the scancode. key &= 0x00FF; } while(not again++ and key); return 0; } // ------------------------------------------------------------------ static void call_func_geutil(VfvCP func) { struct _menu_t* menu; int row, col; bool hidden = vcurhidden(); vposget(&row, &col); menu = gwin.cmenu; (*func)(); gwin.cmenu = menu; vposset(row, col); if(hidden) vcurhide(); else vcurshow(); } // ------------------------------------------------------------------ void call_help() { // search through onkey linked list for a // matching defined onkey. if one is found, // then save the current environment, call the // onkey's function, and restore the environment. KBnd* onkey = gkbd.onkey; while(onkey != NULL) { if(onkey->keycode == Key_F1) { call_func_geutil(onkey->func); break; } onkey = onkey->prev; } } // ------------------------------------------------------------------ void CheckTick(gkey quitkey) { if (gkbd.tickvalue < gkbd.tickpress) gkbd.tickpress = gkbd.tickvalue; Clock idle_secs = (gkbd.tickvalue - gkbd.tickpress)/10; if (CFG->timeout) { if (idle_secs >= CFG->timeout) { kbput(quitkey); return; } } IdleCheckSemaphores(); if(CFG->screenblanker) { if(idle_secs >= CFG->screenblanker) { blanked = true; ScreenBlankIdle(); kbdsettickfunc(ScreenBlankIdle); getxch(); blanked = false; ScreenBlankIdle(); kbdsettickfunc(update_statuslines); //maybe we've scanned areas while in screenblanker, so //update screen if(in_arealist) { PickArealist->update(); PickArealist->do_delayed(); } } } } // ------------------------------------------------------------------ void IdleCheckSemaphores() { // I don't like this solution either... :( static Clock last_secs = 0; if (gkbd.tickvalue < gkbd.tickpress) gkbd.tickpress = gkbd.tickvalue; Clock idle_secs = (gkbd.tickvalue - gkbd.tickpress)/10; // Make sure the stuff below is only run once in a second if(not idle_secs or (idle_secs - last_secs == 0)) return ; if(in_arealist) { if(CFG->semaphore.idletime) { if((idle_secs % CFG->semaphore.idletime) == 0) CheckSemaphores(); } } last_secs = idle_secs; } // ------------------------------------------------------------------ char* strtmp(const char* str) { static INam tmp; return strxcpy(tmp, str, sizeof(tmp)); } // ------------------------------------------------------------------ bool find(const std::vector &vec, const char *str) { std::vector::const_iterator i; for(i = vec.begin(); i != vec.end(); i++) if(streql(*i, str)) return true; return false; } bool find(const std::vector &vec, const std::string &str) { std::vector::const_iterator it = vec.begin(); std::vector::const_iterator end = vec.end(); for (; it != end; it++) { if ((*it) == str) return true; } return false; }