Several on the list have inquired about FB4's interaction with the Unix underpinnings of OS X. At the heart of that interaction are a host of functions ranging from tiny one-trick ponies, such as hostname; to heavy-duty utilities such as sed, awk and grep; all the way to perl and python which are languages unto themselves. At the heart of understanding Unix commands are the man (reference manual) pages for most functions. Written by engineers for engineers, the man pages can be a tough, terse read. But from them a diligent coder can wrest a great deal of power. I have written this little utility-- man[ager] -- to allows easy reference of man pages outside the Terminal environment. It also is capable of generating PDF files of most man pages onto your Desktop where you can print or store them for easy reference. This implementation should be more robust that earlier iterations I have posted here. I have used a popup menu that generates some huge lists of commands. At first I was reluctant to implement the lists with a popup, but I have found the popup easier and faster for me to navigate than a list. YMMV. I'm releasing this source code for review by members of this list, but am reserving rights to it. Comments, suggestions, criticism and/or bug reports are welcome. I am certainly no master Unix user. But as I have the opportunity, I hope to post a few examples and tutorials about how FB coders can harness the power of Unix with user-friendly GUI wrappers from the things I do know. (Michael Evans and I both, on occasion, both have to wrestle with this stuff at work, so we might as well have a little fun with it.) Ken Shmidheiser Somerset, KY '~'A ' Runtime : Rntm Appearance.Incl ' CPU : Carbon ' CALL Req'd : Off '~'B /* TWM - The only OS X, FB GUI builder in the world (probably) <http://homepage.ntlworld.com/bernie.w/twmad.htm> */ /* man[ager] - A Unix man page utility Easily view a Unix man page of save as PDF file to Desktop v0.1a (Alpha distribution to FB list) By Ken Shmidheiser Somerset, KY 42501 Copyright 2004 All rights reserved */ #define ControlSize as UInt16 _kControlSizeNormal = 0 _kControlSizeSmall = 1 _kControlSizeLarge = 2 _kControlSizeTag = _"size" begin globals dim dynamic cmdArr( _maxInt ) as str255 dim as container gC end globals gC = "" begin enum 1 _mainWnd _aboutWnd end enum begin enum 1 _infoEF _rGroup _r1 _r2 _r3 _r4 _cPop _cPush _cStat _cStat1 _cStat2 _cStat3 _cStat4 end enum _UnixMenuID = 128 _maxItems = 999 #define FMFontFamily as SInt16 toolbox fn FMGetFontFamilyFromName(Str255 iName) = FMFontFamily local fn BuildMenus '~'< apple menu "About man[ager]" menu 1, 0, _enable, "File" menu 1, 1, _enable, "Create PDF.../S" edit menu 2 gFBEditSelectAll = _zTrue end fn local fn AboutWindow dim as str255 infoStr dim as rect r '~'< setrect( r, 0, 0, 250, 215 ) appearance Window -_aboutWnd, "About man[ager]", @r,¬ _kDocumentWindowClass, _kWindowCloseBoxAttribute def SetWindowBackground( _kThemeActiveDialogBackgroundBrush,_zTrue) text _helvetica, 16, _boldBit%, _srcCopy color _zBlue setrect( r, 20, 15, 230, 35 ) edit field -10,, @r, _statNoFramed, _centerJust infoStr = "man[ager] 0.1a" edit$(10) = infoStr text _helvetica, 14, _boldBit% setrect( r, 10, 40, 240, 60 ) edit field -11,, @r, _statNoFramed, _centerJust infoStr = "A Unix man page reader" edit$(11) = infoStr text _applFont, 10, 0, _srcCopy setrect( r, 0, 70, 250, 185 ) color _zBlack edit field -12,, @r,_copyOnlyFramed_autoGray,_centerJust infoStr =¬ chr$(13) + " A small programming utility designed"¬ + chr$(13) + "to quickly find and display a Unix man page"¬ + chr$(13) + "and to allow it be saved to the Desktop as a PDF."¬ + string$( 2, 13 ) edit$( 12, _maxInt, _maxInt ) = infoStr infoStr =¬ "Software by Ken Shmidheiser"¬ + chr$(13) + "Copyright ©2004"¬ + chr$(13) + "All rights reserved" edit$( 12, _maxInt, _maxInt ) = infoStr setrect( r, 0, 195, 250, 210 ) color _zRed text _applFont, 9, 0, _srcCopy edit field -14,, @r,_statNoFramed,_centerJust edit$(14) = "Alpha Distribution to FB List" edit field 0 Def WindowReposition( _aboutWnd, _mainWnd,¬ _kWindowAlertPositionOnParentWindowScreen ) window _aboutWnd end fn local fn CreateMenu( menuID as short,¬ menuItems(9999) as str255,¬ nItems as short ) dim as MenuRef mHndl dim as long j '~'1 mHndl = fn NewMenu( menuID, "" ) long if mHndl and ( nItems > 0 ) for j = 0 to nItems - 1 AppendMenu( mHndl, menuItems(j) ) next end if kill dynamic cmdArr end fn = mHndl local fn BuildUnixCommandMenu( menuID as short ) dim as long j dim as str255 c, t '~'1 kill dynamic cmdArr select case ( button( _rGroup ) ) case 1 : c = "ls -A /bin/ | sort -f" case 2 : c = "ls -A /usr/bin/ | sort -f" case 3 : c = "ls -A /usr/sbin/ | sort -f" case 4 : c = "ls -A /usr/share/ | sort -f" end select j = -1 open "Unix", 2, c do : line input #2, t j++ : cmdArr(j) =t until eof (2) : close 2 compress dynamic cmdArr end fn = fn CreateMenu( menuID, cmdArr(0), j+1 ) local fn BuildMainWnd dim as Str255 s dim as ControlFontStyleRec cfs, tfs dim as WindowAttributes wa dim as Rect r dim as ControlSize @ size dim as MenuRef @ mRef '~'< cfs.flags = _kControlUseFontMask_kControlUseJustMask wa = _kWindowCloseBoxAttribute¬ _kWindowCollapseBoxAttribute def NewWindowPositionMethod(_kWindowAlertPositionOnMainScreen) SetRect(r, 0, 0, 640, 480) appearance window -_mainWnd,¬ "man[ager] - A Unix man page reader", @r,¬ _kDocumentWindowClass, wa def NewWindowPositionMethod(0) def SetWindowBackground(_kThemeActiveDialogBackgroundBrush, _zTrue) '~'< SetRect(r, 20, 23, 467, 454) text _newyork, 10 edit = 3 s = "Please select a command from the popup menu..." edit field _infoEF, s, @r, _copyOnlyFramed, _leftJust SetRect(r, 470, 20, 485, 458) scroll button -_infoEF,0,0,0,0, @r, _scrollOther SetRect(r, 498, 76, 619, 182) appearance button _rGroup,¬ _activeBtn, _kControlSupportsEmbedding,,,, @r,¬ _kControlRadioGroupProc SetRect(r, 502, 84, 613, 102) appearance button _r1,¬ _activeBtn, _kControlRadioButtonCheckedValue,,,¬ "Bash commands", @r,¬ _kControlRadioButtonProc def EmbedButton(_r1, _rGroup) size = _kControlSizeSmall def SetButtonData(_r1, _kControlEntireControl, _kControlSizeTag,¬ SizeOf(ControlSize), size ) cfs.font = _kControlFontSmallSystemFont def SetButtonFontStyle(_r1, cfs) SetRect(r, 502, 108, 613, 126) appearance button _r2,¬ _activeBtn, _kControlRadioButtonUncheckedValue,,,¬ "BSD commands", @r,¬ _kControlRadioButtonProc def EmbedButton(_r2, _rGroup) def SetButtonData(_r2, _kControlEntireControl, _kControlSizeTag,¬ SizeOf(ControlSize), size ) def SetButtonFontStyle(_r2, cfs) SetRect(r, 502, 135, 613, 147) appearance button _r3,¬ _activeBtn, _kControlRadioButtonUncheckedValue,,,¬ "OS X commands", @r,¬ _kControlRadioButtonProc def EmbedButton(_r3, _rGroup) def SetButtonData(_r3, _kControlEntireControl, _kControlSizeTag,¬ SizeOf(ControlSize), size ) def SetButtonFontStyle(_r3, cfs) SetRect(r, 502, 159, 613, 171) appearance button _r4,¬ _activeBtn, _kControlRadioButtonUncheckedValue,,,¬ "Misc. commands", @r,¬ _kControlRadioButtonProc def EmbedButton(_r4, _rGroup) def SetButtonData(_r4, _kControlEntireControl, _kControlSizeTag,¬ SizeOf(ControlSize), size ) def SetButtonFontStyle(_r4, cfs) mRef = fn BuildUnixCommandMenu( _UnixMenuID ) SetRect(r, 502, 42, 620, 59) appearance button _cPop,,, -12345, -1,¬ "", @r, _kControlPopupButtonProc def SetButtonFontStyle(_cPop, cfs) if mRef then def SetButtonData( _cPop, _kControlMenuPart,¬ _kControlPopupButtonMenuHandleTag, sizeof( handle), mRef ) appearance button _cPop,, 1, 1, _maxItems SetRect(r, 498, 443, 620, 460) appearance button _cPush,¬ _activeBtn,,,,¬ "Create PDF", @r,¬ _kControlPushButtonProc def SetButtonFontStyle(_cPush, cfs) SetRect(r, 502, 20, 620, 36) appearance button _cStat,¬ _activeBtn,,,,, @r,¬ _kControlStaticTextProc tfs.flags = _kControlUseFontMask_kControlUseSizeMask¬ _kControlUseFaceMask_kControlUseJustMask tfs.font = fn FMGetFontFamilyFromName("Lucida Grande") tfs.size = 13 tfs.style = 0 tfs.just = _teJustLeft def SetButtonFontStyle(_cStat, tfs) s = "Select command:" def SetButtonTextString(_cStat, s) SetRect(r, 502, 228, 607, 263) appearance button _cStat1,¬ _activeBtn,,,,, @r,¬ _kControlStaticTextProc def SetButtonFontStyle(_cStat1, tfs) s = "Terminal tips for man pages:" def SetButtonTextString(_cStat1, s) SetRect(r, 502, 269, 630, 289) appearance button _cStat2,¬ _activeBtn,,,,, @r,¬ _kControlStaticTextProc def SetButtonFontStyle(_cStat2, tfs) s = "Space = Page down" def SetButtonTextString(_cStat2, s) SetRect(r, 502, 288, 620, 304) appearance button _cStat3,¬ _activeBtn,,,,, @r,¬ _kControlStaticTextProc def SetButtonFontStyle(_cStat3, tfs) s = "b = Page up" def SetButtonTextString(_cStat3, s) SetRect(r, 502, 306, 619, 322) appearance button _cStat4,¬ _activeBtn,,,,, @r,¬ _kControlStaticTextProc def SetButtonFontStyle(_cStat4, tfs) s = "q = Exit" def SetButtonTextString(_cStat4, s) edit field 0 end fn local fn ClearMenu( whichMenu as long ) dim as MenuRef menuRef dim as long i, item '~'1 menuRef = fn GetMenuHandle( whichMenu ) long if ( menuRef ) item = fn CountMenuItems( menuRef ) long if ( item ) for i = 1 to item DeleteMenuItem( menuRef, i) next i end if end if end fn local fn GetPopupMenuText$( menuID AS long ) dim as integer mItem dim as str255 txtStr dim as MenuRef mHndl '~'1 mItem = button( menuID ) mHndl = button( menuID, _FBgetControlMenuHandle ) GetMenuItemText( mHndl, mItem, txtStr ) end fn = txtStr local fn SelectCommandType dim as MenuRef @ mRef '~'1 button -_cPop fn ClearMenu( _UnixMenuID ) mRef = fn BuildUnixCommandMenu( _UnixMenuID ) long if ( mRef ) def SetButtonData( _cPop, _kControlMenuPart,¬ _kControlPopupButtonMenuHandleTag, sizeof( handle), mRef ) appearance button _cPop,, 1, 1, _maxItems end if button _cPop end fn local fn UnixCommand( unixCmd as str255 ) dim as str255 tempStr, warnStr '~'1 warnStr = "WARNING:" + string$( 2, 13 ) warnStr += "Results too long to display." warnStr += " Click ""Create PDF"" to make file on your Desktop." open "Unix", 2, unixCmd do : line input #2, tempStr long if ( len( gC ) < 32700 ) gC = gC + tempStr + chr$(13) xelse gC = warnStr edit$( _infoEf ) = #gC edit field 0 close 2 exit fn end if until eof (2) : close 2 end fn local fn GetCommand dim as str255 cmd, warnStr dim as str31 manPage dim as handle tempH '~'1 manPage = fn GetPopupMenuText$( _cPop ) warnStr = "No man page available (or may be subdirectory)." warnStr += string$(2, 13) warnStr += "Try typing """ + manPage + " -h"" in the Terminal" warnStr += " to see if help is available for this command." cmd = "man " cmd += manPage cmd += " | col -b | uniq" gC = "" fn UnixCommand( cmd ) long if (len( gC ) > 3 ) edit$( _infoEF ) = #gC edit field 0 xelse edit$( _infoEF ) = warnStr edit field 0 end if gC = "" end fn local fn CreatePDFManPage dim as str255 cmd, whichMan, tempStr, warnStr '~'1 whichMan = fn GetPopupMenuText$( _cPop ) warnStr = "No man page available (or may be subdirectory)." warnStr += string$(2, 13) warnStr += "Try typing """ + whichMan + " -h"" in the Terminal" warnStr += " to see if help is available for this command." edit$(_infoEF ) = "Searching for " + whichMan + " man page..." edit$(_infoEF, _maxInt, _maxInt) = chr$(13) + "(May take a minute...)" cmd = "man -t " + whichMan cmd = cmd + " | pstopdf -i -o ~/Desktop/""" cmd = cmd + whichMan + " man page.pdf""" open "Unix", 2, cmd do : line input #2, tempStr long if ( tempStr[0] > 0 ) edit$( _infoEF ) = warnStr close 2 exit fn end if until eof (2) : close 2 edit$( _infoEf ) = whichMan + " man page.pdf on your Desktop" end fn local fn DoMenu dim as long menuID, itemID '~'< menuID = menu(_menuID) itemID = menu(_itemID) select case( menuID ) case _applemenu select( itemID ) case 1 : fn AboutWindow end select case 1 select( itemID ) case 1 : fn CreatePDFManPage end select end select menu end fn local fn DoDialog dim as Rect r dim as long ev, id '~'< ev = dialog(0) id = dialog(ev) select( ev ) case _wndClose select( id ) case _mainWnd : gFBQuit = _zTrue case _aboutWnd : window close _aboutWnd end select case _btnClick select window( _outputWnd ) case _mainWnd select( id ) case _rGroup : fn SelectCommandType case _cPop : fn GetCommand case _cPush : fn CreatePDFManPage end select end select end select end fn on menu fn DoMenu on dialog fn DoDialog fn BuildMenus fn BuildMainWnd window 1 do HandleEvents until gFBQuit Copyright 2004 Ken Shmidheiser