home *** CD-ROM | disk | FTP | other *** search
/ MacFormat 1996 March / macformat-035.iso / Shareware City / Developers / ICAppSourceKit1.2 / ICMiscSubs.p < prev    next >
Encoding:
Text File  |  1995-11-07  |  20.1 KB  |  849 lines  |  [TEXT/CWIE]

  1. unit ICMiscSubs;
  2.  
  3. interface
  4.  
  5.     uses
  6.         Files, Windows, Lists;
  7.         
  8.     const
  9.         nulChar = 0;
  10.         homeChar = $01;
  11.         enterChar = $03;
  12.         endChar = $04;
  13.         helpChar = $05;
  14.         backSpaceChar = $08;
  15.         tabChar = $09;
  16.         lfChar = $0A;
  17.         pageUpChar = $0b;
  18.         pageDownChar = $0c;
  19.         crChar = $0D;
  20.         escChar = $1b;
  21.         escKey = $35;
  22.         clearChar = $1b;
  23.         clearKey = $47;
  24.         leftArrowChar = $1c;
  25.         rightArrowChar = $1d;
  26.         upArrowChar = $1e;
  27.         downArrowChar = $1f;
  28.         spaceChar = $20;
  29.         delChar = $7f;
  30.         bulletChar = $a5;
  31.         undoKey = $7a;
  32.         cutKey = $78;
  33.         copyKey = $63;
  34.         pasteKey = $76;
  35.  
  36.     const
  37.         kReturnKeyCode = 36;
  38.         kTabKeyCode = 48;
  39.         kSpaceKeyCode = 49;
  40.         KDeleteKeyCode = 51;
  41.         kEnterKeyCode = 52;
  42.         kCommandKeyCode = 55;
  43.         kShiftKeyCode = 56;
  44.         kCapsLockKeyCode = 57;
  45.         kOptionKeyCode = 58;
  46.         kClearKeyCode = 71;
  47.  
  48.     const
  49.         owner_id = -16096;
  50.         machine_id = -16413;
  51.  
  52.     procedure InitMiscSubs;
  53.  
  54.     function GetVolInfo (var name: str63; var vrn: integer; index: integer; var CrDate: longInt): OSErr;
  55.     function MyGetAPPL (sig: OSType; var fs: FSSpec): OSErr;
  56.     function FSpGetCatInfo (var fs: FSSpec; index: integer; var pb: CInfoPBRec): OSErr;
  57.     function FSpSetCatInfo (var fs: FSSpec; var pb: CInfoPBRec): OSErr;
  58.     function GetWindowContentRegion (theWindow: WindowPtr): RgnHandle;
  59.     function GetWindowStructureRegion (theWindow: WindowPtr): RgnHandle;
  60.     function TitleBarOnScreen (wp: WindowPtr): boolean;
  61.     procedure GetWindowPortRect (theWindow: WindowPtr; var portRect: rect);
  62.     procedure GetWindowRect (theWindow: WindowPtr; var r: rect);
  63.     procedure CentreRect (inside_rect: Rect; var res_rect: Rect);
  64.     procedure CentreAlert (id: integer);
  65.     function GetAString (id, index: integer): Str255;
  66.     procedure Assert (b: boolean);
  67.     procedure SetItemEnable (mh: menuHandle; item: integer; enable: boolean);
  68.     function DirtyKey (ch: char): boolean;
  69.  
  70.     function IsKeyDown (keycode: integer): boolean;
  71.     function SelectedLine (lh: ListHandle): integer;
  72.  
  73.     function FSWriteQ (refnum: integer; count: longint; buf: Ptr): OSErr;
  74.     function FSReadQ (refnum: integer; count: longint; buf: Ptr): OSErr;
  75.  
  76.     procedure DrawIcon (id: integer; r: Rect; highlighted: boolean);
  77.  
  78.     function FileLocked (fss: FSSpec): boolean;
  79.  
  80.     type
  81.         GetEntryNameProcType = function(list: ListHandle; c: cell): str255;
  82.         
  83.     procedure DoListKey (list: ListHandle; var er:EventRecord; getentryname: GetEntryNameProcType);
  84.     procedure LSetNoSelection (list: ListHandle);
  85.     procedure LSetSingleSelection (list: ListHandle; v: integer);
  86.  
  87.     function DecStr (l: longint): Str255;
  88.     function CopyFile (source, dest: FSSpec): OSErr;
  89.  
  90.     function GetOwnerName: str255;
  91.     function GetMachineName: str255;
  92.  
  93.     function StringToOSType (s: str255): OSType;
  94.     function OSTypeToString (t: OSType): Str255;
  95.     function TPpos (sub, str: string): integer;
  96.     function TPcopy (source: string; start, count: integer): string;
  97.     function TPbtst(value:longint; bit:integer):Boolean;
  98.     
  99. implementation
  100.  
  101.     uses
  102.         Icons, Errors, Resources, Dialogs, ToolUtils,
  103.  
  104.         ICGlobals;
  105.  
  106.     var
  107.         typed_chars: str31;
  108.         typed_time: longInt;
  109.         typed_lh: ListHandle;
  110.  
  111.     procedure InitMiscSubs;
  112.     begin
  113.         typed_chars := '';
  114.         typed_time := 0;
  115.         typed_lh := nil;
  116.     end;
  117.  
  118.     function TPbtst(value:longint; bit:integer):Boolean;
  119.     begin
  120.         TPbtst := btst(value, bit);
  121.     end;
  122.     
  123.     function TPcopy (source: string; start, count: integer): string;
  124.     begin
  125.         if (start < 1) then begin
  126.             count := count - (1 - start);
  127.             start := 1;
  128.         end;
  129.         if start + count > length(source) then begin
  130.             count := length(source) - start + 1;
  131.         end;
  132.         if count < 0 then begin
  133.             count := 0;
  134.         end;
  135.         source[0] := chr(count);
  136.         BlockMoveData(@source[start], @source[1], count);
  137.         TPcopy := source;
  138.     end;
  139.  
  140.     function TPpos (sub, str: string): integer;
  141.         var
  142.             i, j, ret: integer;
  143.     begin
  144.         i := 1;
  145.         ret := 1;
  146.         if length(sub) > 0 then begin
  147.             ret := 0;
  148.             while (i <= length(str) - length(sub) + 1) do begin
  149.                 if str[i] = sub[1] then begin
  150.                     j:=2;
  151.                     while j<=length(sub) do begin
  152.                         if str[i+j-1]<>sub[j] then begin
  153.                             leave;
  154.                         end;
  155.                         j:=j+1;
  156.                     end;
  157.                     if j>length(sub) then begin
  158.                         ret:=i;
  159.                         leave;
  160.                     end;
  161.                 end;
  162.                 i := i + 1;
  163.             end;
  164.         end;
  165.         TPpos := ret;
  166.     end;
  167.  
  168.     function StringToOSType (s: str255): OSType;
  169.         var
  170.             t: OSType;
  171.     begin
  172.         s := concat(s, chr(0), chr(0), chr(0), chr(0));
  173.         BlockMoveData(@s[1], @t, 4);
  174.         StringToOSType := t;
  175.     end;
  176.  
  177.     function OSTypeToString (t: OSType): Str255;
  178.         var
  179.             s:Str255;
  180.     begin
  181.         s:=concat(chr(0),chr(0),chr(0),chr(0));
  182.         BlockMoveData(@t,@s[1],4);
  183.         OSTypeToString:=s;
  184.     end;
  185.  
  186.     procedure DrawIcon (id: integer; r: Rect; highlighted: boolean);
  187.         var
  188.             suite: Handle;
  189.             iconh: Handle;
  190.             junk: OSErr;
  191.             transform: integer;
  192.     begin
  193.         if system7 & (GetIconSuite(suite, id, svAllLargeData) = noErr) then begin
  194.             if highlighted then begin
  195.                 transform := ttSelected;
  196.             end else begin
  197.                 transform := ttNone;
  198.             end; (* if *)
  199.             junk := PlotIconSuite(r, 0, transform, suite);
  200.             junk := DisposeIconSuite(suite, false);
  201.         end else begin
  202.             iconh := Get1Resource('ICN#', id);
  203.             if iconh <> nil then begin
  204.                 PlotIcon(r, iconh);
  205.             end; (* if *)
  206.         end; (* if *)
  207.     end; (* if *)
  208.  
  209.     function FSWriteQ (refnum: integer; count: longint; buf: Ptr): OSErr;
  210.     begin
  211.         FSWriteQ := FSWrite(refnum, count, buf);
  212.     end; (* FSWriteQ *)
  213.  
  214.     function FSReadQ (refnum: integer; count: longint; buf: Ptr): OSErr;
  215.     begin
  216.         FSReadQ := FSRead(refnum, count, buf);
  217.     end; (* FSReadQ *)
  218.  
  219.     function SelectedLine (lh: ListHandle): integer;
  220.         var
  221.             acell: Cell;
  222.     begin
  223.         SetPt(acell, 0, 0);
  224.         if LGetSelect(true, acell, lh) then begin
  225.             SelectedLine := acell.v;
  226.         end else begin
  227.             SelectedLine := -1;
  228.         end; (* if *)
  229.     end; (* SelectedLine *)
  230.  
  231.     function IsKeyDown (keycode: integer): boolean;
  232.         var
  233.             mykeys: KeyMap;
  234.     begin
  235.         GetKeys(mykeys);
  236.         IsKeyDown := mykeys[keycode];
  237.     end; (* IsKeyDown *)
  238.  
  239.     function GetVolInfo (var name: str63; var vrn: integer; index: integer; var CrDate: longInt): OSErr;
  240.         var
  241.             pb: paramBlockRec;
  242.             oe: OSErr;
  243.     begin
  244.         if (name <> '') & (name[length(name)] <> ':') then
  245.             name := concat(name, ':');
  246.         pb.ioNamePtr := @name;
  247.         pb.ioVRefNum := vrn;
  248.         pb.ioVolIndex := index;
  249.         oe := PBGetVInfoSync(@pb);
  250.         if oe = noErr then begin
  251.             vrn := pb.ioVRefNum;
  252.             CrDate := pb.ioVCrDate;
  253.         end;
  254.         GetVolInfo := oe;
  255.     end;
  256.  
  257.     function MyGetAPPL (sig: OSType; var fs: FSSpec): OSErr;
  258.         var
  259.             i: integer;
  260.             pbdt: DTPBRec;
  261.             crdate: longInt;
  262.             oe: OSErr;
  263.             found: boolean;
  264.     begin
  265.         found := false;
  266.         if system7 then begin
  267.             i := 1;
  268.             repeat
  269.                 fs.vRefNum := 0;
  270.                 fs.name := '';
  271.                 oe := GetVolInfo(fs.name, fs.vRefNum, i, crdate);
  272.                 i := i + 1;
  273.                 if oe = noErr then begin
  274.                     with pbdt do begin
  275.                         fs.name := '';
  276.                         ioNamePtr := @fs.name;
  277.                         ioVRefNum := fs.vRefNum;
  278.                         oe := PBDTGetPath(@pbdt);
  279.                         if oe = noErr then begin
  280.                             ioIndex := 0;
  281.                             ioFileCreator := sig;
  282.                             oe := PBDTGetAPPLSync(@pbdt);
  283.                             if oe = noErr then
  284.                                 found := true;
  285.                         end;
  286.                     end;
  287.                     oe := noErr;
  288.                 end;
  289.             until found or (oe <> noErr);
  290.         end;
  291.         if found then begin
  292.             oe := noErr;
  293.             fs.parID := pbdt.ioAPPLParID;
  294.         end else begin
  295.             oe := afpItemNotFound;
  296.             fs.vRefNum := 0;
  297.             fs.parID := 2;
  298.             fs.name := '';
  299.         end;
  300.         MyGetAPPL := oe;
  301.     end;
  302.  
  303.     function FSpGetCatInfo (var fs: FSSpec; index: integer; var pb: CInfoPBRec): OSErr;
  304.     begin
  305.         pb.ioVRefNum := fs.vRefNum;
  306.         pb.ioDirID := fs.parID;
  307.         pb.ioNamePtr := @fs.name;
  308.         pb.ioFDirIndex := index;
  309.         FSpGetCatInfo := PBGetCatInfoSync(@pb);
  310.     end;
  311.  
  312.     function FSpSetCatInfo (var fs: FSSpec; var pb: CInfoPBRec): OSErr;
  313.     begin
  314.         pb.ioVRefNum := fs.vRefNum;
  315.         pb.ioDirID := fs.parID;
  316.         pb.ioNamePtr := @fs.name;
  317.         FSpSetCatInfo := PBSetCatInfoSync(@pb);
  318.     end;
  319.  
  320.     function GetWindowContentRegion (theWindow: WindowPtr): RgnHandle;
  321.     begin
  322.         GetWindowContentRegion := WindowPeek(theWindow)^.contRgn;
  323.     end;
  324.  
  325.     function GetWindowStructureRegion (theWindow: WindowPtr): RgnHandle;
  326.     begin
  327.         GetWindowStructureRegion := WindowPeek(theWindow)^.strucRgn;
  328.     end;
  329.  
  330.     function TitleBarOnScreen (wp: WindowPtr): boolean;
  331.         var
  332.             rgn: RgnHandle;
  333.     begin
  334.         rgn := NewRgn;
  335.         CopyRgn(GetWindowStructureRegion(wp), rgn);
  336.         DiffRgn(rgn, GetWindowContentRegion(wp), rgn);
  337.         SectRgn(rgn, GetGrayRgn, rgn);
  338.         TitleBarOnScreen := not EmptyRgn(rgn);
  339.         DisposeRgn(rgn);
  340.     end;
  341.  
  342.     procedure GetWindowPortRect (theWindow: WindowPtr; var portRect: rect);
  343.     begin
  344.         portRect := WindowPeek(theWindow)^.port.portRect;
  345.     end;
  346.  
  347.     procedure GetWindowRect (theWindow: WindowPtr; var r: rect);
  348.     begin
  349.         SetPort(theWindow);
  350.         GetWindowPortRect(theWindow, r);
  351.         LocalToGlobal(r.topleft);
  352.         LocalToGlobal(r.botright);
  353.     end;
  354.  
  355.     procedure CentreRect (inside_rect: Rect; var res_rect: Rect);
  356.         var
  357.             stat_siz: Point;
  358.     begin
  359.         stat_siz := inside_rect.botright;
  360.         SubPt(inside_rect.topleft, stat_siz);
  361.         OffsetRect(res_rect, -res_rect.left, -res_rect.top);
  362.         SubPt(res_rect.botright, stat_siz);
  363.         stat_siz.h := stat_siz.h div 2;
  364.         stat_siz.v := stat_siz.v div 2;
  365.         AddPt(inside_rect.topleft, stat_siz);
  366.         OffsetRect(res_rect, stat_siz.h, stat_siz.v);
  367.     end; (* CentreRect *)
  368.  
  369.     procedure CentreAlert (id: integer);
  370.         var
  371.             alerth: AlertTHndl;
  372.             bounds: Rect;
  373.     begin
  374.         alerth := AlertTHndl(GetResource('ALRT', id));
  375.         if alerth <> nil then begin
  376.             bounds := qd.screenBits.bounds;
  377.             bounds.bottom := (bounds.bottom - bounds.top) * 2 div 3 + bounds.top;
  378.             HLock(Handle(alerth));
  379.             CentreRect(bounds, alerth^^.boundsRect);
  380.             HUnlock(Handle(alerth));
  381.         end; (* if *)
  382.     end; (* CentreAlert *)
  383.  
  384.     function GetAString (id, index: integer): Str255;
  385.         var
  386.             res: Str255;
  387.     begin
  388.         GetIndString(res, id, index);
  389.         GetAString := res;
  390.     end; (* GetAString *)
  391.  
  392.     procedure Assert (b: boolean);
  393.     begin
  394.         if not b then begin
  395.             DebugStr('Assertion failure ; sc');
  396.         end; (* if *)
  397.     end;
  398.  
  399.     procedure SetItemEnable (mh: menuHandle; item: integer; enable: boolean);
  400.     begin
  401.         if enable then begin
  402.             EnableItem(mh, item);
  403.         end else begin
  404.             DisableItem(mh, item);
  405.         end;
  406.     end;
  407.  
  408.     function DirtyKey (ch: char): boolean;
  409.     begin
  410.         case ord(ch) of
  411.             homeChar, endChar, helpChar, pageUpChar, pageDownChar, leftArrowChar, rightArrowChar, upArrowChar, downArrowChar: 
  412.                 DirtyKey := false;
  413.             otherwise
  414.                 DirtyKey := true;
  415.         end;
  416.     end;
  417.  
  418.     function IsVolumeWriteable (vRefNum: integer): OSErr;
  419.         var
  420.             pb: HParamBlockRec;
  421.             err: OSErr;
  422.     begin
  423.         pb.ioVRefNum := vRefNum;
  424.         pb.ioNamePtr := nil;
  425.         pb.ioVolIndex := 0;
  426.         err := PBHGetVInfoSync(@pb);
  427.  
  428.         if err = noErr then begin
  429.             if BAND(pb.ioVAtrb, $0080) <> 0 then begin
  430.                 err := wPrErr;        { volume locked by hardware }
  431.             end else if BAND(pb.ioVAtrb, $8000) <> 0 then begin
  432.                 err := vLckdErr;    { volume locked by software }
  433.             end;
  434.         end;
  435.  
  436.         IsVolumeWriteable := err;
  437.     end;
  438.  
  439.     function IsFileWriteable (fs: FSSpec): OSErr;
  440.         var
  441.             pb: CInfoPBRec;
  442.             err: OSErr;
  443.     begin
  444.         pb.ioNamePtr := @fs.name;
  445.         pb.ioVRefNum := fs.vRefNum;
  446.         pb.ioDirID := fs.parID;
  447.         pb.ioFDirIndex := 0;    { use ioNamePtr and ioDirID }
  448.         err := PBGetCatInfoSync(@pb);
  449.  
  450.         if err = noErr then begin
  451.             if BAND(pb.ioFlAttrib, $01) <> 0 then begin
  452.                 err := fLckdErr;
  453.             end;
  454.         end;
  455.         IsFileWriteable := err;
  456.     end;
  457.  
  458.     function HGetDirAccess (vRefNum: integer; dirID: longInt; name: StringPtr; var ownerID, groupID, accessRights: longInt): OSErr;
  459.         var
  460.             pb: HParamBlockRec;
  461.             err: OSErr;
  462.     begin
  463.         pb.ioNamePtr := name;
  464.         pb.ioVRefNum := vRefNum;
  465.         pb.ioDirID := dirID;
  466.         err := PBHGetDirAccessSync(@pb);
  467.         ownerID := pb.ioACOwnerID;
  468.         groupID := pb.ioACGroupID;
  469.         accessRights := pb.ioACAccess;
  470.         HGetDirAccess := err;
  471.     end;
  472.  
  473.     function FileLocked (fss: FSSpec): boolean;
  474.         var
  475.             locked: boolean;
  476.             junk: longint;
  477.             access: longint;
  478.     begin
  479.         locked := (IsVolumeWriteable(fss.vRefNum) <> noErr);
  480.         if not locked then begin
  481.             locked := (IsFileWriteable(fss) <> noErr);
  482.         end; (* if *)
  483.         if not locked then begin
  484.             if HGetDirAccess(fss.vRefNum, fss.parID, nil, junk, junk, access) = noErr then begin
  485.                 locked := not TPbtst(access, 26);
  486.             end; (* if *)
  487.         end; (* if *)
  488.         FileLocked := locked;
  489.     end; (* FileLocked *)
  490.  
  491.     procedure LSetNoSelection (list: ListHandle);
  492.         var
  493.             c: Cell;
  494.     begin
  495.         c.v := 0;
  496.         c.h := 0;
  497.         while LGetSelect(true, c, list) do begin
  498.             LSetSelect(false, c, list);
  499.             c.v := c.v + 1;
  500.             c.h := 0;
  501.         end;
  502.     end;
  503.  
  504.     procedure LSetSingleSelection (list: ListHandle; v: integer);
  505.         var
  506.             c: Cell;
  507.     begin
  508.         c.h := 0;
  509.         c.v := v;
  510.         LSetSelect(true, c, list);
  511.         c.v := 0;
  512.         c.h := 0;
  513.         while LGetSelect(true, c, list) do begin
  514.             if c.v <> v then begin
  515.                 LSetSelect(false, c, list);
  516.             end;
  517.             c.v := c.v + 1;
  518.             c.h := 0;
  519.         end;
  520.         LAutoScroll(list);
  521.     end;
  522.  
  523.     function LGetUniqueEntryName (list: ListHandle; c: cell; getentryname: GetEntryNameProcType): str255;
  524.         var
  525.             s: str255;
  526.     begin
  527.         s := '';
  528.         if getentryname <> nil then begin
  529.             s := getentryname(list, c);
  530.         end;
  531.         LGetUniqueEntryName := concat(s, chr(0), chr(c.v div 256), chr(c.v mod 256));
  532.     end;
  533.  
  534.     function LGetFirstSelection (list: ListHandle; var c: Cell; getentryname: GetEntryNameProcType): boolean;
  535.         var
  536.             best, n: str255;
  537.             index: integer;
  538.     begin
  539.         LGetFirstSelection := false;
  540.         c.h := 0;
  541.         c.v := 0;
  542.         best := concat(chr(255), chr(255));
  543.         while LGetSelect(true, c, list) do begin
  544.             LGetFirstSelection := true;
  545.             n := getentryname(list, c);
  546.             if IUCompString(n, best) < 0 then begin
  547.                 index := c.v;
  548.                 best := n;
  549.             end;
  550.             c.v := c.v + 1;
  551.         end;
  552.         c.h := 0;
  553.         c.v := index;
  554.     end;
  555.  
  556.     function LSelectFirstBefore (list: ListHandle; s: str255; getentryname: GetEntryNameProcType): boolean;
  557.         var
  558.             i, index: integer;
  559.             c: Cell;
  560.             best, n: str255;
  561.             good: boolean;
  562.     begin
  563.         good := false;
  564.         index := 0;
  565.         best := '';
  566.         for i := 0 to list^^.databounds.bottom - 1 do begin
  567.             c.h := 0;
  568.             c.v := i;
  569.             n := getentryname(list, c);
  570.             if (IUCompString(s, n) > 0) & (IUCompString(n, best) > 0) then begin
  571.                 best := n;
  572.                 index := c.v;
  573.                 good := true;
  574.             end;
  575.         end;
  576.         if good then begin
  577.             LSetSingleSelection(list, index);
  578.         end;
  579.         LSelectFirstBefore := good;
  580.     end;
  581.  
  582.     function LGetLastSelection (list: ListHandle; var c: Cell; getentryname: GetEntryNameProcType): boolean;
  583.         var
  584.             best, n: str255;
  585.             index: integer;
  586.     begin
  587.         LGetLastSelection := false;
  588.         c.h := 0;
  589.         c.v := 0;
  590.         best := '';
  591.         while LGetSelect(true, c, list) do begin
  592.             LGetLastSelection := true;
  593.             n := getentryname(list, c);
  594.             if IUCompString(n, best) > 0 then begin
  595.                 index := c.v;
  596.                 best := n;
  597.             end;
  598.             c.v := c.v + 1;
  599.         end;
  600.         c.h := 0;
  601.         c.v := index;
  602.     end;
  603.  
  604.     function LSelectFirstAfter (list: ListHandle; s: str255; getentryname: GetEntryNameProcType; orequal:Boolean): boolean;
  605.         var
  606.             i, index: integer;
  607.             c: Cell;
  608.             best, n: str255;
  609.             good: boolean;
  610.             comp: integer;
  611.     begin
  612.         good := false;
  613.         best := concat(chr(255), chr(255));
  614.         for i := 0 to list^^.databounds.bottom - 1 do begin
  615.             c.h := 0;
  616.             c.v := i;
  617.             n := getentryname(list, c);
  618.             comp := IUCompString(s, n);
  619.             if ((comp < 0) | ((comp = 0) & orequal)) & (IUCompString(n, best) < 0) then begin
  620.                 best := n;
  621.                 index := c.v;
  622.                 good := true;
  623.             end;
  624.         end;
  625.         if good then begin
  626.             LSetSingleSelection(list, index);
  627.         end;
  628.         LSelectFirstAfter := good;
  629.     end;
  630.  
  631.     procedure DoListKey (list: ListHandle; var er:EventRecord; getentryname: GetEntryNameProcType);
  632.         var
  633.             c: Cell;
  634.             index: integer;
  635.             dummy: boolean;
  636.             curticks: longInt;
  637.             ch:char;
  638.             s:Str255;
  639.             found:Boolean;
  640.     begin
  641.         curticks := er.when;
  642.         ch := chr(BAND(er.message, $FF));
  643.         if (typed_lh <> list) or (ch < ' ') then begin
  644.             typed_time := 0;
  645.             typed_lh := list;
  646.         end;
  647.         case ord(ch) of
  648.             downArrowChar:  begin
  649.                 c.h := 0;
  650.                 c.v := 0;
  651.                 index := 0;
  652.                 while LGetSelect(true, c, list) do begin
  653.                     c.v := c.v + 1;
  654.                     index := c.v;
  655.                 end;
  656.                 if index >= list^^.dataBounds.bottom then begin
  657.                     index := list^^.dataBounds.bottom - 1;
  658.                 end;
  659.                 LSetSingleSelection(list, index);
  660.                 LAutoScroll(list);
  661.             end;
  662.             upArrowChar:  begin
  663.                 c.h := 0;
  664.                 c.v := 0;
  665.                 if not LGetSelect(true, c, list) then begin
  666.                     c.v := list^^.dataBounds.bottom;
  667.                 end;
  668.                 if c.v > 0 then begin
  669.                     c.v := c.v - 1;
  670.                 end;
  671.                 LSetSingleSelection(list, c.v);
  672.                 LAutoScroll(list);
  673.             end;
  674.             homeChar:  begin
  675.                 LScroll(0, -list^^.dataBounds.bottom, list);
  676.             end;
  677.             endChar:  begin
  678.                 LScroll(0, list^^.dataBounds.bottom, list);
  679.             end;
  680.             pageUpChar:  begin
  681.                 LScroll(0, -(list^^.visible.bottom - list^^.visible.top - 2), list);
  682.             end;
  683.             pageDownChar:  begin
  684.                 LScroll(0, (list^^.visible.bottom - list^^.visible.top - 2), list);
  685.             end;
  686.             tabChar:  begin
  687.                 if BAND(er.modifiers, shiftKey) <> 0 then begin
  688.                     found := false;
  689.                     if LGetFirstSelection(list, c, getentryname) then begin
  690.                         s := getentryname(list, c);
  691.                         if LSelectFirstBefore(list, s, getentryname) then begin
  692.                             found := true;
  693.                         end;
  694.                     end;
  695.                     if not found then begin
  696.                         dummy := LSelectFirstBefore(list, chr(255), getentryname);
  697.                     end;
  698.                 end else begin
  699.                     if not LGetLastSelection(list, c, getentryname) | not LSelectFirstAfter(list, LGetUniqueEntryName(list, c, getentryname), getentryname, false) then begin
  700.                         dummy := LSelectFirstAfter(list, '', getentryname, false);
  701.                     end;
  702.                 end;
  703.             end;
  704.             otherwise begin
  705.                 if ch >= ' ' then begin
  706.                     if curticks - typed_time > 60 then begin
  707.                         typed_chars := '';
  708.                     end;
  709.                     typed_time := curticks;
  710.                     typed_chars := concat(typed_chars, ch);
  711.                     if not LSelectFirstAfter(list, typed_chars, getentryname, true) then begin
  712.                         dummy := LSelectFirstBefore(list, chr(255), getentryname);
  713.                     end;
  714.                 end;
  715.             end;
  716.         end;
  717.     end;
  718.  
  719.     function DecStr (l: longint): Str255;
  720.         var
  721.             s:Str255;
  722.     begin
  723.         NumToString(l,s);
  724.         DecStr := s;
  725.     end; (* DecStr *)
  726.  
  727.     function GetDirName (fs: FSSpec): OSErr;
  728.         var
  729.             pb: CInfoPBRec;
  730.     begin
  731.         pb.ioNamePtr := @fs.name;
  732.         pb.ioVRefNum := fs.vRefNum;
  733.         pb.ioDirID := fs.parID;
  734.         pb.ioFDirIndex := -1;    {* get information about ioDirID *}
  735.         GetDirName := PBGetCatInfoSync(@pb);
  736.     end;
  737.  
  738.     function CopyFork (srn, drn: integer; len: longInt): OSErr;
  739.         var
  740.             err: OSErr;
  741.             p: ptr;
  742.             size: longInt;
  743.             count: longInt;
  744.     begin
  745.         err := noErr;
  746.         size := 65536;
  747.         p := nil;
  748.         repeat
  749.             p := NewPtr(size);
  750.             if p <> nil then begin
  751.                 size := size div 2;
  752.             end;
  753.         until (p <> nil) or (size < 512);
  754.         if p = nil then begin
  755.             err := memFullErr;
  756.         end;
  757.         while (err = noErr) & (len > 0) do begin
  758.             count := size;
  759.             if count > len then begin
  760.                 count := len;
  761.             end;
  762.             err := FSRead(srn, count, p);
  763.             if (err = noErr) & (count = 0) then begin
  764.                 err := eofErr;
  765.             end;
  766.             if err = noErr then begin
  767.                 len := len - count;
  768.                 err := FSWrite(drn, count, p);
  769.             end;
  770.         end;
  771.         if p <> nil then begin
  772.             DisposePtr(p);
  773.         end;
  774.         CopyFork := err;
  775.     end;
  776.  
  777.     function CopyFile (source, dest: FSSpec): OSErr;
  778.         var
  779.             err, oerr, junk: OSErr;
  780.             pb: CInfoPBRec;
  781.             srrn, sdrn, drrn, ddrn: integer;
  782.     begin
  783.         junk := HDelete(dest.vRefNum, dest.parID, dest.name);
  784.         err := FSpGetCatInfo(source, 0, pb);
  785.         if err = noErr then begin
  786.             err := HCreate(dest.vRefNum, dest.parID, dest.name, pb.ioFlFndrInfo.fdCreator, pb.ioFlFndrInfo.fdType);
  787.             if err = noErr then begin
  788.                 err := HOpen(dest.vRefNum, dest.parID, dest.name, fsWrPerm, ddrn);
  789.                 if err = noErr then begin
  790.                     err := HOpenRF(dest.vRefNum, dest.parID, dest.name, fsWrPerm, drrn);
  791.                     if err = noErr then begin
  792.                         err := HOpen(source.vRefNum, source.parID, source.name, fsRdPerm, sdrn);
  793.                         if err = noErr then begin
  794.                             err := HOpenRF(source.vRefNum, source.parID, source.name, fsRdPerm, srrn);
  795.                             if err = noErr then begin
  796.                                 err := CopyFork(sdrn, ddrn, pb.ioFlLgLen);
  797.                                 if err = noErr then begin
  798.                                     err := CopyFork(srrn, drrn, pb.ioFlRLgLen);
  799.                                 end;
  800.                                 junk := FSClose(srrn);
  801.                             end;
  802.                             junk := FSClose(sdrn);
  803.                         end;
  804.                         oerr := FSClose(drrn);
  805.                         if err = noErr then begin
  806.                             err := oerr;
  807.                         end;
  808.                     end;
  809.                     oerr := FSClose(ddrn);
  810.                     if err = noErr then begin
  811.                         err := oerr;
  812.                     end;
  813.                 end;
  814.             end;
  815.         end;
  816.         if err = noErr then begin
  817.             err := FSpSetCatInfo(dest, pb);
  818.         end;
  819.         if err <> noErr then begin
  820.             junk := HDelete(dest.vRefNum, dest.parID, dest.name);
  821.         end;
  822.         CopyFile := err;
  823.     end; (* CopyFile *)
  824.  
  825.     function GetName (id1, id2: integer): str255;
  826.         var
  827.             sh: stringHandle;
  828.     begin
  829.         sh := GetString(id1);
  830.         if sh = nil then
  831.             sh := GetString(id2);
  832.         if sh <> nil then
  833.             GetName := sh^^ { Don't release it, someone else may be using it }
  834.         else
  835.             GetName := 'unnamed';
  836.     end;
  837.  
  838.     function GetOwnerName: str255;
  839.     begin
  840.         GetOwnerName := GetName(owner_id, machine_id);
  841.     end;
  842.  
  843.     function GetMachineName: str255;
  844.     begin
  845.         GetMachineName := GetName(machine_id, owner_id);
  846.     end;
  847.  
  848. end.
  849.