Recent

Author Topic: Filtering results that will be displayed via Write / WriteLn  (Read 923 times)

ASBzone

  • Hero Member
  • *****
  • Posts: 713
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Filtering results that will be displayed via Write / WriteLn
« on: August 06, 2024, 04:14:17 am »
Hey, folks:

I am trying to think of the best way to handle the following situation. The app will definitely be running in the Windows console, but I don't necessarily want to limit the answer to a Windows-only solution, but I'll take one that works.

I have a series of WriteLn commands that are going to be used to display some output to the console.   I want to make it possible to allow someone to provide a search filter for a subset of this output and have it only display the lines that contain the search word/term.

What would be the best approach to do this.   Would I be able to send the output to a buffer and the do the search from the buffer to the output?

Code: Pascal  [Select][+][-]
  1. procedure ShowSyntax(const SearchFor: string);
  2.  
  3. begin
  4.         WriteLn(SendTo, ' * Entering ', ThisApp.SName, ' with no parameters will display this help message.');
  5.         WriteLn(SendTo, ' * Parameters surrounded by <> are mandatory; Those surrounded by [] are optional.');
  6.         WriteLn(SendTo, ' * Parameters are case-insensitive, but may be shown in uppercase for clarity.');
  7.         WriteLn(SendTo, ' * Single-character parameters (e.g. -h) can be prefaced by "-" or "/".');
  8.         WriteLn(SendTo, ' * Multi-character parameters (e.g. --help) should be prefaced by "--".');
  9.         WriteLn(SendTo, ' * All parameters need to be separated from each other by at least one space.');
  10.         WriteLn(SendTo, ' * The -H, --?? --Version-Only and --Info parameters supersede all other options -- in that order.');
  11.         WriteLn(SendTo, ' * The -V parameter causes application build mode info to be shown whenever the banner is shown.');
  12.         WriteLn(SendTo, ' * Combining -H/-? and -V will display extended help info plus application exit/return codes.');
  13.         WriteLn(SendTo, ' * The --?? parameter behaves like the -H/-? and -V parameters combined.');
  14.         WriteLn(SendTo, ' * The --Info parameter will ONLY show the banner, with build info, and quit.  It will process no other data.');
  15.         WriteLn(SendTo, ' * The --Version-Only parameter behaves like the --Info parameter, but without showing the banner.');
  16.         WriteLn(SendTo, ' * The application banner is only displayed when Help Syntax is displayed, or when -B is used.', LINEENDING);
  17. end;
  18.  


Example:  I want to make it possible that someone could filter this to show only the lines that contain the word "character"

Thanks
-ASB: https://www.BrainWaveCC.com/

Lazarus v3.5.0.0 (2216170cde) / FPC v3.2.3-1387-g3795cadbc8
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

440bx

  • Hero Member
  • *****
  • Posts: 4560
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #1 on: August 06, 2024, 05:49:39 am »
I have example code that is 16 bit, it runs in Windows 3.1 (yes, 3.1... even before 9x) and Windows XP. It is tested and works but it must be compiled with a 16 bit compiler.

I don't know if there is an FPC mode that emulates Turbo Pascal for Windows, Borland Pascal (which produced 16 bit Windows binaries) or Delphi 1.  If there is then it should be possible to compile and run that code.  Note: the "device" isn't Windows dependent, it is compiler-dependent.  The example program is definitely Windows only but doesn't matter.

I believe, given the right information, FPC's structure of the File Interface Block, it is very easy to port it to 32 and 64 bit but, I don't have the necessary information about FPC to do it.  That part will have to be provided by someone else.

The gist of the thing is to create an  output "device" that is custom managed.  This code shows how to do it in 16 bit:
Code: Pascal  [Select][+][-]
  1. {$S-,R-,V-,I-,B-,F-}
  2.  
  3. {-----------------------------------------------------------------------------}
  4. {  This unit implements functions to format strings using the Pascal procedure}
  5. {  Write.  It is *very* similar to the TurboPower Software TpStrDev unit.     }
  6. {                                                                             }
  7. {  It accomplishes this by sending the output of the Write procedure to a     }
  8. {  "device" that is actually a memory buffer.  The length of the string in the}
  9. {  buffer is retrieved using WWRetL (WinWrite Return Length).  The contents of}
  10. {  the buffer may be retrieved in three (3) different ways:                   }
  11. {                                                                             }
  12. {  1. As a PChar by calling WWRetZ (WinWrite Return asciiZ).                  }
  13. {  2. As a Pointer to a Pascal string by calling WWRetPSt (... Ret ^String)   }
  14. {  3. As a Pascal String by calling WWRetSt (... Return String)               }
  15. {                                                                             }
  16. {  The memory buffer is large enough to contain 257 characters, this size was }
  17. {  chosen to be: SizeOf(string) + 1.  + 1 so that even the largest string     }
  18. {  could be converted to an asciiz and thereby returned as either.  Note that }
  19. {  the length NEVER includes the trailing #0.                                 }
  20. {                                                                             }
  21. {  The routines in this unit have been tested under DOS and Windows.          }
  22. {  They have NOT been tested for protected mode operation under DOS.          }
  23. {                                                                             }
  24. {  LIMITATIONS:                                                               }
  25. {                                                                             }
  26. {  1. If the Write parameters sent to the buffer exceed the buffer size then  }
  27. {     the output is truncated. (Output buffer will have 257 bytes, 1 byte for }
  28. {     the length, 255 bytes of data and 1 trailing NULL byte).                }
  29. {                                                                             }
  30. {  2. Every execution of Pascal's Write resets the buffer therefore the       }
  31. {     formatted string must be created with a single call to Write.  In other }
  32. {     words, unlike TpStrDev, Write calls cannot be accumulated.              }
  33. {                                                                             }
  34. {  The above limitations were added to the original TpStrDev to avoid the     }
  35. {  possibility of infinite loops.                                             }
  36. {                                                                             }
  37. {  OTHER DIFFERENCES:                                                         }
  38. {                                                                             }
  39. {  1. The output buffer/string is NOT reset by the functions Return/Get.  This}
  40. {     allows the result to be used multiple times                             }
  41. {                                                                             }
  42. {  2. The resulting buffer/string may be interpreted as as Pascal string or as}
  43. {     a PChar.                                                                }
  44. {-----------------------------------------------------------------------------}
  45.  
  46. unit WinWrite;
  47.   { routines for reading and writing formatted strings                        }
  48.  
  49. {-----------------------------------------------------------------------------}
  50. INTERFACE
  51. {-----------------------------------------------------------------------------}
  52.  
  53. Type
  54.   PString = ^String;
  55.  
  56. var
  57.   WW : text;              { the "Win-dows Write buffer" device                }
  58.  
  59. function WWRetL : word;
  60.   { return the length of the string in the output buffer                      }
  61.  
  62. function WWRetZ : PChar;
  63.   { return the address of the buffer as a pointer to char (PChar)             }
  64.  
  65. function WWRetPSt : PString;
  66.   { return a pointer to a Pascal String                                       }
  67.  
  68. function WWRetSt : string;
  69.   { return the contents of the buffer into a string                           }
  70.  
  71. procedure WWGetSt (var s : string);
  72.   { copy the buffer contents into s                                           }
  73.  
  74. { procedure WWGetZ (var p : pchar);                                           }
  75. { not implemented.  use WWRetZ instead                                        }
  76.  
  77. {-----------------------------------------------------------------------------}
  78. IMPLEMENTATION
  79. {-----------------------------------------------------------------------------}
  80.  
  81. type
  82.   TextBuffer = array[0..65520] of Byte; { device buffer                       }
  83.  
  84.   { structure of a Turbo File Interface Block --------------------------------}
  85.   FIB =   record
  86.             Handle    : Word;
  87.             Mode      : Word;
  88.             BufSize   : Word;
  89.             Private   : Word;
  90.             BufPos    : Word;
  91.             BufEnd    : Word;
  92.             BufPtr    : ^TextBuffer;
  93.             OpenProc  : Pointer;
  94.             InOutProc : Pointer;
  95.             FlushProc : Pointer;
  96.             CloseProc : Pointer;
  97.  
  98.             { UserData  : array[1..16]  of Byte;   !! first byte used         }
  99.             Flushed   : boolean;
  100.             UserData  : array[1..15] of byte;
  101.  
  102.             Name      : array[0..79]  of Char;
  103.             Buf       : array[0..127] of Char;
  104.           end;
  105.  
  106. const
  107.   FMClosed  = $D7B0;
  108.   StrLenMax = sizeof(string) - 1;               { max string length           }
  109.  
  110. var
  111.   WWBuffer: array [0..sizeof(string)] of char;  { 256 to allow for ending #0  }
  112.   StrBuf  : string absolute WWBuffer;
  113.   StrLen  : byte   absolute StrBuf;
  114.  
  115.  
  116. {-----------------------------------------------------------------------------}
  117.  
  118. function WWRetL : word;
  119.   { return the length of the string in the device buffer                      }
  120. begin
  121.   WWRetL := StrLen;                     { #0 is never included in the length  }
  122. end;
  123.  
  124.  
  125. function WWRetZ : PChar;
  126.   { return the address of the buffer as a pointer to char (PChar)             }
  127. begin
  128.   WWRetZ := PChar(@StrBuf[1]);          { return a PChar                      }
  129. end;
  130.  
  131.  
  132. function WWRetPSt : PString;
  133.   { return a pointer to a Pascal String                                       }
  134. begin
  135.   WWRetPSt := @StrBuf;                  { return a Pointer to a Pascal String }
  136. end;
  137.  
  138.  
  139. function WWRetSt : string;
  140.   { return the contents of the buffer into a string                           }
  141. begin
  142.   WWRetSt := StrBuf;
  143. end;
  144.  
  145.  
  146. procedure WWGetSt (var s : string);
  147.   { copy the buffer contents into s                                           }
  148. begin
  149.   s      := StrBuf;
  150. end;
  151.  
  152. {-----------------------------------------------------------------------------}
  153.  
  154. function Out (var F : FIB) : Word; far;
  155.   { update the length byte of StrBuf                                          }
  156. var
  157.   Count : word;
  158. begin
  159.   Out := 0;
  160.  
  161.   with F do begin
  162.  
  163.     { if the Out function is being executed after a call to the Flush function}
  164.     { this indicates that we are processing a new write statement.  We need to}
  165.     { clear our buffer to make room for the new output of the write statement }
  166.  
  167.     if Flushed then StrLen := 0;        { otherwise append to WWBuffer        }
  168.     Flushed                := FALSE;    { Flush function not executed yet     }
  169.  
  170.     { move the bytes from Turbo's buffer F.buf to our buffer WWBuffer         }
  171.  
  172.     if strlen + bufpos <= StrLenMax
  173.       then Count := bufpos
  174.       else Count := StrLenMax - StrLen;
  175.  
  176.     if Count > 0 then
  177.       begin
  178.         move (buf[0], strbuf[strlen + 1], Count);
  179.         StrLen := StrLen + Count
  180.       end;
  181.  
  182.     { let Turbo know that we are done with its buffer                         }
  183.  
  184.     bufpos := 0;
  185.     bufend := 0;
  186.     WWBuffer[StrLen + 1] := #0;     { Turn our buffer into an asciiz string   }
  187.   end;
  188. end;
  189.  
  190. function flush (var F : FIB) : Word; far;
  191.   { Just return Ok. Do nothing.                                               }
  192. begin
  193.   Flush := 0;
  194.  
  195.   with F do
  196.     begin
  197.       Out(F);
  198.       Flushed := TRUE;
  199.       exit;
  200.     end;
  201. end;
  202.  
  203.  
  204. function OpenClose (var F : FIB) : Word; far;
  205.   { Clear any text that may be laying around in the buffer                    }
  206. begin
  207.   with F do begin
  208.     BufPos  := 0;
  209.     BufEnd  := 0;
  210.   end;
  211.  
  212.   OpenClose := 0;
  213. end;
  214.  
  215. {-----------------------------------------------------------------------------}
  216.  
  217. procedure AssignBuf (var F : Text);
  218.   { initialize the File Interface Block                                       }
  219. begin
  220.   with FIB(F) do begin
  221.     Mode      := FMClosed;
  222.     OpenProc  := @OpenClose;
  223.     FlushProc := @Flush;
  224.     CloseProc := @OpenClose;
  225.     InOutProc := @Out;
  226.     BufEnd    := 0;
  227.     BufPos    := 0;
  228.     BufPtr    := @buf;
  229.     BufSize   := sizeof(buf);
  230.  
  231.     Name[0]   := #0;
  232.  
  233.     Flushed   := TRUE;                  { Flush function executed             }
  234.   end;
  235. end;
  236.  
  237. {-----------------------------------------------------------------------------}
  238.  
  239. begin
  240.   AssignBuf (WW);
  241.   Rewrite   (WW);
  242.   StrLen := 0;
  243. end.
The important part is the definition of the File Interface Block.  The code above uses the TP/BP definition that is valid in 16 bit.  I know there is an equivalent structure in FPC (I've seen it posted by PascalDragon but, I don't remember where and couldn't find it.)

The first thing is to update that record definition.

The "trick" is in the implementation of the "Out" function (which you might have to rename or prefix with an "&".)  That function can be customized to filter the output however you like.

Example program in next post because with it the post was too long for the forum software.

continued in next post...

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

440bx

  • Hero Member
  • *****
  • Posts: 4560
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #2 on: August 06, 2024, 05:51:04 am »
continued from previous post...

An example follows (which only compiles with a 16 bit compiler - TP/BP would work, Delphi 1 maybe, I'm not sure):
Code: Pascal  [Select][+][-]
  1. program generic;
  2.   { generic template program used to incorporate examples of the "Windows API }
  3.   { bible                                                                     }
  4.  
  5. {$R generic.res }
  6.  
  7. uses WinTypes, WinProcs, Resources, WinWrite;
  8.  
  9.  
  10. const
  11.   AppName = 'Generic';
  12.  
  13. {-----------------------------------------------------------------------------}
  14.  
  15. function ChildProc (Wnd    : hWnd;
  16.                   Msg    : word;
  17.                   wParam : Word;
  18.                   lParam : LongInt) : LongInt; export;
  19.   { procedure for Child window.  Note that CHILD windows are never active!    }
  20. begin
  21.   { simply let the default window procedure take care of everything           }
  22.   case msg of
  23.     WM_MOUSEMOVE:
  24.        begin
  25.          SendMessage (GetParent (Wnd), msg, wparam, lParam);
  26.        end;
  27.   end;
  28.  
  29.   ChildProc := DefWindowProc (Wnd, Msg, wParam, lParam);
  30. end;
  31.  
  32. function InitChildClass (ChildClass : PChar) : Bool;
  33.   { registers the Child's window class                                        }
  34. var
  35.   cls : TWndClass;
  36.  
  37. begin
  38.   if not GetClassInfo (hInstance, ChildClass, cls) then
  39.     begin
  40.       with cls do begin
  41.         style           := cs_VRedraw or cs_HRedraw;
  42.         lpfnWndProc     := @ChildProc;
  43.         cbClsExtra      := 0;
  44.         cbWndExtra      := 0;
  45.         hInstance       := system.hInstance;            { qualify instance!   }
  46.         hIcon           := LoadIcon (0, idi_Application);
  47.         hCursor         := LoadCursor (0, idc_Cross);
  48.         hbrBackground   := COLOR_WINDOW + 1;
  49.         lpszMenuName    := nil;                         { cannot have menu!   }
  50.         lpszClassName   := ChildClass;
  51.       end; { with }
  52.  
  53.       InitChildClass := RegisterClass (cls);
  54.     end
  55.   else InitChildClass := True;
  56. end;
  57.  
  58. {-----------------------------------------------------------------------------}
  59.  
  60. function WndProc (Wnd    : hWnd;
  61.                   Msg    : word;
  62.                   wParam : Word;
  63.                   lParam : LongInt) : LongInt; export;
  64.   { procedure for main window                                                 }
  65. const
  66.   Text_1        : hWnd = 0;
  67.   Text_2        : hWnd = 0;
  68.   ChildWnd      : hWnd = 0;
  69.  
  70. const
  71.   ChildClass    = 'ChildWindow';
  72.  
  73. var
  74.  dc             : HDC;
  75.  point          : TPOINT;
  76.  
  77.  PointWnd       : hWnd;                 { window that contains the point      }
  78.  WindowText     : array [0..255] of Char;
  79.  
  80.  
  81. begin
  82.   WndProc := 0;                                 { default function result     }
  83.  
  84.   case Msg of
  85.     WM_CREATE:
  86.        begin
  87.          Text_1 := CreateWindow ('STATIC',
  88.                                  'Static Text Window 1',
  89.                                  WS_CHILD or WS_VISIBLE or BS_PUSHBUTTON,
  90.                                   10,
  91.                                   40,
  92.                                  140,
  93.                                   20,
  94.                                  Wnd,
  95.                                  100,           { Child ID ! not a menu       }
  96.                                  hInstance,
  97.                                  nil);
  98.          if Text_1 = 0 then halt (255);
  99.  
  100.          Text_2 := CreateWindow ('STATIC',
  101.                                  'Static Text Window 2',
  102.                                  WS_CHILD or WS_VISIBLE,
  103.                                   10,
  104.                                   60,
  105.                                  140,
  106.                                   20,
  107.                                  Wnd,
  108.                                  101,           { Child ID                    }
  109.                                  hInstance,
  110.                                  nil);
  111.          if Text_2 = 0 then halt (255);
  112.  
  113.          if not InitChildClass (ChildClass) then halt (255); { register it    }
  114.  
  115.          ChildWnd := CreateWindow (ChildClass,
  116.                                    'ChildWindow',
  117.                                    WS_CHILD or WS_VISIBLE or
  118.                                    WS_BORDER or WS_CAPTION or WS_CLIPSIBLINGS,
  119.                                    70,
  120.                                    70,
  121.                                    240,
  122.                                    340,
  123.                                    Wnd,        { parent window                }
  124.                                    102,
  125.                                    hInstance,
  126.                                    nil);
  127.  
  128.          exit;
  129.        end;
  130.  
  131.     WM_MOUSEMOVE:
  132.        begin
  133.          point    := MAKEPOINT(lParam);
  134.          PointWnd := ChildWindowFromPoint (Wnd, point);
  135.          if PointWnd <> 0
  136.            then GetWindowText (PointWnd, WindowText, sizeof (WindowText))
  137.            else lstrcpy (WindowText,'<<none>>'#0);
  138.  
  139.          dc    := GetDC (Wnd);
  140.          Write (WW, 'Mouse Coordinates are: ', 'X: ', point.x:5,
  141.                                                'Y: ', point.y:5);
  142.          TextOut (dc, 400, 0, WWRetZ, WWRetL);
  143.          ReleaseDC (Wnd, dc);
  144.  
  145.          dc    := GetDC (Wnd);
  146.          Write (WW, 'Child Window Text: ', WindowText);
  147.          TextOut (dc, 0, 0, WWRetZ, WWRetL);
  148.          ReleaseDC (Wnd, dc);
  149.  
  150.          { do the same thing but using WindowFromPoint instead                }
  151.  
  152.          PointWnd := WindowFromPoint (point);
  153.          if PointWnd <> 0
  154.            then GetWindowText (PointWnd, WindowText, sizeof (WindowText))
  155.            else lstrcpy (WindowText,'<<none>>'#0);
  156.  
  157.          dc    := GetDC (Wnd);
  158.          Write (WW, 'WindowFromPoint says: ', WindowText);
  159.          TextOut (dc, 0, 20, WWRetZ, WWRetL);
  160.          ReleaseDC (Wnd, dc);
  161.  
  162.          exit;
  163.        end;
  164.  
  165.  
  166.     WM_COMMAND :
  167.        begin
  168.          case wParam of
  169.            IDM_QUIT :
  170.                begin
  171.                  DestroyWindow (Wnd);
  172.                  exit;
  173.                end;
  174.          end;
  175.        end;
  176.  
  177.     WM_DESTROY :
  178.        begin
  179.          PostQuitMessage (0);                           { send WM_QUIT msg    }
  180.          exit;
  181.        end;
  182.   end; { case }
  183.  
  184.   WndProc := DefWindowProc (Wnd, Msg, wParam, lParam);
  185. end;
  186.  
  187.  
  188. function InitAppClass: Bool;
  189.   { registers the application's window classes                                }
  190. var
  191.   cls : TWndClass;
  192.  
  193. begin
  194.   if not GetClassInfo (hInstance, AppName, cls) then
  195.     begin
  196.       with cls do begin
  197.         style           := cs_VRedraw or cs_HRedraw;
  198.         lpfnWndProc     := @WndProc;
  199.         cbClsExtra      := 0;
  200.         cbWndExtra      := 0;
  201.         hInstance       := system.hInstance;            { qualify instance!   }
  202.         hIcon           := LoadIcon (0, idi_Application);
  203.         hCursor         := LoadCursor (0, idc_Arrow);
  204.         hbrBackground   := COLOR_WINDOW + 1;
  205.         lpszMenuName    := AppName;
  206.         lpszClassName   := AppName;
  207.       end; { with }
  208.  
  209.       InitAppClass := RegisterClass (cls);
  210.     end
  211.   else InitAppClass := True;
  212. end;
  213.  
  214.  
  215. Function WinMain : integer;
  216.   { application entry point                                                   }
  217. var
  218.   Wnd : hWnd;
  219.   Msg : TMsg;
  220.  
  221. begin
  222.   if not InitAppClass then Halt (255);  { register application's class        }
  223.  
  224.   { Create the main application window                                        }
  225.  
  226.   Wnd := CreateWindow (AppName,                 { class name                  }
  227.                        AppName,                 { window caption text         }
  228.                        ws_OverlappedWindow or   { window style                }
  229.                        ws_clipchildren,
  230.                        cw_UseDefault,           { x pos on screen             }
  231.                        cw_UseDefault,           { y pos on screen             }
  232.                        cw_UseDefault,           { window width                }
  233.                        cw_UseDefault,           { window height               }
  234.                        0,                       { parent window handle        }
  235.                        0,                       { menu handle 0 = use class   }
  236.                        hInstance,               { instance handle             }
  237.                        Nil);                    { parameter sent to WM_CREATE }
  238.  
  239.   if Wnd = 0 then halt;                         { could not create the window }
  240.  
  241.   { the call to showwindow is not needed if ws_visible is specified in create }
  242.   { window call.  However, it should still be done so that the window is dis- }
  243.   { played according to the cmdShow parameter                                 }
  244.  
  245.   ShowWindow (Wnd, cmdShow);                    { make the window visible     }
  246.   UpdateWindow (Wnd);                           { send 1st WM_PAINT message   }
  247.  
  248.  
  249.   while GetMessage (Msg, 0, 0, 0) do            { wait for message            }
  250.     begin
  251.       TranslateMessage (Msg);                   { key conversions             }
  252.       DispatchMessage  (Msg);                   { send to window procedure    }
  253.     end;
  254.  
  255.   WinMain := msg.wParam;                        { terminate with return code  }
  256. end;
  257.  
  258. begin
  259.   WinMain;
  260. end.
Notice the highlighted lines, those show how to use the custom output device.

It would be quite easy to port the example program to FPC.  I believe that with the correct FPC equivalent of FIB, the unit would also be easy to port.

HTH.

NOTE: that code is a little older than 30 years old. <chuckle>

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

dseligo

  • Hero Member
  • *****
  • Posts: 1372
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #3 on: August 06, 2024, 09:35:33 am »
I would put those strings in some data structure and then search before outputting:
Code: Pascal  [Select][+][-]
  1. const ThisAppSName = 'ThisAppSName';
  2.  
  3. var options: array of String =
  4.   (
  5.     ' * Entering ' + ThisAppSName + ' with no parameters will display this help message.',
  6.     ' * Parameters surrounded by <> are mandatory; Those surrounded by [] are optional.',
  7.     ' * Parameters are case-insensitive, but may be shown in uppercase for clarity.',
  8.     ' * Single-character parameters (e.g. -h) can be prefaced by "-" or "/".',
  9.     ' * Multi-character parameters (e.g. --help) should be prefaced by "--".',
  10.     ' * All parameters need to be separated from each other by at least one space.',
  11.     ' * The -H, --?? --Version-Only and --Info parameters supersede all other options -- in that order.',
  12.     ' * The -V parameter causes application build mode info to be shown whenever the banner is shown.',
  13.     ' * Combining -H/-? and -V will display extended help info plus application exit/return codes.',
  14.     ' * The --?? parameter behaves like the -H/-? and -V parameters combined.',
  15.     ' * The --Info parameter will ONLY show the banner, with build info, and quit.  It will process no other data.',
  16.     ' * The --Version-Only parameter behaves like the --Info parameter, but without showing the banner.',
  17.     ' * The application banner is only displayed when Help Syntax is displayed, or when -B is used.'
  18.   );
  19.  
  20. var i: Integer;
  21.     reg: TRegExpr;
  22.  
  23. ...
  24.  
  25.   For i := 0 to High(options) do
  26.     If Pos('character', LowerCase(Options[i])) > 0 then
  27.       WriteLn(Options[i]);
  28.  
  29.   // or regex
  30.   reg := TRegExpr.Create;
  31.   reg.Expression := '.character.';
  32.   For i := 0 to High(options) do
  33.     If reg.Exec(Options[i]) then
  34.       WriteLn(Options[i]);
  35.   reg.Free;

MarkMLl

  • Hero Member
  • *****
  • Posts: 7708
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #4 on: August 06, 2024, 09:54:39 am »
I am trying to think of the best way to handle the following situation. The app will definitely be running in the Windows console, but I don't necessarily want to limit the answer to a Windows-only solution, but I'll take one that works.

I have a series of WriteLn commands that are going to be used to display some output to the console.   I want to make it possible to allow someone to provide a search filter for a subset of this output and have it only display the lines that contain the search word/term.

What would be the best approach to do this.   Would I be able to send the output to a buffer and the do the search from the buffer to the output?

You could do it by messing around at the TTextRec level, but this was intended to be opaque by the FPC developers and having been there (for a Telnet server and client) my experience is that there were reliability issues before FPC v3.

I'd strongly recommend that you do not do that.

Replace your WriteLn()s by something using either Str() or Format(), and (as suggested by 440bx) implement your own filtering.

MarkMLl

p.s. And don't try interleaving stuff going to OUTPUT and stdout, they're distinct.
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

Thaddy

  • Hero Member
  • *****
  • Posts: 15729
  • Censorship about opinions does not belong here.
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #5 on: August 06, 2024, 10:34:08 am »
And don't try interleaving stuff going to OUTPUT and stdout, they're distinct.
They are the same!
It is an alias.
That is clearly documented:
https://www.freepascal.org/docs-html/rtl/system/stdout.html
If I smell bad code it usually is bad code and that includes my own code.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7708
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #6 on: August 06, 2024, 10:36:27 am »
And don't try interleaving stuff going to OUTPUT and stdout, they're distinct.
They are the same!
It is an alias.
That is clearly documented:
https://www.freepascal.org/docs-html/rtl/system/stdout.html

I didn't say StdOut, I said stdout.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

ASBzone

  • Hero Member
  • *****
  • Posts: 713
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #7 on: August 08, 2024, 04:51:57 am »
NOTE: that code is a little older than 30 years old. <chuckle>

Can we consider this code millennial code? 😁😁

Thanks for this, 440bx.    I'll greatly appreciate this effort.  I will review and let you know if I have any questions.
-ASB: https://www.BrainWaveCC.com/

Lazarus v3.5.0.0 (2216170cde) / FPC v3.2.3-1387-g3795cadbc8
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

ASBzone

  • Hero Member
  • *****
  • Posts: 713
  • Automation leads to relaxation...
    • Free Console Utilities for Windows (and a few for Linux) from BrainWaveCC
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #8 on: August 08, 2024, 04:59:40 am »
Replace your WriteLn()s by something using either Str() or Format(), and (as suggested by 440bx) implement your own filtering.

MarkMLl

p.s. And don't try interleaving stuff going to OUTPUT and stdout, they're distinct.

Thanks, MarkMLl and Thaddy

Also, thank you kindly, dseligo     I was originally going down this sort of path, but didn't think setup the array of strings that way.

Lots to consider here.  I greatly appreciate it.
-ASB: https://www.BrainWaveCC.com/

Lazarus v3.5.0.0 (2216170cde) / FPC v3.2.3-1387-g3795cadbc8
(Windows 64-bit install w/Win32 and Linux/Arm cross-compiles via FpcUpDeluxe on both instances)

My Systems: Windows 10/11 Pro x64 (Current)

440bx

  • Hero Member
  • *****
  • Posts: 4560
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #9 on: August 08, 2024, 05:01:17 am »
Thanks for this, 440bx.    I'll greatly appreciate this effort.  I will review and let you know if I have any questions.
You're welcome.  The really important thing is to find the updated layout of the File Interface Block (the record that has the pointers that control the output device behavior.)  I vividly remember seeing it in a post by PascalDragon but, I can't find it nor where it is documented (I'm probably looking in all the wrong places.)

Anyway, if you have any questions, I'll be glad to answer them.
(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7708
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #10 on: August 08, 2024, 10:02:07 am »
You're welcome.  The really important thing is to find the updated layout of the File Interface Block (the record that has the pointers that control the output device behavior.)  I vividly remember seeing it in a post by PascalDragon but, I can't find it nor where it is documented (I'm probably looking in all the wrong places.)

That was probably related to a question I asked about 18 months ago relating to writing Telnet code. TextRec is documented as "not for application use" or similar, but his position was that it was a couple of steps removed from "if you're not part of the core team don't touch it".

However it wasn't 100% straightforward, and I'd suggest not going down that path unless absolutely unavoidable.

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

440bx

  • Hero Member
  • *****
  • Posts: 4560
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #11 on: August 08, 2024, 11:04:42 am »
TextRec is documented as "not for application use" or similar, but his position was that it was a couple of steps removed from "if you're not part of the core team don't touch it".
Yes, that's it.  It's the layout of TextRec.  Now that you mentioned it, it was really easy to find :)


Found the layout at https://www.freepascal.org/docs-html/rtl/system/textrec.html and as you stated it says "It should be treated as opaque and never manipulated directly."

Now that I've read that, I am itching to port that old code to FPC. :)  x-rays are great to take care of opaque things ;)

(FPC v3.0.4 and Lazarus 1.8.2) or (FPC v3.2.2 and Lazarus v3.2) on Windows 7 SP1 64bit.

Thaddy

  • Hero Member
  • *****
  • Posts: 15729
  • Censorship about opinions does not belong here.
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #12 on: August 08, 2024, 11:36:51 am »
Note that the TextRec layout is rather different from Delphi.
When I did some tricks with it, I needed to write two separate versions to keep it working in Delphi too.
If I smell bad code it usually is bad code and that includes my own code.

MarkMLl

  • Hero Member
  • *****
  • Posts: 7708
Re: Filtering results that will be displayed via Write / WriteLn
« Reply #13 on: August 08, 2024, 11:43:29 am »
Note that the TextRec layout is rather different from Delphi.
When I did some tricks with it, I needed to write two separate versions to keep it working in Delphi too.

Also I had problems with it using FPC < v3.

(Context: a laptop I keep for debugging with relatively-old display hardware hence a relatively-old Debian version which encourages testing with GTK (as distinct from GTK2) hence an older Lazarus etc.).

MarkMLl
MT+86 & Turbo Pascal v1 on CCP/M-86, multitasking with LAN & graphics in 128Kb.
Logitech, TopSpeed & FTL Modula-2 on bare metal (Z80, '286 protected mode).
Pet hate: people who boast about the size and sophistication of their computer.
GitHub repositories: https://github.com/MarkMLl?tab=repositories

 

TinyPortal © 2005-2018