_                _   _                 ____            _     _ 	
   / \   _ __   ___ | |_| |__   ___ _ __  |  _ \ _ __ ___ (_) __| |	
  / _ \ | '_ \ / _ \| __| '_ \ / _ \ '__| | | | | '__/ _ \| |/ _\` |	
 / ___ \| | | | (_) | |_| | | |  __/ |    | |_| | | | (_) | | (_| |	
/_/   \_\_| |_|\___/ \__|_| |_|\___|_|    |____/|_|  \___/|_|\__,_|	
                                                                bbs
  XQTRs lair...
Home // Blog // NULL emag. // Files // Docs // Tutors // GitHub repo

                                                                                
                                                                                
    below is a complete oneliner editor for mystic bbs, default oneliner.       
    you are able to edit, delete, add oneliners as you wish, but this script    
    is here, more to learn some stuff about MPL. so lets take the script        
    line by line and so some explaining. at the end you can copy/paste the      
    entire script.                                                              
                                                                                
                                                                                
    this command gives us access to some very useful variables. in our case     
    the cfgdatapath, which contains the path to the mystic data directory.      
                                                                                
Uses cfg;                                                                       
                                                                                
    this is the format/record/structure of each liner inside the oneliners.dat  
    file. we need this to be able to read/write oneliners.                      
                                                                                
Type OneLineRec = Record                                                        
    Text : String[79];                                                          
    From : String[30];                                                          
  End;                                                                          
                                                                                
    this is procedure to turn a mystic box code into something we can use       
    more easy.                                                                  
                                                                                
Procedure XWindow(H1:String;T,X1,Y1,X2,Y2:Integer);                             
Var T1,A1,A2,B1,B2  : String;                                                   
Begin                                                                           
  A1 := Int2Str(X1);                                                            
        A2:=Int2Str(X2);                                                        
        B1:=Int2Str(Y1);                                                        
        B2:=Int2Str(Y2);                                                        
        T1:=Int2Str(T);                                                         
        Write('|#X#'+T1+'#'+H1+'#'+A1+'#'+B1+'#'+A2+'#'+B2+'#');                
End;                                                                            
                                                                                
    with this procedure we create a yes/no box, that also restores the screen,  
    when it's closed. we use it to take yes/no replies from the user. it        
    uses the class system of mystic bbs to display the box. we could also use   
    the above procedure to just display a box.                                  
                                                                                
function yesnobox(title:string):boolean;                                        
var                                                                             
  bb:longint;                                                                   
begin                                                                           
  ClassCreate (bb, 'box');                                                      
  BoxOptions (bb, 1, true, 8, 8, 7, 15, false, 112);                            
  BoxOpen (bb, 27, 8, 47, 12);                                                  
  writexypipe(29,8,7,MCILength(title),title);                                   
  gotoxy(33,10);                                                                
  yesnobox:= inputyn('')                                                        
  BoxClose  (bb);                                                               
  ClassFree (bb);                                                               
end;                                                                            
                                                                                
                                                                                
    this is how we save all the oneliner records, stored in an array of 10      
    records (lines[]). the function, makes a backup copy of the original file,  
    rewrites a new one and saves all records, until it finds an empty one. if   
    we found an empty, we stop saving the rest records, so we don't save        
    any blank/empty records.                                                    
                                                                                
procedure savelines;                                                            
var                                                                             
  k:byte;                                                                       
  f:file;                                                                       
begin                                                                           
  filecopy(oneliner,oneliner+'.1lb');  // copy backup file                      
  fassign(f,oneliner,66);              // assign file to a variable             
  frewrite(f);                         // rewrite it                            
  k:=1;                                                                         
  while k<11 and lines[k].from<>'' do begin  // while we have records, save     
    fwrite(f,lines[k],sizeof(ll));                                              
    k:=k+1;                                                                     
  end;                                                                          
  fclose(f);                           // close the file                        
  changed:=false;                                                               
end;                                                                            
                                                                                
                                                                                
    here we just reading the file, into an array of 10 records. first we fill   
    the array with empty strings to initialize it, then we open the file and    
    read it until the end of it. this way, if a oneliner.dat file has less      
    than 10 records, we are sure, that the rest of the array, is initialized    
    with empty spaces (#0) and if the user will save the file, it will stop     
    saving in the first empty record.                                           
                                                                                
procedure loadoneliner;                                                         
var                                                                             
  f : file;                                                                     
  ol:onelinerec;                                                                
  i:byte;                                                                       
begin                                                                           
  for i:=1 to 10 do                                                             
    fillchar(lines[i],sizeof(ol),#0);  // fill the array with #0 chars          
  fassign(f,oneliner,66);              // assign file to variable               
  freset(f);                           // open for reading                      
  i:=0;                                                                         
  while not feof(f) do begin           // while we are not in the end of file   
                                       // read records.                         
    i:=i+1;                                                                     
    fillchar(ol,sizeof(ol),#0);                                                 
    fread(f,ol,sizeof(ol))                                                      
    lines[i]:=ol;                                                               
  end;                                                                          
  fclose(f);                           // close the file... always!             
end;                                                                            
                                                                                
                                                                                
    below is our main function, that displays the info and waits for the user   
    to press a key. this is the same logic, for a lightbar menu. it's the       
    same thing here. the logic is... display all 10 records, with the           
    "unselected" color and after draw the record, that is selected, with a      
    more intense ("selected") color. to know which record is selected, we       
    store it's index number in a variable (sel)                                 
                                                                                
procedure select;                                                               
var                                                                             
  sel : byte = 1;                                                               
  done : boolean = false;                                                       
  c : char;                                                                     
                                                                                
  procedure listlines;   // display all records!                                
  var                                                                           
    i:byte;                                                                     
    cl:byte;                                                                    
  begin                                                                         
    for i := 0 to 9 do begin                                                    
      writexypipe(1,3+(i*2),7,79,lines[i+1].from)                               
      writexypipe(1,3+(i*2)+1,7,79,lines[i+1].text)                             
    end;                                                                        
  end;                                                                          
                                                                                
  procedure showsel;  // display the selected one                               
  begin                                                                         
    textcolor(14+16);                                                           
    gotoxy(1,3+((sel-1)*2));                                                    
    writeraw(padrt(lines[sel].from,79,' '));                                    
    gotoxy(1,3+((sel-1)*2)+1)                                                   
    writeraw(padrt(lines[sel].text,79,' '));                                    
  end;                                                                          
                                                                                
                                                                                
    to delete a record, i chose this method... move all records below the       
    selected one, one place up and fill the last one with empty chars. this     
    way, the selected record is delete (actually filled, with info from the     
    record below) and the empty record, that will appear at the end, we fill    
    it with space.                                                              
                                                                                
  procedure deleterec;                                                          
  var                                                                           
    j:byte;                                                                     
  begin                                                                         
    // if the user said NO, we exit the procedure                               
    if yesnobox(' |14Delete record?  ') = false then exit;                      
    for j:=sel to 9 do begin                                                    
      lines[j]:=lines[j+1]   // move next record to the previous one            
    end;                                                                        
    fillchar(lines[10],sizeof(ll),#0);  // fill record with empty chars.        
    changed:=true;                                                              
  end;                                                                          
                                                                                
                                                                                
    to clear all lines, we just fill all records with #0.                       
                                                                                
  procedure clearall;                                                           
  var                                                                           
    k:byte;                                                                     
  begin                                                                         
    for k:=1 to 10 do fillchar(lines[k],sizeof(ll),#0);                         
    changed:=true;                                                              
  end;                                                                          
                                                                                
    for the user to edit a record, we just use a box and two getstr functions.  
    nothing complicated. just show stuff and wait for the user to enter the     
    new strings. if the user accepts the new values, we pass them into our      
    array that we keep all records, else we ignore everything.                  
                                                                                
  procedure editrec;                                                            
  var                                                                           
    j:byte;                                                                     
    ok:boolean=false;                                                           
    from,txt:string;                                                            
  begin                                                                         
    xwindow('',1,5,10,75,16);                                                   
    writexy(7,10,14,' Edit record #'+int2str(sel)+' ');                         
                                                                                
      writexy(7,12,7,padrt(lines[sel].from,30,' '));                            
      writexy(7,13,7,padrt(copy(lines[sel].text,1,68),68,' '));                 
      gotoxy(7,12);                                                             
      from:=input(30,30,11,lines[sel].from);                                    
      writexy(7,12,7,padrt(from,30,' '));                                       
      gotoxy(7,13);                                                             
      txt:=input(67,79,11,lines[sel].text);                                     
      writexy(7,13,7,padrt(copy(txt,1,68),68,' '));                             
      gotoxy(25,15);                                                            
      textcolor(3);                                                             
      ok:=inputyn('Apply changes?: ');                                          
    if ok then begin                                                            
      lines[sel].from:=from;                                                    
      lines[sel].text:=txt;                                                     
      changed:=true;                                                            
    end;                                                                        
  end;                                                                          
                                                                                
    now we just have make a loop, to accept user commands. to do that, we       
    use a repeat/until loop. inside we do these things:                         
      1. draw stuff                                                             
      2. wait for keypress/command                                              
      3. execute the command                                                    
      4. go back to 1...                                                        
                                                                                
begin                                                                           
  writexypipe(1,24,7,79,'|11E|03:Edit | |11D|03:Delete | |11S|03:Save | '+      
  '|11C|03:Clear All | |11R|03:Revert | |11ESC|03:Exit | |11H|03:Help');        
  repeat                                                                        
    listlines;    // draw stuff...                                              
    showsel;                                                                    
    c:=readkey;   // wait for user to press a key                               
    if isarrow then begin   // is the key an arrow key?                         
      case c of             // if yes, c holds the key code                     
        #72 : begin         // move selection up                                
                sel:=sel -1;                                                    
                if sel < 1 then sel:=1;                                         
              end;                                                              
        #80 : begin         // move selection down                              
                sel:=sel+1;                                                     
                if sel>10 then sel:=10;                                         
              end;                                                              
        #71 : sel:=1;       // move selection to top                            
        #79 : sel:=10;      // and bottom...                                    
      end;                                                                      
    end else begin                                                              
      case c of       // the key is a simple one                                
        #13 : begin   // enter? do nothing, not care                            
                                                                                
              end;                                                              
        #27 : begin   // pressed esc? ask to save if changes are made.          
                if changed then save;                                           
                Done := True;   // if we change this to true we will exit       
                                // the loop.                                    
              end;                                                              
        'c','C': clearall;  // a key responding to a command pressed.           
        'd','D': deleterec  // execute the command                              
        'e','E': editrec;                                                       
        's','S': save;                                                          
        'h','H': help;                                                          
        'r','R': begin                                                          
                  loadoneliner;                                                 
                  changed:=false;                                               
                 end;                                                           
      end;                                                                      
    end;                                                                        
                                                                                
  until Done;   // repeat the loop, until the user presses esc.                 
                                                                                
end;                                                                            
                                                                                
    this is our main block of code. we get the data path, in a weird way :)     
    just to show you, that there are more ways to do the same thing, even       
    if it's stupid :) then load the records in memory and display the           
    menu selection to the user.                                                 
                                                                                
begin                                                                           
  dir := cfgsyspath;                                                            
  oneliner := dir +'data'+pathchar+'oneliner.dat';                              
  textcolor(15);                                                                
  clrscr;                                                                       
  writexy(1,1,15,cprt);                                                         
  loadoneliner;                                                                 
  select;                                                                       
  textcolor(7);                                                                 
  clrscr;                                                                       
end;                                                                            
                                                                                
;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:  
  actuall script                                                                
;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:;:  
                                                                                
Uses cfg;                                                                       
                                                                                
Const                                                                           
  cprt = 'OneLiner Editor by XQTR//2019';                                       
                                                                                
Type OneLineRec = Record                                                        
    Text : String[79];                                                          
    From : String[30];                                                          
  End;                                                                          
                                                                                
var                                                                             
  dir : string;                                                                 
  ll : OneLineRec;                                                              
  oneliner : string;                                                            
  lines : array[1..10] of OneLineRec;                                           
  changed:boolean = false;                                                      
                                                                                
Procedure XWindow(H1:String;T,X1,Y1,X2,Y2:Integer);                             
Var T1,A1,A2,B1,B2  : String;                                                   
Begin                                                                           
  A1 := Int2Str(X1);                                                            
        A2:=Int2Str(X2);                                                        
        B1:=Int2Str(Y1);                                                        
        B2:=Int2Str(Y2);                                                        
        T1:=Int2Str(T);                                                         
        Write('|#X#'+T1+'#'+H1+'#'+A1+'#'+B1+'#'+A2+'#'+B2+'#');                
End;                                                                            
                                                                                
function yesnobox(title:string):boolean;                                        
var                                                                             
  bb:longint;                                                                   
begin                                                                           
  ClassCreate (bb, 'box');                                                      
  BoxOptions (bb, 1, true, 8, 8, 7, 15, false, 112);                            
  BoxOpen (bb, 27, 8, 47, 12);                                                  
  writexypipe(29,8,7,MCILength(title),title);                                   
  gotoxy(33,10);                                                                
  yesnobox:= inputyn('')                                                        
  BoxClose  (bb);                                                               
  ClassFree (bb);                                                               
end;                                                                            
                                                                                
procedure savelines;                                                            
var                                                                             
  k:byte;                                                                       
  f:file;                                                                       
begin                                                                           
  filecopy(oneliner,oneliner+'.1lb');                                           
  fassign(f,oneliner,66);                                                       
  frewrite(f);                                                                  
  k:=1;                                                                         
  while k<11 and lines[k].from<>'' do begin                                     
    fwrite(f,lines[k],sizeof(ll));                                              
    k:=k+1;                                                                     
  end;                                                                          
  fclose(f);                                                                    
  changed:=false;                                                               
end;                                                                            
                                                                                
procedure loadoneliner;                                                         
var                                                                             
  f : file;                                                                     
  ol:onelinerec;                                                                
  i:byte;                                                                       
begin                                                                           
  for i:=1 to 10 do                                                             
    fillchar(lines[i],sizeof(ol),#0);                                           
  fassign(f,oneliner,66);                                                       
  freset(f);                                                                    
  i:=0;                                                                         
  while not feof(f) do begin                                                    
    i:=i+1;                                                                     
    fillchar(ol,sizeof(ol),#0);                                                 
    fread(f,ol,sizeof(ol))                                                      
    lines[i]:=ol;                                                               
  end;                                                                          
  fclose(f);                                                                    
end;                                                                            
                                                                                
procedure select;                                                               
var                                                                             
  sel : byte = 1;                                                               
  done : boolean = false;                                                       
  c : char;                                                                     
                                                                                
  procedure listlines;                                                          
  var                                                                           
    i:byte;                                                                     
    cl:byte;                                                                    
  begin                                                                         
    for i := 0 to 9 do begin                                                    
      //cl:=i%2;                                                                
      //if cl=1 then textcolor(3) else textcolor(11);                           
      //gotoxy(1,3+(i*2));                                                      
      //writeraw(padrt(lines[i+1].from,79,' '));                                
      writexypipe(1,3+(i*2),7,79,lines[i+1].from)                               
      //gotoxy(1,3+(i*2)+1)                                                     
      //writeraw(padrt(lines[i+1].text,79,' '));                                
      writexypipe(1,3+(i*2)+1,7,79,lines[i+1].text)                             
    end;                                                                        
  end;                                                                          
                                                                                
  procedure showsel;                                                            
  begin                                                                         
    textcolor(14+16);                                                           
    gotoxy(1,3+((sel-1)*2));                                                    
    writeraw(padrt(lines[sel].from,79,' '));                                    
    gotoxy(1,3+((sel-1)*2)+1)                                                   
    writeraw(padrt(lines[sel].text,79,' '));                                    
  end;                                                                          
                                                                                
  procedure deleterec;                                                          
  var                                                                           
    j:byte;                                                                     
  begin                                                                         
    if yesnobox(' |14Delete record?  ') = false then exit;                      
    for j:=sel to 9 do begin                                                    
      lines[j]:=lines[j+1]                                                      
    end;                                                                        
    fillchar(lines[10],sizeof(ll),#0);                                          
    changed:=true;                                                              
  end;                                                                          
                                                                                
  procedure clearall;                                                           
  var                                                                           
    k:byte;                                                                     
  begin                                                                         
    for k:=1 to 10 do fillchar(lines[k],sizeof(ll),#0);                         
    changed:=true;                                                              
  end;                                                                          
                                                                                
  procedure help                                                                
  begin                                                                         
    xwindow('',1,2,7,78,20);                                                    
    writexy(4,7,14,' Help ');                                                   
                                                                                
    writexy(4,9 ,7,'Edit the OneLine records of the oneliners.dat file.'+       
    ' The commands');                                                           
    writexy(4,10,7,'are self explanatory. You only need to know these:');       
                                                                                
    writexy(4,12,7,'() No changes are saved in the file, unless you press '+    
    'the (S)ave command');                                                      
    writexy(4,13,7,'() You can revert to the current file by pressing'+         
    ' (R)evert');                                                               
    writexy(4,14,7,'() When you save changes a backup file of the original'+    
    ' one, is saved as');                                                       
    writexy(4,15,7,'   oneliners.dat.1lb. If you mess things up, '+             
    'restore this file.');                                                      
    readkey;                                                                    
  end;                                                                          
                                                                                
  procedure editrec;                                                            
  var                                                                           
    j:byte;                                                                     
    ok:boolean=false;                                                           
    from,txt:string;                                                            
  begin                                                                         
    xwindow('',1,5,10,75,16);                                                   
    writexy(7,10,14,' Edit record #'+int2str(sel)+' ');                         
                                                                                
      writexy(7,12,7,padrt(lines[sel].from,30,' '));                            
      writexy(7,13,7,padrt(copy(lines[sel].text,1,68),68,' '));                 
      gotoxy(7,12);                                                             
      from:=input(30,30,11,lines[sel].from);                                    
      writexy(7,12,7,padrt(from,30,' '));                                       
      gotoxy(7,13);                                                             
      txt:=input(67,79,11,lines[sel].text);                                     
      writexy(7,13,7,padrt(copy(txt,1,68),68,' '));                             
      gotoxy(25,15);                                                            
      textcolor(3);                                                             
      ok:=inputyn('Apply changes?: ');                                          
    if ok then begin                                                            
      lines[sel].from:=from;                                                    
      lines[sel].text:=txt;                                                     
      changed:=true;                                                            
    end;                                                                        
  end;                                                                          
                                                                                
  procedure save;                                                               
  begin                                                                         
    if yesnobox(' Save changes? ') then savelines;                              
  end;                                                                          
                                                                                
begin                                                                           
  writexypipe(1,24,7,79,'|11E|03:Edit | |11D|03:Delete | |11S|03:Save | '+      
  '|11C|03:Clear All | |11R|03:Revert | |11ESC|03:Exit | |11H|03:Help');        
  repeat                                                                        
    listlines;                                                                  
    showsel;                                                                    
    c:=readkey;                                                                 
    if isarrow then begin                                                       
      case c of                                                                 
        #72 : begin                                                             
                sel:=sel -1;                                                    
                if sel < 1 then sel:=1;                                         
              end;                                                              
        #80 : begin                                                             
                sel:=sel+1;                                                     
                if sel>10 then sel:=10;                                         
              end;                                                              
        #71 : sel:=1;                                                           
        #79 : sel:=10;                                                          
      end;                                                                      
    end else begin                                                              
      case c of                                                                 
        #13 : begin                                                             
                                                                                
              end;                                                              
        #27 : begin                                                             
                if changed then save;                                           
                Done := True;                                                   
              end;                                                              
        'c','C': clearall;                                                      
        'd','D': deleterec                                                      
        'e','E': editrec;                                                       
        's','S': save;                                                          
        'h','H': help;                                                          
        'r','R': begin                                                          
                  loadoneliner;                                                 
                  changed:=false;                                               
                 end;                                                           
      end;                                                                      
    end;                                                                        
                                                                                
  until Done;                                                                   
                                                                                
end;                                                                            
                                                                                
                                                                                
begin                                                                           
  dir := cfgsyspath;                                                            
  oneliner := dir +'data'+pathchar+'oneliner.dat';                              
  textcolor(15);                                                                
  clrscr;                                                                       
  writexy(1,1,15,cprt);                                                         
  loadoneliner;                                                                 
  select;                                                                       
  textcolor(7);                                                                 
  clrscr;                                                                       
end;