home *** CD-ROM | disk | FTP | other *** search
/ Garbo / Garbo.cdr / mac / source / menustuf.sit / MenuStuffCommon.p < prev    next >
Text File  |  1990-04-16  |  8KB  |  385 lines

  1. Unit MenuStuffCommon;
  2. {
  3.     Definitions and utilties common to the MPW menu-manipulation tools.
  4.  
  5.     First working version by LDO 1989 January 4.
  6.     Modified 1989 January 6 to add general menu-traversal routines,
  7.         and modify search routines to use them.
  8.     Modified 1989 January 9 to add quoting routine.
  9.     Modified 1989 January 23 to simplify quoting routine.
  10.     Modified 1989 April 17 to add new special character for MPW 3.0.
  11.     Modified 1990 February 19 to ignore case and diacritical marks in
  12.         string comparisons, to be consistent with AddMenu and DeleteMenu.
  13. }
  14.  
  15. Interface
  16.  
  17.     Uses
  18.         MemTypes,
  19.         QuickDraw,
  20.         OSIntf,
  21.         ToolIntf;
  22.  
  23.     Type
  24.         MenuListHeader =
  25.             Record
  26.                 LastMenu : Integer;
  27.                 LastRight : Integer;
  28.                 mbProcID : Integer
  29.             End {Record};
  30.         MenuListPtr = ^MenuListHeader;
  31.         MenuListHandle = ^MenuListPtr;
  32.         MenuRec =
  33.             Record
  34.                 MenuOH : MenuHandle;
  35.                 MenuLeft : Integer
  36.             End {Record};
  37.         HMenuRec =
  38.             Record
  39.                 MenuHOH : MenuHandle;
  40.                 Reserved : Integer
  41.             End {Record};
  42.  
  43. {
  44.     Closures
  45. }
  46.  
  47.     Function CurrentA6 : LongInt;
  48.       { returns the current value of the stack frame register. }
  49.  
  50.         Inline
  51.             $2E8E;                { move.l a6, (sp) }
  52.  
  53. {
  54.     Menu-handling utilities
  55. }
  56.  
  57.     Procedure TraverseMenus
  58.       (
  59.         Handler : ProcPtr;
  60.         HandlerArg : univ LongInt
  61.       );
  62.       { traverses the top-level menu list, invoking the
  63.         handler procedure with each menu found. The handler
  64.         should be declared like this:
  65.  
  66.             Procedure Handler
  67.               (
  68.                 TheMenu : MenuHandle;
  69.                 var KeepGoing : Boolean;
  70.                 HandlerArg : univ LongInt
  71.               );
  72.  
  73.         where TheMenu is the next menu in the list, and KeepGoing
  74.         is initially True, but may be set to False by the
  75.         handler to stop the traversal of the menu list.
  76.         HandlerArg may be interpreted in any way the handler
  77.         wishes. }
  78.  
  79.     Procedure TraverseSubMenus
  80.       (
  81.         Handler : ProcPtr;
  82.         HandlerArg : univ LongInt
  83.       );
  84.       { traverses the hierarchical/pop-up section of the
  85.         menu list, invoking the handler procedure with
  86.         each menu found. See the description of TraverseMenus
  87.         to see how to declare the Handler. }
  88.  
  89.     Function FindMenu
  90.       (
  91.         MenuName : Str255
  92.       ) : MenuHandle;
  93.       { returns a handle to the menu in the current menu bar
  94.         with the specified name, or Nil if not found. }
  95.  
  96.     Function FindSubMenu
  97.       (
  98.         MenuName : Str255
  99.       ) : MenuHandle;
  100.       { returns a handle to the menu in the hierarchical portion of
  101.         the current menu list with the specified name, or Nil if not found. }
  102.  
  103.     Function FindItem
  104.       (
  105.         InMenu : MenuHandle;
  106.         WithName : Str255
  107.       ) : Integer;
  108.       { returns the number of the item in the given menu with the
  109.         given name, or 0 if not found. }
  110.  
  111. {
  112.     Argument quoting
  113. }
  114.  
  115.     Function Quote
  116.       (
  117.         Arg : Str255
  118.       ) : Str255;
  119.       { returns Arg suitably quoted as necessary to avoid interpretation
  120.         of any of the Shell's special characters. }
  121.  
  122. Implementation
  123.  
  124.     Type
  125.         MenuHandlePtr = ^MenuHandle;
  126.         IntPtr = ^Integer;
  127.  
  128. {
  129.     Menu-handling utilities
  130. }
  131.  
  132.     Function GetMenuList : MenuListHandle;
  133.       { returns the value of MenuList global. }
  134.  
  135.         Inline
  136.             $2EB8, $0A1C;        {move.l $0A1C, (sp)}
  137.  
  138.     Procedure CallHandler
  139.       (
  140.         TheMenu : MenuHandle;
  141.         var KeepGoing : Boolean;
  142.         HandlerArg : univ LongInt;
  143.         Handler : ProcPtr
  144.       );
  145.       { invokes the handler with the specified arguments. }
  146.  
  147.         Inline
  148.             $205F,            {move.l (sp)+, a0}
  149.             $4E90;            {jsr (a0)}
  150.  
  151.     Procedure TraverseMenus
  152.       (
  153.         Handler : ProcPtr;
  154.         HandlerArg : univ LongInt
  155.       );
  156.       { traverses the top-level menu list, invoking the
  157.         handler procedure with each menu found. }
  158.  
  159.         Var
  160.             TheMenuList : MenuListHandle;
  161.             ThisOffset : Integer;
  162.             ThisMenu : MenuHandle;
  163.             KeepGoing : Boolean;
  164.  
  165.       Begin
  166.         TheMenuList := GetMenuList;
  167.         ThisOffset := SizeOf(MenuListHeader);
  168.         KeepGoing := True;
  169.         Repeat {until left}
  170.             If ThisOffset > TheMenuList^^.LastMenu then
  171.                 Leave;
  172.             ThisMenu := MenuHandlePtr(Ord4(TheMenuList^) + ThisOffset)^;
  173.             CallHandler(ThisMenu, KeepGoing, HandlerArg, Handler);
  174.             If not KeepGoing then
  175.                 Leave;
  176.             ThisOffset := ThisOffset + SizeOf(MenuRec)
  177.         Until
  178.             False
  179.       End {TraverseMenus};
  180.  
  181.     Procedure TraverseSubMenus
  182.       (
  183.         Handler : ProcPtr;
  184.         HandlerArg : univ LongInt
  185.       );
  186.       { traverses the hierarchical/pop-up section of the
  187.         menu list, invoking the handler procedure with
  188.         each menu found. }
  189.  
  190.         Var
  191.             TheMenuList : MenuListHandle;
  192.             LastHMenu, ThisOffset : Integer;
  193.             ThisMenu : MenuHandle;
  194.             KeepGoing : Boolean;
  195.  
  196.       Begin
  197.         TheMenuList := GetMenuList;
  198.         ThisOffset := TheMenuList^^.LastMenu + SizeOf(MenuRec);
  199.         LastHMenu := ThisOffset + IntPtr(LongInt(TheMenuList^) + ThisOffset)^;
  200.         ThisOffset := ThisOffset + 6; { point to first hierarchical menu }
  201.         KeepGoing := True;
  202.         Repeat {until left}
  203.             If ThisOffset > LastHMenu then
  204.                 Leave;
  205.             ThisMenu := MenuHandlePtr(Ord4(TheMenuList^) + ThisOffset)^;
  206.             CallHandler(ThisMenu, KeepGoing, HandlerArg, Handler);
  207.             If not KeepGoing then
  208.                 Leave;
  209.             ThisOffset := ThisOffset + SizeOf(HMenuRec)
  210.         Until
  211.             False
  212.       End {TraverseSubMenus};
  213.  
  214.     Function FindMenu
  215.       (
  216.         MenuName : Str255
  217.       ) : MenuHandle;
  218.       { returns a handle to the menu in the current menu bar
  219.         with the specified name, or Nil if not found. }
  220.  
  221.         Procedure FindHandler
  222.           (
  223.             TheMenu : MenuHandle;
  224.             var KeepGoing : Boolean
  225.           );
  226.           { checks menu name against that desired. }
  227.  
  228.           Begin
  229.             If EqualString(TheMenu^^.MenuData, MenuName, False, False) then
  230.               Begin
  231.                 FindMenu := TheMenu;
  232.                 KeepGoing := False
  233.               End {If}
  234.           End {FindHandler};
  235.  
  236.       Begin {FindMenu}
  237.         FindMenu := Nil; { initial assumption }
  238.         TraverseMenus(@FindHandler, CurrentA6)
  239.       End {FindMenu};
  240.  
  241.     Function FindSubMenu
  242.       (
  243.         MenuName : Str255
  244.       ) : MenuHandle;
  245.       { returns a handle to the menu in the hierarchical portion of
  246.         the current menu list with the specified name, or Nil if not found. }
  247.  
  248.         Procedure FindHandler
  249.           (
  250.             TheMenu : MenuHandle;
  251.             var KeepGoing : Boolean
  252.           );
  253.           { checks menu name against that desired. }
  254.  
  255.           Begin
  256.             If EqualString(TheMenu^^.MenuData, MenuName, False, False) then
  257.               Begin
  258.                 FindSubMenu := TheMenu;
  259.                 KeepGoing := False
  260.               End {If}
  261.           End {FindHandler};
  262.  
  263.       Begin {FindSubMenu}
  264.         FindSubMenu := Nil; { initial assumption }
  265.         TraverseSubMenus(@FindHandler, CurrentA6)
  266.       End {FindSubMenu};
  267.  
  268.     Function FindItem
  269.       (
  270.         InMenu : MenuHandle;
  271.         WithName : Str255
  272.       ) : Integer;
  273.       { returns the number of the item in the given menu with the
  274.         given name, or 0 if not found. }
  275.  
  276.         Var
  277.             ThisItem, NrItems : Integer;
  278.             ThisName : Str255;
  279.  
  280.       Begin
  281.         NrItems := CountMItems(InMenu);
  282.         ThisItem := 0;
  283.         Repeat {until left}
  284.             If ThisItem = NrItems then
  285.               Begin
  286.                 FindItem := 0; { not found }
  287.                 Leave;
  288.               End {If};
  289.             ThisItem := ThisItem + 1;
  290.             GetItem(InMenu, ThisItem, ThisName);
  291.             If EqualString(ThisName, WithName, False, False) then
  292.               Begin
  293.                 FindItem := ThisItem; { found }
  294.                 Leave
  295.               End {If}
  296.         Until
  297.             False
  298.       End {FindItem};
  299.  
  300. {
  301.     Argument quoting
  302. }
  303.  
  304.     Function AnyPresent
  305.       (
  306.         Chars, InString : Str255
  307.       ) : Boolean;
  308.       { returns True iff any of the characters in Chars are
  309.         present in InString. }
  310.  
  311.         Var
  312.             ThisPos : Integer;
  313.  
  314.       Begin
  315.         ThisPos := Length(Chars);
  316.         Repeat {until left}
  317.             If ThisPos = 0 then
  318.               Begin
  319.                 AnyPresent := False;
  320.                 Leave
  321.               End {If};
  322.             If Pos(Chars[ThisPos], InString) <> 0 then
  323.               Begin
  324.                 AnyPresent := True;
  325.                 Leave
  326.               End {If};
  327.             ThisPos := ThisPos - 1
  328.         Until
  329.             False
  330.       End {AnyPresent};
  331.  
  332.     Function Quote
  333.       (
  334.         Arg : Str255
  335.       ) : Str255;
  336.       { returns Arg suitably quoted as necessary to avoid interpretation
  337.         of any of the Shell's special characters. }
  338.  
  339.         Const
  340.             SingleQuote = '''';
  341.             QuoteNext = '╢';
  342.             SpecialChars = ';|&()╔#╢"/\{}`?┼[]*+╟╚<>│╖ ';
  343.  
  344.         Var
  345.             QuotePos : Integer;
  346.             Result : Str255;
  347.  
  348.         Function SimpleQuote
  349.           (
  350.             Arg : Str255
  351.           ) : Str255;
  352.           { quotes Arg if it contains any special characters. Assumes
  353.             no single quotes are present. }
  354.  
  355.           Begin
  356.             If AnyPresent(Concat(SpecialChars, Chr(9), Chr(13)), Arg) then
  357.                 SimpleQuote := Concat(SingleQuote, Arg, SingleQuote)
  358.             else
  359.                 SimpleQuote := Arg
  360.           End {SimpleQuote};
  361.  
  362.       Begin {Quote}
  363.         Result := '';
  364.         Repeat {until left}
  365.             QuotePos := Pos(SingleQuote, Arg);
  366.             If QuotePos = 0 then
  367.               Begin
  368.                 Result := Concat(Result, SimpleQuote(Arg));
  369.                 Leave
  370.               End {If};
  371.             Result := Concat
  372.               (
  373.                 Result,
  374.                 SimpleQuote(Copy(Arg, 1, QuotePos - 1)),
  375.                 QuoteNext,
  376.                 SingleQuote
  377.               );
  378.             Delete(Arg, 1, QuotePos)
  379.         Until
  380.             False;
  381.         Quote := Result
  382.       End {Quote};
  383.  
  384. End {MenuStuffCommon}.
  385.