[futurebasic] man[ager] - A Unix man page utility

Message: < previous - next > : Reply : Subscribe : Cleanse
Home   : October 2004 : Group Archive : Group : All Groups

From: Ken Shmidheiser <kshmidheiser@...>
Date: Sat, 16 Oct 2004 08:31:39 -0400
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