1 
2 //  ------------------------------------------------------------------
3 //  GoldED+
4 //  Copyright (C) 1990-1999 Odinn Sorensen
5 //  Copyright (C) 1999-2000 Alexander S. Aganichev
6 //  ------------------------------------------------------------------
7 //  This program is free software; you can redistribute it and/or
8 //  modify it under the terms of the GNU General Public License as
9 //  published by the Free Software Foundation; either version 2 of the
10 //  License, or (at your option) any later version.
11 //
12 //  This program is distributed in the hope that it will be useful,
13 //  but WITHOUT ANY WARRANTY; without even the implied warranty of
14 //  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15 //  General Public License for more details.
16 //
17 //  You should have received a copy of the GNU General Public License
18 //  along with this program; if not, write to the Free Software
19 //  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
20 //  MA 02111-1307 USA
21 //  ------------------------------------------------------------------
22 //  $Id: geutil.cpp,v 1.44 2011/02/22 20:25:14 stas_degteff Exp $
23 //  ------------------------------------------------------------------
24 //  Global utility functions (not overlayed in 16-bit DOS).
25 //  ------------------------------------------------------------------
26 
27 #include <cstdarg>
28 #include <golded.h>
29 
30 #define UPDATE_STATUSLINE_ERROR    " ERROR! Please look a log file and make a report to developers! "
31 
32 //  ------------------------------------------------------------------
33 
34 extern bool in_arealist;
35 extern GPickArealist* PickArealist;
36 
37 
38 //  ------------------------------------------------------------------
39 
update_statuslines()40 void update_statuslines() {
41 # define BUFSIZE 200
42 # define BUFLEN  199
43   char buf[BUFSIZE]="";    /* FIXME: it is need to use dynamic arrays in this fuction to prevent buffer overflow or screen garbage */
44   char * const buf_end = buf+BUFLEN;
45   static char old_status_line[BUFSIZE] = "";
46   char * const old_status_line_end = old_status_line+BUFLEN;
47   static int called = NO;
48   const int WIDE= BUFLEN>MAXCOL? MAXCOL : BUFLEN;
49 
50   HandleGEvent(EVTT_REMOVEVOCBUF);
51 
52   if(CFG->switches.get(dispstatusline) or not called) // FIXME: Strange, status line displayed always in first call. May be need to change?
53   {
54 
55     called = YES;
56 
57     vchar sep = _box_table(W_BSTAT, 3);
58     char help[BUFSIZE], clkinfo[BUFSIZE];
59     *clkinfo = NUL;
60     *help = NUL;
61 
62     if(CFG->switches.get(statuslineclock))
63     {
64       time32_t t = gtime(NULL);
65       struct tm tm; glocaltime(&tm, &t);
66       if( strftimei(help, 40, LNG->StatusLineTimeFmt, &tm) )
67         gsprintf(PRINTF_DECLARE_BUFFER(clkinfo), "   %s", help);
68     }
69 
70     if(CFG->statuslinehelp == -1)
71       *help = NUL;
72     else if(CFG->statuslinehelp)
73       gsprintf(PRINTF_DECLARE_BUFFER(help), "%s   ", LNG->StatusLineHelp);
74     else
75       gsprintf(PRINTF_DECLARE_BUFFER(help), "%s%s%s%s %s%i.%i.%i%s   ",
76         __gver_prename__,
77         __gver_name__,
78         __gver_postname__,
79         __gver_platform__,
80         __gver_preversion__,
81         __gver_major__,
82         __gver_minor__,
83         __gver_release__,
84         __gver_postversion__
85       );
86 
87     int help_len = strlen(help);
88     int clk_len = strlen(clkinfo);
89     int len = WIDE-help_len-clk_len-2;
90     gsprintf(PRINTF_DECLARE_BUFFER(buf), "%c%s%-*.*s%s ", goldmark, help, len, len, information, clkinfo);
91 
92     char *begin = buf;
93     char *obegin = old_status_line;
94     char *end = buf + WIDE-1;               // last position before final '\0'
95     char *oend = old_status_line + WIDE-1;  // last position before final '\0'
96     while((*begin != NUL) and (*begin == *obegin) and (begin<buf_end) and (obegin<old_status_line_end)) {
97       ++begin;
98       ++obegin;
99     }
100     if(begin == end)
101       return;
102     // we have at least one mismatch
103     if(*obegin) {
104       while((*end == *oend) and (buf<end) and (old_status_line<oend) ) {
105         --end;
106         --oend;
107       }
108     }
109     len = end-begin+1;
110     memcpy( obegin, begin, (len<sizeof(old_status_line))? len : sizeof(old_status_line) );
111 
112     #ifdef GOLD_MOUSE
113     gmou.GetStatus();
114     if(gmou.Row() == MAXROW-1)
115       gmou.HideCursor();
116     #endif
117     int row, col;
118     vposget(&row, &col);
119     *(++end) = NUL;
120     wwprintstr(W_STAT, 0,begin-buf, C_STATW, begin);
121     if(*help and ((begin - buf) < (help_len-1)) and ((end - buf) > (help_len-1)))
122       wwprintc(W_STAT, 0,help_len-1, C_STATW, sep);
123     if(((begin - buf) < (WIDE-clk_len)) and ((end - buf) > (WIDE-clk_len)))
124       wwprintc(W_STAT, 0,WIDE-clk_len, C_STATW, sep);
125     vposset(row, col);
126     #ifdef GOLD_MOUSE
127     if(gmou.Row() == MAXROW-1)
128       gmou.ShowCursor();
129     #endif
130   }
131 # undef BUFSIZE
132 # undef BUFLEN
133 } /* update_statuslines() */
134 
135 
136 //  ------------------------------------------------------------------
137 
update_statusline(const char * info)138 void update_statusline(const char* info) {
139 
140   if ( !(info) )
141   {
142     LOG.errpointer(__FILE__, __LINE__);
143     LOG.printf( "! Parameter is NULL pointer: update_statusline(NULL).");
144     strxcpy(information, UPDATE_STATUSLINE_ERROR, sizeof(information));
145   }
146   else if (*info)
147   {
148     strxcpy(information, info, sizeof(information));
149   }
150   else
151     *information = '\0';
152   update_statuslines();
153 }
154 
155 
156 //  ------------------------------------------------------------------
157 
update_statuslinef(const char * format,const char * token,...)158 void update_statuslinef(const char *format, const char *token, ...)
159 {
160   if ( !(format && *format && token) )
161   {
162     LOG.errpointer(__FILE__, __LINE__);
163     LOG.printf( "! Parameter is NULL pointer or empty string: update_statuslinef(\"%s\",\"%s\",...).",
164                 (format?(*format)?format:"":"(NULL)"), (token?token:"(NULL)") );
165     update_statusline(UPDATE_STATUSLINE_ERROR);
166     return;
167   }
168 
169   bool error = false;
170   char winfobuf[350];
171   va_list argptr;
172   va_start(argptr, token);
173 
174   try
175   {
176     vsprintf(winfobuf, format, argptr);
177   }
178   catch(...)
179   {
180     if (*token)
181       sprintf(winfobuf, "ERROR: Update %s in your GOLDLANG.CFG or report to author.", token);
182     else
183       sprintf(winfobuf, "ERROR: \"%s\". Report to author.", format);
184 
185     error = true;
186   }
187 
188   va_end(argptr);
189   update_statusline(winfobuf);
190 
191   if (error)
192   {
193     SayBibi();
194     waitkeyt(1000);
195   }
196 }
197 
198 
199 //  ------------------------------------------------------------------
200 
w_shadow()201 void w_shadow() {
202 
203   if(CFG->switches.get(screenshadows))
204     wshadow(C_SHADOW);
205 }
206 
207 
208 //  ------------------------------------------------------------------
209 
w_info(const char * info)210 void w_info(const char* info) {
211 
212   static int wh=-1;
213   static int srow;
214   static int scol;
215   static int erow;
216   static int ecol;
217   static int len;
218   static char buf[150] = { "" };
219   char* buf2 = NULL;
220 
221   int prev_wh = whandle();
222   if(wh != -1)
223     wactiv_(wh);
224 
225   if(info) {
226     int tmp = strlen(info);
227     if(tmp > MAXCOL-5) {
228       buf2 = (char *)throw_malloc(MAXCOL-5);
229       strxcpy(buf2, info, MAXCOL-5);
230       info = buf2;
231       tmp = MAXCOL-6;
232     }
233     if(wh == -1) {
234       len = tmp;
235       srow = inforow;
236       erow = srow+3-1;
237       scol = ((MAXCOL-len)/2)-1;
238       ecol = scol+len+1;
239       wh = wopen(srow, scol, erow, ecol, W_BINFO, C_INFOB, C_INFOW);
240       w_shadow();
241     }
242     else {
243       if(len != tmp) {
244         len = tmp;
245         scol = ((MAXCOL-len)/2)-1;
246         ecol = scol+len+1;
247         wclose();
248         wh = wopen(srow, scol, erow, ecol, W_BINFO, C_INFOB, C_INFOW);
249         w_shadow();
250       }
251     }
252     if(not streql(buf, info)) {
253       strcpy(buf, info);
254       wprints(0, 0, C_INFOW, buf);
255     }
256   }
257   else {
258     if(wh != -1) {
259       *buf = NUL;
260       wclose();
261       wh = -1;
262     }
263   }
264 
265   wactiv_(prev_wh);
266 
267   if(buf2)
268     throw_free(buf2);
269 }
270 
271 
272 //  ------------------------------------------------------------------
273 
274 
w_infof(const char * format,...)275 void w_infof(const char* format, ...) {
276 
277   char winfobuf[350];
278   va_list argptr;
279   va_start(argptr, format);
280   vsprintf(winfobuf, format, argptr);
281   va_end(argptr);
282   w_info(winfobuf);
283 }
284 
285 
286 //  ------------------------------------------------------------------
287 
w_progress(int mode,vattr attr,long pos,long size,const char * title)288 void w_progress(int mode, vattr attr, long pos, long size, const char* title) {
289 
290   static int wh = -1;
291   static long prev_pos = 0;
292 
293   int prev_wh = whandle();
294   if(wh != -1)
295     wactiv_(wh);
296 
297   switch(mode) {
298     case MODE_NEW:
299       oops:
300       if(wh == -1) {
301         wh = wopen_(inforow, ((MAXCOL-63)/2)-1, 3, 63, W_BINFO, C_INFOB, C_INFOW);
302         set_title(title, TCENTER, C_INFOT);
303         title_shadow();
304         goto force_update;
305       }
306     case MODE_UPDATE:
307       if(wh == -1)
308         goto oops;  // Oops, someone forgot to open the window..
309       if((pos*58/size) != (prev_pos*58/size)) {
310       force_update:
311         wpropbar(1, 0, 59, attr, pos, size);
312       }
313       prev_pos = pos;
314       break;
315     case MODE_QUIT:
316       if(wh != -1) {
317         wclose();
318         wunlink(wh);
319         wh = -1;
320         prev_pos = 0;
321       }
322       break;
323   }
324 
325   wactiv_(prev_wh);
326 }
327 
328 
329 //  ------------------------------------------------------------------
330 
maketitle()331 void maketitle() {
332 
333   wtitle(m_title, m_titlepos, m_titleattr);
334 }
335 
336 
337 //  ------------------------------------------------------------------
338 
maketitle_and_status(char * dir)339 int maketitle_and_status(char *dir) {
340 
341   maketitle();
342   update_statuslinef(LNG->ImportStatus, "ST_IMPORTSTATUS", dir);
343   return 0;
344 }
345 
346 //  ------------------------------------------------------------------
347 
set_title(const char * t,int p,vattr a)348 void set_title(const char* t, int p, vattr a) {
349 
350   strcpy(m_title, t);
351   m_titlepos  = p;
352   m_titleattr = a;
353 }
354 
355 
356 //  ------------------------------------------------------------------
357 
title_shadow()358 void title_shadow() {
359 
360   maketitle();
361   w_shadow();
362 }
363 
364 
365 //  ------------------------------------------------------------------
366 
IsQuoteChar(const char * s)367 int IsQuoteChar(const char* s) {
368 
369   if(*s) {
370     if(*s == '>')
371       return true;
372     if(*AA->Quotechars())
373       if(strchr(AA->Quotechars(), *s))
374         return true;
375   }
376   return false;
377 }
378 
379 
380 //  ------------------------------------------------------------------
381 
is_quote(const char * ptr)382 int is_quote(const char* ptr) {
383 
384   const char* endptr = ptr + 11;
385 
386   // Skip leading whitespace
387   while((*ptr == ' ') or (*ptr == LF) or issoftcr(*ptr))
388     ptr++;
389 
390   // Check for empty string
391   if((*ptr == NUL) or (ptr >= endptr))
392     return false;
393 
394   // Check for userdefined quotechars after first whitespace
395   if(IsQuoteChar(ptr))
396     return true;
397 
398   endptr = ptr + 11; // match 10 chars after whitespaces
399 
400   while (*ptr && !IsQuoteChar(ptr) &&
401          !iscntrl(*ptr) &&
402          !strchr(AA->Quotestops(), *ptr) &&
403          !isspace(*ptr)) ptr++;
404 
405   if ((ptr < endptr) && IsQuoteChar(ptr))
406     return true;
407 
408 /*
409   int spaces = 0;
410   while((ptr < endptr) and *ptr) {
411 
412     if(*ptr == LF or issoftcr(*ptr)) {
413       // Ignore LF's and SOFTCR's and extend check zone if found
414       endptr++;
415     }
416     else if(*ptr == '>') {
417       // Found true quote char
418       return true;
419     }
420     else if(*ptr == ' ') {
421       spaces++;
422       if(spaces > 1)
423         return false;
424     }
425     else if(iscntrl(*ptr) or strchr(AA->Quotestops(), *ptr)) {
426       // Found a char that cannot occur in a quotestring
427       return false;
428     }
429     ptr++;
430   }
431 */
432 
433   return false;
434 }
435 
436 
437 //  ------------------------------------------------------------------
438 
is_quote2(Line * line,const char * ptr)439 bool is_quote2(Line* line, const char* ptr)
440 {
441   if (!CFG->quoteusenewai) return true;
442 
443   char *head = (char *)ptr;
444 
445   // search first '>' before CR, NUL or any other quote character
446   for (bool found = false; !found; ptr++)
447   {
448     if (*ptr == '>')
449       found = true;
450     else
451     {
452       if (IsQuoteChar(ptr) || (*ptr == CR) || !*ptr)
453         return true;
454     }
455   }
456 
457   // line is double quoted?
458   if (is_quote(ptr))
459     return true;
460 
461   // if "SPACE*[a-zA-Z]{0, 3}>"
462   for (ptr--; isspace(*head); head++);
463 
464   int nr = 0;
465   for (char *tmp = head; tmp < ptr; tmp++)
466   {
467     char ch = g_toupper(*tmp);
468     if ((ch >= 'A') && (ch <= 'Z'))
469       nr++;
470   }
471 
472   if ((nr < 4) && (nr == (ptr-head)))
473     return true;
474 
475   // take a look at previous lines
476   Line *paragraph = NULL;
477   for (Line *ln = line->prev; ln; ln = ln->prev)
478   {
479     // previous line is quoted?
480     if (ln->isquote())
481       return true;
482     // or begin of paragraph?
483     if ((ln->txt.length() == 0) ||
484         (ln->txt[0] == LF) ||
485         (ln->txt[0] == CR))
486     {
487       if (paragraph) return true;
488       else
489       {
490         paragraph = ln;
491         continue;
492       }
493     }
494     // or kludge?
495     if (ln->txt[0] == CTRL_A)
496       return true;
497 
498     // found begin of citation?
499     const char *begin = strrchr(ln->txt.c_str(), '<');
500     if (begin)
501     {
502       // found both '<' and '>'?
503       if (strchr(begin, '>'))
504         return true;
505 
506       for (Line *ln2 = ln->next; ln2 != line; ln2 = ln2->next)
507       {
508         // found both '<' and '>'?
509         if (strchr(ln2->txt.c_str(), '>'))
510           return true;
511       }
512 
513       // hide false paragraph
514       if (paragraph) paragraph->type |= GLINE_TXTH;
515       return false;   // don't quote current line
516     }
517   }
518 
519   return true;
520 }
521 
522 
523 //  ------------------------------------------------------------------
524 
quotecolor(const char * line)525 vattr quotecolor(const char* line) {
526 
527   char buf[MAXQUOTELEN];
528   uint len;
529 
530   GetQuotestr(line, buf, &len);
531   uint qc = 0;
532 
533   for(uint i=0; i<len; i++)
534     if(IsQuoteChar(&buf[i]))
535       qc++;
536 
537   return (qc & 1) ? C_READQ : C_READQ2;
538 }
539 
540 
541 //  ------------------------------------------------------------------
542 
GetQuotestr(const char * ptr,char * qbuf,uint * qlen)543 int GetQuotestr(const char* ptr, char* qbuf, uint* qlen) {
544 
545   if(is_quote(ptr)) {
546 
547     const char* lp = ptr;
548     int n, x;
549 /*
550     for(;;) {
551 
552       // Skip leading spaces
553       while(isspace(*lp) or issoftcr(*lp))
554         lp++;
555       if(IsQuoteChar(lp)) {      // Type 1 : ">xxxx>" and ">xxxx:"
556         lp++;
557         while(isspace(*lp) or issoftcr(*lp))
558           lp++;
559         if(is_quote(lp))
560           continue;
561         if(not (IsQuoteChar(lp-1) or (*(lp-1) == ':'))) {
562           while(not IsQuoteChar(lp))
563             lp--;
564           lp++;
565         }
566       }
567       else {                     // Type 2: "xxxx>"
568         while(not (IsQuoteChar(lp) and not IsQuoteChar(lp+1)) and (*lp != CR) and (*lp != NUL))
569           ++lp;
570         if(is_quote(lp))
571           continue;
572         if(*lp)
573           lp++;
574       }
575 
576       break;
577     }
578 */
579 
580     while (isspace(*lp) or issoftcr(*lp)) lp++;
581     while (!IsQuoteChar(lp)) lp++;
582     while (IsQuoteChar(lp)) lp++;
583 
584     // lp now points to the character after the quotestring
585 
586     x = lp - ptr;
587     if((*lp != NUL) and (isspace(*lp) or issoftcr(*lp)))
588       x++;
589 
590     for(*qlen = n = 0; (n < x) and ((*qlen) < MAXQUOTELEN-1); n++, ptr++) {
591       if((*ptr != LF) and not issoftcr(*ptr)) {
592         *qbuf++ = *ptr;
593         (*qlen)++;
594       }
595     }
596     *qbuf = NUL;
597   }
598   else {
599     *qbuf = NUL;
600     *qlen = 0;
601   }
602 
603   return *qlen;
604 }
605 
606 
607 //  ------------------------------------------------------------------
608 
KeyCmp(const gkey * a,const gkey * b)609 static int KeyCmp(const gkey* a, const gkey* b) {
610 
611   return CmpV(*a, *b);
612 }
613 
614 
615 //  ------------------------------------------------------------------
616 
SearchKey(gkey key,std::list<CmdKey>::iterator keys,int totkeys)617 gkey SearchKey(gkey key, std::list<CmdKey>::iterator keys, int totkeys) {
618 
619   std::list<CmdKey>::iterator kmin;
620   int again = 0;
621 
622   do {
623     kmin = keys;
624     int tkeys=totkeys;
625     while(tkeys > 0) {
626       int j = KeyCmp(&key, &(kmin->key));
627       if(j == 0)
628         return(kmin->cmd);
629       else if(j < 0)
630         break;
631       else {
632         kmin++;
633         tkeys--;
634       }
635     }
636 
637     // Key not found. Try again, this time without the scancode.
638     key &= 0x00FF;
639   } while(not again++ and key);
640 
641   return 0;
642 }
643 
644 
645 //  ------------------------------------------------------------------
646 
call_func_geutil(VfvCP func)647 static void call_func_geutil(VfvCP func) {
648 
649   struct _menu_t* menu;
650   int row, col;
651 
652   bool hidden = vcurhidden();
653   vposget(&row, &col);
654   menu = gwin.cmenu;
655   (*func)();
656   gwin.cmenu = menu;
657   vposset(row, col);
658   if(hidden)
659     vcurhide();
660   else
661     vcurshow();
662 }
663 
664 
665 //  ------------------------------------------------------------------
666 
call_help()667 void call_help() {
668 
669   // search through onkey linked list for a
670   // matching defined onkey.  if one is found,
671   // then save the current environment, call the
672   // onkey's function, and restore the environment.
673 
674   KBnd* onkey = gkbd.onkey;
675   while(onkey != NULL) {
676     if(onkey->keycode == Key_F1) {
677       call_func_geutil(onkey->func);
678       break;
679     }
680     onkey = onkey->prev;
681   }
682 }
683 
684 
685 //  ------------------------------------------------------------------
686 
CheckTick(gkey quitkey)687 void CheckTick(gkey quitkey)
688 {
689   if (gkbd.tickvalue < gkbd.tickpress)
690     gkbd.tickpress = gkbd.tickvalue;
691 
692   Clock idle_secs = (gkbd.tickvalue - gkbd.tickpress)/10;
693 
694   if (CFG->timeout)
695   {
696     if (idle_secs >= CFG->timeout)
697 	{
698       kbput(quitkey);
699       return;
700     }
701   }
702 
703   IdleCheckSemaphores();
704 
705   if(CFG->screenblanker) {
706     if(idle_secs >= CFG->screenblanker) {
707 
708       blanked = true;
709       ScreenBlankIdle();
710       kbdsettickfunc(ScreenBlankIdle);
711 
712       getxch();
713 
714       blanked = false;
715       ScreenBlankIdle();
716       kbdsettickfunc(update_statuslines);
717 
718       //maybe we've scanned areas while in screenblanker, so
719       //update screen
720       if(in_arealist) {
721         PickArealist->update();
722         PickArealist->do_delayed();
723       }
724     }
725   }
726 }
727 
728 
729 //  ------------------------------------------------------------------
730 
IdleCheckSemaphores()731 void IdleCheckSemaphores()
732 {
733   // I don't like this solution either... :(
734   static Clock last_secs = 0;
735 
736   if (gkbd.tickvalue < gkbd.tickpress)
737     gkbd.tickpress = gkbd.tickvalue;
738 
739   Clock idle_secs = (gkbd.tickvalue - gkbd.tickpress)/10;
740 
741   // Make sure the stuff below is only run once in a second
742   if(not idle_secs or (idle_secs - last_secs == 0))
743     return ;
744 
745   if(in_arealist) {
746     if(CFG->semaphore.idletime) {
747       if((idle_secs % CFG->semaphore.idletime) == 0)
748         CheckSemaphores();
749     }
750   }
751 
752   last_secs = idle_secs;
753 }
754 
755 
756 //  ------------------------------------------------------------------
757 
strtmp(const char * str)758 char* strtmp(const char* str) {
759 
760   static INam tmp;
761   return strxcpy(tmp, str, sizeof(tmp));
762 }
763 
764 
765 //  ------------------------------------------------------------------
766 
find(const std::vector<const char * > & vec,const char * str)767 bool find(const std::vector<const char *> &vec, const char *str) {
768 
769   std::vector<const char *>::const_iterator i;
770 
771   for(i = vec.begin(); i != vec.end(); i++)
772     if(streql(*i, str))
773       return true;
774 
775   return false;
776 }
777 
find(const std::vector<std::string> & vec,const std::string & str)778 bool find(const std::vector<std::string> &vec, const std::string &str)
779 {
780   std::vector<std::string>::const_iterator it = vec.begin();
781   std::vector<std::string>::const_iterator end = vec.end();
782 
783   for (; it != end; it++)
784   {
785     if ((*it) == str)
786       return true;
787   }
788 
789   return false;
790 }
791