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