Footnotesupport include

From 40tude Dialog Wiki

Contents

Footnote-Support (Include-File)

The following script brings footnote-support into 40tude Dialog. This enhanced version of the script corrects many bugs and brings up a lot of new features. Its based on a early version from Mirko D. Walter (mwalter@2via.de) and currently was modified by homas Barghahn.


Little docu

Please read this extensive documentation for more details on making footnotes.

In short:
Enter the following text inside your editor window:

This is a test #fn# With a very stupid footnote.## with blank.
This is another test#fn# With a very intelligent footnote.## without blank.

And you will get this output:

This is a test [1] with blank.
This is another test[2] without blank.

Footnotes:
==========
[1] With a very stupid footnote.
[2] With a very intelligent footnote.

Specials


Questions, Bugs & Comments

If you have questions, comments or found a bug please post to de.comm.software.40tude-dialog.


Install & Setup the script

Please note that this script is an include-file!. You have to copy the following script inside a new custom script (for example "Footnote_include") and safe it. Please don't compile this custom script! After that you have to add the following lines to your OnBeforeSending-Script:

{$I Footnote_include.ds}

and

result := doFootNoteNew ( Message );

This may look like this:

program OnBeforeSendingMessage;
{$I Footnote_include.ds}

function OnBeforeSendingMessage(var Message: TStringlist; Servername: string; IsEmail: boolean):boolean;
begin
  result:=true;

  result := doFootNoteNew ( Message );

  //possibly some other calls to scripts

end;

begin
end.

Just compile this OnBeforeSending-Script now to get your include-file to work. The setup of the script is shown inside the script. Please take a look at this to customize the script to your own fits. Please note that whenever you reconfigure the footnote custom script, you have to recompile the OnBeforeSending-Script to apply the changes.


Setup in the script:
If you want to change the setup for the footnotes, you have to edit the lines below inside the script.

//
// Configuration Options:
//
// Set this to true, if you want a footnote-header like this:
//
// Footnotes:
// ==========
ConstFootnoteHead = true;

// Define the text, you want to see in your footnote-header.
ConstFootnoteHeadTxt = 'Footnotes:';

// Here you can define the character which one should underline the
// footnote-header.  If there should be no underline, just set
// "ConstFootnoteHeadUnderline = '';" (without double quotes).
ConstFootnoteHeadUnderline = '=';

// If there should be a blank line between footnote-header and
// footnotes, set this to true.  Otherwhise (false) there will be
// no empty line between them.
ConstEmptyLine = false;

// Defines start tag for footnote recognition.
// Everything after that (and between end tag) is recogniced as footnote.
ConstStartupFootnote = '#fn#';

// Defines end tag of footnote recognation.
// Please be sure to use chars, you will not put in normal (footnote) text.
ConstEndFootnote = '##';

// For longer footnotes its important to reformat their line length.
// The number below is the column number where the line break will
// occur at the latest (should always be 1 char more than inside Dialog;
// You will find this option in Settings -> General settings ... ->
// Posting -> Wrap lines after xx chars)
ConstReWrapEdge = 73;

// Defines a control character which expands to a blank line in the
// footnote.  Change it as you like - but be aware:  same warning as
// for the ConstEndFootnote applies.
ConstMultiLine = '%%';

// Defines char(s) until this the paragraph will be reformatted by the
// footnote-logic.  Its very important to put this at the end of your
// footnote (or at least at the end of the text to be boxquoted) if you
// want to use footnotes inside boxquotes!
ConstRewrapToLine = '<<';

// Useful if you want to talk about this footnote-skript inside 40tude
// Dialog:  Just comment them out.  Note that the comment-chars will not
// be deleted in the article.
ConstComments = '//';

// By default this script adds a blank line before the footnote block.
// Set this to false if you don't want the blank line.
ConstEmptyLineBeforeFootnote = true;

The Script

//
// program Footnotes   -   Date: 2004/11/05
//

procedure Init_doFootNoteNew ( var ConstFootnoteHead            : boolean;
                               var ConstFootnoteHeadTxt         : String;
                               var ConstFootnoteHeadUnderline   : String;
                               var ConstEmptyLine               : Boolean;
                               var ConstEmptyLineBeforeFootnote : Boolean;
                               var ConstStartupFootnote         : String;
                               var ConstEndFootnote             : String;
                               var ConstReWrapEdge              : Integer;
                               var ConstMultiLine               : String;
                               var ConstRewrapToLine            : String;
                               var ConstComments                : String
);

begin

//  ----------------------------------------------------
//  Configuration settings
//  ----------------------------------------------------

   // Footnote-Support:
   //    configure your settings here:
   //
   // Set this to true, if you want a footnote-header like this:
   // Footnotes:
   // ==========
   ConstFootnoteHead := true;

   // Define the text, you want to see in your footnote-header.
   ConstFootnoteHeadTxt := 'Footnotes:';

   // Here you can define the character which should underline the
   // footnote-header. If there should be no underline, just set
   // "ConstFootnoteHeadUnderline = '';" (without double quotes).
   ConstFootnoteHeadUnderline := '=';

   // If there should be a blank line between footnote-header
   // and footnotes,set this to "true". Otherwhise (false) there
   // is no empty line between.
   ConstEmptyLine := false;

   // By default this script adds a blank line before the footnote block.
   // Set this to false if you do not want the blank line.
   ConstEmptyLineBeforeFootnote := true;

   // Defines start-tag for footnote recognition.
   // Everything after that (and between end-tag) is recogniced as footnote.
   ConstStartupFootnote := '#fn#';

   // Defines end-tag of footnote recognation.
   // Please use chars, you normaly not type inside your text.
   ConstEndFootnote := '##';

   // For longer footnotes its important to reformat the footnote.
   // This number defines the column-number (should always be 1 char higher
   // than inside Dialog). You will find this option in Settings -> General
   // settings... -> Posting -> Wrap lines after xx chars
   ConstReWrapEdge := 73;

   // Defines a control character to expand the footnote to a blank line.
   // Change it as your own wish.
   ConstMultiLine := '%%';

   // Define char(s) till which the paragraph will be reformated by the
   // footnote-logic. Its very important if you want to use footnotes
   // inside boxquotes, to put this at the end of your footnote!
   ConstRewrapToLine := '<<';

   // Useful if you want to talk about this footnote-skript inside 40tude
   // Dialog, just comment them out. Note that the comment-chars will not
   // be deleted in the article.
   ConstComments := '//';



//  ----------------------------------------------------
//  End of configuration settings
//  ---------------------------------------------------- 

end;   
   
   // --------------------------------------------------------------- //
   // ----  No user maintainable parts below this line -------------- //
   // --------------------------------------------------------------- //
   
   //
   // Flags to indicate the buttons contained in the message box:
   //

   // MB_OK = 0;                          // 1 button:  OK.
   // MB_OKCancel = 1;                    // 2 buttons: OK and Cancel.
   // MB_AbortRetryIgnore = 2;            // 3 buttons: Abort, Retry, and Ignore.
   // MB_VbYesNoCancel = 3;               // 3 buttons: Yes, No, and Cancel.
   // MB_YesNo = 4;                       // 2 buttons: Yes and No.
   // MB_RetryCancel = 5;                 // 2 buttons: Retry and Cancel.

   //
   // Flags to display an icon in the message box:
   //

   // MB_IconCritical = 16;               // stop sign
   // MB_IconQuestion = 32;               // question mark
   // MB_IconExclamation = 48;            // exclamation point 
   // MB_IconInformation = 64;            // lowercase i in a circle
   

function MessageBox( hWnd : Cardinal; lpText, lpCaption : PChar; uType : longword ) : Integer;
   external 'MessageBoxA@user32.dll stdcall';


function GetText(
   var Txt         : TStringlist;
   var FoundLine   : Integer;
   var FoundPosi   : Integer;
   var CurrLine    : Integer;
   var CurrPosi    : Integer;
   var ConstMultiL : String   
) : String;                               // Function by Mirko D. Walter

var
   res    : String;
   i      : Integer;
   bposi  : Integer;
   MaxInt : Integer;
begin
   MaxInt := 2147483647;
   result :='';
   res := '';
   if FoundLine = CurrLine then begin
      res := Copy( txt.strings[foundline], FoundPosi, CurrPosi - FoundPosi );
   end
   else begin
      BPosi := FoundPosi;
      for i := FoundLine to CurrLine do begin
         if i < CurrLine then begin
            res := Res + Trim( Copy(txt.strings[i], BPosi, MaxInt) ) + ' ';
            BPosi := 0;
         end
         else begin
            res := res + Copy( txt.strings[i], 1, CurrPosi-1 );
         end;
      end;
   end;
   //
   // Multine-Special-Character?
   //
   BPosi := AnsiPos( ConstMultiL, res );
   if BPosi > 0 then begin
      repeat
         //
         // if the following characters are #13#10
         // then do no linebreak, simply remove
         //    1234567890123
         //    ABCDEF%%gaga#
         //
         if Copy( res, BPosi + Length(ConstMultiL), 2 ) = #13#10
            then res := Copy( res, 1, BPosi - 1 )
                        + #13#10
                        + Trim( Copy(res, BPosi + Length(ConstMultiL), MaxInt) )
            else res := Copy( res, 1, BPosi - 1 )
                        + #13#10
                        + #13#10
                        + Trim( Copy(res, BPosi + Length(ConstMultiL), MaxInt) );
         BPosi := AnsiPos( ConstMultiL, res );
      until BPosi <= 0;
      res := Trim( res );
   end;
   result := Trim( res );
end;  // function GetText()


function Rewrap_Str(
       StrL        : String;
       WEdge       : Integer;
       FootNote    : Boolean;
       ConstRewrap : String   
) : String;

var
   Space_Old  : Integer;
   Space_New  : Integer;
   i          : Integer;
   Space_Pos  : Integer;
   Break_L    : Boolean;

begin
   Space_Old := 1;
   Space_New := 1;
   Space_Pos := WEdge;
   if Copy( StrL, Length(StrL), 1 ) <> ' '
      then StrL := StrL + ' ';
   if AnsiPos( ConstRewrap, StrL ) > 0
      then Delete( StrL, AnsiPos(ConstRewrap, StrL), 2 );
   for i:=1 to Length( StrL ) do begin
      if (StrL[i] = ' ') and (i > 1) and (i < Length(StrL)) then begin
         if StrL[i+1] = ' ' then begin    // found double blank
            if     (StrL[i-1] <> '.')        // it's perfectly fine to
               and (StrL[i-1] <> '?')        // have double blanks after
               and (StrL[i-1] <> '!')        // punctuation marks (at
               and (StrL[i-1] <> ':')        // least beyond sentence
               and (StrL[i-1] <> ';')        // delimiters).
            then begin                    // but otherwise not!
               Delete( StrL, i, 1 );
            end;
         end;
      end;
   end;
   i := 0;
   while i <= Length( StrL ) do begin
      i := i + 1;
      if    (Copy(StrL, i, 1) = ' ')
         or (Copy(StrL, i, 4) = (#13#10 + #13#10))
      then begin
         Break_L   := false;
         Space_Old := Space_New;
         Space_New := i;
         if Copy( StrL, i , 4 ) = (#13#10 + #13#10) then begin
            Insert( '    ', StrL, i + 4 );
            Break_L := true;
            if Space_New < Space_Pos then begin
               Space_Pos := i + 4 + WEdge;
               Space_Old := i + 4;
               Space_New := i + 4;
               i := i + 4;
            end;
         end;
         if     (Space_New >= Space_Pos)
            and (Space_old <= Space_Pos)
         then begin
            if     (Space_New = Space_Pos)
               and (Length(StrL) > Space_Pos)
            then begin
               if Footnote = false then begin
                  Delete( StrL, Space_New, 1 );
                  Insert( #13#10, StrL, Space_New );
                  Space_Pos := Space_New + WEdge + 1;
               end
               else begin
                  Insert( #13#10 + '   ', StrL, Space_New );
                  if Break_L then begin
                     Space_Pos := i + 4 + WEdge;
                     Space_Old := i + 4;
                     Space_New := i + 4;
                     i := i + 4;
                  end
                  else Space_Pos := Space_New + WEdge + 1;
                  i := i + 3;
               end;
            end
            else begin
               if Footnote = false then begin
                  if Length( StrL ) > Space_Pos then begin
                     Delete( StrL, Space_Old, 1 );
                     Insert( #13#10, StrL, Space_Old );
                  end;
                  Space_Pos := Space_Old + WEdge + 1;
                  if     (Space_New >= Space_Pos)
                     and (Length(StrL) > Space_Pos)
                  then begin
                     Delete( StrL, Space_New + 1, 1 );
                     Insert( #13#10, StrL, Space_New + 1 );
                     Space_Pos := Space_New + WEdge + 2;
                     i := i + 1;
                  end;
               end
               else begin
                  if Space_Old > 5 then begin
                     if Length( StrL ) > Space_Pos
                        then Insert( #13#10 + '   ', StrL, Space_Old );
                     if Break_L then begin
                        Space_Pos := i + 4 + WEdge;
                        Space_Old := i + 4;
                        Space_New := i + 4;
                        i := i + 4;
                     end
                     else begin
                        Space_Pos := Space_Old + WEdge + 1;
                        if Space_New >= Space_Pos then begin
                           Insert( #13#10 + '   ', StrL, Space_New + 5 );
                           Space_Pos := Space_New + WEdge + 6;
                        end;
                     end;
                     i := i + 3;
                  end
                  else begin
                     Insert( #13#10 + '   ', StrL, Space_New );
                     Space_Pos := Space_New + WEdge + 1;
                     i := i + 3;
                  end;
               end;
            end;
            i := i + 1;
         end;
      end;
   end;  // while
   result := TrimRight( StrL );
end;  // function Rewrap_Str()


function doFootNoteNew(
   var Message : TStringlist
) : Boolean;                    // is message ok?

var
   ConstFootnoteHead            : boolean;
   ConstFootnoteHeadTxt         : String;
   ConstFootnoteHeadUnderline   : String;
   ConstEmptyLine               : boolean;
   ConstEmptyLineBeforeFootnote : Boolean;
   ConstStartupFootnote         : String;
   ConstEndFootnote             : String;
   ConstReWrapEdge              : Integer;
   ConstMultiLine               : String;
   ConstRewrapToLine            : String;
   ConstComments                : String;
   i                            : Integer;
   Posi                         : Integer;
   Mult_Posi                    : Integer;
   FoundLine                    : Integer;
   FoundPosi                    : Integer;
   OLength                      : Integer;
   RFoundPosi                   : Integer;
   Rest                         : String;
   FN_Temp                      : String;
   FN                           : String;
   FNR                          : Integer;
   Skip                         : Boolean;
   Sig                          : Boolean;
   txt2                         : String;
   txt3                         : String;
   Temp_Str                     : String;
   Add_txt3                     : Boolean;
   FootnoteStr                  : String;
   zw                           : Integer;
   MB_OK                        : LongWord;
   MB_IconExclamation           : LongWord;
   MaxInt                       : Integer;

begin
   Init_doFootNoteNew ( ConstFootnoteHead, ConstFootnoteHeadTxt, ConstFootnoteHeadUnderline,
                        ConstEmptyLine, ConstEmptyLineBeforeFootnote, ConstStartupFootnote, 
                        ConstEndFootnote, ConstReWrapEdge, ConstMultiLine, ConstRewrapToLine, 
                        ConstComments );
   result := false;
   if ConstFootnoteHead then begin
      if Length( ConstFootnoteHeadUnderline ) = 1 then begin
         for i := 1 to Length( ConstFootnoteHeadTxt ) do begin
            FootnoteStr := FootnoteStr + ConstFootnoteHeadUnderline;
         end;
      end
      else FootnoteStr := '';
   end
   else FootnoteStr := '';

   i                  := -1;
   posi               := -1;
   foundposi          := -1;
   rest               := '';
   fn                 := '';
   sig                := false;
   fnr                := 0;
   txt2               := '';
   txt3               := '';
   Mult_Posi          := -1;
   Add_Txt3           := false;
   FN_Temp            := '';
   Temp_Str           := '';
   MB_OK              := 0;
   MB_IconExclamation := 48;
   MaxInt             := 2147483647;
   while (i <= message.count-1) and (sig = false) do begin
      if Rest = '' then begin
         i := i + 1;
         // ignore quotes and empty lines
         Skip := true;
         while Skip and (i <= message.count - 1) do begin
            Skip := false;
            if Sig then begin
               txt2 := txt2 + message.strings[i] + #13#10;
               i := i + 1;
               Skip := true;
            end
            else begin
               if Length( message.strings[i] ) > 0 then begin
                  if Copy( message.strings[i], 1, 1 ) = '>' then begin
                     txt2 := txt2 + message.strings[i] + #13#10;
                     i := i + 1;
                     Skip := true;
                  end;
                  if Length( message.strings[i] ) > 2 then begin
                     if Copy( message.strings[i], 1, 3 ) = '-- ' then begin
                        if Length( FN ) > 0 then begin
                           WriteToLog('FN: >' + FN + '<', 7);
                           if ConstEmptyLineBeforeFootnote = true then begin
                              txt2 := txt2 + #13#10 + FN;
                           end
                           else begin
                              txt2 := txt2 + FN;
                           end;
                        end;
                        Sig := true;
                        Skip := true;
                     end;
                  end;
               end
               else begin
                  txt2 := txt2 + message.strings[i] + #13#10;
                  i := i + 1;
                  Skip := true;
               end;
            end;
         end;
         if i > message.count-1 then break;           // fix added by MM (Oct. 30th, 2003)
         Rest := message.strings[i];
         OLength := Length(Rest);
      end;
      if not Sig then begin
         if FoundPosi > 0 then begin
            Posi := AnsiPos( ConstEndFootNote, Rest );
            if Posi > 0 then begin
               Mult_Posi := AnsiPos( ConstStartupFootnote, Rest );
               if (i + 1) = message.count
                  then Temp_Str := ''
                  else Temp_Str := message.strings[i + 1];
               if    (AnsiPos(ConstRewrapToLine, Rest) > 0)
                  or (Temp_Str = '')
                  or (Temp_Str = '-- ')
               then begin
                  Add_Txt3 := false;
                  if Mult_Posi = 0 then begin
                     if AnsiPos( ConstRewrapToLine, Rest ) > 0
                        then txt3 := txt3
                                     + Copy( Rest, posi+Length(ConstEndFootnote),
                                             AnsiPos(ConstRewrapToLine, Rest)+1 )
                        else txt3 := txt3
                                     + Copy( Rest, posi+Length(ConstEndFootnote), MaxInt );
                  end;
               end
               else Add_Txt3 := true;
               zw := posi + olength - Length( rest );
               FN_Temp := '[' + IntToStr(FNR) + '] '
                          + GetText( message, FoundLine, FoundPosi, i, zw, ConstMultiLine);
               FN_Temp := Rewrap_Str( FN_Temp, ConstReWrapEdge, true, ConstRewrapToLine );
               if     (FN = '')
                  and (FN_Temp <> '')
                  and (ConstFootnoteHead = true)
               then begin
                  if FootnoteStr <> ''
                     then FN := ConstFootnoteHeadTxt + #13#10 + FootnoteStr + #13#10
                     else FN := ConstFootnoteHeadTxt + #13#10;
                  if ConstEmptyLine = true then FN := FN + #13#10;
               end;
               FN := FN + FN_Temp + #13#10;
               // FN := FN
               //       + '[' + IntToStr(FNR) + '] '
               //       + GetText(message, FoundLine, FoundPosi, i, zw) + #13#10;
               Rest := Copy( Rest,posi+Length(ConstEndFootnote), MaxInt );
               If Rest = '' then Rest := ' '; //08.10.2004  !!
               FoundPosi := -1;
               Mult_Posi := -1;
            end
            else begin
               Rest:='';
            end;
         end
         else begin
            // WriteToLog('R: ' + Rest, 7);
            // 1. char = #, ignore this, could be a control character
            if Copy( Rest + ' ', 1, Length(ConstComments) ) <> ConstComments then begin
               Posi := AnsiPos(ConstStartupFootnote, Rest);
               if Posi > 0 then begin
                  // WriteToLog('FN: ' + IntToStr(Posi), 7);
                  RFoundPosi := Posi + Length( ConstStartupFootnote );
                  FoundPosi := RFoundPosi + OLength - Length( Rest );
                  FoundLine := i;
                  FNR := FNR + 1;
                  // txt2 := txt2 + Copy( Rest, 1, Posi - 1 ) + '[' + IntToStr(FNR) + ']';
                  txt3 := txt3 + Copy( Rest, 1, Posi - 1 ) + '[' + IntToStr(FNR) + ']';
                  Rest := Copy( Rest, RFoundPosi, MaxInt );     // 08.10.2004 Trim entfernt
               end
               else begin
                  if FoundPosi = -1 then begin
                     if Add_Txt3 then txt3 := txt3 + Rest + ' ';
                     if (i + 1) = message.count
                         then Temp_Str := ''
                         else Temp_Str := message.strings[i + 1];
                     if     (   (AnsiPos(ConstRewrapToLine, Rest) > 0)
                             or (Temp_Str = '') or (Temp_Str = '-- '))
                        and (txt3 <> '')
                     then begin
                        Add_Txt3 := false;
                        txt3 := Rewrap_Str( txt3, ConstReWrapEdge, false, ConstRewrapToLine );
                        txt2 := txt2 + txt3;
                        txt3 := '';
                        Rest := '';
                     end;
                     if Add_Txt3 = false then txt2 := txt2 + Rest + #13#10;
                     Rest := '';
                  end;
               end;
            end
            else begin
               txt2 := txt2 + Rest + #13#10;
               Rest := '';
            end;
         end;
      end;
   end;
   if txt3 = '' then begin
      result := true;
      if Sig = false then begin
         if Length( FN ) > 0 then begin
            message.text := txt2 + #13#10 + FN;
         end;
      end
      else message.text := txt2;
   end
   else begin
      message.text  := message.text;
      result := false;
      MessageBox( 0, 'End-Tag ''' + ConstEndFootnote + ''' of footnote not found!',
                  'Abort sending!', MB_OK or MB_IconExclamation );
   end;
end;  // function doFootNoteNew()

René Fischer