_                _   _                 ____            _     _ 	
   / \   _ __   ___ | |_| |__   ___ _ __  |  _ \ _ __ ___ (_) __| |	
  / _ \ | '_ \ / _ \| __| '_ \ / _ \ '__| | | | | '__/ _ \| |/ _\` |	
 / ___ \| | | | (_) | |_| | | |  __/ |    | |_| | | | (_) | | (_| |	
/_/   \_\_| |_|\___/ \__|_| |_|\___|_|    |____/|_|  \___/|_|\__,_|	
                                                                bbs
  XQTRs lair...
Home // Blog // NULL emag. // Files // Docs // Tutors // GitHub repo
        __  _                        __ _                           _  __
  ______\ \_\\_______________________\///__________________________//_/ /______
  \___\                                                                   /___/
   | .__                                 __                                  |
   | |                   ___  __________/  |________                         |
   |                     \  \/  / ____/\   __\_  __ \                        |
   ;                      >    < <_|  | |  |  |  | \/                        ;
   :                     /__/\_ \__   | |__|  |__|                           :
   .                           \/  |__|                                      .
   .                                                                         .
   :           H/Q Another Droid BBS - andr01d.zapto.org:9999                :
   ;                                                                         ;
   + --- --  -   .     -        ---    ---    ---        -     .    - -- --- +
   :                                                                         :
   |                     Write Pipes With Pascal In Pi                       |
   :                                                                         :
   ` --- --  -   .     -        ---    ---    ---        -     .    - -- --- '
   
   Actually, not only in Pi... but it rimes better :p
   
   So... PIPES are codes that are used in BBSes to change color in text. You
   probably have seen them. Usually are something like this |07. The symbol in
   front (the pipe) defines that the next two numbers are a color. To change
   the foreground color we use numbers from 00 to 15 and for the background
   from 16 to 23... but why?
   
   In Pascal the color of the text is defined by a variable, which is called
   TextAttr. The size of this attribute is one byte, so it can take values
   from 0 to 255. To represent foreground and background color, we use this
   formula: 
                  TextAttr := Foreground + (Background * 16)
                  
    Where Foreground is 0 to 15 and Background from 0 to 7. But in pipe codes
    we use the values 16 to 23 for the background color, cause the first 16 
    values are taken and we can't use again 0 to 7. So we continue counting 
    from 16. 
    
    +---------------------- FG ---------------------+---------- BG ---------+
    00 01 02 03 04 05 06 07 08 09 10 11 12 13 14 15 | 16 17 18 19 20 21 22 23
    
    In a Pipe code to take the actual background value we calculate it like
    this:
    
                        Background = BG Pipe Code - 16
                        
    So, |23 is 23 - 16 = 7, which is actually white/grey in Pascal.
    
    Sometimes, the pipe symbol is used for ASCII graphics, so if we translate
    it every time we encounter it, as a pipe code, we may garble the text. We
    must be sure that after the pipe symbol, two digits are following, else we
    print the pipe as it is. 
    
    This is the theory... lets code...

    Program writepipe;
    {$MODE objfpc}  // Use FreePascal format
    {$H-}           // We don't want extended strings
    Uses Crt;

    We will use our own String to Integer conversion, because we must know if
    an error occurred while converting. If there is an error, then we know, 
    that we didn't process a valid color number and we have to print the text
    instead of converting it in a color value.
    
    Function S2I(N:String):Smallint;
    Var
      I,Code:Word;
    Begin
      Result := -1;          // Set default value for function
      Val (N,I,Code);
      If Code<>0 Then Exit;  // Is Everything OK? if not exit.
      Result:=I;             // If it's OK then our result is a color number
    End;


    Now... this is the sweet part.
   
    
                           +--+-- Really? i have to explain this?
                           |  |
                           |  |  +-- Default color to use
                           |  |  |  
                           |  |  |     +-- TextAttr valid value
                           |  |  |     |
                           |  |  |     |     + Our text with pipe codes
                           |  |  |     |     |
    Procedure WriteXYPipe (X, Y, Attr: Byte; Text: String);
    Const
      Seth = '|';   // We could also use any other symbol we want ex. '
    Var
      Count   : Byte;        // Variable to know the position we are in the 
                             // text
      Code    : String[2];   // Color values as text
      CodeNum : Smallint;    // Our color value from the pipe code
      OldAttr : Byte;       -\
      OldX    : Byte;         > Values to restore color and cursor position
      OldY    : Byte;       -/
    Begin
      OldAttr := TextAttr;
      OldX    := WhereX;
      OldY    := WhereY;

      GotoXY (X, Y);        // Go to new position
      TextAttr:=Attr;       // Save old attribute

      Count := 1;           // Start in the beginning of the text

      While Count <= Length(Text) Do Begin    // While we are processing the
                                              // text, check for colors
        If Text[Count] = Seth Then Begin      // We found a pipe color?
          Code    := Copy(Text, Count + 1, 2);  // Get two characters in front
          CodeNum := S2I(Code);               // Convert them to integer num.
          if CodeNum<0 Then Begin             // If the conversion fails, then
                                              // this wasn't actually a pipe
                                              // code, so write the char
                                              // instead of processing it.
            Write(Text[Count]);
            Count+=1;
          End;
          If (CodeNum>0) Or (Code='00') Then Begin
                                   // We actually got a pipe code!
            Count+=3;              // Increase the counter by three cause
                                   // pipes are |23 ;)
            If CodeNum in [00..15] Then   // Is the color code from 0 to 15?
                                          // then we have to change the 
                                          // foreground color.
              
              // We only need to change the foreground color, so we need to 
              // know, what is the currect background color. To do that, we
              // divide the current TextAttr by 16 and then multiple the
              // result again with 16. This way, we get the value for the
              // background only! After, we just add, the number for the 
              // foreground color.
              
                             +-- Foreground Color
                             |
                             |               +-- Get the old value and 
              //             |               |   re-apply it
              TextAttr := CodeNum + (TextAttr Div 16) * 16
            Else
            
            // If our pipe color is between 16 and 23, then we change the 
            // background color, but we have to keep the same foreground
            // color. To extract foreground color from the textattr variable
            // we mod it... we want the modulus of the division TextAttr / 16
            
            // As we said earlier, the background value is from 0 to 7, so to 
            // convert our background pipe color (16 to 23) we just sub 16 and
            // then multiple by 16
            
                                 +-- Current Foreground Color
                                 |
                                 |                   +-- Background Value
                                 |                   |          
              TextAttr :=((TextAttr Mod 16) + (CodeNum - 16) * 16);
          End;
        End Else Begin  // No pipe code, so we print the character and move on
          Write(Text[Count]);
          Count+=1;
        End;
        
      End;
      TextAttr:=OldAttr;   // At the end, restore old color and position
      GotoXY (OldX, OldY);
    End;

    Begin
      ClrScr;
      WriteXYPipe(10,5,7,'|Hello| |15|17World |1this is '+
      '|08|03write|11XY|06|23Pipe');
      
      
      For f:=0 to 7 Do
        For b:=0 to 7 Do
          WriteXYPipe(10+f*8,8+b,7,'|'+I2S(f)+'|'+I2S(b+16)+'TEXT ');
          
    End.
    
    
   + --- --  -   .     -        ---    ---    ---        -     .    - -- --- '
      Complete Program
   + --- --  -   .     -        ---    ---    ---        -     .    - -- --- '
    
    Program writepipe;
    {$MODE objfpc}  // Use FreePascal format
    {$H-}           // We don't want extended strings
    Uses Crt;
    
    Var
      f,b:Byte;
      
    Function I2S (N: LongInt): String;
    Var
      T : String;
    Begin
      Str(N, T);
      If Length(T)=1 Then T:='0'+T;
      Result := T;
    End;

    Function S2I(N:String):Smallint;
    Var
      I,Code:Word;
    Begin
      Result := -1;
      Val (N,I,Code);
      If Code<>0 Then Exit;
      Result:=I;
    End;

    Procedure WriteXYPipe (X, Y, Attr: Byte; Text: String);
    Const
      Seth = '|';
    Var
      Count   : Byte;
      Code    : String[2];
      CodeNum : Smallint;
      OldAttr : Byte;
      OldX    : Byte;
      OldY    : Byte;
    Begin
      OldAttr := TextAttr;
      OldX    := WhereX;
      OldY    := WhereY;

      GotoXY (X, Y);
      TextAttr:=Attr;

      Count := 1;

      While Count <= Length(Text) Do Begin
        If Text[Count] = Seth Then Begin
          Code    := Copy(Text, Count + 1, 2);
          CodeNum := S2I(Code);
          if CodeNum<0 Then Begin
            Write(Text[Count]);
            Count+=1;
          End;
          If (CodeNum>0) Or (Code='00') Then Begin
            Count+=3;
            If CodeNum in [00..15] Then
              TextAttr := CodeNum + (TextAttr Div 16) * 16
            Else
              TextAttr :=((TextAttr Mod 16) + (CodeNum - 16) * 16);
          End;
        End Else Begin
          Write(Text[Count]);
          Count+=1;
        End;
        
      End;
      TextAttr:=OldAttr;
      GotoXY (OldX, OldY);
    End;

    Begin
      ClrScr;
      WriteXYPipe(10,5,7,'|Hello| |15|17World |1this is '+
      '|08|03write|11XY|06|23Pipe');
      
      
      For f:=0 to 7 Do
        For b:=0 to 7 Do
          WriteXYPipe(10+f*8,8+b,7,'|'+I2S(f)+'|'+I2S(b+16)+'TEXT ');
          
    End.
    
   + --- --  -   .     -        ---    ---    ---        -     .    - -- --- '
         _____         _   _              ____          _   _ 
        |  _  |___ ___| |_| |_ ___ ___   |    \ ___ ___|_|_| |        8888
        |     |   | . |  _|   | -_|  _|  |  |  |  _| . | | . |     8 888888 8
        |__|__|_|_|___|_| |_|_|___|_|    |____/|_| |___|_|___|     8888888888
                                                                   8888888888
                DoNt Be aNoTHeR DrOiD fOR tHe SySteM               88 8888 88
                                                                   8888888888
 /: HaM RaDiO   /: ANSi ARt!     /: MySTiC MoDS   /: DooRS         '88||||88'
 /: NeWS        /: WeATheR       /: FiLEs         /: SPooKNet       ''8888"'
 /: GaMeS       /: TeXtFiLeS     /: PrEPardNeSS   /: FsxNet            88
 /: TuTors      /: bOOkS/PdFs    /: SuRVaViLiSM   /: ArakNet    8 8 88888888888
                                                              888 8888][][][888
   TeLNeT : andr01d.zapto.org:9999 [UTC 11:00 - 20:00]          8 888888##88888
   SySoP  : xqtr                   eMAiL: xqtr@gmx.com          8 8888.####.888
   DoNaTe : https://paypal.me/xqtr                              8 8888##88##888