home *** CD-ROM | disk | FTP | other *** search
/ Amiga ISO Collection / AmigaUtilCD2.iso / Programming / Pascal / HISOFTPASCAL2,0-2.DMS / in.adf / Extras / FileRequest.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1992-05-21  |  6.0 KB  |  224 lines

  1.  
  2. (*    FileRequest.pas
  3.  *        An example program which shows how to use the ASL and ARP file
  4.  *        requesters from a HighSpeed Pascal program.  It also illustrates
  5.  *        some methods of string conversion, handling of path names, the
  6.  *        XASSEMBLER keyword, use of 'tags' from Pascal and a way of
  7.  *        implementing function calls via pointers.
  8.  *
  9.  *        Written by Keith Wilson, HiSoft.
  10.  *)
  11.  
  12. program FileRequest;
  13. { ARP.unit and some 2.0 units are required to compile this }
  14. { so you will have to set up your Units Path accordingly }
  15. uses Amiga, AmigaDOS, ARP, ASL, Exec, Intuition, Utility;
  16.  
  17.  
  18. const
  19. { required library versions }
  20.     ASL_REV = 36;
  21.     ARP_REV = 33;
  22.  
  23.  
  24. (*    SplitName extracts the directory and filename components of an
  25.  *    AmigaDOS pathname.  It is similar to FSplit in the DOS unit but
  26.  *    handles up to 255 character names.
  27.  *)
  28.  
  29. procedure SplitName (path: string; var dir, name: string);
  30. var i: integer;
  31. begin
  32.     i := Length(path);
  33.     repeat
  34.         dec(i)
  35.     until (i = 0) or (path[i] = ':') or (path[i] = '/');
  36.     name := Copy(path, i+1, Length(path)-i);
  37.  
  38.     if dir[i] = '/' then dec(i);    { don't give a trailing slash }
  39.     dir := Copy(path, 1, i)
  40. end;
  41.  
  42.  
  43. (*    You should use this routine to glue a directory and filename back
  44.  *    together.  It automatically adds a slash separator if necessary.
  45.  *)
  46.  
  47. procedure AddName (var dir: string; name: string);
  48. var c: char;
  49. begin
  50.     c := dir[Length(dir)];
  51.     if (c <> #0) and (c <> ':') and (c <> '/') then dir := dir + '/';
  52.     dir := dir + name;
  53. end;
  54.  
  55.  
  56. (*    This function turns any Pascal string into a C string by adding
  57.  *    a null to the end and returning a pointer to the first character.
  58.  *    Note that the string can still be used as a Pascal string.
  59.  *)
  60.  
  61. function NullTerm (var s: string): STRPTR;
  62. var i: integer;
  63. begin
  64.     i := Length(s) + 1;
  65.     if i > 255 then
  66.     begin
  67.         Delete(s, 255, 1);        { ensure there is a spare byte }
  68.         Dec(i)
  69.     end;
  70.     s[i]     := #0;
  71.     NullTerm := @s[1]
  72. end;
  73.  
  74.  
  75. (*    To make a Pascal string from a C string which starts at s[1], we
  76.  *    fool the Pos function into searching the whole string for a null
  77.  *    byte then place the string length in s[0].
  78.  *)
  79.  
  80. procedure MakeString (var s: string);
  81. begin
  82.     s[0] := #255;
  83.     s[0] := Chr(Pos(#0, s) - 1)        { gives -1 (255) if not found }
  84. end;
  85.  
  86.  
  87. (*    Here is an assembly language implementation of the C strncpy.
  88.  *    It differs from the standard by not padding unused destination bytes.
  89.  *    Note that when all bytes are used, the string does not get null-
  90.  *    terminated.
  91.  *
  92.  *    The XASSEMBLER keyword means that no LINK and UNLK instructions are
  93.  *    generated although this does mean that we have to use stack offsets
  94.  *    rather than names for accessing the parameters.
  95.  *)
  96.  
  97. function strncpy (dest, source: pointer; n: integer): STRPTR; xassembler;
  98. asm
  99.     move.w    4(sp),d0            { D0 = max }
  100.     movem.l    6(sp),a0-a1            { A0 = source, A1 = dest }
  101.     move.l    a1,14(sp)            { return dest for convenience }
  102.     bra        @2                    { so we don't do one too many }
  103. @1:
  104.     move.b    (a0)+,(a1)+            { copy characters }
  105. @2:    dbeq    d0,@1                { until reached null or maximum }
  106. end;
  107.  
  108.  
  109. (*    This function produces an ASL file requester.  Note that the supplied
  110.  *    dir and name string buffers must be 255 characters long.
  111.  *
  112.  *    Like many Release 2 libraries, ASL uses 'tags'.  These are arrays
  113.  *    tTagItem records (see Utility.pas), each containing an identifying
  114.  *    tag value and some associated data.  TAG_END terminates the list.
  115.  *    C can pass taglists in function calls but Pascal has to use an array
  116.  *    although you can use pairs of long integers rather than tTagItems.
  117.  *)
  118.  
  119. function ASLRequest (win: pWindow; title, dir, name: STRPTR): boolean;
  120. var fr: ASL.pFileRequester; arg: array [0..8] of long; junk: STRPTR;
  121. begin
  122.     ASLRequest := false;
  123.     arg[0] := ASL_Window;    arg[1] := long(win);
  124.     arg[2] := ASL_Hail;        arg[3] := long(title);
  125.     arg[4] := ASL_Dir;        arg[5] := long(dir);
  126.     arg[6] := ASL_File;        arg[7] := long(name);
  127.     arg[8] := TAG_END;
  128.  
  129.     fr := AllocASLRequest(ASL_FileRequest, @arg);
  130.     if fr <> NIL then
  131.     begin
  132.         ASLRequest := RequestFile(fr);
  133.         with fr^ do begin
  134.             junk := strncpy(name, rf_File, 255);
  135.             junk := strncpy(dir, rf_Dir, 255)
  136.         end;
  137.         FreeASLRequest(fr)
  138.     end
  139. end;
  140.  
  141.  
  142. (*    The ARP version is simple by comparison!
  143.  *)
  144.  
  145. function ARPRequest (win: pWindow; title, dir, name: STRPTR): boolean;
  146. var fr: ARP.tFileRequester;
  147. begin
  148.     FillChar(fr, sizeof(fr), 0);
  149.     with fr do
  150.     begin
  151.         fr_Window    := win;
  152.         fr_Hail        := title;
  153.         fr_Dir        := dir;
  154.         fr_File        := name
  155.     end;
  156.     ARPRequest := ARP.FileRequest(@fr) <> NIL
  157. end;
  158.  
  159.  
  160. (*    Although HighSpeed Pascal does not support procedures as parameters,
  161.  *    a little bit of assembly code magic does the job nicely.  This dummy
  162.  *    function takes the same parameters as the functions we are calling
  163.  *    followed by the function to call.  This is popped off the stack and
  164.  *    jumped to, leaving the correct parameters for our function.
  165.  *)
  166.  
  167. function CallRequest (win: pWindow;
  168.         title, dir, name: STRPTR; func: pointer): boolean; inline
  169.     $205F,        { move.l (sp)+,a0    }
  170.     $4E90;        { jsr (a0)            }
  171.  
  172.  
  173. (*    The main file requester function.  It first looks for the ASL library
  174.  *    and if this is not found, the ARP library.  This means that programs
  175.  *    using it will work under 2.0 and 1.3.  Adding support for other file
  176.  *    requesters is made simple by the use of a function pointer.
  177.  *)
  178.  
  179. function FRequest(win: pWindow;
  180.         title: string; var selection: string): boolean;
  181. var dir, name: string; lib: pLibrary; func: Pointer;
  182. begin
  183.     FRequest := false;
  184.     lib := OpenLibrary('asl.library', ASL_REV);
  185.     if lib <> NIL then
  186.     begin
  187.         ASLBase    := lib;
  188.         func    := @ASLRequest
  189.     end
  190.     else
  191.     begin
  192.         lib        := OpenLibrary('arp.library', ARP_REV);
  193.         ArpBase    := pArpBase(lib);
  194.         func    := @ARPRequest
  195.     end;
  196.  
  197.     if lib <> NIL then
  198.     begin
  199.         SplitName(selection, dir, name);
  200.         if CallRequest(win, NullTerm(title),
  201.                 NullTerm(dir), NullTerm(name), func) then
  202.         begin
  203.             MakeString(dir);
  204.             MakeString(name);
  205.             AddName(dir, name);
  206.             selection    := dir;
  207.             FRequest    := true
  208.         end;
  209.         CloseLibrary(lib)
  210.     end
  211. end;
  212.  
  213.  
  214. (* And just to prove that it really works, here's a sample program! *)
  215. var name: string;
  216. begin
  217.     name := '';
  218.     if FRequest(NIL, 'HighSpeed Pascal Requester', name) then
  219.         WriteLn(name, ' selected')
  220.     else
  221.         WriteLn('Cancelled');
  222.     Delay(100)
  223. end.
  224.