home *** CD-ROM | disk | FTP | other *** search
/ ftp.robelle3000.ai 2014 / 2014.06.ftp.robelle3000.ai.tar / ftp.robelle3000.ai / papers / progci.pro < prev    next >
Text File  |  1995-09-10  |  54KB  |  1,422 lines

  1. .com.sel(1)
  2. .com {ifout starts here}
  3. .comment  Choose the output device parameters for this document
  4. .if outfinal
  5. .  if outrecord
  6. .    out(las 30 c1 r+ s4).com Robelle bound version, attached
  7. .  else
  8. .    out(las 30 c1 r- s4).com Robelle bound version
  9. .  endif
  10. .elseif outhelpcomp
  11. .  out(lpt q+ w80).com helpcomp;parm=1
  12. .elseif outa4
  13. .  if outlpt
  14. .    if outrecord
  15. .      out(lpt s4 r+).com A4 paper, $Stdlist/LP/disc, attached
  16. .    else
  17. .      out(lpt s4 r-).com A4 paper, $Stdlist/LP/disc
  18. .    endif
  19. .  elseif outlaser
  20. .    if outrecord
  21. .      if outdouble
  22. .        out(las 30 s5 r+ d+).com A4 paper, LaserJet, attached, duplex
  23. .      else
  24. .        out(las 30 s5 r+).com A4 paper, LaserJet, attached
  25. .      endif
  26. .    else
  27. .      if outdouble
  28. .        out(las 30 s5 r- d+).com A4 paper, LaserJet, duplex
  29. .      else
  30. .        out(las 30 s5 r-).com A4 paper, LaserJet
  31. .      endif
  32. .    endif
  33. .  else.com No other outxxx jcws specified
  34. .    out(lpt s4 r-).com generic: A4 paper, $Stdlist/LP/disc
  35. .  endif
  36. .else
  37. .  if outlpt
  38. .    if outrecord
  39. .      out(lpt s3 r+).com Letter, $Stdlist/LP/disc, attached
  40. .    else
  41. .      out(lpt s3 r-).com Letter, $Stdlist/LP/disc
  42. .    endif
  43. .  elseif outlaser
  44. .    if outrecord
  45. .      if outdouble
  46. .        out(las 30 s4 r+ d+).com Letter, LaserJet, attached, duplex
  47. .      else
  48. .        out(las 30 s4 r+).com Letter, LaserJet, attached
  49. .      endif
  50. .    else
  51. .      if outdouble
  52. .        out(las 30 s4 r- d+).com Letter, LaserJet, duplex
  53. .      else
  54. .        out(las 30 s4 r-).com Letter, LaserJet
  55. .      endif
  56. .    endif
  57. .  else.com No outxxx jcws specified
  58. .    out(lpt s3 r-).com Letter, generic: $Stdlist/LP/disc
  59. .  endif
  60. .endif
  61. .comment
  62. .include f92286f.qlibdata.robelle
  63. .include styles.qlibdata.robelle
  64. .form(k1 [ ///l51 / #31"Programming the CI"/#34"4018-"Pn:0////])
  65. .form(k2 [ ////l51 //// ])
  66. .form 2
  67. .if not outhelpcomp
  68. .   mar(k1 l0)
  69. .   mar(k2 l0)
  70. .endif
  71. .opt (f- l- r-)
  72. .title 4018
  73.  
  74.  
  75.  
  76.  
  77.  
  78.  
  79. .com |6PAPER NUMBER 4018|
  80.  
  81.  
  82.  
  83. .font 3
  84. Programming the Command Interpreter
  85.  
  86.  
  87.  
  88. |1An Introduction, a Dog, and New Tricks|
  89.  
  90.  
  91.  
  92.  
  93.  
  94.  
  95.  
  96.  
  97. .font 1
  98. by Ken Robertson
  99. July 1995
  100.  
  101.  
  102.  
  103.  
  104.  
  105.  
  106.  
  107.  
  108.  
  109.  
  110.  
  111.  
  112.  
  113. Robelle Consulting Ltd.
  114. Unit 201, 15399-102A Ave.
  115. Surrey, B.C.@@Canada V3R 7K1
  116. Toll-free:@@1-800-561-8311
  117. Phone:@@(604) 582-1700
  118. Fax:@@(604) 582-1799
  119.  
  120. E-mail:@@ken_robertson&@robelle.com
  121. WWW:@@http://www.robelle.com
  122. .font 0
  123.  
  124. Copyright Robelle Consulting Ltd. 1995
  125.  
  126. Permission is granted to reprint this document (but ~not~
  127. for profit), provided that copyright notice is given.
  128. .opt
  129. .font 0
  130. .count 0
  131. .form 1
  132. .page
  133. .opt (l- r- f-)
  134. |3 Programming the Command Interpreter|
  135.  
  136. |1An Introduction, a Dog, and New Tricks|
  137.  
  138. |1by Ken Robertson|
  139.  
  140.  
  141. .opt
  142. |3Introduction|
  143.  
  144. An overworked, understaffed data processing department is all too common
  145. in today's ever belt-tightening, downsizing and de-staffing
  146. companies.
  147.  
  148. An ad-hoc request may come to the harried data processing manager.  She may
  149. throw her hands up in despair and say, "It can't be done.  Not within the time
  150. frame that you need it in."   Of course, every computer-literate person knows
  151. deep down in his heart that every programming request can be fulfilled, if the programmer
  152. has enough
  153. hours to code, debug, test, document and implement the new program.  The informed DP manager
  154. knows that programming the Command Interpreter (CI) can sometimes reduce that
  155. time, changing the "impossible deadline" into something more
  156. achievable.
  157.  
  158. In this paper you will learn some of the programming concepts
  159. of the CI.  You will also learn how you can use the CI to solve some common
  160. data processing problems.
  161.  
  162. You will find a short glossary at the end that explains
  163. some of the terms used in this paper.
  164.  
  165.  
  166. |3A Little History|
  167.  
  168. Before MPE/iX, (and even before MPE/XL), there was a run-time
  169. environment for the MPE/V class of HP computers called the Command
  170. Interpreter (CI).
  171.  
  172. The Command Interpreter on MPE/V machines had limited programming capability,
  173. with If@/@@Else constructs and numeric variables limited to values between
  174. 0 and 65535.  The basic interface of the MPE/V CI
  175. was ported to MPE/iX machines, and beefed up to be usable as a
  176. run-time shell.
  177.  
  178. The MPE/iX Command Interpreter has a generous
  179. command set that pushes the shell into the realm of a true programming
  180. tool.  Its ability to evaluate expressions, and to perform I/O on
  181. files allows the end user to perform simple data processing
  182. functions without having to resort to using a 3GL.
  183. The CI can be used to solve complex problems.
  184. Since its code is interpreted, a CI solution to a problem may execute too
  185. slowly for practical purposes.  In this case, a 3GL, 4GL, or third- party software solution would
  186. have to be investigated.
  187.  
  188.  
  189. |3What are Command Files?|
  190.  
  191. Command files are a collection of commands in flat files, of either variable or
  192. fixed length record structure, that reside in the MPE or POSIX
  193. file space.  Phew!  Basically, command files are what you could call MPE macros.
  194. Anything that you can do interactively in the CI, you can do with command files,
  195. and then some.
  196. You can use command files in situations that call for
  197. repetitive functions, such as recompiling source code, special spooler commands,
  198. etc.  Command files are also great
  199. when you want to hide details from the
  200. end user.
  201.  
  202. A command file is executed when its name is
  203. typed in the CI, or
  204. invoked from a command file or programming shell.  Just as in
  205. program execution, the user's Hppath is searched to determine the location of
  206. the command file.
  207.  
  208. When you're deciding where to store a command file,
  209. it's a good idea to have some conventions in mind.
  210. One common convention involves creating
  211. a CMD group (short for command group) in every account for local command files, and a
  212. production CMD group that everyone can access.  You can set up a logon UDC to
  213. ensure that the Hppath variable is set correctly.
  214.  
  215. Hey - why not have a logon command file?  Well, you can't, because the current
  216. version of MPE doesn't support it.
  217. If you insist on having one, you can always make a logon UDC that executes
  218. your logon command file.
  219.  
  220. .style example
  221.    ***********************
  222.    logonudc
  223.    option logon, nobreak
  224.    logon.cmd.prod
  225.    bye
  226. .style body
  227.  
  228. The above UDC is invoked at logon, and executes the command file
  229. called |5logon.cmd.prod|.  The last line in the command file logs the user off.
  230.  
  231. One question that often arises is "Which are better - command files or UDC's?"
  232. Interestingly enough, UDC stands for User Defined Command.  UDC's must be managed
  233. differently from command files, and have small differences in their internal organization.
  234.  
  235. A UDC file is a library of callable commands with multiple entry points, whereas a command file
  236. has but one entry point.  You manage UDC files via the Setcatalog and Showcatalog commands.  If
  237. you need to make
  238. modifications to a UDC, you must make sure that no
  239. users are accessing the file when you want to save your changes.
  240.  
  241. UDC files must be attached to a session using the Setcatalog command.  This means that the
  242. UDC file (and all of the UDC's you set up) will be in use while a user is logged on.
  243. In order to make changes to a UDC file, you will have to either bump the users accessing the file off
  244. the system, or create a brand new UDC file and issue a new Setcatalog command.  The changes that you made
  245. will take effect only when the user logs back on again.
  246.  
  247. With command files, on the other hand,
  248. you may create new ones at any time.  They will be immediately accessible to anyone who is
  249. logged on.
  250. You still need exclusive access to delete or to make changes to an existing command file,
  251. but users are also less likely to be accessing command files.
  252.  
  253. In the current operating system, UDC's do tend to be more secure - you can use |5option nohelp| to prevent snooping
  254. eyes from reading the contents of a particular user command.  (Note:  A future operating system release
  255. will allow execute access for command files.  Currently, you must have execute and read access to the files in order
  256. to use them.)
  257.  
  258.  
  259. .page 12
  260. |3The Command File Structure|
  261.  
  262. The structure of a command file is as follows:
  263.  
  264. .style example
  265.    PARM parameter declarations       (optional)
  266.    MPE command
  267.    .
  268.    .
  269.    .
  270.    MPE command
  271. .style body
  272.  
  273. Any MPE command can be used.  This includes If@/@@Else,
  274. and While to form looping constructs.
  275. You can also invoke any command file or UDC by its name.  Command files
  276. can be called recursively, nesting levels up to 30
  277. times deep.  |2(Note to Qedit users:  Qedit has a maximum recursive level
  278. of 10, which should be enough.)|
  279.  
  280. .page 7
  281.  
  282. |3The Programming Environment|
  283.  
  284. Programmers will tell you that they need an "environment in which to
  285. operate".  Development of code should progress smoothly, with a minimum of
  286. effort required to translate ideas into working programs.
  287.  
  288. For this you need an editor, and in the case of 3GL and 4GL, a program
  289. (compiler) to compile your code.  Strictly speaking, you don't need an editor to
  290. create CI "programs", but it does make your job of writing the code a lot easier.
  291. Qedit, from Robelle Consulting, is a flexible editor in which to develop CI
  292. programs.  You can stay inside Qedit to write, to keep and to test your command
  293. files, which can save you steps in the traditional
  294. "Text, Keep, Exit,
  295. Try Again, and Edit" cycle.
  296.  
  297. If you don't want to use an editor to create command files, you can use a
  298. feature of the CI called I/O redirection.  For example, the following CI commands
  299. will build a simple command file called |5sj|.
  300. .font 5
  301.  
  302.     echo echo All executing jobs: > sj
  303.     echo showjob;exec  >> sj
  304.  
  305. .font 0
  306. Note that as your command files become more complex, you may find it trickier
  307. to edit them in this manner.
  308. Consider a command file that can be used
  309. to look up telephone numbers from a flat file:
  310.  
  311. .style example
  312.    anyparm search_string = "?"
  313.    if "!search_string" = "?" then
  314.        echo  command file:  phone  search_string
  315.        return
  316.    endif
  317.    grep.hpbin.sys "-i '!search_string' PHONES"
  318. .style body
  319.  
  320. How can you echo variables into a file without getting the assigned value of the variable?
  321. Say, for example, the value of the variable |5my_time| was equal to "10:02".
  322. The statement,
  323.  
  324. .style example
  325.    echo echo The time is !mytime > cmdfile
  326. .style body
  327.  
  328. would put the string "echo The time is 10:02" into the first record of the file.
  329. To get the variable name into the file, you must use two exclamation marks at
  330. the beginning of the variable name, like this:
  331.  
  332. .style example
  333.    echo echo The time is !!mytime > cmdfile
  334. .style body
  335.  
  336. That would write the string "echo The time is !my_time" into the first
  337. record of Cmdfile.
  338.  
  339. .page 8
  340.  
  341. |3Variables|
  342.  
  343. As in any program, you use variables to keep track of things.  HP
  344. provides three types of variables in the CI:  numeric, boolean
  345. and string.  Numerics are limited to integers, booleans to true or false,
  346. and strings to lengths up to 255 characters.
  347. Unfortunately, there is no provision for arrays.  However, if you really
  348. need them, they can be simulated (slowly!) using either files or
  349. strings, or translatable naming conventions.  We'll discuss this
  350. a bit later.
  351.  
  352. The variable name itself can be a combination of alphanumeric characters
  353. and the underbar character, but the name must start with either a
  354. letter or an underbar.
  355.  
  356. .page 7
  357.  
  358. |3Setting and Displaying Variables|
  359.  
  360. You have two methods for setting variables:  use the typical
  361. assignment command, or
  362. prompt a value from a terminal.
  363. .font 5.opt (f-)
  364.  
  365.    1.  setvar |2variable_name|  |2expression|
  366.    2.  input  |2variable_name|  |2prompt|
  367. .font 0
  368. .opt
  369.  
  370. The expressions for Setvar can be made up of either numerics, strings,
  371. booleans, variable names, or variable dereferencing (sort of like pointers),
  372. all glued together with operators.  For example, to concatenate the values of two
  373. string variables, you can do the following:
  374.  
  375. .font 5
  376.   setvar  group_account  "!hpgroup"@+@"."@+@"!hpaccount"
  377. .font 0
  378.  
  379. If the logon group and account were Pub and Sys, the above would set the variable
  380. |5group_account| to the value of Pub.Sys.
  381. Figure 1 shows a list of all of the possible operators in a Setvar command.
  382.  
  383. .page 12
  384. .font 6
  385. .box(h9 w21).box(r+1 h1 w55).box(r+2 w55).box(r+3 w55)
  386. .box(r+4 w55).box(r+5 h2 w55).box(r+7 h1 w55)
  387. .box(h9 w55)
  388. .opt (f-).mar(r+12)
  389. #+2Logical operators:             #+23AND, OR, XOR, NOT
  390. #+2Boolean functions and values:  #+23BOUND, TRUE, FALSE, ALPHA, ALPHANUM, NUMERIC, ODD
  391. #+2Comparison operators:          #+23=, <>, <, >, <=, >=
  392. #+2Bit manipulation operators:    #+23LSL, LSR, CSR, CSL, BAND, BOR, BXOR, BNOT
  393. #+2Arithmetic operators:          #+23MOD, ABS, * , / , + , -, ^ (exponentiation)
  394. #+2Functions returning strings:   #+23CHR, DWNS, UPS, HEX, OCTAL, INPUT, LFT, RHT, RPT,
  395. #+2                               #+23LTRIM, RTRIM, STR
  396. #+2Functions returning integers:  #+23ABS, LEN, MAX, MIN, ORD, POS, TYPEOF
  397. #+2Other functions:               #+23FINFO, SETVAR
  398. #+2
  399. .font 0
  400. .opt.opt(l- r-).mar
  401. |2Figure 1.  Setvar Operators|
  402. .opt.font 0
  403.  
  404. .style body
  405. .page 4
  406.  
  407. |3Variable Locality and Longevity|
  408.  
  409. Although some variables seem permanent, only a few
  410. system-supplied, read-only variables are permanent.  For example, the HPSUSAN variable
  411. contains the special CPU number unique to each HP 3000/iX computer.
  412. All HP-defined variables start with the letters HP, and appear
  413. in upper case.  To see a list of them, simply enter this command,
  414.  
  415. .style example
  416.    showvar hp&@
  417. .style body
  418.  
  419. User variables@-@the variables that you create@-@can have
  420. a lifetime as long as your session, but no longer.
  421. You create variables using the Setvar command, and delete
  422. them using the Deletevar command.
  423.  
  424. CI variables are global to your session.  If you create a variable and then start up a new CI
  425. shell, the variables will be accessible from the new shell as well.  You do have
  426. the ability to create local variables which exist only during
  427. the execution of a command file.  You define local variables with the
  428. Parm line in the command file.  For example,
  429.  
  430. .style example
  431.   parm local_myvar="Not Available In Stores"
  432.   echo !local_myvar
  433. .style body
  434.  
  435. If after executing the above command file, you do a |5showvar local_myvar|, the variable will
  436. not exist, and a CI error will grace your screen.
  437. The temporary variable |5my_var| existed only during the execution of the command file.
  438.  
  439. Local variables cannot be modified, and are only accessed by reference
  440. within the command files.  If you have a local variable and a permanent variable
  441. with the same name, then the local variable takes precedence during expansion.
  442. Make sure that
  443. your local variables have different names from your permanent ones, otherwise you'll have
  444. more confusion than you need at debugging time.
  445. The following command file illustrates local versus permanent variable referencing.
  446.  
  447. .style example
  448. |1hithere|
  449.   parm hpjobname="ZZTOP"
  450.   echo Good evening, !hpjobname.
  451.   showvar hpjobjname
  452.  
  453. Executing Hithere gives us:
  454.  
  455.   Good evening, ZZTOP
  456.   HPJOBNAME = KEN
  457. .style body
  458.  
  459. Attention System Managers:  Don't worry!@
  460. This trick won't fool programs that retrieve the value of variables using the HPCIGETVAR
  461. intrinsic, or command files that are nested within a command file.  The value of
  462. the local variable will be returned during expansion |1only| within the command file
  463. that defines it.
  464.  
  465. .page 10
  466.  
  467. |3Getting Data Into and Out of Files|
  468.  
  469. So you want to keep some data around for awhile?  Use a file!  Well, you knew
  470. that already, I'll bet.  What you probably didn't know is that you can get data into and
  471. out of files fairly easily using I/O redirection and the print command.
  472. I/O redirection allows input or output to be directed to a file instead of to
  473. your terminal.
  474. I/O redirection uses the symbols ">", ">>" and "<".  Use ">" to redirect
  475. output to a temporary file (you can make the file permanent if you use
  476. a file command);
  477. use ">>" to append output to the file; finally, use "<"
  478. to re-direct input from a file.
  479.  
  480. .style example
  481.   echo Value 96 > myfile
  482.   echo This is the second line >> myfile
  483.   input my_var < myfile
  484.   setvar mynum_var str("!my_var",7,2)
  485.   setvar mynum_var_2 !mynum_var - (6 * 9 )
  486.   echo The answer to the meaning of life, the universe
  487.   echo and everything is !mynum_var_2.
  488. .style body
  489.  
  490. After executing the above command file, the file Myfile will contain two lines,
  491. "Value 96" and "This is the second line" (without quotes, of course). The Input
  492. command uses I/O redirection to read the first record of the file, and assigns
  493. the value to the variable |5my_var|.
  494. The first Setvar
  495. extracts the number from the middle of the string, and proceeds to use the value
  496. in an important calculation in the next line.
  497.  
  498. How can you assign the data in the second and subsequent lines of a file to
  499. variables?  You use the Print command to select the record that you want from
  500. the file, and send the output to a new file.
  501.  
  502. .style example
  503.   print myfile;start=2;end=2 > myfile2
  504. .style body
  505.  
  506. You can then use the Input command to extract the string from the second
  507. file.
  508.  
  509. .page 4
  510.  
  511. |3Rolling Your Own System Variables|
  512.  
  513. It's easy enough to create a static file of Setvar commands
  514. that gets invoked at logon time, and it's not difficult to modify
  515. the file programmatically.  For example, let's say that you would like
  516. to remember a particular variable from session to session, such
  517. as the name of your favorite printer.  You can name
  518. the file that contains the Setvars, Mygvars.  It will contain
  519. the line:
  520.  
  521. .style example
  522.    setvar my_printer "biglaser"
  523. .style body
  524.  
  525. The value of this variable may change during your session, but you may want
  526. to keep it for the next time that you log on.  To do this,
  527. you must replace your normal logoff procedure (the Bye or Exit command) with
  528. a command file that saves the variable in a file, and then
  529. logs you off.
  530.  
  531. .style example
  532. |1byebye|
  533.    purge mygvars > $null
  534.    file mygvars;save
  535.    echo setvar my_printer "!my_printer" > *mygvars
  536.    bye
  537. .style body
  538.  
  539. Whenever you type |5byebye|, the Setvar command is written to Mygvars,
  540. and you are then logged off.  The default close disposition of an I/O redirection
  541. file is TEMP, which is why you have to specify a file equation.  Because you are never
  542. certain that this file exists beforehand, doing a Purge ensures that it does not.
  543.  
  544. .page 3
  545.  
  546. |3Program Control - If/Else and While|
  547.  
  548. One of the reasons I like programming the CI is its lack of
  549. |2goto's|.  This much-debated programming style has sparked many a heated discussion.
  550. Consider the following:
  551.  
  552. .style example
  553.    echo Powers of 2...
  554.    if "!hpjobname" = "KARNAK" then
  555.        setvar loop_count 1
  556.        setvar temp 1
  557.        while !loop_count < 10 do
  558.           setvar temp  !temp * 2
  559.           echo 2^!loop_count = !temp
  560.           setvar loop_count !loop_count + 1
  561.        endwhile
  562.    else
  563.       echo Sorry, you're not authorized to know.
  564.    endif
  565.  
  566. .style body
  567. The above command file will display a powers of two table from one though
  568. nine for the user who is logged on as KARNAK.  It is good programming
  569. practice to indent code inside If and While blocks, because it makes debugging
  570. much easier.  The CI doesn't care about leading spaces or blank lines,
  571. but you must use the Comment command to insert comments.
  572.  
  573. There are times when you wish to get out of a loop in an ungraceful
  574. manner.  To do this, use the Return command.  I often use this
  575. when I display help in a command file, and I don't want to clutter
  576. further code with a big If@/@@Endif block.
  577.  
  578. .style example
  579.   parm hidden_away="?"
  580.   if "!hidden_away" = "?" then
  581.      echo This command file doesn't do much,
  582.      echo but it does it well.
  583.      return
  584.   endif
  585.   echo Local variable is !hidden_away.
  586. .style body
  587.  
  588. Another way to terminate loops and nested command files is to use
  589. the Escape command.  This command will blow you right back to
  590. the CI.  (Using the Return command only exits the current command file.)  You can optionally
  591. set the CIERROR JCW by adding a value to the end of the Escape command.
  592.  
  593. .style example
  594.   escape 007
  595. .style body
  596.  
  597. .page 5
  598.  
  599. |3Simulating Arrays|
  600.  
  601. It's true - arrays are not directly supported in the CI.  However,
  602. because of some undocumented techniques (read |2tricks|), you can simulate
  603. arrays.
  604.  
  605. One question that may immediately pop into your head is "Why would I want
  606. to use arrays?"  Arrays
  607. are useful for table driven events, such as returning days per month, sessions on
  608. ldevs, etc.
  609.  
  610. .page 5
  611. I won't keep you in suspense. Here's the core method:
  612.  
  613. .style example
  614.   setvar !variable_name!variable_index   |2value|
  615. .style body
  616.  
  617. By using the expression evaluation feature of the CI, you
  618. can have a changeable variable name in the Setvar command.
  619. |1CAVEAT USER:|  This only works within command files!|  If you try
  620. to do this
  621. interactively, the expression evaluation on the Setvar command is
  622. performed for the part of the command line |2after| the variable
  623. name.  Within a command file, the entire line is
  624. evaluated before being passed to the CI for re-evaluation.
  625.  
  626. In much the same way, you can use command files to change sequences of
  627. commands, such as creating self-modifying code.  For example,
  628.  
  629. .style example
  630. |1weirdcmd|
  631.    setvar variable_command "setvar apple ""orange"""
  632.    !variable_command
  633. .style body
  634.  
  635. If you run
  636. the command file, and then display the contents of the variable, you will see:
  637.  
  638. .style example
  639.    weirdcmd                |0{execute command file, above}|
  640.    showvar apple
  641.    |APPLE = orange|
  642. .style body
  643.  
  644. To simulate arrays, you must assign one variable for each element.
  645. For example, you would assign months_12 for months(12).
  646. This variable can be
  647. either string or numeric, but keep in mind that string variables can be up to
  648. 256 characters long.
  649.  
  650. Here are a few command files that allow you to manipulate arrays.
  651.  
  652. .style example
  653. |1arraydef|
  654.    parm array_name nbr_elements=0 initial_value=0
  655.    setvar array_index 0
  656.    while !array_index <= !nbr_elements do
  657.       setvar !array_name!array_index !initial_value
  658.       setvar array_index array_index + 1
  659.    endwhile
  660.  
  661. .style body
  662. The command file Arraydef allocates variables for each element of the
  663. array that you need.  The call sequence would be something like,
  664.  
  665. .style example
  666.    arraydef months_ 12
  667. .style body
  668.  
  669. Just as you put
  670. an index in parentheses, I like to put underbars at the
  671. end of array names so that they are more readable.
  672.  
  673. You can
  674. use this command file to ensure that you have enough room in the
  675. CI data area to store
  676. your array.  Under MPE/iX release 5.0, space for variables is
  677. limited to roughly 20K. The space used can be calculated by adding the number of characters
  678. in each variable name, plus 4 bytes per integer variable
  679. or the length of each string variable.  For example, the integer
  680. variable "XYZZY" takes up 5 bytes for the name, and four more
  681. bytes for its integer value.  When you run out of space, you
  682. get the following error from the CI:
  683.  
  684. .style example
  685. Symbol table full: addition failed.  To continue, delete
  686. some variables, or start a new session. (CIERR 8122)
  687. .style body
  688.  
  689. At the 1995 IPROF conference, I asked the MPE roundtable how much
  690. symbol space was actually available, but no one could give a definitive answer.
  691. As a question to my question, the roundtable countered with "How many people have ever run
  692. out of symbol space?"  Only one person put up his hand in a room of 200 or so programmers - me.
  693. Just wait until more people start using arrays.
  694.  
  695. The following command file allows you to return the space used
  696. by your pseudo-array when you are finished with it.
  697.  
  698. .style example
  699. |1arraydel
  700.    parm array_name nbr_elements=0
  701.    setvar array_index 0
  702.    while !array_index < !nbr_elements do
  703.       deletevar !array_name!array_index
  704.       setvar array_index array_index + 1
  705.    endwhile
  706.  
  707. .style body
  708. To demonstrate how arrays can be set (and values returned), the following two
  709. command files, Arrayset and Arrayget, use the expression evaluation
  710. feature of the CI to convert the element number to the actual variable name.
  711. Setvar is called to set either the value, or the name of the variable
  712. passed to the command file.
  713.  
  714. .style example
  715. |1arrayset|
  716.    parm array_name element_nbr=0
  717.    anyparm set_value
  718.    setvar !array_name!element_nbr !setvalue
  719. .page 4
  720.  
  721. |1arrayget|
  722.    parm destination_var array_name element_nbr=0
  723.    anyparm get_value
  724.    setvar !destination_var !array_name!element_nbr
  725. .style body
  726.  
  727. Here's a quick command file to show how you can use arrays in a month
  728. table.  It uses the Input command to prompt the user for the
  729. number of days for each month.
  730.  
  731. .style example
  732.    setvar months_nbr 0
  733.    while !months_nbr < 12 do
  734.       setvar months_nbr months_nbr + 1
  735.       input months_!months_nbr;                       &&
  736.       prompt="Enter the number of days in month
  737.                                      !months_nbr:  "
  738.    endwhile
  739.    deletevar months_nbr
  740. .style body
  741.  
  742. .page 5
  743.  
  744. |3Calling All Functions!|
  745.  
  746. The CI has a number of built-in functions that you can call
  747. from the CI commands
  748. If and Setvar.  The purpose of these functions
  749. is to provide some higher programming features at the CI level.
  750. For example, when you accept user input, you may want to upshift
  751. the string to minimize your If logic.
  752.  
  753. .style example
  754.    input yes_no,"Please enter yes or no:  "
  755.    if ups("!yes_no") = "YES" then
  756. .style body
  757.  
  758. Since people generally like to reply with one-character
  759. answers, you can add one more function to your command file.
  760.  
  761. .style example
  762.    input yes_no,"Please enter yes or no:  "
  763.    if lft(ups("!yes_no"),1) = "Y" then
  764. .style body
  765.  
  766. In the above two examples, the |5ups()| function upshifts the argument
  767. string.  |5lft()| returns the number of specified characters.
  768. The characters start at the leftmost portion of the string argument. If you
  769. look closely, you'll notice that there are no quotes around the
  770. inside function call, that is you do |1not| say,
  771.  
  772. .style example
  773.    if lft("ups("!yes_no")",1) = "Y" then
  774. .style body
  775.  
  776. Because of CI expansion rules, you cannot use quotes when you embed a function within a function.
  777. If you think about it, the |5ups()| function
  778. in the above statement would never get resolved.  If you play computer and expand the above
  779. statement, you get the following:
  780.  
  781. .style example
  782.    IF lft("ups("yes")",1) = "Y" THEN
  783. .style body
  784.  
  785. which, when executed, produces the error, |5A string operator was expected but none was found. (CIERR 9755)|
  786. .page 8
  787.  
  788. Here are a couple of useful functions.  You'll find the rest (as of MPE/iX 4.5)
  789. described at the end of this paper, or you can check Appendix B
  790. in Volume 2 of the HP's |2MPE/iX Commands Reference Manual|.
  791.  
  792. .style example
  793.    dwns(@)  #15Shift string to lowercase
  794.    finfo(@) #15Returns file info, such as eof, etc.
  795.    rht(@)   #15Returns rightmost count of characters
  796.    str(@)   #15Extract a portion from the middle of a string
  797. .style body
  798.  
  799. .page 5
  800.  
  801. |3Popular Command Files|
  802.  
  803. To finish off this paper, I've included
  804. some sample command files that not only
  805. illustrate previously discussed techniques, but also include a few new
  806. tricks.
  807.  
  808. .page 4
  809.  
  810. |3Obtaining the Remote CIERROR|
  811.  
  812. If you have multiple HP 3000's linked with NS services, then you will
  813. know exactly why you need this functionality.  You cannot get the remote value of
  814. the CIERROR JCW using traditional methods.
  815. More importantly, you cannot easily detect when a remote command fails.
  816. For example, the following commands inside a job will |1not| work as you expect:
  817.  
  818. .style example
  819.   remote purge bigfile
  820.   if cierror <> 0 then
  821.      echo error!
  822.   endif
  823. .style body
  824.  
  825. In fact, the HP Commands reference manual states:
  826.  
  827. .mar (l+4 r-4)
  828. .font 0
  829. When used to invoke commands on remote systems the COMMAND or HPCICOMMAND
  830. intrinsics do not return a meaningful status code.  For more information
  831. on calling intrinsics refer to the MPE/iX Intrinsics Reference Manual
  832. (32650-90028).
  833. .font 0
  834. .mar
  835.  
  836. .style body
  837. Clearly you must do a bit more work to get your desired results.
  838. I've created two command files that you will need called
  839. Remci.Cmd.Prod and Echoci.Cmd.Prod.
  840. .page 5
  841. .style example
  842. |1remci.cmd.prod|
  843.   remote echoci tempci
  844.   remote purge tempci > $null
  845.   remote save tempci
  846.   dscopy tempci:remmach;tempci;rep
  847.   continue
  848.   tempci
  849.  
  850. |1echoci.cmd.prod
  851.   parm tempfile
  852.   echo setjcw cierror !cierror > !tempfile
  853.  
  854. .style body
  855. You will need to keep the Remci command file on the local machine, and the
  856. Echoci command file on the remote one.  The first thing the
  857. Remci command file does is remotely invoke the Echoci command
  858. file.  This inserts the line |5setjcw cierror [cierror value]| into
  859. the temporary file Tempci.  Remci then pulls the
  860. file over to the local machine via Dscopy, and executes the file,
  861. setting the current |5cierror| to the value of the remote |5cierror|.
  862.  
  863. You can now insert this command file call into your first jobstream
  864. and make it work.
  865.  
  866. .style example
  867.   remote purge bigfile
  868.   remci
  869.   if cierror <> 0 then
  870.      echo error purging remote bigfile!
  871.   endif
  872. .style body
  873. .page 4
  874.  
  875.  
  876. |3Job Monitoring|
  877.  
  878. In a perfect world, jobs would never fail, and no one
  879. would never mistype a job number when aborting a job.  Since the world is
  880. far from perfect, it's nice to have something that helps
  881. monitor critical jobs.
  882.  
  883. .style example
  884. |1checkjob|
  885.    anyparm jobname
  886.    purge sojfile >$null
  887.    purge sojfile,temp >$null
  888.    purge grepout,temp >$null
  889.    purge grepout > $null
  890.    showjob job=&@j;exec >sojfile
  891.    save sojfile
  892.    run grep.hpbin.sys;info="-ci '!jobname' SOJFILE" > grepout
  893.    save grepout
  894.    input nbr_found < grepout
  895.    if !nbr_found = 0 then
  896.       echo [esc]&dB!jobname is not running.
  897.       setvar job_is_running FALSE
  898.    else
  899.       setvar job_is_running TRUE
  900.       echo !jobname is in exec status.
  901.    endif
  902. .style body
  903.  
  904. A gotcha about |5grep|:  |5grep| will only read |2permanent| files, and
  905. it doesn't pay attention to file equations.
  906. This powerful tool ported from UNIX is
  907. used to quickly find occurrences of strings within a file.  The |2-c| option used
  908. above tells |5grep| to return only the count of strings found, while the |2i| indicates that
  909. the search shouldn't care about upper or lower case, (|1I|gnore case,
  910. I guess.)  In our command file, the search file is in the MPE name
  911. space, and must appear in UPPER CASE.
  912.  
  913.  
  914. |3Displaying Active Jobs|
  915.  
  916. At Robelle, our shop occasionally has two to three hundred jobs in a scheduled state.
  917. Typing Showjob produces pages of data that one doesn't necessarily wish
  918. to view.  The following command file called Sja will show only the
  919. jobs that are in the EXEC state, and some statistics about jobs in
  920. other states.
  921. .page 5
  922.  
  923. .style example
  924. |1sja|
  925.    echo JOBNUM  STATE IPRI JIN  JLIST    INTRODUCED
  926.    JOB NAME&&[esc]&&a65C[esc]&&dJ!hpsysname
  927.    purge sojfile,temp >$null
  928.    showjob job=&@j;exec >sojfile
  929.    setvar lastline finfo("sojfile","eof") - 4
  930.    print sojfile;start=4;end=!lastline
  931.    if !hpjoblimit < !hpjobcount then
  932.       echo [esc]&&dA************ W A R N I N G ***********
  933.       echo [esc]&&dBNumber of jobs executing exceeds
  934.                                                   JOBLIMIT
  935.       echo [esc]&&dA**************************************
  936.    elseif (!hpjobcount + 1) < !hpjoblimit then
  937.       echo [esc]&&dA******* W A R N I N G ****************
  938.       echo [esc]&&dB  Joblimit will allow two jobs to run
  939.       echo [esc]&&dB         at the same time
  940.       echo [esc]&&dA**************************************
  941.    elseif !hpjoblimit = !hpjobcount then
  942.       echo [esc]&&dH** WARNING:  The JLIMIT queue is full.
  943.    endif
  944.    echo &&
  945.    [esc]&&dJ  Sessions:  !hpsescount &&
  946.    [esc]&&dBJobs EXEC:  !hpjobcount (limit !hpjoblimit) &&
  947.    [esc]&&dB  WAIT:  !hpwaitjobs &&
  948.    [esc]&&dJ  SCHED: !hpschedjobs [esc]&&d@&&
  949.    [esc]&&dJ  SUSP: !hpsuspjobs
  950. .style body
  951.  
  952. The above command file doesn't have any sneaky tricks, but it does use
  953. I/O redirection
  954. and a file function call
  955. to determine the number of lines in the output of the Showjob;exec
  956. command.  If you subtract four from the EOF, you get the number of jobs
  957. executing.
  958.  
  959. Note that |5[esc]| indicates the escape character, ASCII 27.  That is, |5[esc]&&dB|
  960. is the escape sequence to turn on inverse video.
  961.  
  962.  
  963. |3Creating a Job History|
  964.  
  965. .com new KR
  966. Have you ever streamed a job, cleared your screen, then wished you could
  967. remember the job number that MPE assigned the stream?  The following
  968. command file, Jstream, takes care of this requirement nicely.  It streams the job passed to it, and
  969. maintains a history of stream events.  It
  970. creates a new variable called |5jobhist_&#|, where &# is a unique
  971. job number.  The jobname, current time, and job number are kept
  972. in this variable.  The command file Jobhist provides a simple
  973. history viewer.
  974. .com endnew
  975. .style example
  976.  
  977. .page
  978. |1jstream|
  979.  
  980.   anyparm stream_jobname = ?
  981.   echo JSTREAM 1.2   Type JOBHIST to see your jobstream history.
  982.   if finfo("!stream_jobname","exists") = FALSE then
  983.      echo Yowza!  I can't access !stream_jobname
  984.      escape 52
  985.      return
  986.   endif
  987.   setjcw cierror 0
  988.   continue
  989.   stream !stream_jobname > str52673
  990.   setvar temp_cierror !cierror
  991.   if temp_cierror <> 0 then
  992.      print str52673
  993.   endif
  994.   input stream_out < str52673
  995.   purge str52673,temp > $null
  996.   if lft(stream_out, 3) <> " #J" then
  997.      escape !temp_cierror
  998.   endif
  999.   if bound(job_nbr_streamed) = FALSE then
  1000.      setvar job_nbr_streamed 0
  1001.   endif
  1002.   setvar job_nbr_streamed !job_nbr_streamed + 1
  1003.   if !job_nbr_streamed > 100 then
  1004.      setvar job_nbr_streamed 1
  1005.   endif
  1006.   setvar jobhist_!job_nbr_streamed "!stream_out !hptimef !stream_jobname"
  1007.   echo Job !stream_out !hptimef  !stream_jobname
  1008.  
  1009.  
  1010. |1jobhist|
  1011.   showvar jobhist&@ > jobhistt
  1012.   print jobhistt
  1013.  
  1014. .style body
  1015. .page 4
  1016.  
  1017. |3Listing Spoolfiles|
  1018.  
  1019. In order to see the output spoolfile from a job, you must first
  1020. know its spoolfile number.  This task is really a number of steps which
  1021. are easily replaced by the following command file.
  1022.  
  1023. .style example
  1024. |1ljob|
  1025.   parm jnum="&@",listcommand="/ljq"
  1026.   if "!hpjobtype" <> "S" then
  1027.      echo I'm sorry, but LJOB can only be run
  1028.                                         from a session.
  1029.      return
  1030.   endif
  1031.   setvar ljob_jnum ups("!jnum")-"J"-"&#"
  1032.   if not numeric("!ljob_jnum")
  1033.      echo
  1034.      echo usage:  LJOB  job_number
  1035.                                <,print command = '/LQJ'>
  1036.      echo
  1037.      echo         eg.  LJOB 1010,/lqj
  1038.                                (use Qedit lqj command)
  1039.      echo              LJOB 590,/lqj ]-50
  1040.                                (list last 50 lines)
  1041.      echo              LJOB 42
  1042.      return
  1043.   endif
  1044.   setjcw cierror = 0
  1045.   continue
  1046.   spoolf o&@;seleq=[jobnum=#j!ljob_jnum and
  1047.                      filedes="$STDLIST"] &&
  1048.           ;show >ljobtmp
  1049.   if cierror <> 0 then
  1050.      setvar ljobtmp_eof 0
  1051.   else
  1052.      setvar ljobtmp_eof finfo("ljobtmp","eof")
  1053.   endif
  1054.   if ljobtmp_eof < 4 then
  1055.      echo Spoolfile for job #&!ljob_jnum does not exist.
  1056.   else
  1057.      print ljobtmp;start=4;end=4 >ljobtmp2
  1058.      input spooline < ljobtmp2
  1059.      setvar spoolid str("!spooline",2,7)
  1060.      !listcommand !spoolid.out.hpspool
  1061.   endif
  1062. .style body
  1063.  
  1064. The default print command in the Ljob command file is |5/lqj|, which is
  1065. a Qedit command to list the file
  1066. without displaying line numbers, and to pause every 22 lines.  If you do not have
  1067. Qedit, you can set the default list command to "print".
  1068.  
  1069. .page 4
  1070.  
  1071. |3CI Programming Inside Qedit|
  1072.  
  1073. You can use all MPE/iX CI commands in Qedit.  One of the neatest tricks you
  1074. can try is to get a line of data from a Qedit file into a variable.  You can do this with
  1075. one of Qedit's undocumented features:  put a colon in front of the "/"
  1076. in a Qedit command, and
  1077. then on the next line, use an Input command.
  1078. For example,
  1079.  
  1080. .style example
  1081.   comment This command file puts the data from the current
  1082.   comment line into the variable, myline
  1083.   /set list init off
  1084.   /:/listq * > tempfile
  1085.   /set list init on
  1086.   input myline < tempfile
  1087. .style body
  1088.  
  1089. As printing is by nature a complex operation, there is no simple way for
  1090. Qedit to handle carriage control.
  1091. Depending on the source file, it is possible that Qedit would decide to
  1092. write an initial cctl record to the re-directed output file.
  1093. This is an
  1094. undesirable feature in most cases.
  1095.  
  1096. To ensure that this does not occur, use
  1097. the above
  1098. undocumented Qedit command, |2set list init off|.
  1099. After you are finished with your re-directions, you must remember to set list init on.
  1100.  
  1101. This trick can really help you when you're adding custom features to Qedit.  Use the following
  1102. command file to find COBOL paragraph names without changing the current line pointer.
  1103. I use this feature when I can't recall the exact name of the paragraph that I want to reference.
  1104.  
  1105. .style example
  1106. |1findpara|
  1107.    parm para_name left_window=7
  1108.    :/ver zz > zztemp   {save old zz in temp file}
  1109.    /zz */*             {save the current line number}
  1110.    setvar g_para_name "!para_name"
  1111.    setvar g_left_window "!left_window"
  1112.    setvar right_window len("!g_para_name")
  1113.                           + !g_left_window
  1114.    /list "!para_name" (!g_left_window/!right_window)
  1115.    :/list zz > $null   {return to line number w/o seeing
  1116.                         the line number
  1117.    /useq zztemp        {restore old zz}
  1118. .style body
  1119.  
  1120. .break
  1121. You can invoke Findpara at any time, but I usually use it while in Visual mode.
  1122. Paragraph names must start in column eight for this command file to work properly.
  1123. You'll notice that Findpara saves your old ZZ marker in a file, and restores the original after doing its work.
  1124. Qedit
  1125. doesn't have this feature.  Hey!  We just extended Qedit's command set.
  1126. With a little bit of work, we could even have multiple bookmarks.  I'll leave this as an exercise for the reader.
  1127.  
  1128. |3Where to go from here...|
  1129.  
  1130. No doubt you've often heard that the only way to learn
  1131. something is to actually do it.  This thought applies directly to learning to
  1132. program the CI - you must jump in and get your feet wet.  Start programming
  1133. the CI today!
  1134.  
  1135. A very well written HP manual, the |2MPE/iX Commands Reference Manual|,
  1136. is available on CD-ROM and on paper.  I recommend
  1137. that you at least browse through it.  Pay particular attention to Appendices A, B and
  1138. C in Volume 2 which deal mostly with handling
  1139. variables.
  1140.  
  1141. You can get instant help on the subject of variables.  As of MPE/iX 5.0,
  1142. the on-line Help command |5help variables| provides pages
  1143. of text.  (In pre-5.0 environments, the on-line Help in MPEX from VESOFT
  1144. will display approximately the same thing.)
  1145.  
  1146. And of course, if you really get stuck, you always have the Internet, and the list-server HP3000-L.
  1147. But that's a topic for another paper entirely.
  1148.  
  1149. .style example
  1150.    while awake = TRUE
  1151.       program the_ci
  1152.    endwhile
  1153. .style body
  1154. .page
  1155.  
  1156.  
  1157. |3Glossary|
  1158.  
  1159. Some acronyms require no explanation; others are fairly obscure to the
  1160. uninitiated.
  1161. This short glossary
  1162. explains some of the terms and acronyms specific to this paper.
  1163.  
  1164. .mar (l+14)
  1165. .par (s0+ u14)
  1166. `3GL #+1Third Generation Programming Language.  COBOL, FORTRAN and Pascal are 3GL's.
  1167. `4GL #+1A programming language for managers; requires less knowledge about the operating
  1168. system and/or hardware internals.
  1169. `CI #+1Command Interpreter.  This is the program that is run right after you log on.
  1170. `MPE/V #+1Mostly harmless.  Precursor to the MPE/iX operating system, run on overworked
  1171. machines.
  1172. `HP3000-L #+1A list-server available via the Internet.  Lots of juicy tidbits can
  1173. be gleaned from this list.
  1174. `Hppath #+1A string variable used by the CI as a reference to determine where to look for
  1175. programs and command files to execute.
  1176. `Interpreted Code#+1Programs that are compiled "on the fly".  Each statement in an interpreted
  1177. program is evaluated every time it is executed.  Interpreted code tends to be a lot slower to
  1178. execute than compiled code.
  1179. `IPROF #+1|1I|nterex |1Pro|grammers |1F|orum, held every spring at the HP Cupertino labs.
  1180. `JCW #+1Job Control Word.  An integer variable limited to the CM space.
  1181. `Local Variable #+1A variable that can be referenced only within some "local" area,
  1182. such as a command file.
  1183. `Macro #+1A collection of commands designed to perform a task more efficiently.
  1184. `Shell #+1A program, such as the CI, that is used as a working environment for launching
  1185. processes, editing code, and maintaining a command interface.
  1186. `UDC #+1User Defined Command.  A file of callable commands with multiple
  1187. entry points.  See page 2 of this paper.
  1188. `WYGIWYG#+1What You Got Is What You Get.  Basically software without support.
  1189.  
  1190.  
  1191. .mar.par
  1192. .page
  1193. .style body
  1194. |3Addendum|
  1195.  
  1196. Although this table appears in the |2MPE/iX Commands Reference Manual|, you may not always have access
  1197. to it.  I am inserting it here for convenience.
  1198.  
  1199. .opt (f- l- r-)
  1200. Expression Evaluator Functions
  1201. .opt
  1202. .opt (f-)
  1203. .if not outhelpcomp
  1204. .font 6
  1205.   Symbol                     Function               Example                    Result
  1206. .box (h0)
  1207.   +(numeric)                 addition               4 + 5                      9
  1208.   +(string)                  concatenate            "abc" + "de"               abcde
  1209.   -(numeric)                 subtraction            12 - 6                     6
  1210.   -(string)                  deletion of first      "abc" - "b"                ac
  1211.                              occurrence
  1212.   *                          multiplication         4 * 5                      20
  1213.   /                          integer division       79/ 10                     7
  1214.   ^                          exponentiation (9)     2^3                        8
  1215.   either " or '              string identifier      either "abc" or 'abc'      abc
  1216.   ()                         parentheses            (3 + 4) * 2                14
  1217.   <                          less than (1)          5 < 6                      TRUE
  1218.   <=                         less than or equal     "abc" <= "abc"             TRUE
  1219.                              (1)
  1220.   >                          greater than (1)       "xyz" > "abc"              TRUE
  1221.   >=                         greater than or        "abc" >= "abc"             TRUE
  1222.                              equal (1)
  1223.   <>                         not equal              5 <> 6                     TRUE
  1224.   =                          equal                  "xyz"= "xyz"               TRUE
  1225.   ABS(integer)               absolute value         abs(-4)                    4
  1226.   ALPHA(string)              check if a string is   alpha('abcd')              TRUE
  1227.                              alphabetic             alpha('ab3d ef')           FALSE
  1228.   ALPHANUM(string)           check if a string is   alphanum('abCd')           TRUE
  1229.                              only alphabetics and   alphanum('45abd')          TRUE
  1230.                              digits                 alphanum('3d ef')          FALSE
  1231.   AND                        logical and            7=7 and 5=5                TRUE
  1232.   BAND                       bitwise and            7 band 13                  5
  1233.   BNOT                       bitwise not            bnot 5                     -6
  1234.   BOR                        bitwise or             5 bor 2                    7
  1235.   BOUND(varname)             variable               bound(HPPATH)              TRUE
  1236.                              definition
  1237.                              test (2)
  1238.   BXOR                       bitwise                7 bxor 5                   2
  1239.                              exclusive or
  1240.   CHR(integer)               ASCII value            chr(65)                    A
  1241.                              (integer) ===>
  1242.                              character
  1243.   CSL                        circular shift         -2 csl 2                   -5
  1244.                              left (3)
  1245.   CSR                        circular shift         -7 csr 1                   -4
  1246.                              right (3)
  1247.   DWNS(string)               shift string           dwns('aBC&&#dE')            abc&#de
  1248.                              to lowercase
  1249.                              (7)
  1250.   FINFO(filename,option)     file                   FINFO('x.pub',0)           TRUE
  1251.                              information
  1252.                              (6)
  1253.   HEX(integer)               convert to             hex(329)                   $149
  1254.                              hexadecimal
  1255.                              string
  1256.   INPUT([prompt][,wait])     accept user            input('Enter              Enter choice: Y
  1257.                              input (10)             choice:',20)               Return "Y"
  1258.   LEN(string)                string length          len("abc")                 3
  1259.   LFT(string, &# chars)       left string            lft('abc',2)               ab
  1260.                              extraction
  1261.   LSL                        logical shift          7 lsl 1                    14
  1262.                              left
  1263.   LSR                        logical shift          -7 lsr 1                   2,147,483,644
  1264.                              right
  1265.   LTRIM(string[,trimstr])    trim left end          'X'+ltrim(' abc')          Xabc
  1266.                              of string (11)         "X"+ltrim('...abc',        Xabc
  1267.                                                     '.')
  1268.   MAX(num1[,num2...])        find largest           max(5,4-3,70,0)            70
  1269.                              of several
  1270.                              integers
  1271.   MIN(num1[,num2...])        find smallest          min(5,4,-3,70,0)           -3
  1272.                              of several
  1273.                              integers
  1274.   MOD                        modulo (4)             25 mod 2                   1
  1275.   NOT                        logical not            not(2>1)                   FALSE
  1276.   NUMERIC (string)           check if a             numeric('12345')           TRUE
  1277.                              string is all          numeric('$a234ef')         FALSE
  1278.                              digits
  1279.   OCTAL(integer)             convert to             octal(329)                       %511
  1280.                              octal string
  1281.   ODD(integer)               determine if           odd(233)                         TRUE
  1282.                              integer is odd         odd(-2)                          FALSE
  1283.   OR                         logical or             5=5 or 2=3                       TRUE
  1284.   ORD(string)                ordinal (8)            ord('AbcD')                      65
  1285.   POS(find str,source        find Nth               pos('ab','cgabd')                3
  1286.   str[,n])                   occurrence of          pos('.','file.grp.acct    ',2)   9
  1287.                              find str in            pos('.','file.grp.acct    ',-    9
  1288.                              source str (-N         1)
  1289.                              searches from
  1290.                              right) (12)
  1291.   RHT(string, &# chars)       right string           rht("abc",2)                     bc
  1292.                              extraction
  1293.   RPT(string,count)          repeat a               rpt('aBc',3)               aBcaBcaBc
  1294.  
  1295.                              string (-count         rpt('aBc',-3)              cBacBacBa
  1296.                              reverses
  1297.                              string)
  1298.   RTRIM(string[,trimstr])    trim right end         rtrim('abc ')+'X'                abcX
  1299.                              of string (11)         rtrim('abc...','.')+"X    "      abc X
  1300.   SETVAR(varname,expr)       return result          setvar(myvar,2*3+5)       sets variable
  1301.   @@@@@@@@@@@@@@@@@@@@       of expr and            @@@@@@@@@@@@@@@@@@@       myvar to 11 and
  1302.   @@@@@@@@@@@@@@@@@@@@       set varname to         @@@@@@@@@@@@@@@@@@@       returns 11
  1303.   @@@@@@@@@@@@@@@@@@@@       result (13)            @@@@@@@@@@@@@@@@@@@
  1304.   STR(string,start pos, &#    general string         str('abcde',2,3)                 bcd
  1305.   chars)                     extraction
  1306.   TYPEOF(expression)         type of                typeof(HPPATH)             2 (string)
  1307.                              variable or
  1308.                              expression (5)
  1309.   UPS(string)                shift string           ups('aBc5d')                     ABC5D
  1310.                              to uppercase
  1311.                              (7)
  1312.   XOR                        logical                7=7 xor 5=5                      TRUE
  1313.                              exclusive or
  1314. .else
  1315. Symbol               Function               Example                    Result
  1316. +(numeric)           addition               4 + 5                      9
  1317. +(string)            concatenate            "abc" + "de"               abcde
  1318. -(numeric)           subtraction            12 - 6                     6
  1319. -(string)            deletion of first      "abc" - "b"                ac
  1320.                      occurrence
  1321. *                    multiplication         4 * 5                      20
  1322. /                    integer division       79/ 10                     7
  1323. ^                    exponentiation (9)     2^3                        8
  1324. either " or '        string identifier      either "abc" or 'abc'      abc
  1325. ()                   parentheses            (3 + 4) * 2                14
  1326. <                    less than (1)          5 < 6                      TRUE
  1327. <=                   less than or equal     "abc" <= "abc"             TRUE
  1328.                      (1)
  1329. >                    greater than (1)       "xyz" > "abc"              TRUE
  1330. >=                   greater than or        "abc" >= "abc"             TRUE
  1331.                      equal (1)
  1332. <>                   not equal              5 <> 6                     TRUE
  1333. =                    equal                  "xyz"= "xyz"               TRUE
  1334. ABS(integer)         absolute value         abs(-4)                    4
  1335. ALPHA(string)        check if a string is   alpha('abcd')              TRUE
  1336.                      alphabetic             alpha('ab3d ef')           FALSE
  1337. ALPHANUM(string)     check if a string is   alphanum('abCd')           TRUE
  1338.                      only alphabetics and   alphanum('45abd')          TRUE
  1339.                      digits                 alphanum('3d ef')          FALSE
  1340. AND                  logical and            7=7 and 5=5                TRUE
  1341. BAND                 bitwise and            7 band 13                  5
  1342. BNOT                 bitwise not            bnot 5                     -6
  1343. BOR                  bitwise or             5 bor 2                    7
  1344. BOUND(varname)       variable               bound(HPPATH)              TRUE
  1345.                      definition
  1346.                      test (2)
  1347. BXOR                 bitwise                7 bxor 5                   2
  1348.                      exclusive or
  1349. CHR(integer)         ASCII value            chr(65)                    A
  1350.                      (integer) ===>
  1351.                      character
  1352. CSL                  circular shift         -2 csl 2                   -5
  1353.                      left (3)
  1354. CSR                  circular shift         -7 csr 1                   -4
  1355.                      right (3)
  1356. DWNS(string)         shift string           dwns('aBC&&#dE')          abc&#de
  1357.                      to lowercase
  1358. FINFO(filename       file                   FINFO('x.pub',0)          TRUE
  1359.        ,option)      information
  1360. HEX(integer)         convert to             hex(329)                  $149
  1361.                      hexadecimal
  1362.                      string
  1363. INPUT([prompt]       accept user            input('Enter              Enter choice:  Y
  1364.        [,wait])      input (10)             choice:',20)              Return "Y"
  1365. LEN(string)          string length          len("abc")                3
  1366. LFT(string,          left string            lft('abc',2)              ab
  1367.     &# chars)         extraction
  1368. LSL                  logical shift          7 lsl 1                   14
  1369.                      left
  1370. LSR                  logical shift          -7 lsr 1          2,147,483,644
  1371.                      right
  1372. LTRIM(string         trim left end          'X'+ltrim(' abc')          Xabc
  1373.       [,trimstr])    of string (11)         "X"+ltrim('...abc',        Xabc
  1374.                                                   '.')
  1375. MAX(num1[,num2...])  ind largest           max(5,4-3,70,0)             70
  1376.                      of several
  1377.                      integers
  1378. MIN(num1[,num2...])  find smallest          min(5,4,-3,70,0)           -3
  1379.                      of several
  1380.                      integers
  1381. MOD                  modulo (4)             25 mod 2                   1
  1382. NOT                  logical not            not(2>1)                   FALSE
  1383. NUMERIC (string)     check if a             numeric('12345')           TRUE
  1384.                      string is all          numeric('$a234ef')         FALSE
  1385.                      digits
  1386. OCTAL(integer)       convert to             octal(329)                 %511
  1387.                      octal string
  1388. ODD(integer)         determine if           odd(233)                   TRUE
  1389.                      integer is odd         odd(-2)                    FALSE
  1390. OR                   logical or             5=5 or 2=3                 TRUE
  1391. ORD(string)          ordinal (8)            ord('AbcD')                65
  1392. POS(find str,source  find Nth               pos('ab','cgabd')          3
  1393. str[,n])             occurrence of          pos('.','file.grp.acct',2) 9
  1394.                      find str in            pos('.','file.grp.acct',-  9
  1395.                      source str (-N         1)
  1396.                      searches from
  1397.                      right) (12)
  1398. RHT(string, &# chars) right string           rht("abc",2)               bc
  1399.                      extraction
  1400. RPT(string,count)    repeat a               rpt('aBc',3)          aBcaBcaBc
  1401.                      string (-count         rpt('aBc',-3)         cBacBacBa
  1402.                      reverses
  1403.                      string)
  1404. RTRIM(string         trim right end         rtrim('abc ')+'X'          abcX
  1405.       [,trimstr])    of string (11)         rtrim('abc...','.')+"X "   abc X
  1406. SETVAR(varname,expr) return result          setvar(myvar,2*3+5)  sets variable
  1407.                      of expr and                                 myvar to 11 and
  1408.                      set varname to                              returns 11
  1409.                      result (13)
  1410. STR(string,start     general string         str('abcde',2,3)     bcd
  1411. pos, &# chars)        extraction
  1412. TYPEOF(expression)   type of                typeof(HPPATH)       2 (string)
  1413.                      variable or
  1414.                      expression (5)
  1415. UPS(string)          shift string           ups('aBc5d')              ABC5D
  1416.                      to uppercase
  1417.                      (7)
  1418. XOR                  logical                7=7 xor 5=5                TRUE
  1419.                      exclusive or
  1420. .endif
  1421. .mar
  1422.