Faceless LiveCode App for CLI on Mac OS X and Windows 7

Richard Gaskin ambassador at fourthworld.com
Mon Apr 29 11:08:20 EDT 2013

Bob Cole wrote:

 > I am looking for an example of how to create a utility program in LC
 > to process a text file on Mac OS X and Windows 7.
 > I want to put it in a faceless processing stream perhaps with pipes
 > or redirection or options. Such as:
 >     ...
 >     cat textfile1 | myLCprogram | more
 >     ...
 > or
 >     ...
 >     myLCprogram < textfile1 > textfile2
 >     ...
 > or
 >     ...
 >     myLCprogram -f textfile1 -o textfile2
 >     ...
 > I have read the dictionary about open process and open file but I
 > don't know how to save the LC program without triggering the ui.
 > What I need is an example of how myLCprogram is structured or wrapped
 > in a shell script that can be used as cli command.
 >     Do I need to use -ui somewhere?

Yes.  Add -ui, and avoid flags the engine currently expects, and you'll 
be fine.

The latter is the harder part of this, since the engine still reserves a 
great many flags it no longer uses - these are listed here in this 
request to remove the ones that are no longer relevant (perhaps this 
will be one of the first pull requests submitted, since I can't imagine 
it'll take long to fix):

           [-f[iles] (disable access to files and processes)
           [-g[eometry] ={+-}<xoffset>{+-}<yoffset>]
           [-i[nput] fd] read commands from fd (0 is stdin) or named pipe
           [-m[map]] (don't memory map files)
           [-n[opixmaps]] (draw direct to screen)
           [-p[ointerfocus]] (use active focus)
           [-s[haredoff]] (don't use shared memory server extension)
           [+s[haredon]] (use shared memory server extension)
           [-u[i]] (don't create graphical user interface)
           [-v[isualid] n] (use visual id n as listed from xdpyinfo)
           [-w[indowid] n] (watch window id n for commands)
           [stackname(s) | argument(s)]

One challenge for apps that support both GUI and CLI is to determine 
whether the app has been called with "-ui", and it turns out if so the 
windowID will be "1", so you can use:

on startup
   if the windowID of this stack = 1 then
   end if
end startup

My HandleCommandLineInterface handler does a lot of app-specific things 
not relevant here, but one of the first things it calls is a handler to 
parse the arguments which may be useful, using "$#" to obtain the number 
of args passed in:

on CLIInit
   -- Parse args:
   put $# into sCLINumArgs
   repeat with i = 1 to sCLINumArgs
     do ("put $"& i &" into sCLIArgsA[i]")
   end repeat
   -- Get App Name:
   put $0 into tmp
   if the platform is "Win32" then
     replace "\" with "/" in tmp
   end if
   set the itemdel to "/"
   put last item of tmp into sCLIAppName
   -- Get log file:
   put CLIArg("-l") into sCLIErrLogFile
end CLIInit

That uses a function named CLIArg, defined as:

-- CLIArg
-- Returns the data in the argument following the one
-- matching the data supplied in pFlag.  If pRequired
-- is not empty and no matching arg is found, logs
-- an error:
function CLIArg pFlag, pRequired
   repeat with i = 1 to sCLINumArgs
     if sCLIArgsA[i] = pFlag then
       return sCLIArgsA[i+1]
     end if
   end repeat
   -- If we got here, then no arg was supplied:
   if pRequired is empty then
     return empty
     CLIErr "Couldn't find required argument for flag "& pFlag
   end if
end CLIArg

Some other supporting handlers I use:

function CLIFlag pFlag
   repeat with i = 1 to sCLINumArgs
     if sCLIArgsA[i] = pFlag then
       return true
     end if
   end repeat
   return empty
end CLIFlag

-- CLILog
-- Outputs s only if log file provided:
on CLILog s
   if sCLIErrLogFile is not empty then
     CLIOut s
   end if
end CLILog

-- CLIErr
-- Checks if s is empty, and if not it logs the string
-- in p; if p is empty s is logged instead
on CLIErr s, p
   if s is not empty then
     if p is empty then put s into p
     CLIOut p
   end if
end CLIErr

-- CLIOut
-- Writes s to stdout, also write s to log file
-- if path provided in arg after -l
on CLIOut s
   if sCLIErrLogFile is not empty then
     open file sCLIErrLogFile for append
     CLIErr the result, "Couldn't open log file: "& sCLIErrLogFile
     write s&cr to file sCLIErrLogFile
     close file sCLIErrLogFile
   end if
   write sCLIAppName &">: "&s &cr to stdout
end CLIOut

The vars preceded with "s" (e.g., sCLINumArgs) are script-local vars 
declared outside the handlers at the top of the script so they can be 
used in any subsequent handlers.

Hope that helps.  Keep us posted with how it goes.  It may be a bit 
geeky, but I find making CLI apps in LiveCode very rewarding. :)

  Richard Gaskin
  Fourth World
  LiveCode training and consulting: http://www.fourthworld.com
  Webzine for LiveCode developers: http://www.LiveCodeJournal.com
  Follow me on Twitter:  http://twitter.com/FourthWorldSys

More information about the use-livecode mailing list