root/trunk/txlib/txcon.c

Revision 14, 31.0 kB (checked in by jvw, 2 years ago)

HEX/ASCII (sector) editor control added

Line 
1//
2//                     TxWin, Textmode Windowing Library
3//
4//   Original code Copyright (c) 1995-2005 Fsys Software and Jan van Wijk
5//
6// ==========================================================================
7//
8// This file contains Original Code and/or Modifications of Original Code as
9// defined in and that are subject to the GNU Lesser General Public License.
10// You may not use this file except in compliance with the License.
11// BY USING THIS FILE YOU AGREE TO ALL TERMS AND CONDITIONS OF THE LICENSE.
12// A copy of the License is provided with the Original Code and Modifications,
13// and is also available at http://www.dfsee.com/txwin/lgpl.htm
14//
15// This library is free software; you can redistribute it and/or modify
16// it under the terms of the GNU Lesser General Public License as published
17// by the Free Software Foundation; either version 2.1 of the License,
18// or (at your option) any later version.
19//
20// This library is distributed in the hope that it will be useful,
21// but WITHOUT ANY WARRANTY; without even the implied warranty of
22// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
23// See the GNU Lesser General Public License for more details.
24//
25// You should have received a copy of the GNU Lesser General Public License
26// along with this library; (lgpl.htm) if not, write to the Free Software
27// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
28//
29// Questions on TxWin licensing can be directed to: txwin@fsys.nl
30//
31// ==========================================================================
32//
33// Screen output using ANSI X3.64 terminal escape definitions and
34// file-logging facilities
35//
36// Author: J. van Wijk
37//
38// JvW  24-01-2003 Removed thread-id from default hex-dump display
39// JvW  01-02-2002 Added 7 bit ASCII filtering using switch '-7'
40// JvW  10-12-2001 Added TxStrListAdd
41// JvW  29-08-2001 Rename to TXCON
42// JvW  17-01-2000 Added UNICODE modus to FormatMixedStr function
43// JvW  08-03-1998 Added WIN32 ANSI expansion function (JvD)
44// JvW  20-04-1997 Ported to WIN32
45// JvW  27-01-1996 Made more generic, for LPTIO tests
46// JvW  15-02-1996 Added ddl global debugging variable
47// JvW  09-03-1996 Added trace macro's and implementation
48// JvW  26-12-1996 Added RetBool support for 64 threads
49// JvW  17-06-1995 Initial version, split off from DHPFS.C
50
51#include <txlib.h>
52#include <txwpriv.h>                            // private window interface
53#include <txtpriv.h>                            // private text   interface
54
55static  DEVICE_STATE   screen_act  = DEVICE_ON;
56static  DEVICE_STATE   logfile_act = DEVICE_ON;
57
58#if defined (USEWINDOWING)
59static  char txConfirmTitle[] = " Confirmation request ";
60static  char txMsgWarnTitle[] = " Notification or warning message ";
61#endif
62
63                                                // Hook control structures
64        TXH_INFO   *txh_clean = NULL;           // clean TxPrint handler
65        TXH_INFO   *txh_raw   = NULL;           // raw ansi TxPrint handler
66
67static  char       *txm_buff  = NULL;           // temporary buffer for TxPrint
68
69static  BOOL        txk_Abort = FALSE;          // TX KB-system abort notify
70static  ULONG       txkThread = 0;              // TX KB-system owning thread
71
72#define ANSI_S_TIMEOUT  10000                   // 10 seconds timeout on claim
73
74static  BOOL  txc_ascii7 = FALSE;               // ASCII filtering off
75static  char  txc_ansi   = A_ON;
76
77//- logfile cycling and size control, first size includes closing message ...
78static  ULONG      log_written = 50;            // bytes written on this file
79static  ULONG      log_maxsize = 0;             // maximum size per logfile
80static  ULONG      log_seq_num = 0;             // sequence number 0..n
81static  ULONG      log_retain  = 0;             // log recycle retain count
82
83//- Note: 256 color strings sorted in default PC order
84ANSIDEFS  ansi =
85{
86   "",
87   "",
88   "",
89   "",
90   "",
91   "",
92   "",
93   "",
94   "",
95   "",
96   "",
97   "",
98   "",
99   "",
100   "",
101   "",
102   "",
103   "",
104   "",
105   "",
106   "",
107   "",
108   "",
109   "",
110   "",
111   "",
112   "",
113   "",
114   "",
115   "",
116   "",
117   "",
118   "",
119   "",
120   "",
121   "",
122   "",
123   "",
124   "",
125   "",
126   "",
127   "",
128   "",
129   "",
130   "",
131   "",
132   "",
133   "",
134   "",
135   "",
136   "",
137   "",
138   "",
139   "",
140   "",
141   "",
142   "",
143   "",
144   "",
145   "",
146   "",
147   "",
148   "",
149   "",
150   "",
151   "",
152   "",
153   "",
154   "",
155   "",
156   "",
157   "",
158   "",
159   "",
160   "",
161   "",
162   "",
163   "",
164   "",
165   "",
166   "",
167   "",
168   "",
169   "",
170   "",
171   "",
172   "",
173   "",
174   "",
175   "",
176   "",
177   "",
178   "",
179   "",
180   "",
181   "",
182   "",
183   "",
184   "",
185   "",
186   "",
187   "",
188   "",
189   "",
190   "",
191   "",
192   "",
193   "",
194   "",
195   "",
196   "",
197   "",
198   "",
199   "",
200   "",
201   "",
202   "",
203   "",
204   "",
205   "",
206   "",
207   "",
208   "",
209   "",
210   "",
211   "",
212   "",
213   "",
214
215   "",
216   "",
217   "",
218   "",
219   "",
220   "",
221   "",
222   "",
223   "",
224   "",
225   "",
226   "",
227   "",
228   "",
229   "",
230   "",
231   "",
232   "",
233   "",
234   "",
235   "",
236   "",
237   "",
238   "",
239   "",
240   "",
241   "",
242   "",
243   "",
244   "",
245   "",
246   "",
247   "",
248   "",
249   "",
250   "",
251   "",
252   "",
253   "",
254   "",
255   "",
256   "",
257   "",
258   "",
259   "",
260   "",
261   "",
262   "",
263   "",
264   "",
265   "",
266   "",
267   "",
268   "",
269   "",
270   "",
271   "",
272   "",
273   "",
274   "",
275   "",
276   "",
277   "",
278   "",
279   "",
280   "",
281   "",
282   "",
283   "",
284   "",
285   "",
286   "",
287   "",
288   "",
289   "",
290   "",
291   "",
292   "",
293   "",
294   "",
295   "",
296   "",
297   "",
298   "",
299   "",
300   "",
301   "",
302   "",
303   "",
304   "",
305   "",
306   "",
307   "",
308   "",
309   "",
310   "",
311   "",
312   "",
313   "",
314   "",
315   "",
316   "",
317   "",
318   "",
319   "",
320   "",
321   "",
322   "",
323   "",
324   "",
325   "",
326   "",
327   "",
328   "",
329   "",
330   "",
331   "",
332   "",
333   "",
334   "",
335   "",
336   "",
337   "",
338   "",
339   "",
340   "",
341   "",
342   "",
343
344   "",                                      // NORMAL
345   "",                                      // CURSOR_UP1
346   "",                                      // CURSOR_UP2
347   "",                                      // CURSOR_UP4
348   "",                                      // CURSOR_UP8
349   "",                                      // CURSOR_DOWN1
350   "",                                      // CURSOR_DOWN2
351   "",                                      // CURSOR_DOWN4
352   "",                                      // CURSOR_DOWN8
353   "",                                      // CURSOR_RIGHT1
354   "",                                      // CURSOR_RIGHT2
355   "",                                      // CURSOR_RIGHT4
356   "",                                      // CURSOR_RIGHT8
357   "",                                      // CURSOR_LEFT1
358   "",                                      // CURSOR_LEFT2
359   "",                                      // CURSOR_LEFT4
360   "",                                      // CURSOR_LEFT8
361   "",                                       // CURSOR_SAVEP
362   "",                                       // CURSOR_RESTP
363   "",                                       // CLEAR_TO_EOL
364   "",                                   // CURS_GO_1_70
365   "",                                   // CURS_GO_1_75
366   "",                                    // CURS_GO_1_01
367   "",                                    // CURS_GO_2_01
368   "",                                   // CURS_GO23_01
369   ""                                    // CURS_GO24_01
370};
371
372
373/*****************************************************************************/
374// Set 7-bit ASCII mode
375/*****************************************************************************/
376void TxSetAscii7Mode
377(
378   BOOL                mode                     // IN    ASCII 7-bit mode
379)
380{
381   TRACES(( "ASCII7 set 1: %s\n", (mode) ? "TRUE" : "FALSE"));
382   txc_ascii7 = mode;
383}                                               // end 'TxSetAscii7Mode'
384/*---------------------------------------------------------------------------*/
385
386
387/*****************************************************************************/
388// Get ASCII mode, 7-bit or full
389/*****************************************************************************/
390BOOL TxGetAscii7Mode                              // RET   ASCII 7-bit in use
391(
392   void
393)
394{
395   return( txc_ascii7);
396}                                               // end 'TxGetAscii7Mode'
397/*---------------------------------------------------------------------------*/
398
399
400/*****************************************************************************/
401// Set ansi string definitions active or inactive
402/*****************************************************************************/
403void TxSetAnsiMode
404(
405   char                mode                     // IN    ansi mode
406)
407{
408   int                 i;
409
410   txc_ansi = mode;
411   for (i = 0; i < NUMBER_ANSIS; i++)
412   {
413      ansi[i][0] = mode;
414   }
415}                                               // end 'TxSetAnsiMode'
416/*---------------------------------------------------------------------------*/
417
418
419/*****************************************************************************/
420// Get ansi string definitions active or inactive
421/*****************************************************************************/
422char TxGetAnsiMode                              // RET   ansi mode
423(
424   void
425)
426{
427   return( txc_ansi);
428}                                               // end 'TxGetAnsiMode'
429/*---------------------------------------------------------------------------*/
430
431
432/*****************************************************************************/
433// Test and set TxScreenState
434/*****************************************************************************/
435DEVICE_STATE TxScreenState                      // RET   screen active
436(
437   DEVICE_STATE        action                   // IN    screen action
438)
439{
440   if (action != DEVICE_TEST)
441   {
442      screen_act = action;
443   }
444   return (screen_act);
445}                                               // end 'TxScreenState'
446/*---------------------------------------------------------------------------*/
447
448
449/*****************************************************************************/
450// Test and set TxLogfileState, logging when state = ON and file opened
451/*****************************************************************************/
452DEVICE_STATE TxLogfileState                     // RET   logfile active
453(
454   DEVICE_STATE        action                   // IN    screen action
455)
456{
457   if (action != DEVICE_TEST)
458   {
459      logfile_act = action;
460   }
461   return (logfile_act);
462}                                               // end 'TxLogfileState'
463/*---------------------------------------------------------------------------*/
464
465
466/*****************************************************************************/
467// Set logfile maximum size per file
468/*****************************************************************************/
469void TxSetLogMaxSize
470(
471   ULONG               size                     // IN    maximum size, bytes
472)
473{
474   log_maxsize = size;
475}                                               // end 'TxSetLogMaxSize'
476/*---------------------------------------------------------------------------*/
477
478
479/*****************************************************************************/
480// Set logfile number of files to retain on cycle, #files besides .log itself
481/*****************************************************************************/
482void TxSetLogRetain
483(
484   ULONG               retain                   // IN    retain count
485)
486{
487   log_retain = retain;
488}                                               // end 'TxSetLogRetain'
489/*---------------------------------------------------------------------------*/
490
491
492/*****************************************************************************/
493// printf-like print on stdout, LOG filehandle and raw/clean copy hooks
494/*****************************************************************************/
495void TxPrint
496(
497   char               *fmt,                     // IN    format string (printf)
498   ...                                          // IN    variable arguments
499)
500{
501   va_list             varargs;
502   ULONG               size = 0;
503   BOOL                log7bit;
504   BOOL                logreopen;
505   FILE               *log_handle = TxQueryLogFile( &log7bit, &logreopen);
506   TXH_INFO           *hinfo;                   // current hook info
507
508   va_start(varargs, fmt);
509   if (txm_buff == NULL)
510   {
511      txm_buff = calloc( 1, TXMAX4K);
512   }
513   if (txm_buff != NULL)
514   {
515      size = vsprintf( txm_buff, fmt, varargs); // expanded string in buffer
516
517      if (txc_ascii7)                           // filter to 7-bit ASCII
518      {
519         TxAscii827( txm_buff, TXASCII827_TRANS);
520      }
521
522      if ((screen_act    == DEVICE_ON) &&       // screen output ON
523          (txh_raw       == NULL))              // and not redirected to a RAW
524      {                                         // stream (like scrollbuffer)
525         #if defined (WIN32)
526            txNtConsoleDisplay( txm_buff);      // ANSI expand and print
527         #else
528            printf( "%s", txm_buff);            // just print formatted buffer
529         #endif
530         fflush(stdout);
531      }
532      for (hinfo = txh_raw; hinfo != NULL; hinfo = hinfo->next)
533      {
534         if ((size < hinfo->size) && (hinfo->active) &&
535             ((screen_act == DEVICE_ON) ||
536              (hinfo->follow_screen_toggle == FALSE)))
537         {
538            strcpy( hinfo->cbuf, txm_buff);
539            (hinfo->copy) (hinfo->cbuf, hinfo->user);
540         }
541      }
542      if ((log_handle != 0) || (txh_clean != NULL))
543      {
544         size = TxStripAnsiCodes( txm_buff);    // update size as well!
545         for (hinfo = txh_clean; hinfo != NULL; hinfo = hinfo->next)
546         {
547            if ((size < hinfo->size) && (hinfo->active) &&
548                ((screen_act == DEVICE_ON) ||
549                 (hinfo->follow_screen_toggle == FALSE)))
550            {
551               strcpy( hinfo->cbuf, txm_buff);
552               (hinfo->copy) (hinfo->cbuf, hinfo->user);
553            }
554         }
555         if ((log_handle != 0) && (logfile_act == DEVICE_ON))
556         {
557            if (!txc_ascii7 && log7bit)         // 7-bit ASCII for log only ?
558            {
559               TxAscii827( txm_buff, TXASCII827_TRANS);
560            }
561
562            if ((log_maxsize > size) && (log_written > (log_maxsize - size)))
563            {
564               TXLN    fname;
565
566               log_written = size + 150;        // start size new logfile
567
568               fprintf( log_handle, "\nClosing logfile at size limit\n");
569
570               TxAppendToLogFile( NULL, FALSE); // close current log, quiet
571               if (log_seq_num >= log_retain)   // need to delete one
572               {
573                  TxBuildLogName( log_seq_num - log_retain,
574                                  log_retain, fname);
575                  remove( fname);               // delete a logfile (cycle)
576               }
577               TxBuildLogName( (log_retain) ? ++log_seq_num : 0,
578                                log_retain, fname);
579               TxAppendToLogFile( fname, FALSE); // open next logfile, quiet
580               log_handle  = TxQueryLogFile( &log7bit, &logreopen);
581               fprintf( log_handle, "Start logfile nr %lu : '%s'\n",
582                        log_seq_num, fname);
583            }
584            else
585            {
586               log_written += size;             // maintain total size in log
587            }
588
589            fprintf( log_handle, "%s", txm_buff);
590            if (logreopen)
591            {
592               TxCloseReopenLogFile();          // close/reopen (force flush)
593            }
594            else
595            {
596               fflush(  log_handle);            // soft flush
597            }
598         }
599      }
600   }
601   va_end(varargs);
602}                                               // end 'TxPrint'
603/*---------------------------------------------------------------------------*/
604
605
606/*****************************************************************************/
607// Remove ANSI control code from a text-string (in place conversion)
608/*****************************************************************************/
609ULONG TxStripAnsiCodes                          // RET   length stripped string
610(                                               //       corrected for CR/LF
611   char               *text                     // INOUT ANSI text to strip
612)
613{
614   char               *rd = text;               // read-pointer in string
615   char               *wr = text;               // write pointer
616   ULONG               ls = 0;                  // length stripped string
617
618   while (*rd)
619   {
620      if ((*rd == TXK_ESCAPE) && (*(rd+1) == '['))
621      {
622         rd += 2;
623         while ((isdigit(*rd)) || (*rd == ';'))
624         {
625            rd++;
626         }
627      }
628      else
629      {
630         *(wr++) = *rd;                         // copy the character
631
632         #if !defined(LINUX)
633         if (*rd == '\n')                       // when end of line
634         {
635            ls++;                               // correct for CR/LF char
636         }
637         ls++;                                  // count for length
638         #endif
639      }
640      rd++;
641   }
642   *wr = '\0';                                  // terminate stripped string
643   return( ls);
644}                                               // end 'TxStripAnsiCodes'
645/*---------------------------------------------------------------------------*/
646
647
648/*****************************************************************************/
649// Claim TX keyboard access-functions for current thread (TxAbort etc)
650/*****************************************************************************/
651ULONG TxClaimKeyboard                           // RET   previous owner
652(
653   void
654)
655{
656   ULONG               rc = txkThread;          // function return
657
658   ENTER();
659
660   txkThread = TXCURTHREAD;
661
662   RETURN (rc);
663}                                               // end 'TxClaimKeyboard'
664/*---------------------------------------------------------------------------*/
665
666
667/*****************************************************************************/
668// Cancel any pending abort status (as returned by TxAbort)
669/*****************************************************************************/
670void TxCancelAbort
671(
672   void
673)
674{
675   ENTER();
676
677   txk_Abort = FALSE;
678
679   VRETURN ();
680}                                               // end 'TxCancelAbort'
681/*---------------------------------------------------------------------------*/
682
683/*****************************************************************************/
684// Set abort status to pending, for other threads (as returned by TxAbort)
685/*****************************************************************************/
686void TxSetPendingAbort
687(
688   void
689)
690{
691   ENTER();
692
693   txk_Abort = TRUE;
694
695   VRETURN ();
696}                                               // end 'TxSetPendingAbort'
697/*---------------------------------------------------------------------------*/
698
699
700/*****************************************************************************/
701// Return kbhit status and latest More ... reply, read away the hit
702/*****************************************************************************/
703BOOL TxAbort                                    // RET   TRUE when abort wanted
704(
705   void
706)
707{
708   BOOL                aborting = FALSE;
709   ULONG               key;
710
711   if ((txk_Abort) ||                           // already aborting
712       (txkThread != TXCURTHREAD))              // or not KB owning thread
713   {
714      aborting = txk_Abort;
715   }
716   else
717   {
718      if (kbhit())
719      {
720         #if defined (USEWINDOWING)
721            key = txwGetInputEvent( NULL);
722         #else
723            key = getch();
724         #endif
725         switch (key)
726         {
727            case TXK_ESCAPE:
728               aborting  = TRUE;                // abort if <Esc>
729               txk_Abort = TRUE;                // remember abort status
730               break;
731
732#if defined (DUMP)
733            case TXa_SLASH:                     // toggle trace value
734               switch (TxTrLevel)
735               {
736                  case 0:  TxTrLevel = 1;   break;
737                  case 1:  TxTrLevel = 100; break;
738                  default: TxTrLevel = 0;   break;
739               }
740               break;
741#endif
742            default:                            // route some keys to focus-win
743               #if defined (USEWINDOWING)
744               if (txwa->desktop != NULL)       // if windowing is active
745               {
746                  switch (key)                  // do not send critical keys
747                  {
748                     case TXk_ENTER:
749                        break;
750
751                     default:
752                        txwSendMsg((TXWHANDLE) txwa->focus, TXWM_CHAR, 0, key);
753                        break;
754                  }
755               }
756               #endif                           // USEWINDOWING
757               break;
758         }
759      }
760   }
761   return( aborting);
762}                                               // end 'TxAbort'
763/*---------------------------------------------------------------------------*/
764
765
766/*****************************************************************************/
767// Display a message using format string and ask confirmation
768/*****************************************************************************/
769BOOL TxConfirm                                  // RET   Confirmed
770(
771   ULONG               helpid,                  // IN    helpid confirmation
772   char               *fmt,                     // IN    format string (printf)
773   ...                                          // IN    variable arguments
774)
775{
776   BOOL                cf = TRUE;               // return value
777   TX1K                text;
778   int                 reply = 'n';
779   va_list             varargs;
780   char              **mText;                   // formatted text for display
781   int                 ll;                      // real max line length
782   int                 lines;                   // nr of lines
783   DEVICE_STATE        sa = screen_act;
784
785   if ((ll = TxScreenCols() -12) < 20)          // ScreenCols will be 0 if
786   {                                            // output is redirected!
787      ll = 20;
788   }
789   if ((txwa->desktop != NULL) && (!TxaExeSwitch('p')))
790   {
791      screen_act = DEVICE_OFF;                  // no regular text if windowed
792   }                                            // and not 'pedantic mode'
793   else
794   {
795      screen_act = DEVICE_ON;                   // force screen for confirm
796   }
797   va_start(varargs, fmt);
798   vsprintf( text, fmt, varargs);               // format the message
799
800   mText = txString2Text( text, &ll, &lines);   // convert to multi-line
801   TxPrint( "\n");                              // force empty line before
802   TxShowTxt(  mText);                          // display in scrollbuffer
803   txFreeText( mText);                          // free the text memory
804
805   screen_act = sa;                             // restore screen state
806                                                // to allow sbView output while
807                                                // MsgBox is up (other threads!)
808   #if defined (USEWINDOWING)
809   if (txwa->desktop != NULL)                   // there is a desktop
810   {
811      char            *yn;
812
813      TxStripAnsiCodes( text);                  // remove colors for popup
814      if ((yn = strstr( text, "[Y/N]")) != NULL)
815      {
816         *yn = '\0';                            // remove [y/n] part
817      }
818      switch (txwMessageBox( TXHWND_DESKTOP, TXHWND_DESKTOP,
819                             text, txConfirmTitle, helpid,
820                             TXMB_YESNOCANCEL | TXMB_MOVEABLE |
821                             TXMB_HCENTER     | TXMB_VCENTER) )
822      {
823         case TXMBID_OK:                        // F4=OK
824         case TXMBID_YES:
825            reply = 'y';                        // for logging only
826            break;
827
828         case TXMBID_CANCEL:
829            TxSetPendingAbort();
830            TxPrint( "Abort");
831            reply = '!';
832         default:
833            cf = FALSE;                         // not confirmed
834            break;
835      }
836   }
837   else                                         // use non-windowed interface
838   #endif                                       // USEWINDOWING
839   {
840      if (TxAbort())
841      {
842         reply = TXK_ESCAPE;
843      }
844      else
845      {
846         reply = getch();                       // wait for next keystroke
847      }
848      switch (reply)
849      {
850         case 'y': case 'Y':
851         case 'j': case 'J':
852            break;
853
854         case TXK_ESCAPE: