1 /**
2  * @namespace   biew
3  * @file        bconsole.c
4  * @brief       This file contains low level BIEW console functions.
5  * @version     -
6  * @remark      this source file is part of Binary vIEW project (BIEW).
7  *              The Binary vIEW (BIEW) is copyright (C) 1995 Nickols_K.
8  *              All rights reserved. This software is redistributable under the
9  *              licence given in the file "Licence.en" ("Licence.ru" in russian
10  *              translation) distributed in the BIEW archive.
11  * @note        Requires POSIX compatible development system
12  *
13  * @author      Nickols_K
14  * @since       1995
15  * @note        Development, fixes and improvements
16  * @author      Mauro Giachero
17  * @date        02.11.2007
18  * @note        Added "ungotstring" function to enable inline assemblers
19 **/
20 #include <stdarg.h>
21 #include <string.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <limits.h>
27 #include <time.h>
28 
29 #include "editor.h"
30 #include "colorset.h"
31 #include "biewutil.h"
32 #include "tstrings.h"
33 #include "search.h"
34 #include "bconsole.h"
35 #include "biewlib/pmalloc.h"
36 #include "biewlib/kbd_code.h"
37 
38 extern TWindow * ErrorWnd;
39 
40 #define MAXINPUT 79
41 
42 #define FORMFEED 12
43 
44 static int KB_Buff[64];
45 static unsigned char KB_freq = 0;
46 extern char biew_codepage[];
47 
initBConsole(unsigned long vio_flg,unsigned long twin_flg)48 void __FASTCALL__ initBConsole( unsigned long vio_flg,unsigned long twin_flg )
49 {
50   twInit(biew_codepage,vio_flg,twin_flg);
51   if(tvioWidth < 80 || tvioHeight < 3)
52   {
53     if(tvioWidth>16&&tvioHeight>2) {
54 	unsigned evt,x,y;
55 	TWindow *win;
56 	x = (tvioWidth-17)/2;
57 	y = (tvioHeight-3)/2;
58 	win = WindowOpen(x,y,x+16,y+2,TWS_NONE | TWS_NLSOEM);
59 	if(!win) goto done;
60 	twSetTitleAttr(win," Error ",TW_TMODE_CENTER,error_cset.border);
61 	twCentredWin(win,NULL);
62 	twSetColorAttr(error_cset.main);
63 	twSetFrameAttr(win,TW_DOUBLE_FRAME,error_cset.border);
64 	twGotoXY(1,1);
65 	twPutS("Screensize<80x3");
66 	twShowWin(win);
67 	do {
68 	    evt = GetEvent(NULL,NULL,ErrorWnd);
69 	}while(!(evt == KE_ESCAPE || evt == KE_F(10) || evt == KE_ENTER));
70 	twDestroyWin(win);
71     }
72     done:
73     twDestroy();
74     printm("Size of video buffer must be larger than 79x2\n"
75            "Current size of video buffer is: w=%u h=%u\n",tvioWidth,tvioHeight);
76     exit(EXIT_FAILURE);
77   }
78 }
79 
termBConsole(void)80 void __FASTCALL__ termBConsole( void )
81 {
82   twDestroy();
83 }
84 
85 /**
86    read the next keyboard character
87 */
getkey(int hard,void (* func)(void))88 static int __NEAR__ __FASTCALL__ getkey(int hard, void (*func)(void))
89 {
90  return KB_freq ? KB_Buff[--KB_freq] :
91                   GetEvent( func ? func : hard ? hard > 1 ?
92 			    drawAsmEdPrompt : drawEditPrompt : drawEmptyPrompt,
93 			    func ? NULL : hard ? hard > 1 ?
94 			    EditAsmActionFromMenu: NULL: NULL,
95 			    NULL);
96 }
97 
ungotkey(int keycode)98 static tBool __NEAR__ __FASTCALL__ ungotkey(int keycode)
99 {
100   tBool ret = False;
101   if(KB_freq < sizeof(KB_Buff)/sizeof(int))
102   {
103     KB_Buff[KB_freq++] = keycode;
104     ret = True;
105   }
106   return ret;
107 }
108 
ungotstring(char * string)109 tBool __FASTCALL__ ungotstring(char *string)
110 {
111   int pos;
112   for (pos = strlen(string)-1; pos>=0; pos--) {
113     if (ungotkey(string[pos]) == False)
114       return False;
115   }
116   return True;
117 }
118 
xeditstring(char * s,const char * legal,unsigned maxlength,void (* func)(void))119 int __FASTCALL__ xeditstring(char *s,const char *legal,unsigned maxlength, void (*func)(void))
120 {
121   return eeditstring(s,legal,&maxlength,1,NULL,__ESS_ENABLEINSERT,NULL,func);
122 }
123 
124 #define isSpace(val) (((int)val+1)%3 ? 0 : 1)
125 #define isFirstD(pos) (isSpace(pos-1))
126 #define isSecondD(pos) (isSpace(pos+1))
127 
128 static tBool insert = True;
129 
eeditstring(char * s,const char * legal,unsigned * maxlength,unsigned _y,unsigned * stx,unsigned attr,char * undo,void (* func)(void))130 int __FASTCALL__ eeditstring(char *s,const char *legal, unsigned *maxlength,unsigned _y,unsigned *stx,unsigned attr,char *undo, void (*func)(void))
131 {
132  int c;
133  unsigned len = attr & __ESS_HARDEDIT ? *maxlength : attr & __ESS_NON_C_STR ? _y : strlen(s);
134  unsigned pos = len;
135  unsigned y = attr & __ESS_HARDEDIT ? _y : 1;
136  int lastkey,func_getkeys;
137  char ashex = attr & __ESS_ASHEX;
138  tBool freq = (attr & __ESS_HARDEDIT) == __ESS_HARDEDIT;
139  if(stx) pos = *stx;
140  if(!(attr & __ESS_HARDEDIT))
141    twSetCursorType(attr & __ESS_ENABLEINSERT ? insert ? TW_CUR_NORM : TW_CUR_SOLID : TW_CUR_NORM);
142  do
143  {
144   unsigned i;
145   Loop:
146   twFreezeWin(twUsedWin());
147   if(!(attr & __ESS_NOREDRAW))
148   {
149     if(!undo) twDirectWrite(1,y,s,len);
150     else
151     {
152       for(i = 0;i < len;i++)
153       {
154         twSetColorAttr(s[i] == undo[i] ? browser_cset.edit.main : browser_cset.edit.change);
155         twDirectWrite(i+1,y,&s[i],1);
156       }
157     }
158     if(!(attr & __ESS_HARDEDIT))
159     {
160       twGotoXY(len + 1,y);
161       if(ashex)
162         if(isSecondD(pos) && pos >= len)
163         {
164           twPutChar('.');
165           twGotoXY(len + 2,y);
166         }
167       for(i = len; i < *maxlength;i++)
168          twPutChar((attr & __ESS_FILLER_7BIT) == __ESS_FILLER_7BIT ? TWC_DEF_FILLER : TWC_MED_SHADE);
169     }
170   }
171   twRefreshLine(twUsedWin(),y);
172   twGotoXY(pos + 1, y);
173   func_getkeys = attr & __ESS_HARDEDIT ? attr & 0x0020 ? 2 : 1 : 0;
174   new_keycode:
175   c = getkey(func_getkeys, func);
176   lastkey = c;
177   attr |= __ESS_NOREDRAW;
178   switch(c)
179   {
180    case KE_MOUSE:
181    case KE_SHIFTKEYS:
182                       goto new_keycode;
183    case KE_HOME : if(!(ashex && isSecondD(pos))) pos = 0; break;
184    case KE_END  : if(!(ashex && isSecondD(pos))) pos = len; break;
185    case KE_LEFTARROW : if(pos)
186                        {
187                          if(!ashex) pos--;
188                          else
189                           if(!isSecondD(pos))
190                           {
191                             if(pos > 3) pos -=3;
192                             else        pos = 0;
193                           }
194                        }
195                        break;
196    case KE_RIGHTARROW: if(pos < len)
197                        {
198                          if(!ashex) pos++;
199                          else
200                           if(!isSecondD(pos))
201                           {
202                              pos += 3;
203                              if(pos >= len) pos = len;
204                           }
205                        }
206                        break;
207    case KE_BKSPACE   : if (pos > 0 && !(attr & __ESS_HARDEDIT))
208                        {
209                          attr &= ~__ESS_NOREDRAW;
210                          memmove(&s[pos-1], &s[pos], len - pos + 1);
211                          pos--; len--;
212                          if(ashex)
213                            if(isSpace(pos) && pos > 2)
214                            {
215                              memmove(&s[pos-2], &s[pos], len - pos + 2);
216                              pos-=2; len-=2;
217                            }
218                        }
219                        break;
220    case KE_DEL : if (pos < len && !(attr & __ESS_HARDEDIT))
221                     {
222                       attr &= ~__ESS_NOREDRAW;
223                       memmove(&s[pos], &s[pos+1], len - pos);
224                       len--;
225                          if(ashex)
226                            if(!isSpace(pos) && pos > 2)
227                            {
228                              memmove(&s[pos], &s[pos+2], len - pos);
229                              len-=2;
230                            }
231                     }
232                     break;
233    case KE_CTL_BKSPACE:
234                    if(undo)
235                    {
236                      attr &= ~__ESS_NOREDRAW;
237                      if(pos) pos--; if(ashex) if(isSpace(pos) && pos) pos--;
238                      s[pos] = undo[pos];
239                    }
240                    break;
241    case KE_INS :   if(attr & __ESS_ENABLEINSERT &&
242                       !(attr & __ESS_HARDEDIT) &&
243                       !ashex)
244                             insert = insert ? False : True;
245                     twSetCursorType(attr & __ESS_ENABLEINSERT ? insert ? TW_CUR_NORM : TW_CUR_SOLID : TW_CUR_NORM);
246                     break;
247    case KE_ENTER  : break;
248    case KE_ESCAPE : len = 0; break;
249    default     :
250                   /** FunKey trough int 16 returned XX00 exclude Ctrl0-CtrlZ */
251                   if(!(c & 0x00FF) || c == KE_TAB || c == KE_SHIFT_TAB || c == KE_BKSPACE) { c = KE_ENTER; break; }
252                   if ( legal == 0 || strchr(legal, c) != NULL )
253                   {
254                     attr &= ~__ESS_NOREDRAW;
255                     if(!freq && !(attr & __ESS_WANTRETURN)) { freq = True; s[0] = 0; len = pos = 0; ungotkey(c); break; }
256                     if(pos < *maxlength)
257                     {
258                      if(insert)
259                      {
260                       if(len < *maxlength)
261                       {
262                         memmove(&s[pos + 1], &s[pos], len - pos + 1);
263                         len++;
264                       }
265                      }
266                      else
267                        if (pos >= len) len++;
268                      if(len > *maxlength) len = *maxlength;
269                      s[pos++] = c;
270                        if(ashex)
271                        {
272                          if(isSpace(pos))
273                          {
274                            if (pos >= len) len++;
275                            if(len > *maxlength) len = *maxlength;
276                            s[pos] = attr & __ESS_HARDEDIT && !((pos + 1) % 12) ? '-' : ' ';
277                            pos++;
278                          }
279                          if(isSecondD(pos) && pos < len) s[pos] = '.';
280                        }
281                     }
282                     else s[pos - 1] = c;
283                   }
284                   break;
285   } /* switch */
286   if(!freq) freq = True;
287   if(!(attr & __ESS_HARDEDIT)) s[len] = 0;
288   if(ashex)
289     if(!isFirstD(pos))
290       if(c != KE_ESCAPE) goto Loop;
291   if(attr & __ESS_WANTRETURN) if(!(ashex && isSecondD(pos))) break;
292  }
293  while ( (c != KE_ENTER) && (c != KE_ESCAPE));
294  if(!(attr & __ESS_HARDEDIT)) twSetCursorType(TW_CUR_OFF);
295  if(!(attr & __ESS_WANTRETURN && attr & __ESS_NOTUPDATELEN)) *maxlength = len;
296  if(stx) *stx = pos;
297  return lastkey;
298 } /* editstring */
299 
PleaseWaitWnd(void)300 TWindow *__FASTCALL__ PleaseWaitWnd( void )
301 {
302    TWindow *w,*usd;
303    usd = twUsedWin();
304    w = CrtDlgWndnls(SYSTEM_BUSY,14,1);
305    twGotoXY(1,1); twPutS(PLEASE_WAIT);
306    twUseWin(usd);
307    return w;
308 }
309 
MemOutBox(const char * user_msg)310 void __FASTCALL__ MemOutBox(const char *user_msg)
311 {
312   ErrMessageBox(user_msg," Not enough memory! ");
313 }
314 
315 struct percent_data
316 {
317   time_t   _time;
318   time_t   prev_time;
319   unsigned _percents;
320   tBool    is_first;
321 };
322 
PercentWndCallBack(TWindow * it,unsigned event,unsigned long param,void * data)323 static long __FASTCALL__ PercentWndCallBack(TWindow *it,unsigned event, unsigned long param, void *data)
324 {
325   struct percent_data *my_data;
326   UNUSED(param);
327   UNUSED(data);
328   switch(event)
329   {
330     case WM_CREATE:
331                      if((my_data=malloc(sizeof(struct percent_data))) != NULL)
332                      {
333                         twSetUsrData(it,my_data);
334                      }
335                      break;
336     case WM_DESTROY:
337                      my_data = twGetUsrData(it);
338                      if(my_data) free(my_data);
339                      break;
340      default: break;
341   }
342   return 0L;
343 }
344 
345 
PercentWnd(const char * text,const char * title)346 TWindow *__FASTCALL__ PercentWnd(const char *text,const char *title)
347 {
348   TWindow *ret,*usd;
349   static time_t sttime;
350   struct percent_data* my_data;
351   usd = twUsedWin();
352   twcRegisterClass("PERCENT_WND", __CS_ORDINAL, PercentWndCallBack);
353   ret = twCreateWinEx(1,1,53,6,TWS_FRAMEABLE | TWS_NLSOEM,NULL,"PERCENT_WND");
354   twCentredWin(ret,NULL);
355   twSetColorAttr(dialog_cset.main);
356   twSetFrameAttr(ret,TW_UP3D_FRAME,dialog_cset.main);
357   twSetTitleAttr(ret,title,TW_TMODE_CENTER,dialog_cset.title);
358   twSetFooterAttr(ret," [ Ctrl-Break ] - Abort ",TW_TMODE_RIGHT,dialog_cset.footer);
359   twClearWin();
360   twGotoXY(1,1); twPutS(text);
361   twinDrawFrameAttr(1,2,52,4,TW_DN3D_FRAME,dialog_cset.main);
362   twShowWin(ret);
363   twUseWin(usd);
364   time(&sttime);
365   my_data = twGetUsrData(ret);
366   if(my_data)
367   {
368      my_data->_time = my_data->prev_time = sttime;
369      my_data->_percents = 0;
370      my_data->is_first = True;
371   }
372   return ret;
373 }
374 
ShowPercentInWnd(TWindow * pw,unsigned percents)375 tBool __FASTCALL__ ShowPercentInWnd(TWindow *pw,unsigned percents)
376 {
377   TWindow *usd;
378   unsigned cells,remaind, prev_prcnt = 0;
379   time_t sttime =0,curtime,deltat, prev_time = 0;
380   struct tm *tm;
381   struct percent_data* my_data;
382   tBool is_first = True;
383   char outb[50];
384   tBool ret;
385   usd = twUsedWin();
386   twUseWin(pw);
387   my_data = twGetUsrData(pw);
388   if(my_data)
389   {
390     prev_prcnt = my_data->_percents;
391     sttime = my_data->_time;
392     prev_time = my_data->prev_time;
393     is_first = my_data->is_first;
394   }
395   if(percents != prev_prcnt || is_first)
396   {
397     if(percents > 100) percents = 100;
398     cells = percents/2;
399     remaind = percents%2;
400     memset(outb,TWC_FL_BLK,cells);
401     if(remaind) outb[cells++] = TWC_LF_HBLK;
402     if(cells < sizeof(outb)) memset(&outb[cells],TWC_DEF_FILLER,sizeof(outb)-cells);
403     twDirectWrite(2,3,outb,sizeof(outb));
404   }
405   time(&curtime);
406   if(prev_time != curtime || is_first)
407   {
408     deltat = curtime - sttime;
409     tm = gmtime(&deltat);
410     strftime(outb,sizeof(outb),"%X",tm);
411     twGotoXY(1,5);
412     twPutS("Elapsed time: ");
413     twPutS(outb);
414   }
415   if(my_data)
416   {
417     my_data->_percents = percents;
418     my_data->is_first = False;
419     my_data->prev_time = curtime;
420   }
421   twUseWin(usd);
422   ret = !IsKbdTerminate();
423   CleanKbdTermSig();
424   return ret;
425 }
426 
WindowOpen(tAbsCoord x1,tAbsCoord y1,tAbsCoord x2,tAbsCoord y2,unsigned flags)427 TWindow * __FASTCALL__ WindowOpen(tAbsCoord x1,tAbsCoord y1,tAbsCoord x2,tAbsCoord y2,unsigned flags)
428 {
429   TWindow *ret;
430   ret = twCreateWin(x1,y1,x2-x1+1,y2-y1+1,flags);
431   if(!ret) { MemOutBox(NULL); exit(EXIT_FAILURE); }
432   return ret;
433 }
434 
CloseWnd(TWindow * w)435 void __FASTCALL__ CloseWnd(TWindow *w)
436 {
437    twDestroyWin(w);
438 }
439 
_CreateWindowDD(const char * title,tAbsCoord x2,tAbsCoord y2,tBool is_nls)440 static TWindow * __NEAR__ __FASTCALL__ _CreateWindowDD(const char * title,tAbsCoord x2,tAbsCoord y2,tBool is_nls)
441 {
442  TWindow *win;
443  unsigned flags;
444  char frame[8];
445  flags = TWS_FRAMEABLE;
446  if(is_nls) flags |= TWS_NLSOEM;
447  win = WindowOpen(0,0,x2,y2,flags);
448  twCentredWin(win,NULL);
449  twSetColorAttr(dialog_cset.main);
450  twClearWin();
451  memcpy(frame,TW_DOUBLE_FRAME,8);
452  if(!is_nls) __nls_OemToOsdep((unsigned char *)frame,8);
453  twSetFrameAttr(win,frame,dialog_cset.border);
454  if(title) twSetTitleAttr(win,title,TW_TMODE_CENTER,dialog_cset.title);
455  twShowWin(win);
456  return win;
457 }
458 
459 #define _CreateWindowDDnls(title,x2,y2) (_CreateWindowDD(title,x2,y2,True))
460 
CrtDlgWnd(const char * title,tAbsCoord width,tAbsCoord height)461 TWindow * __FASTCALL__ CrtDlgWnd(const char * title,tAbsCoord width,tAbsCoord height )
462 {
463   return _CreateWindowDD(title,width,height,False);
464 }
465 
CrtDlgWndnls(const char * title,tAbsCoord width,tAbsCoord height)466 TWindow * __FASTCALL__ CrtDlgWndnls(const char * title,tAbsCoord width,tAbsCoord height )
467 {
468   return _CreateWindowDDnls(title,width,height);
469 }
470 
_CrtMnuWindowDD(const char * title,tAbsCoord x1,tAbsCoord y1,tAbsCoord x2,tAbsCoord y2,tBool is_nls)471 static TWindow * __NEAR__ __FASTCALL__ _CrtMnuWindowDD(const char *title,tAbsCoord x1, tAbsCoord y1, tAbsCoord x2,tAbsCoord y2,tBool is_nls)
472 {
473  TWindow *win;
474  unsigned flags;
475  flags = TWS_FRAMEABLE;
476  if(is_nls) flags |= TWS_NLSOEM;
477  win = WindowOpen(x1,y1,x2,y2,flags);
478  if(!x1 && !y1) twCentredWin(win,NULL);
479  twSetColorAttr(menu_cset.main);
480  twClearWin();
481  twSetFrameAttr(win,TW_DOUBLE_FRAME,menu_cset.border);
482  if(title) twSetTitleAttr(win,title,TW_TMODE_CENTER,menu_cset.title);
483  twShowWin(win);
484  return win;
485 }
486 
CrtMnuWnd(const char * title,tAbsCoord x1,tAbsCoord y1,tAbsCoord x2,tAbsCoord y2)487 TWindow * __FASTCALL__ CrtMnuWnd(const char * title,tAbsCoord x1, tAbsCoord y1,tAbsCoord x2,tAbsCoord y2)
488 {
489   return _CrtMnuWindowDD(title,x1,y1,x2,y2,False);
490 }
491 
CrtMnuWndnls(const char * title,tAbsCoord x1,tAbsCoord y1,tAbsCoord x2,tAbsCoord y2)492 TWindow * __FASTCALL__ CrtMnuWndnls(const char * title,tAbsCoord x1, tAbsCoord y1,tAbsCoord x2,tAbsCoord y2)
493 {
494   return _CrtMnuWindowDD(title,x1,y1,x2,y2,True);
495 }
496 
CrtLstWnd(const char * title,tAbsCoord x2,tAbsCoord y2)497 TWindow * __FASTCALL__ CrtLstWnd(const char * title,tAbsCoord x2,tAbsCoord y2)
498 {
499   return _CrtMnuWindowDD(title,0,0,x2,y2,False);
500 }
501 
CrtLstWndnls(const char * title,tAbsCoord x2,tAbsCoord y2)502 TWindow * __FASTCALL__ CrtLstWndnls(const char * title,tAbsCoord x2,tAbsCoord y2)
503 {
504   return _CrtMnuWindowDD(title,0,0,x2,y2,True);
505 }
506 
_CreateHlpWnd(const char * title,tAbsCoord x2,tAbsCoord y2,tBool is_nls)507 static TWindow * __NEAR__ __FASTCALL__ _CreateHlpWnd(const char * title,tAbsCoord x2,tAbsCoord y2,tBool is_nls)
508 {
509  TWindow *win;
510  unsigned flags;
511  flags = TWS_FRAMEABLE;
512  if(is_nls) flags |= TWS_NLSOEM;
513  win = WindowOpen(0,0,x2,y2,flags);
514  twCentredWin(win,NULL);
515  twSetColorAttr(help_cset.main);
516  twClearWin();
517  twSetFrameAttr(win,TW_DOUBLE_FRAME,help_cset.border);
518  if(title) twSetTitleAttr(win,title,TW_TMODE_CENTER,help_cset.title);
519  twShowWin(win);
520  return win;
521 }
522 
CrtHlpWnd(const char * title,tAbsCoord x2,tAbsCoord y2)523 TWindow * __FASTCALL__ CrtHlpWnd(const char * title,tAbsCoord x2,tAbsCoord y2)
524 {
525   return _CreateHlpWnd(title,x2,y2,False);
526 }
527 
CrtHlpWndnls(const char * title,tAbsCoord x2,tAbsCoord y2)528 TWindow * __FASTCALL__ CrtHlpWndnls(const char * title,tAbsCoord x2,tAbsCoord y2)
529 {
530   return _CreateHlpWnd(title,x2,y2,True);
531 }
532 
CreateEditor(tAbsCoord X1,tAbsCoord Y1,tAbsCoord X2,tAbsCoord Y2,unsigned flags)533 TWindow * __FASTCALL__ CreateEditor(tAbsCoord X1,tAbsCoord Y1,tAbsCoord X2,tAbsCoord Y2,unsigned flags)
534 {
535  TWindow *ret;
536  ret = WindowOpen(X1,Y1,X2,Y2,flags);
537  twSetColorAttr(dialog_cset.editor.active);
538  twClearWin();
539  return ret;
540 }
541 
__MB(const char * text,const char * title,ColorAttr base,ColorAttr frame)542 static void __NEAR__ __FASTCALL__ __MB(const char * text,const char * title,
543                                        ColorAttr base,ColorAttr frame)
544 {
545  unsigned slen,tlen;
546  slen = strlen(text) + 3;
547  tlen = strlen(title) + 2;
548  slen = min(max(slen,tlen)+1,78);
549  twResizeWin(ErrorWnd,slen,3);
550  twCentredWin(ErrorWnd,NULL);
551  twSetFrameAttr(ErrorWnd,TW_DOUBLE_FRAME,frame);
552  twSetTitleAttr(ErrorWnd,title,TW_TMODE_CENTER,frame);
553  twSetColorAttr(base);
554  twClearWin();
555  twShowWinOnTop(ErrorWnd);
556  twGotoXY(2,1);
557  twPutS(text);
558 }
559 
__MessageBox(const char * text,const char * title,ColorAttr base,ColorAttr frame)560 static void __NEAR__ __FASTCALL__ __MessageBox(const char * text,const char * title,
561                                                ColorAttr base,ColorAttr frame)
562 {
563  TWindow *prev;
564  unsigned evt;
565  prev = twUsedWin();
566  twUseWin(ErrorWnd);
567  __MB(text,title,base,frame);
568  do
569  {
570    evt = GetEvent(drawEmptyPrompt,NULL,ErrorWnd);
571  }
572  while(!(evt == KE_ESCAPE || evt == KE_F(10) || evt == KE_SPACE || evt == KE_ENTER));
573  twHideWin(ErrorWnd);
574  twUseWin(prev);
575  twResizeWin(ErrorWnd,tvioWidth,tvioHeight); /* It for reserving memory */
576 }
577 
578 
TMessageBox(const char * text,const char * title)579 void __FASTCALL__ TMessageBox(const char * text,const char * title)
580 {
581  __MessageBox(text,title ? title : "",dialog_cset.main,dialog_cset.title);
582 }
583 
NotifyBox(const char * text,const char * title)584 void __FASTCALL__ NotifyBox(const char * text,const char * title)
585 {
586  __MessageBox(text,title ? title : NOTE_MSG,notify_cset.main,notify_cset.border);
587 }
588 
ErrMessageBox(const char * text,const char * title)589 void __FASTCALL__ ErrMessageBox(const char * text,const char * title)
590 {
591  __MessageBox(text,title ? title : ERROR_MSG,error_cset.main,error_cset.border);
592 }
593 
WarnMessageBox(const char * text,const char * title)594 void __FASTCALL__ WarnMessageBox(const char * text,const char * title)
595 {
596  __MessageBox(text,title ? title : WARN_MSG,warn_cset.main,warn_cset.border);
597 }
598 
errnoMessageBox(const char * text,const char * title,int __errno__)599 void __FASTCALL__ errnoMessageBox(const char *text,const char *title,int __errno__)
600 {
601   char stmp[256];
602   sprintf(stmp,"%s: %i (%s)",text,__errno__,strerror(__errno__));
603   ErrMessageBox(stmp,title);
604 }
605 
PaintLine(unsigned i,const char * name,unsigned width,unsigned mord_width,tBool isOrdinal,tBool useAcc,tBool is_hl)606 static void __NEAR__ __FASTCALL__ PaintLine(unsigned i,const char *name,
607                                             unsigned width,unsigned mord_width,
608                                             tBool isOrdinal,
609                                             tBool useAcc,tBool is_hl)
610 {
611   size_t namelen;
612   char buffer[__TVIO_MAXSCREENWIDTH + 1];
613   memset(buffer,TWC_DEF_FILLER,sizeof(buffer));
614   buffer[__TVIO_MAXSCREENWIDTH] = 0; /* [dBorca] play it safe for strchr below */
615   namelen = name?strlen(name):0;
616   if(isOrdinal)
617   {
618     char * endptr;
619     endptr = name?strrchr(name,LB_ORD_DELIMITER):NULL;
620     if(endptr)
621     {
622       unsigned len, rlen;
623       // write name
624       len = endptr - name;
625       rlen = len;
626       if(len > width - mord_width-1)
627           rlen = width - mord_width-3;
628       memcpy(buffer,name,rlen);
629       if(len > rlen) memcpy(buffer+rlen,"..", 2);           // using 2 dots now -XF
630       // write ordinal. it's left aligned now -XF
631       buffer[width - mord_width - 1] = '@';
632       len = rlen = namelen - (len+1);
633       if(rlen > mord_width) rlen = mord_width - 2;
634       memcpy(&buffer[width - mord_width], endptr+1, rlen);
635       if(len > rlen) memcpy(buffer+width-mord_width+rlen,"..", 2);
636     }
637   }
638   else if(name) memcpy((char *)buffer,name,min(namelen,width));
639   if(useAcc)
640   {
641     char *st,*ends,*ptr;
642     char ch;
643     twGotoXY(3,i+1);
644     st = buffer;
645     ends = buffer+width;
646     while(1)
647     {
648       ptr = strchr(st,'~');
649       if(ptr)
650       {
651         unsigned outlen;
652         outlen = ptr-st;
653         twDirectWrite(twWhereX(),twWhereY(),st,outlen);
654         twGotoXY(twWhereX()+outlen,twWhereY());
655         st = ptr;
656         ch = *(++st);
657         if(ch != '~')
658         {
659           ColorAttr ca;
660           ca = twGetColorAttr();
661           twSetColorAttr(is_hl ? menu_cset.hotkey.focused : menu_cset.hotkey.active);
662           twPutChar(ch);
663           twSetColorAttr(ca);
664         }
665         st++;
666       }
667       else
668       {
669         twDirectWrite(twWhereX(),twWhereY(),st,(unsigned)(ends-st));
670         break;
671       }
672     }
673   }
674   else  twDirectWrite(3,i+1,buffer,width);
675 }
676 
Paint(TWindow * win,const char ** names,unsigned nlist,unsigned start,unsigned height,unsigned width,unsigned mord_width,tBool isOrdinal,tBool useAcc,unsigned cursor)677 static void __NEAR__ __FASTCALL__ Paint(TWindow *win,const char ** names,
678                                         unsigned nlist,unsigned start,
679                                         unsigned height,unsigned width,
680                                         unsigned mord_width,
681                                         tBool isOrdinal,tBool useAcc,
682                                         unsigned cursor)
683 {
684  unsigned i, pos = 0;
685  twUseWin(win);
686  twFreezeWin(win);
687  width -= 3;
688  if (height>2 && height<nlist)
689      pos = 1 + (start+cursor)*(height-2)/nlist;
690  for(i = 0;i < height;i++)
691  {
692    twSetColorAttr(menu_cset.main);
693    twGotoXY(1,i + 1);
694    if (i == 0)
695        twPutChar(start ? TWC_UP_ARROW : TWC_DEF_FILLER);
696    else if(i == height-1)
697        twPutChar(start + height < nlist ? TWC_DN_ARROW : TWC_DEF_FILLER);
698    else if (i == pos)
699        twPutChar(TWC_THUMB);
700    else twPutChar(TWC_DEF_FILLER);
701    twGotoXY(2,i + 1);
702    twPutChar(TWC_SV);
703    twSetColorAttr(menu_cset.item.active);
704    PaintLine(i,names[i + start],width,mord_width,isOrdinal,useAcc,cursor == i);
705  }
706  twRefreshWin(win);
707 }
708 
709 static char byNam;
710 
_lb_searchtext(const char * str,const char * tmpl,unsigned searchlen,const int * cache,unsigned flg)711 tBool __FASTCALL__ _lb_searchtext(const char *str,const char *tmpl,unsigned searchlen,const int *cache, unsigned flg)
712 {
713   return strFind(str, strlen(str), tmpl, searchlen, cache, flg) ? True : False;
714 }
715 
listcompare(const void __HUGE__ * v1,const void __HUGE__ * v2)716 static tCompare __FASTCALL__ listcompare(const void __HUGE__ *v1,const void __HUGE__ *v2)
717 {
718   tCompare ret;
719   if(byNam)  ret = stricmp(*((const char **)v1),*((const char **)v2));
720   else
721   {
722     const char *o1,*o2;
723     const char *s1,*s2;
724 
725     s1 = *((const char **)v1);
726     s2 = *((const char **)v2);
727     o1 = strrchr(s1,LB_ORD_DELIMITER);
728     o2 = strrchr(s2,LB_ORD_DELIMITER);
729     if(o1 && o2)
730     {
731       unsigned long ord1,ord2;
732       char buff1[7], buff2[7];
733        strncpy(buff1,o1 + 1,6);
734        strncpy(buff2,o2 + 1,6);
735        ord1 = atol(buff1);
736        ord2 = atol(buff2);
737        ret = __CmpLong__(ord1,ord2);
738     }
739     else  ret = stricmp(s1,s2);
740   }
741   return ret;
742 }
743 
__ListBox(const char ** names,unsigned nlist,unsigned defsel,const char * title,int assel)744 static int __NEAR__ __FASTCALL__ __ListBox(const char ** names,unsigned nlist,unsigned defsel,const char * title,int assel)
745 {
746  TWindow * wlist;
747  char *acctable = 0;
748  unsigned i,j,width,height,mwidth = strlen(title);
749  unsigned mordstr_width, mord_width;
750  int ret,start,ostart,cursor,ocursor,scursor;
751  tBool isOrdinal,sf;
752  if(!names || !nlist) return -1;
753  isOrdinal = True;
754  scursor = -1;
755  i = 0;
756  if((assel & LB_USEACC) == LB_USEACC)
757  {
758    acctable = PMalloc(nlist*sizeof(char));
759    if(!acctable)
760    {
761      MemOutBox("Displaying list");
762      return -1;
763    }
764    memset(acctable,0,nlist*sizeof(char));
765    for(i = 0;i < nlist;i++)
766    {
767      unsigned len;
768      len = names[i]?strlen(names[i]):0;
769      for(j = 0;j < len;j++)
770      {
771        if(names[i][j] == '~' && names[i][j+1] != '~')
772        {
773          acctable[i] = toupper(names[i][j+1]);
774          break;
775        }
776      }
777    }
778  }
779  if(names[0]) if(!strrchr(names[0],LB_ORD_DELIMITER)) isOrdinal = False;
780  mordstr_width = mord_width = 0;
781  if(!isOrdinal)
782    for(i = 0;i < nlist;i++)
783    {
784      j = names[i]?strlen(names[i]):0;
785      if(j > mwidth) mwidth = j;
786    }
787  else
788  {
789    char *ord_delimiter;
790    for(i = 0;i < nlist;i++)
791    {
792      ord_delimiter = names[i]?strrchr(names[i], LB_ORD_DELIMITER):NULL;
793      if(ord_delimiter)
794      {
795        j = ord_delimiter - names[i];
796        if(j > mordstr_width) mordstr_width = j;
797        j = &names[i][strlen(names[i])] - ord_delimiter;
798        if(j > mord_width) mord_width = j;
799      }
800    }
801    // name now has higher priority than ordinal -XF
802    if(mordstr_width > (unsigned)(tvioWidth-10))
803        mordstr_width = (unsigned)(tvioWidth-10);
804    if(mord_width > (unsigned)(tvioWidth-4)-mordstr_width-1)
805        mord_width = (unsigned)(tvioWidth-4)-mordstr_width-1;
806    mwidth = mordstr_width+mord_width+1;
807  }
808  mwidth += 4;
809  if(mwidth > (unsigned)(tvioWidth-1)) mwidth = tvioWidth-1;         // maximal width increased to tvioWidth-1 -XF
810  height = nlist < (unsigned)(tvioHeight - 4) ? nlist : tvioHeight - 4;
811  wlist = CrtLstWndnls(title,mwidth-1,height);
812  if((assel & LB_SELECTIVE) == LB_SELECTIVE) twSetFooterAttr(wlist," [ENTER] - Go ",TW_TMODE_RIGHT,dialog_cset.selfooter);
813  restart:
814  ostart = start = cursor = ocursor = 0;
815  if(defsel != UINT_MAX && defsel < nlist)
816  {
817     cursor = defsel;
818     while((unsigned)cursor > height) { start += height; cursor -= height; }
819     ostart = start;
820     ocursor = cursor;
821  }
822  Paint(wlist,names,nlist,(unsigned)start,height,mwidth,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,(unsigned)cursor);
823  width = mwidth - 3;
824  if((assel & LB_SELECTIVE) == LB_SELECTIVE)
825  {
826    twSetColorAttr(menu_cset.item.focused);
827    PaintLine((unsigned)cursor,names[cursor + start],width,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,True);
828  }
829  sf = False;
830  for(;;)
831  {
832    unsigned ch;
833    ch = GetEvent(isOrdinal ? drawOrdListPrompt : (assel & LB_SORTABLE) ? drawListPrompt : drawSearchListPrompt,NULL,wlist);
834    if(ch == KE_ESCAPE || ch == KE_F(10)) { ret = -1; break; }
835    if(ch == KE_ENTER)                    { ret = start + cursor; break; }
836    if(ch!=KE_F(7) && ch!=KE_SHIFT_F(7))  scursor = -1;
837    switch(ch)
838    {
839      case KE_F(2):
840      case KE_F(3):
841               if(isOrdinal || (assel & LB_SORTABLE))
842               {
843                 byNam = ch == KE_F(2);
844                 if(!isOrdinal && !byNam) break;
845                 HQSort(names,nlist,sizeof(char *),listcompare);
846                 goto restart;
847               }
848               break;
849      case KE_F(4): /** save content to disk */
850               {
851                 char ofname[256];
852                 ofname[0] = 0;
853                 if(GetStringDlg(ofname," Save info to file : "," [ENTER] - Proceed ",NAME_MSG))
854                 {
855                   FILE * out;
856                   out = fopen(ofname,"wt");
857                   if(out)
858                   {
859                     strncpy(ofname,title,sizeof(ofname));
860                     ofname[sizeof(ofname)-1] = '\0';
861                     if(GetStringDlg(ofname," User comments : "," [ENTER] - Proceed "," Description : "))
862                     {
863                       fprintf(out,"%s\n\n",ofname);
864                     }
865                     for(i = 0;i < nlist;i++)
866                     {
867                       char *p;
868                       p = names[i]?strchr(names[i],LB_ORD_DELIMITER):NULL;
869                       if(p)
870                       {
871                         *p = 0;
872                         fprintf(out,names[i]);
873                         for(j = p - names[i];j < 50;j++) fprintf(out," ");
874                         fprintf(out," @%s",p+1);
875                         if(p) *p = LB_ORD_DELIMITER;
876                       }
877                       else fprintf(out,names[i]);
878                       fprintf(out,"\n");
879                     }
880                     fclose(out);
881                   }
882                   else errnoMessageBox(WRITE_FAIL,NULL,errno);
883                 }
884               }
885               break;
886      case KE_F(7): /** perform binary search in list */
887      case KE_SHIFT_F(7):
888              {
889                static char searchtxt[21] = "";
890                static unsigned char searchlen = 0;
891                static unsigned sflg = SF_NONE;
892 
893                if (!(ch==KE_SHIFT_F(7) && searchlen) &&
894                    !SearchDialog(SD_SIMPLE,searchtxt,&searchlen,&sflg))
895                    break;
896 
897                {
898                   int direct, cache[UCHAR_MAX+1];
899                   tBool found;
900                   int ii,endsearch,startsearch;
901                   searchtxt[searchlen] = 0;
902                   endsearch = sflg & SF_REVERSE ? -1 : (int)nlist;
903                   direct = sflg & SF_REVERSE ? -1 : 1;
904                   startsearch = (assel & LB_SELECTIVE) == LB_SELECTIVE ?
905                                  cursor + start :
906                                  scursor != -1 ?
907                                    scursor :
908                                    start;
909                   if(startsearch > (int)(nlist-1)) startsearch = nlist-1;
910                   if(startsearch < 0) startsearch = 0;
911                   if((assel & LB_SELECTIVE) == LB_SELECTIVE || scursor != -1)
912                   {
913                     sflg & SF_REVERSE ? startsearch-- : startsearch++;
914                   }
915                   found = False;
916                   fillBoyerMooreCache(cache, searchtxt, searchlen, sflg & SF_CASESENS);
917                   for(ii = startsearch;ii != endsearch;ii+=direct)
918                   {
919 		    if(names[ii])
920 		    {
921                      if(_lb_searchtext(names[ii],searchtxt,searchlen,cache,sflg))
922                      {
923                         start = scursor = ii;
924                         if((unsigned)start > nlist - height) start = nlist - height;
925                         ostart = start - 1;
926                         if((assel & LB_SELECTIVE) == LB_SELECTIVE)
927                                     cursor = scursor - start;
928                         found = True;
929                         break;
930                      }
931 		    }
932                   }
933                   if(!found) scursor = -1;
934                   if(scursor == -1) ErrMessageBox(STR_NOT_FOUND,SEARCH_MSG);
935                }
936              }
937              break;
938      case KE_DOWNARROW : if((assel & LB_SELECTIVE) == LB_SELECTIVE) cursor ++; else start ++; break;
939      case KE_UPARROW   : if((assel & LB_SELECTIVE) == LB_SELECTIVE) cursor --; else start --; break;
940      case KE_PGDN   : start += height; break;
941      case KE_PGUP   : start -= height; break;
942      case KE_CTL_PGDN  : start = nlist - height; cursor = height; break;
943      case KE_CTL_PGUP  : start = cursor = 0; break;
944      default :
945               /** Try accelerate choose */
946               if((assel & LB_USEACC) == LB_USEACC)
947               {
948                  if((unsigned char)(ch & 0x00FF) > 31)
949                  {
950                    ch = toupper(ch & 0x00FF);
951                    for(i = 0;i < nlist;i++)
952                    {
953                      if(ch == (unsigned)acctable[i]) { ret = i; goto Done; }
954                    }
955                  }
956               }
957    }
958    if((assel & LB_SELECTIVE) == LB_SELECTIVE)
959    {
960      if(cursor < 0) { cursor = 0; start--; }
961      if((unsigned)cursor > height - 1) { cursor = height - 1; start++; }
962    }
963    if(start < 0) start = 0;
964    if((unsigned)start > nlist - height) start = nlist - height;
965    if(start != ostart)
966    {
967      ostart = start;
968      Paint(wlist,names,nlist,(unsigned)start,height,mwidth,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,(unsigned)cursor);
969      sf = True;
970    }
971    if((cursor != ocursor || sf) && (assel & LB_SELECTIVE) == LB_SELECTIVE)
972    {
973      twSetColorAttr(menu_cset.item.active);
974      PaintLine((unsigned)ocursor,names[ocursor + start],width,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,False);
975      twSetColorAttr(menu_cset.item.focused);
976      PaintLine((unsigned)cursor,names[cursor + start],width,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,True);
977      ocursor = cursor;
978      sf = False;
979    }
980    if(scursor != -1)
981    {
982      twSetColorAttr(menu_cset.highlight);
983      if(scursor >= start && (unsigned)scursor < start + height)
984          PaintLine((unsigned)(scursor - start),names[scursor],width,mord_width,isOrdinal,(assel & LB_USEACC) == LB_USEACC,True);
985    }
986  }
987  Done:
988  CloseWnd(wlist);
989  if(acctable) PFREE(acctable);
990  return ret;
991 }
992 
CommonListBox(const char ** names,unsigned nlist,const char * title,int acc,unsigned defsel)993 int __FASTCALL__ CommonListBox(const char **names,unsigned nlist,const char *title,int acc,unsigned defsel)
994 {
995   return __ListBox(names,nlist,defsel,title,acc);
996 }
997 
DisplayBox(const char ** names,unsigned nlist,const char * title)998 void __FASTCALL__ DisplayBox(const char **names,unsigned nlist,const char *title)
999 {
1000   __ListBox(names,nlist,UINT_MAX,title,0); /** not sortable & not selective */
1001 }
1002 
ListBox(const char ** names,unsigned nlist,const char * title)1003 void __FASTCALL__ ListBox(const char ** names,unsigned nlist,const char * title)
1004 {
1005   __ListBox(names,nlist,UINT_MAX,title,LB_SORTABLE);
1006 }
1007 
SelListBox(const char ** names,unsigned nlist,const char * title,unsigned defsel)1008 int __FASTCALL__ SelListBox(const char ** names,unsigned nlist,const char * title,unsigned defsel)
1009 {
1010   return __ListBox(names,nlist,defsel,title,LB_SELECTIVE | LB_SORTABLE);
1011 }
1012 
SelBox(const char ** names,unsigned nlist,const char * title,unsigned defsel)1013 int __FASTCALL__ SelBox(const char ** names,unsigned nlist,const char * title,unsigned defsel)
1014 {
1015   return __ListBox(names,nlist,defsel,title,LB_SELECTIVE);
1016 }
1017 
SelBoxA(const char ** names,unsigned nlist,const char * title,unsigned defsel)1018 int __FASTCALL__ SelBoxA(const char ** names,unsigned nlist,const char * title,unsigned defsel)
1019 {
1020   return __ListBox(names,nlist,defsel,title,LB_SELECTIVE | LB_USEACC);
1021 }
1022 
PageBox(unsigned width,unsigned height,const void ** __obj,unsigned nobj,pagefunc func)1023 int __FASTCALL__ PageBox(unsigned width,unsigned height,const void ** __obj,unsigned nobj,pagefunc func)
1024 {
1025  TWindow * wlist;
1026  int start,ostart,ret;
1027  if(height>tvioHeight-2) height=tvioHeight-2;
1028  wlist = _CreateWindowDD(0,width-1,height,True);
1029  ostart = start = 0;
1030  (*func)(wlist,__obj,(unsigned)start,nobj);
1031  for(;;)
1032  {
1033    unsigned ch;
1034    ch = GetEvent(drawEmptyPrompt,NULL,wlist);
1035    if(ch == KE_ESCAPE || ch == KE_F(10)) { ret = -1; break; }
1036    if(ch == KE_ENTER)                    { ret = start; break; }
1037    switch(ch)
1038    {
1039      case KE_PGDN : start ++; break;
1040      case KE_PGUP   : start --; break;
1041      case KE_CTL_PGDN : start = nobj - 1; break;
1042      case KE_CTL_PGUP : start = 0; break;
1043      default : break;
1044    };
1045    if(start < 0) start = 0;
1046    if((unsigned)start > nobj - 1) start = nobj - 1;
1047    if(start != ostart)
1048    {
1049      ostart = start;
1050      twGotoXY(1,1);
1051      (*func)(wlist,__obj,(unsigned)start,nobj);
1052    }
1053  }
1054  CloseWnd(wlist);
1055  return ret;
1056 }
1057