home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Professional Developers Kit 1992 November / Disc01 / Disc01.mdf / prodtool / epm / e_macros / stdprocs.e < prev    next >
Encoding:
Text File  |  1992-08-27  |  53.2 KB  |  1,622 lines

  1. ; A useful subroutine:  asks "Are you sure (Y/N)?" (same as DOS's prompt
  2. ; after "erase *.*") and returns uppercase keystroke.
  3. ; If called with a string parameter, displays it at start of prompt, e.g.
  4. ;   usersays = askyesno("About to erase.")
  5. ;   ==>   "About to erase. Are you sure (Y/N)? "
  6. ; EPM 5.12B:  Now enabled for EPM, using entrybox().  Optional second argument
  7. ; is a flag to prevent the "Are you sure" from being appended.
  8. ; EPM 5.15:  Now uses WinMessageBox to get Yes, No buttons.  [\toolktxx\c\include\pmwin.h]
  9. defproc askyesno
  10.    prompt=arg(1)
  11. compile if EVERSION < 5
  12.    if not arg(2) then
  13.       prompt=prompt || ARE_YOU_SURE_YN__MSG
  14.    endif
  15.    return upcase(mgetkey(prompt))     /* Accept key from macro. */
  16. compile else
  17.    if not arg(2) then
  18.       prompt=prompt\13 || ARE_YOU_SURE__MSG
  19.    endif
  20.    return substr(YES_CHAR || NO_CHAR, winmessagebox('', prompt, 16388) - 5, 1)  -- YESNO + MOVEABLE
  21. compile endif
  22.  
  23.  
  24. compile if EVERSION >= 4
  25. ; Does an atol of its argument, then a word reversal and returns the result.
  26. defproc atol_swap(num)
  27.    hwnd=atol(num)
  28.  compile if EVERSION >= '5.17'
  29.    return rightstr(hwnd,2) || leftstr(hwnd,2)
  30.  compile else
  31.    return substr(hwnd,3,2) || substr(hwnd,1,2)
  32.  compile endif
  33. compile endif
  34.  
  35.  
  36. defproc checkmark()        /* Common routine, save space.  from Jim Hurley.*/
  37.   if marktype()='' then
  38. compile if EPM
  39.     sayerror NO_MARK_HERE__MSG
  40. compile else
  41.     sayerror NO_MARK__MSG
  42. compile endif
  43.     stop
  44.   endif
  45.  
  46. ; Routine to tell if a mark is visible on the screen.  (Actually, only on the
  47. ; current window; if the window is less than full size, a mark could be visible
  48. ; in an inactive window without our being able to tell.)  Also, if a character
  49. ; mark begins above the top of the window and ends below the bottom, and the
  50. ; window contains only blank lines, then this routine will return 1 (since the
  51. ; mark spans the window) even though no sign of the mark will be visible.
  52. defproc check_mark_on_screen =
  53.    if marktype() = '' then return 0; endif  -- If no mark, then not on screen.
  54.    getmark first_mark_line, last_mark_line, first_mark_col, last_mark_col
  55.    first_screen_line = .line - .cursory + 1
  56.    last_screen_line = .line - .cursory + .windowheight
  57.    if last_mark_line < first_screen_line then return 0; endif
  58.    if first_mark_line > last_screen_line then return 0; endif
  59.    no_char_overlap = marktype()<>'CHAR' or first_mark_line=last_mark_line
  60.    if last_mark_col < .col - .cursorx + 1 and
  61.       (no_char_overlap or last_mark_line=first_screen_line)
  62.    then return 0; endif
  63.    if first_mark_col > .col - .cursorx + .windowwidth and
  64.       (no_char_overlap or first_mark_line=last_screen_line)
  65.    then return 0; endif
  66.    return 1
  67.  
  68. ; Tests whether the "filename" is actually a printer
  69. ; device, so we'll know whether to test printer readiness first.
  70. ; Called by savefile() in SAVELOAD.E.  Returns 0 if not, else printer number.
  71. defproc check_for_printer(name)
  72.    if not name then return 0; endif
  73. compile if EVERSION >= '5.50'
  74.    if leftstr(name,1)='"' & rightstr(name,1)='"' then
  75.       name=substr(name,2,length(name)-2)
  76.    endif
  77. compile endif
  78. compile if EVERSION >= '5.17'
  79.    if rightstr(name,1) = ':' then  -- a device
  80.       name = leftstr(name,length(name)-1)
  81. compile else
  82.    if substr(name,length(name),1) = ':' then  -- a device
  83.       name = substr(name,1,length(name)-1)
  84. compile endif
  85.    else       -- Might be a full pathspec, C:\EDIT\PRN, and still go to a device!
  86.       indx = lastpos('\',name)
  87.       if not indx then indx = lastpos(':',name) endif
  88.       if indx then name=substr(name,indx+1) endif
  89.       indx = pos('.',name)
  90.       if indx then name=substr(name,1,indx-1) endif
  91.    endif
  92.    if upcase(name)='PRN' then return 1; endif
  93. compile if EVERSION >= 4  -- Check_for_printer always returns true, so we don't need to distinguish COMn.
  94.    return (4+pos('.'upcase(name)'.','.LPT1.LPT2.LPT3.LPT4.LPT5.LPT6.LPT7.LPT8.LPT9.COM1.COM2.COM3.COM4.')) % 5
  95. compile else
  96.    return (4+pos('.'upcase(name)'.','.LPT1.LPT2.LPT3.')) % 5
  97. compile endif
  98.  
  99. compile if WANT_WINDOWS
  100. ; This proc is called only by DEFC EDIT in messy-desk mode.
  101. defproc create_window_for_each_file(emptyfileid)
  102.    fileidlist=''
  103.    activatefile emptyfileid /* Start list at beginning so we get 'em all.    */
  104.    nextfile                 /* Except first one, can leave one in each ring. */
  105.    loop
  106.       nextfile
  107.       .box=1
  108.       getfileid fileid
  109.       if fileid=emptyfileid then
  110.          leave
  111.       endif
  112.       fileidlist=fileidlist fileid
  113.    endloop
  114.    rest=fileidlist
  115.    loop
  116.       parse value rest with fileid rest
  117.       if fileid='' then
  118.          leave
  119.       endif
  120.       rc=0
  121.       newwindow fileid
  122.       if rc then leave endif
  123.       getfileid cur_fileid
  124.       activatefile fileid
  125.       quitview
  126.       activatefile cur_fileid
  127.    endloop
  128. compile endif
  129.  
  130.  
  131. COMPILE IF EVERSION >= 4
  132. defproc dec_to_string(string)    -- for dynalink usage
  133.    line = ''
  134.    for i = 1 to length(string)
  135.      line= line || asc(substr(string,i,1)) || ' '
  136.    endfor
  137.    return line
  138. COMPILE ENDIF
  139.  
  140. define
  141. compile if EVERSION >= '5.20'  -- 5.20 adds a HINI to the *Profile calls.
  142.    HINI_PARM = 'HINI_PROFILE,'
  143. compile else
  144.    HINI_PARM = ' '
  145. compile endif
  146.  
  147. defproc default_printer
  148. compile if defined(my_printer)
  149.    return MY_PRINTER
  150. compile elseif EPM
  151.    parse value queryprofile($HINI_PARM 'PM_SPOOLER', 'PRINTER') with printername ';'
  152.    if printername<>'' then
  153.       parse value queryprofile($HINI_PARM 'PM_SPOOLER_PRINTER', printername) with dev ';'
  154.       if dev<>'' then return dev; endif
  155.    endif
  156. compile endif
  157.    return 'LPT1'
  158.  
  159. ;  Returns DOS version number, multiplied by 100 so we can treat
  160. ;  it as an integer string.  That is, DOS 3.2 is reported as "320".
  161. ;  Needed by DEFPROC SUBDIR.
  162.  
  163. defproc dos_version()
  164. compile if E3
  165.    parse value int86x(DOS_INT,DOS_GET_VERSION,'') with ax .
  166.    major = ax // 256                  /* AL = major version number */
  167. ;  minor = (ax - major) % 256
  168.    return 100*major + (ax - major) % 256
  169. compile else
  170.       verbuf = 'nn'
  171.       res= dynalink('DOSCALLS',          /* dynamic link library name */
  172.                     '#92',               /* ordinal for DOSGETVERSION */
  173.                     selector(verbuf) ||  /* string selector           */
  174.                     offset(verbuf))      /* string offset             */
  175. ;     major = asc(substr(verbuf,2,1))
  176. ;     minor = asc(substr(verbuf,1,1))
  177.       return 100*asc(substr(verbuf,2,1)) + asc(substr(verbuf,1,1))
  178. compile endif
  179.  
  180.  
  181. compile if WANT_ET_COMMAND     -- Let user omit ET command.
  182. defproc ec_position_on_error(tempfile)   /* load file containing error */
  183.    'xcom e 'tempfile
  184.    if rc then    -- Unexpected error.
  185.       sayerror ERROR_LOADING__MSG tempfile
  186.       if rc=-282 then 'xcom q'; endif  -- sayerror('New file')
  187.       return
  188.    endif
  189.    if .last<=4 then
  190.       getline msg,.last
  191.       'xcom q'
  192.    else
  193.       getline msg,2
  194. compile if EPM
  195.       if leftstr(msg,3)='(C)' then  -- 5.20 changed output
  196.          getline msg,4
  197.       endif
  198. compile endif
  199.       getline temp,.last
  200.       parse value temp with 'col= ' col
  201.       getline temp,.last-1
  202.       parse value temp with 'line= ' line
  203.       getline temp,.last-2
  204.       parse value temp with 'filename=' filename
  205.       'xcom q'
  206.       'e 'filename               -- not xcom here, respect user's window style
  207.       if line<>'' and col<>'' then
  208. compile if EPM
  209.          .cursory=min(.windowheight%2,.last)
  210. compile else
  211.          .cursory=15
  212. compile endif
  213.          if col>0 then
  214.             .col=col
  215.             line
  216.          else
  217.             .line=line-1   /* sometimes the compiler is off by 1 */
  218.             getline s
  219.             .col=length(s) /* position cursor at end of previous line */
  220.          endif
  221.       endif
  222.    endif
  223.    sayerror msg
  224. compile endif
  225.  
  226. defproc einsert_line
  227.    insert
  228.    up
  229.    getline line
  230.    parse value pmargins() with leftcol . paracol .
  231.    if line='' or not .line then
  232.       .col=paracol
  233.    else
  234.       call pfirst_nonblank()
  235.       if .col=paracol then .col=leftcol; endif
  236.    endif
  237.    down
  238.  
  239. compile if ENHANCED_ENTER_KEYS
  240. defproc enter_common(action)
  241.  compile if WANT_STREAM_MODE = 'SWITCH'
  242.    universal stream_mode
  243.    if stream_mode then
  244.  compile endif
  245.  compile if WANT_STREAM_MODE
  246.       if .line then
  247.          split
  248.          .col=1
  249.          down
  250.       else
  251.          insert
  252.          .col=1
  253.       endif
  254.       return
  255.  compile endif
  256.  compile if WANT_STREAM_MODE = 'SWITCH'
  257.    endif
  258.  compile endif
  259.  compile if WANT_STREAM_MODE <> 1
  260.    if .line = .last  & (action=3 | action=5) then  -- 'ADDATEND' | 'DEPENDS+'
  261.       call einsert_line()
  262.       down                       -- This keeps the === Bottom === line visible.
  263.       return
  264.    endif
  265. ;     'NEXTLINE' 'ADDATEND'                        'DEPENDS'  'DEPENDS+'
  266.    if action=2 | action=3 | (not insert_state() & (action=4 | action=5)) then
  267.       down                          -- go to next line
  268.       begin_line
  269.       return
  270.    endif
  271.    if action=6 then
  272.       call splitlines()
  273.       call pfirst_nonblank()
  274.       down
  275. ;;    refresh
  276.       return
  277.    endif
  278.    call einsert_line()           -- insert a line
  279.  compile endif  -- WANT_STREAM_MODE <> 1
  280. compile endif
  281.  
  282. ;  Erasetemp erases a file quietly (no "File not found" message) on both DOS
  283. ;  and OS/2.  Thanks to Larry Margolis.  Returns 0 if successful erase, or
  284. ;  the error code (if on DOS) which will usually be 2 for 'file not found'.
  285. defproc erasetemp(filename)
  286.    asciiz = filename\0
  287. compile if E3
  288.    call free()    -- Keep variables from moving around before int86x.
  289.    parse value int86x(DOS_INT,DOS_UNLINK 0 0 ofs(asciiz), seg(asciiz)) with ax . . . . . cf ',' .
  290.    -- Most callers will ignore error code, don't care file doesn't exist.
  291.    -- if cf then sayerror 'DOS error code' ax endif
  292.    if cf then return ax; endif
  293. compile else
  294.    return dynalink('DOSCALLS',          /* dynamic link library name */
  295.                    '#60',               /* ordinal value for DOSDELETE */
  296.                    selector(asciiz) ||  /* string selector           */
  297.                    offset(asciiz)   ||  /* string offset             */
  298.                    atoi(0)||            /* reserved                  */
  299.                    atoi(0))             /* reserved                  */
  300. compile endif
  301.  
  302. compile if EPM
  303. defproc find_token(var startcol, var endcol)  -- find a token around the cursor.
  304.    if arg(3)='' then
  305.       token_separators = ' ~`!#%^&*()-+=][{}|\:;?/><,.'''
  306.    else
  307.       token_separators = arg(3)
  308.    endif
  309.    getline line
  310.    len = length(line)
  311.    endcol = verify(line, token_separators, 'M', .col)
  312.    if endcol = .col | .col>len then
  313.       return
  314.    endif
  315.    if endcol then
  316.       endcol = endcol - 1
  317.    else
  318.       endcol = len
  319.    endif
  320.    startcol = verify(reverse(line), token_separators, 'M', len - .col + 1)
  321.    if startcol then
  322.       startcol = len - startcol + 2
  323.    else
  324.       startcol = 1
  325.    endif
  326.    return 1
  327. compile endif
  328.  
  329. ; Note on a speed trick:  The following routine is used to both verify that
  330. ; an external program exists, and to get its path.  After that first search,
  331. ; the exact path location of the routine is known; it can be remembered so that
  332. ; all future calls can supply the exact location to avoid the path search.
  333. ; See SUBDIR for an example of its use.
  334.  
  335. defproc find_routine(utility)  -- Split from SUBDIR
  336.    parse arg util opts         -- take first word, so can pass options too.
  337.    findfile fully_qualified,util,'PATH','P'
  338.    if rc then return -1 endif
  339. compile if E3
  340.    if dos_version() < 300 then
  341.       return utility             --DOS 2 can't handle the path
  342.    endif                         --in front of the command.
  343. compile endif
  344.    return fully_qualified opts
  345.  
  346. compile if EVERSION >='5.50'    -- For GPI version, we must manage the cursor ourself
  347. defproc fixup_cursor()
  348.  compile if UNDERLINE_CURSOR
  349.    cursorh = 3 - 67*insert_state()         -- 0 -> 3; 1 -> -64
  350.    cursorw = '-128'
  351.  compile else
  352.    cursorw = 2 - 130*(not insert_state())  -- 0 -> -128; 1 -> 2
  353.    cursorh = '-128'
  354.  compile endif
  355.    cursor_dimensions cursorw, cursorh
  356. compile endif
  357.  
  358. compile if EVERSION < 5
  359. defproc init_operation_on_commandline
  360.    universal comsfileid,oldline
  361.    if command_state() then
  362.       activatefile comsfileid
  363.       oldline=.line
  364.       getcommand line,col,scrollpos
  365.       insertline line,.last+1
  366.       .cursorx=col-scrollpos+1
  367.       .col=col
  368.       bottom
  369.    endif
  370. compile endif
  371.  
  372. ; Returns true if parameter given is a number.
  373. ; Leading and trailing spaces are ignored.
  374. defproc isnum
  375.    zzi=pos('-',arg(1))           -- Optional minus sign?
  376.    if zzi then                   -- If there is one,
  377.       parse arg zz1 '-' zz zz2   --   zz1 <- before it, zz <- number, zz2 <- after
  378.    else
  379.       parse arg zz zz1 zz2       --   zz <- number; zz1, zz2 <- after it
  380.    endif
  381.    zz=strip(zz)                  -- Delete leading & trailing spaces.
  382.    if zz1||zz2 <> '' or          -- If there were more tokens on the line
  383.       zz==''                     -- or if the result is null
  384.    then return 0 endif           -- then not a number.
  385. compile if EVERSION >= 4         -- OS/2 version - real numbers
  386.    if pos(DECIMAL,zz) <> lastpos(DECIMAL,zz) then return 0 endif
  387.                                  -- Max. of one decimal point.
  388.    return not verify(zz,'0123456789'DECIMAL)
  389. compile else                        -- DOS version - integers only
  390.    return not verify(zz,'0123456789')
  391. compile endif
  392.  
  393. defproc isoption(var cmdline,optionletter)
  394.    i=pos(argsep||upcase(optionletter),upcase(cmdline))
  395.    if i then
  396. compile if EPM
  397.       cmdline=delstr(cmdline,i,2)
  398. compile else
  399.       cmdline=substr(cmdline,1,i-1)||substr(cmdline,i+2)
  400. compile endif
  401.       return 1
  402.    endif
  403.  
  404. defproc joinlines()
  405.    if .line<.last and .line then
  406. compile if EPM           -- Can't use REPLACELINE because it wipes out attributes.
  407.       oldcol = .col
  408.       down                   -- ensure one space at start of second line
  409.       call pfirst_nonblank()
  410.       col2 = .col
  411.       .col = 1
  412.       getsearch savesearch
  413.       if col2 > 2 then       -- Shift line left
  414.          'xcom c/'copies(' ',col2-2)'//'  -- Change first n-1 blanks to null
  415.       elseif col2=1 then     -- Shift line right
  416.          'xcom c/^/ /g'         -- insert a space at beginning of line
  417.       endif
  418.       setsearch savesearch
  419.       up                     -- ensure no spaces at end of first line
  420.       .col = length(strip(textline(.line),'T')) + 1
  421.       erase_end_line
  422.       .col = oldcol
  423. compile else           -- E3 and EOS2 can still use the old, simple way.
  424.       /* remove all but one trailing space of current line */
  425.       getline line
  426.       replaceline strip(line,'T')' '
  427.       /* remove all leading spaces of next line */
  428.       getline line,.line+1
  429.       replaceline strip(line),.line+1
  430. compile endif
  431.       join
  432.    endif
  433.  
  434. compile if EVERSION < 5
  435. defproc leave_last_command
  436.    if (not arg() or arg(2)) and arg(1) then
  437.       cursor_command
  438.       up
  439.       for i = 1 to arg(1)-1
  440.          right
  441.       endfor
  442.    endif
  443. compile endif
  444.  
  445. compile if WANT_LAN_SUPPORT
  446. defproc lock(file)
  447.    newhandle='??'
  448.    actiontaken=atoi(1)   -- File exists
  449.    file=file\0
  450.    result = dynalink('DOSCALLS',
  451.                      '#70',                     /* dosopen          */
  452.                      selector(file)||
  453.                      offset(file)||
  454.                      selector( newhandle )||
  455.                      offset( newhandle )||
  456.                      selector( actiontaken )||
  457.                      offset( actiontaken )||
  458.                      atol(0)||         -- file size
  459.                      atoi(0)||         -- file attribute
  460.                      atoi(17)||        -- open flag; open if exists, else create
  461.                      atoi(146)||       -- openmode; deny Read/Write
  462.                      atol(0))
  463.    if result then
  464. ;     'quit'  /* quit since the file could not be locked */
  465.       messageNwait('DOSOPEN' ERROR__MSG result NOT_LOCKED__MSG)
  466.       return result
  467.    endif
  468.    if newhandle = \0\0 then  -- Handle of 0 - bad news
  469.       newhandle2=atoi(65535)
  470.       result = dynalink('DOSCALLS',
  471.                         '#61',                     /* DosDupHandle     */
  472.                         newhandle ||
  473.                         selector( newhandle2 )||
  474.                         offset( newhandle2 ))
  475.       call dynalink('DOSCALLS',    -- Free the original handle
  476.                     '#59',                    -- dosclose
  477.                     newhandle)
  478.       if result then
  479.          messageNwait('DosDupHandle' ERROR__MSG result NOT_LOCKED__MSG)
  480.          return result
  481.       endif
  482.       newhandle = newhandle2
  483.    endif
  484.    .lockhandle=itoa(newhandle,10)
  485. compile endif
  486.  
  487. defproc max(a,b)  -- Support as many arguments as E3 will allow.
  488.    maximum=a
  489.    do i=2 to arg()
  490.       if maximum<arg(i) then maximum=arg(i); endif
  491.    end
  492.    return maximum
  493.  
  494. compile if E3
  495. definit  /* Keep this definit close to the proc it serves. */
  496.    universal lines_entered
  497.    lines_entered=0
  498.  
  499. defproc maybe_autosave    -- For E3 users, this routine increments the autosave
  500.    universal autosave,lines_entered  -- counter, and does an autosave if necessary.
  501.    if autosave then
  502.       lines_entered = lines_entered +1
  503.       if lines_entered >= autosave then
  504.          'xcom save' MakeTempName()  -- Don't worry about HPFS files in E3.
  505.          if rc=-2  then  -- sayerror('File not found') -> Invalid filename
  506.             'xcom save' MakeTempName('BAD-NAME')
  507.          endif
  508.          .modify=1                  /* Reraise the modify flag. */
  509.          lines_entered =0
  510.       endif
  511.    endif
  512. compile endif
  513.  
  514.  
  515. compile if BACKUP_PATH <> ''
  516. ;  Procedure to pick a filename for backup purposes, like STDPROCS.E$.
  517. defproc MakeBakName
  518.    name = arg(1)
  519.    -- Change name as little as possible, but enough to identify it as
  520.    -- a noncritical file.  Replace the last character with '$'.
  521.    ext = filetype(name)
  522.    if length(ext)=3 then
  523.       ext = substr(ext,1,2)'$'
  524.    else
  525.       ext = ext'$'
  526.    endif
  527.    -- We still use MakeTempName() for its handling of host names.
  528.    bakname = MakeTempName(name)
  529.    i=lastpos('\',bakname)       -- but with a different directory
  530.    if i then
  531.       bakname = substr(bakname,i+1)
  532.    endif
  533.    parse value bakname with fname'.'.
  534.    bakname = BACKUP_PATH || fname'.'ext
  535.    return bakname
  536. compile endif
  537.  
  538.  
  539. ;  Procedure to pick a temporary filename like ORIGNAME.$$1.
  540. ;  First argument is the filename, 2nd is the fileid.  Both are optional,
  541. ;  default to the current filename and fileid if absent.
  542. ;  Revised by BTTUCKER to catch all cases and work with E3EMUL.
  543. defproc MakeTempName
  544.    universal vAUTOSAVE_PATH
  545.    TempName  = arg(1)
  546.    extension = arg(2)
  547.    if TempName = '' then   /* if no arg given, default to current filename */
  548.       TempName = .filename
  549.    endif
  550.    if TempName = '' then
  551.       TempName = '$'       /* new file? o.k. then $  */
  552.    else /* We want only PC file name, VM filename, or MVS firstname          */
  553.         /* These next statements will strip everything else off...           */
  554.      p = lastpos('\',TempName)                      /* PC filename with path */
  555.      if p then TempName=substr(TempName,p+1) endif
  556.      p = pos('.',TempName)                          /* PC or MVS filename    */
  557.      if p then TempName=substr(TempName,1,p-1) endif
  558.      p = pos(' ',TempName)                          /* VM filename (or HPFS) */
  559.      if p then TempName=substr(TempName,1,p-1) endif
  560.      p = pos(':',TempName)                          /* VM or MVS filename    */
  561.      if p then TempName=substr(TempName,p+1) endif
  562.      p = pos("'",TempName)                          /* MVS filename          */
  563.      if p then TempName=substr(TempName,p+1) endif
  564.      if length(tempname)>8 then tempname=substr(tempname,1,8); endif  /* HPFS names */
  565.    endif
  566.  
  567.    -- TempName might still be blank, as for '.Unnamed file'.
  568.    if TempName='' then TempName='$'; endif
  569.  
  570.    TempName = vAUTOSAVE_PATH || TempName
  571.    if extension='' then            /* default is current fileid              */
  572.       getfileid extension
  573.    endif
  574. compile if EVERSION < 5
  575.    extension = '$$' || extension
  576. compile else
  577.    /* In EPM we can have the same filename in multiple edit windows without
  578.     * knowing it, because different edit windows are actually separate
  579.     * instances of the editor.  So try to make the tempname unique by
  580.     * combining the window handle with the fileid.  Combine two middle
  581.     * digits of the window handle with the last digit of the fileid.
  582.     */
  583.    extension = substr(getpminfo(EPMINFO_EDITCLIENT),2,2) || extension
  584. compile endif
  585.    if length(extension)>3 then     /* could be >one digit, or something else */
  586.       extension=substr(extension,2,3)
  587.    endif
  588.    return TempName'.'extension
  589.  
  590. defproc message
  591.    getfileid fileid
  592.    sayerror arg(1)
  593.    activatefile fileid
  594.  
  595. ; Print message and wait for a key press.
  596. ; Preserve active file and activate ring.
  597. ; Note:  There is no need to use "call" to invoke this procedure,  since it
  598. ; returns the null string.  Execution of a null string does nothing
  599. defproc messageNwait
  600.    getfileid zzfileid
  601. compile if EPM
  602.    display -4                    -- Force a messagebox popup from the SAYERROR
  603. compile endif
  604.    sayerror arg(1)
  605. compile if EVERSION < 5
  606.    call getkey()
  607. compile else
  608.    display 4
  609. compile endif
  610.    activatefile zzfileid
  611.  
  612. compile if EVERSION < 5
  613. ; Mgetkey() acts the same as a call to getkey(), but first checks
  614. ; whether we're in mid-execution of a key-string (Ctrl-R/Ctrl-T).
  615. ; If so it gets the next key from the string.  Call this in place of
  616. ; getkey() if you want the user to be able to record the response.
  617. ; Don't call this for unusual inputs, such as messageNwait after errors.
  618.  
  619. ; Optional argument is prompt string, will be displayed on status line.
  620.  
  621. defproc mgetkey()
  622.    universal Kstring,inKstring          /* See c_r in STDKEYS.E. */
  623.    prompt=arg(1)
  624.    if prompt<>'' and inKstring<=0 then
  625.       sayerror prompt
  626.    endif
  627.    if inKstring=0 then     /* If not recording or replaying, normal input. */
  628.       k=getkey()
  629.    elseif inKstring=-1 then /* If recording, stash key in string.          */
  630.       k=getkey()
  631.       Kstring=Kstring||k   /* Trust that it doesn't get longer than 255.   */
  632.    else           /* inKstring>0 ==> replaying; get next key from Kstring. */
  633.       k=substr(Kstring,inKstring,1)
  634.       ksize=1
  635.       if k==substr(esc,1,1) then       /* extended key ? */
  636.          k=substr(Kstring,inKstring,2) /* Yes, 2 bytes for extended key.   */
  637.          ksize=2
  638.       endif
  639.       inKstring=inKstring+ksize        /* bump index AFTER execution */
  640.    endif
  641.    if prompt<>'' and inKstring<=0 then
  642.       sayerror 0
  643.    endif
  644.    return k
  645. compile endif
  646.  
  647. defproc min(a,b)  -- Support as many arguments as E3 will allow.
  648.    minimum=a
  649.    do i=2 to arg()
  650.       if minimum>arg(i) then minimum=arg(i); endif
  651.    end
  652.    return minimum
  653.  
  654. compile if EVERSION < 5
  655. defproc move_results_to_commandline
  656.    universal oldline
  657.    if command_state() then
  658.       getline line
  659.       deleteline
  660.       setcommand line,.col,.col-.cursorx+1
  661.       oldline
  662.    endif
  663. compile endif
  664.  
  665. ; The following two routines (from Larry Margolis) let the
  666. ; user decide what action should be taken when the Enter and Ctrl-Enter
  667. ; keys are pressed.  The possible values for the action constants are
  668. ; defined in STDCNF.
  669.  
  670. compile if C_ENTER_ACTION & not ENHANCED_ENTER_KEYS  -- If null, don't define - user will supply.
  671. defproc my_c_enter
  672.    compile if C_ENTER_ACTION = 'ADDATEND' | C_ENTER_ACTION = 'DEPENDS+'
  673.    if .line = .last then         -- If we're on the last line, then add a line.
  674. compile if EVERSION < '4.12'
  675.       call maybe_autosave()
  676. compile endif
  677.       call einsert_line()
  678.       down                       -- This keeps the === Bottom === line visible.
  679.    else
  680.    compile endif
  681.  
  682.    compile if C_ENTER_ACTION = 'DEPENDS' | C_ENTER_ACTION = 'DEPENDS+'
  683.    if insert_state() then        -- DEPENDS means if insertstate() then ...
  684.    compile endif
  685.  
  686.    compile if C_ENTER_ACTION = 'NEXTLINE' | C_ENTER_ACTION = 'DEPENDS' |
  687.               C_ENTER_ACTION = 'ADDATEND' | C_ENTER_ACTION = 'DEPENDS+'
  688.    down                          -- go to next line
  689.    begin_line
  690.    compile endif
  691.  
  692.    compile if C_ENTER_ACTION = 'DEPENDS' | C_ENTER_ACTION = 'DEPENDS+'
  693.    else                          -- otherwise ...
  694.    compile endif
  695.  
  696.    compile if C_ENTER_ACTION = 'ADDLINE' | C_ENTER_ACTION = 'DEPENDS' | C_ENTER_ACTION = 'DEPENDS+'
  697. compile if EVERSION < '4.12'
  698.    call maybe_autosave()
  699. compile endif
  700.    call einsert_line()           -- insert a line
  701.    compile endif
  702.  
  703.    compile if C_ENTER_ACTION = 'DEPENDS' | C_ENTER_ACTION='ADDATEND' | C_ENTER_ACTION = 'DEPENDS+'
  704.    endif
  705.    compile endif
  706.  
  707.    compile if C_ENTER_ACTION = 'DEPENDS+'
  708.    endif
  709.    compile endif
  710.  
  711.    compile if C_ENTER_ACTION = 'STREAM'
  712.    call splitlines()
  713.    call pfirst_nonblank()
  714.    down
  715.     compile if EPM
  716.    refresh
  717.     compile endif
  718.    compile endif
  719. compile endif
  720.  
  721. compile if not ENHANCED_ENTER_KEYS & ENTER_ACTION   -- If null, don't define - user will supply.
  722. defproc my_enter
  723.  compile if WANT_STREAM_MODE = 'SWITCH'
  724.    universal stream_mode
  725.  compile endif
  726.  compile if EVERSION < 5
  727.    if command_state() then
  728.       execute
  729.  compile else
  730.    if 0 then   -- EPM has no command_state()
  731.  compile endif
  732.  compile if WANT_STREAM_MODE = 'SWITCH'
  733.    elseif stream_mode then
  734.  compile endif
  735.  compile if WANT_STREAM_MODE
  736.       if .line then
  737.          split
  738.          .col=1
  739.          down
  740.       else
  741.          insert
  742.          .col=1
  743.       endif
  744.       return
  745.  compile endif
  746.  compile if WANT_STREAM_MODE <> 1
  747.  compile if ENTER_ACTION = 'ADDATEND' | ENTER_ACTION = 'DEPENDS+'
  748.    elseif .line = .last then     -- If we're on the last line, then add a line.
  749. compile if EVERSION <= '4.12'
  750.       call maybe_autosave()
  751. compile endif
  752.       call einsert_line()
  753.       down                       -- This keeps the === Bottom === line visible.
  754.  compile endif
  755.    else
  756.       compile if ENTER_ACTION = 'DEPENDS' | ENTER_ACTION = 'DEPENDS+'
  757.       if insert_state() then     -- DEPENDS means if insertstate() then ...
  758.       compile endif
  759.  
  760.       compile if ENTER_ACTION = 'ADDLINE' | ENTER_ACTION = 'DEPENDS' | ENTER_ACTION = 'DEPENDS+'
  761. compile if EVERSION < '4.12'
  762.       call maybe_autosave()
  763. compile endif
  764.       call einsert_line()        -- insert a line
  765.       compile endif
  766.  
  767.       compile if ENTER_ACTION = 'DEPENDS' | ENTER_ACTION = 'DEPENDS+'
  768.       else                       -- otherwise ...
  769.       compile endif
  770.  
  771.       compile if ENTER_ACTION = 'NEXTLINE' | ENTER_ACTION = 'DEPENDS' |
  772.                  ENTER_ACTION = 'ADDATEND' | ENTER_ACTION = 'DEPENDS+'
  773.       down                       -- go to next line
  774.       begin_line
  775.       compile endif
  776.  
  777.       compile if ENTER_ACTION = 'DEPENDS' | ENTER_ACTION = 'DEPENDS+'
  778.       endif
  779.       compile endif
  780.  
  781.       compile if ENTER_ACTION = 'STREAM'
  782.       if .line then
  783.          if .col<=length(textline(.line)) then
  784.             split
  785.             .col=1
  786.          else
  787.             split
  788.             call pfirst_nonblank()
  789.          endif
  790.          down
  791.       else
  792.          insert
  793.          .col=1
  794.       endif
  795.        compile if EPM
  796.       refresh
  797.        compile endif
  798.       compile endif
  799.  compile endif  -- WANT_STREAM_MODE <> 1
  800.    endif
  801. compile endif
  802.  
  803.  
  804. ;  A common routine to parse an argument string containing a mix of
  805. ;  options and DOS file specs.  The DOS file specs can contain an "=" for the
  806. ;  path or the fileid, which will be replaced by the corresponding part of the
  807. ;  previous file (initially, the current filename).
  808. defproc parse_file_n_opts(argstr)
  809.    prev_filename = .filename
  810.    output = ''
  811.    do while argstr<>''
  812. compile if EVERSION >= '5.50'
  813.       parse value argstr with filename rest
  814.       if leftstr(filename,1)='"' then
  815.          parse value argstr with '"' filename '"' argstr
  816.          filename = '"'filename'"'
  817.       else
  818.          argstr = rest
  819.       endif
  820. compile else
  821.       parse value argstr with filename argstr
  822. compile endif
  823.       if substr(filename,1,1)<>'/' then
  824.          call parse_filename(filename,prev_filename)
  825.          prev_filename = filename
  826.       endif
  827.       output = output filename
  828.    end
  829.    return substr(output,2)
  830.  
  831. ;  A common routine to parse a DOS file name.  Optional second argument
  832. ;  gives source for = when used for path or fileid.  RC is 0 if successful, or
  833. ;  position of "=" in first arg if no second arg given but was needed.
  834. defproc parse_filename(var filename)
  835. compile if EVERSION >= '5.50'
  836.    if leftstr(filename,1)='"' & rightstr(filename,1)='"' then
  837.       return 0
  838.    endif
  839. compile endif
  840.    sourcefile = strip(arg(2))
  841.    if sourcefile='' then return pos('=',filename) endif
  842.  
  843.    if filename='=' then filename=sourcefile; return 0; endif
  844.  
  845.    lastsep = lastpos('\',sourcefile)
  846.    if not lastsep & substr(sourcefile,2,1) = ':' then lastsep=2; endif
  847.  
  848.    /* E doesn't handle the = prefix if it's on the first file given on      */
  849.    /* the E command line.  This replaces = with path of current file.  LAM  */
  850.    if substr(filename,1,1) = '=' & lastsep then
  851.       if substr(filename,2,1) = '.' then filename='='filename endif
  852.       filename=substr(sourcefile,1,lastsep) || substr(filename,2)
  853.    endif
  854.  
  855.    /* Also accept '=' after the pathspec, like 'c:\bat\=', */
  856.    /* or c:\bat\=.bat or c:\doc\new.=                      */
  857.    p = pos('=',filename)
  858.    if p > 1 then
  859.       sourcefileid=substr(sourcefile,max(lastsep+1,1))
  860.       parse value sourcefileid with sourcefilename '.' sourcefileext
  861.       lastsep2 = lastpos('\',filename)
  862.       if not lastsep2 & substr(filename,2,1) = ':' then lastsep2=2; endif
  863.       dot1=pos('.',filename,max(lastsep2,1))
  864.       firstpart=substr(filename,1,p-1)
  865.       if dot1 then
  866.          if dot1<p then  -- filename.=
  867.             filename= firstpart || sourcefileext
  868.          else            -- =.ext
  869.             filename= firstpart || sourcefilename || substr(filename,dot1)
  870.          endif
  871.       else            -- d:\path\         ||        filename.ext
  872.          filename= firstpart || sourcefileid
  873.       endif -- dot1
  874.    endif -- p > 1
  875.    return 0
  876.  
  877. ;  This proc is called by DEFC EDIT.
  878. ;  Does *not* assume all options are specified before filenames.
  879. defproc parse_leading_options(var rest,var options)
  880.    options=''
  881.    loop
  882.       parse value rest with wrd more
  883.       if substr(wrd,1,1)='/' then
  884.          options = options wrd
  885.          rest = more
  886.       else
  887.          leave
  888.       endif
  889.    endloop
  890.  
  891.  
  892. ; PBEGIN_MARK: this procedure moves the cursor to the first character of the
  893. ; mark area.  If the mark area is not in the active file, the marked file is
  894. ; activated.
  895. defproc pbegin_mark
  896.    call checkmark()
  897.    getmark  firstline,lastline,firstcol,lastcol,fileid
  898.    activatefile fileid
  899. compile if EVERSION < 5
  900.    cursor_data
  901. compile endif
  902.    firstline
  903.    if marktype()<>'LINE' then
  904.       .col=firstcol
  905.    endif
  906.  
  907.  
  908. ; PBEGIN_WORD: moves the cursor to the beginning of the word if the cursor is on
  909. ; this word.  If it's not on a word, it's moved to the beginning of the first
  910. ; word on the left.  If there is no word on the left it's moved to the beginning
  911. ; of the word on the right.  If the line is empty the cursor doesn't move.
  912. defproc pbegin_word
  913.    getline line,.line
  914.    if  substr(line,.col,1)=' ' then
  915.       p=verify(line,' ')       /* 1st case: the cursor on a space */
  916.       if p>=.col then
  917.          .col=p
  918.       else
  919.          if p then
  920.             q=p
  921.             loop
  922.                p=verify(line,' ','M',p)
  923.                if not p or p>.col then leave endif
  924.                p=verify(line,' ','',p)
  925.                if not p or p>.col then leave endif
  926.                q=p
  927.             endloop
  928.             .col=q
  929.          endif
  930.       endif
  931.    else
  932.       if .col<>1 then          /* 2nd case: not on a space */
  933.          .col=lastpos(' ',line,.col)+1
  934.       endif
  935.    endif
  936.  
  937.  
  938. ; PBLOCK_REFLOW: reflow the text in the marked area.  Then the destination block
  939. ; area must be selected and a second call to this procedure reflow the source
  940. ; block in the destination block.  The source block is fill with spaces.
  941. ;   option=0 saves the marked block in temp file
  942. ;   option=1 reflow temp file text and copies it to marked area
  943. defproc pblock_reflow(option,var spc,var tempofid)
  944.    call checkmark()
  945.    if not option then
  946.       usedmk=marktype()
  947.       getmark  firstline1,lastline1,firstcol1,lastcol1,fileid1
  948.       /* move the source mark to a temporary file */
  949. compile if EPM
  950.       'xcom e 'argsep'q 'argsep'n .tempo'
  951.       .visible = 0                                  -- Make hidden
  952. compile else
  953.       'xcom e 'argsep'q 'argsep'n 'argsep'h .tempo'
  954.       sayerror 1
  955. compile endif
  956.       getfileid tempofid
  957.       activatefile tempofid
  958.       call pcopy_mark()
  959.       activatefile fileid1
  960. compile if EVERSION < 5
  961.       cursor_data
  962. compile endif
  963.       call pset_mark(firstline1,lastline1,firstcol1,lastcol1,usedmk,fileid1)
  964.       if usedmk='LINE' then
  965.          begin_line
  966.       endif
  967.       spc=usedmk firstline1 lastline1 firstcol1 lastcol1 fileid1
  968.       return 0
  969.    else
  970.       if marktype() <> 'BLOCK' then
  971.          sayerror NEED_BLOCK_MARK__MSG
  972.          /* release tempo */
  973.          getfileid fid
  974.          rc=0
  975.          activatefile tempofid
  976.          if rc then return rc; endif
  977.          .modify=0
  978.          'xcom q'
  979.          activatefile fid
  980.          return 1
  981.       endif
  982.       parse value spc with usedmk firstline1 lastline1 firstcol1 lastcol1 fileid1
  983.       getmark  firstline2,lastline2,firstcol2,lastcol2,fileid2
  984.       /* fill source with space */
  985.       if usedmk='LINE' then
  986.          for i = firstline1 to lastline1
  987.             replaceline '',i,fileid2
  988.          endfor
  989.       else
  990.          call pset_mark(firstline1,lastline1,firstcol1,lastcol1,usedmk,fileid1)
  991.          call pfill_mark(' ')
  992.       endif
  993.       call pset_mark(firstline2,lastline2,firstcol2,lastcol2,'BLOCK',fileid2)
  994.       delete_mark
  995.       /* let's reflow in the hidden file */
  996.       activatefile tempofid
  997.       width = lastcol2+1-firstcol2
  998.       height = lastline2+1-firstline2
  999. compile if EVERSION < '4.12'
  1000.       savemargins= pmargins()
  1001. compile endif
  1002.       'xcom ma 1 'width
  1003.       unmark; mark_line; bottom; mark_line
  1004.       reflow
  1005. compile if EVERSION < '4.12'
  1006.       'xcom ma 'savemargins
  1007. compile endif
  1008.       nbl = .last
  1009.       /* go back to the destination */
  1010.       activatefile fileid2
  1011.       if nbl > height then
  1012.          fix = nbl-height
  1013.          getline line,lastline2
  1014.          for i = 1 to fix
  1015.             insertline line,lastline2+1
  1016.          endfor
  1017.       elseif nbl < height then
  1018.          fix=0
  1019.          for i = nbl+1 to height
  1020.             insertline '',tempofid.last+1,tempofid
  1021.          endfor
  1022.          nbl=height
  1023.       else
  1024.          fix=0
  1025.       endif
  1026.       call pset_mark(1,nbl,1,width,'BLOCK',tempofid)
  1027.       firstline2; .col=firstcol2; copy_mark; unmark
  1028.       call pset_mark(firstline2,lastline2+fix,firstcol2,lastcol2,'BLOCK',fileid2)
  1029.       /* release tempo */
  1030.       activatefile tempofid
  1031.       .modify=0
  1032.       'xcom q'
  1033.       activatefile fileid2
  1034.       sayerror 1
  1035.     endif
  1036.  
  1037.  
  1038. ; PCENTER_MARK: center the strings between the block marks
  1039. defproc pcenter_mark
  1040.    if  marktype() = 'BLOCK' then
  1041.       getmark  firstline,lastline,firstcol,lastcol,fileid
  1042.    elseif marktype() = 'LINE' then
  1043.       getmark  firstline,lastline,firstcol,lastcol,fileid
  1044.       parse value pmargins() with  firstcol lastcol .
  1045.    elseif marktype() = '' then
  1046.       getfileid fileid
  1047.       parse value pmargins() with  firstcol lastcol .
  1048.       firstline=.line;lastline=.line
  1049.    else
  1050.       sayerror CHAR_INVALID__MSG
  1051.       stop
  1052.    endif
  1053.    sz = lastcol+1-firstcol
  1054.    for i=firstline to lastline
  1055.       getline line,i,fileid
  1056.       inblock=strip(substr(line,firstcol,sz))
  1057.       if inblock='' then iterate endif
  1058. compile if EPM
  1059.       replaceline strip(overlay(center(inblock, sz), line, firstcol),'T'), i, fileid
  1060. compile else
  1061.       replaceline substr(line,1,firstcol-1) ||
  1062.          substr(substr('',1,(sz-length(inblock))%2)||inblock,1,sz) ||
  1063.          substr(line,lastcol+1) ,i,fileid
  1064. compile endif
  1065.    endfor
  1066.  
  1067.  
  1068. compile if EVERSION < 5
  1069. ;  A built-in function command_state() is now provided for better
  1070. ;  efficiency.  This defproc is kept only for compatibility with older macros.
  1071. ;  Please use command_state() instead.
  1072. defproc pcommand_state
  1073.    return command_state()
  1074.  
  1075.  
  1076. ; PCOMMON_TAB_MARGIN: subroutine common to ptabs and pmargins
  1077.  
  1078. defproc pcommon_tab_margin(TabOrMargins)
  1079. ;    the tricky stuff:  execute ma (or tabs) and get the result from coms.e file
  1080.    getcommand oldcmd,oldcol,oldscroll    -- Save old cmdline status
  1081.    TabOrMargins                          -- Execute the command
  1082.    getcommand setting                    -- Get current setting from cmdline
  1083.    setcommand oldcmd,oldcol,oldscroll    -- Restore old cmdline status
  1084.    parse value setting with . val        -- Get the stuff we want
  1085.    return val
  1086. compile endif
  1087.  
  1088. compile if 0    -- The following two routines are unused; why waste space??  LAM
  1089. ; PDISPLAY_MARGINS: put the margins mark on the current line
  1090.  
  1091. defproc pdisplay_margins()
  1092.    i=insert_state()
  1093.    if i then insert_toggle endif
  1094.    call psave_pos(save_pos)
  1095.    insert
  1096.    parse value pmargins() with lm rm pm .
  1097.    .col=lm;keyin'L';.col=pm;keyin'P';.col=rm;keyin'R'
  1098.    begin_line
  1099.    call prestore_pos(save_pos)
  1100.    if i then insert_toggle endif
  1101.    return 0
  1102.  
  1103.  
  1104. ; PDISPLAY_TABS: put the tab stops on the current line
  1105.  
  1106. defproc pdisplay_tabs()
  1107.    i=insert_state()
  1108.    if i then insert_toggle endif
  1109.    call psave_pos(save_pos)
  1110.    insert
  1111.    tabstops = ptabs()
  1112.    do forever
  1113.       parse value tabstops with tabx tabstops
  1114.       if tabx = '' then leave endif
  1115.       .col=tabx
  1116.       keyin'T'
  1117.    end
  1118.    begin_line
  1119.    call prestore_pos(save_pos)
  1120.    if i then insert_toggle endif
  1121.    return 0
  1122. compile endif
  1123.  
  1124. ; PEND_MARK: moves the cursor to the end of the marked area
  1125. defproc pend_mark
  1126.    call checkmark()
  1127.    getmark  firstline,lastline,firstcol,lastcol,fileid
  1128.    activatefile fileid
  1129. compile if EVERSION < 5
  1130.    cursor_data
  1131. compile endif
  1132.    if marktype()<>'LINE' then
  1133.       .col=lastcol
  1134.    endif
  1135.    lastline
  1136.  
  1137. ; PEND_WORD: moves the cursor to the end of the word if the cursor is on this
  1138. ; word.  If it's not on a word, it's moved to the end of the first word on the
  1139. ; right.  If there is no word on the right it's moved to the end of the word on
  1140. ; the left.  If the line is empty the cursor doesn't move.
  1141. defproc pend_word
  1142.    getline line,.line
  1143.    if  substr(line,.col,1)=' '  then
  1144.       if substr(line,.col)=' ' then
  1145.          if  line<> ' ' then
  1146.             for i=.col to 2 by -1
  1147.                if substr(line,i-1,1)<>' ' then leave endif
  1148.             endfor
  1149.            .col=i-1
  1150.          endif
  1151.       else
  1152.          p=verify(line,' ','',.col)
  1153.          p=verify(line' ',' ','M',p)
  1154.          .col=p-1
  1155.       endif
  1156.    else
  1157.       if .col<>MAXCOL then
  1158.          i=pos(' ',line,.col)
  1159.          if i then
  1160.             .col=i-1
  1161.          else
  1162.             .col=length(line)
  1163.          endif
  1164.       endif
  1165.    endif
  1166.  
  1167.  
  1168. defproc pfile_exists /* Check if file already exists in ring */
  1169.    if substr(arg(1),2,1)=':'  then
  1170.       /* parse off drive specifier and try again */
  1171.       getfileid zzfileid,substr(arg(1),3)
  1172.    else
  1173.       getfileid zzfileid,arg(1)
  1174.    endif
  1175.    return zzfileid<>''
  1176.  
  1177. defproc pfind_blank_line
  1178.    -- Find first blank line after the current one.  Make that the new current
  1179.    -- line.  If no such line is found before the end of file, don't change the
  1180.    -- current line.
  1181.    for i = .line+1 to .last
  1182.       getline line,i
  1183.       -- Ver 3.11:  Modified to respect GML tags:  stop at first blank line
  1184.       -- or first line with a period or a colon (".:") in column 1.
  1185.       if line='' or not verify(substr(line,1,1), ".:" ) then
  1186.          i
  1187.          leave
  1188.       endif
  1189.    endfor
  1190.  
  1191. defproc pfirst_nonblank
  1192.    /* different from PE */
  1193.    if not .line then .col=1
  1194.    else
  1195.       getline line
  1196.       .col=max(1,verify(line,' '))
  1197.    endif
  1198.  
  1199.  
  1200. ; PLOWERCASE: force to lowercase the marked area
  1201.  
  1202. defproc plowercase
  1203.    call checkmark()
  1204.    /* invoke pinit_extract, pextract_string, pput_string_back to do the job */
  1205.    call psave_pos(save_pos)
  1206.    call pinit_extract()
  1207.    do forever
  1208.       code = pextract_string(string)
  1209.       if code = 1 then leave; endif
  1210.       if code = 0 then
  1211.          string = lowcase(string)
  1212.          call pput_string_back(string)
  1213.       endif
  1214.    end
  1215.    call prestore_pos(save_pos)
  1216.  
  1217.  
  1218. ; PMARGINS: return the current margins setting. (Uses pcommon_tab_margin)
  1219.  
  1220. defproc pmargins
  1221. compile if EVERSION < 5
  1222.    return pcommon_tab_margin('ma')
  1223. compile else
  1224.    return .margins
  1225. compile endif
  1226.  
  1227.  
  1228. ; PMARK: mark at the cursor position (mark type received as argument).  Used by
  1229. ; pset_mark
  1230. defproc pmark(mt)
  1231.    if mt= 'LINE' then
  1232.       mark_line
  1233.    elseif mt = 'CHAR' then
  1234.       mark_char
  1235.    else
  1236.       mark_block
  1237.    endif
  1238.  
  1239.  
  1240. ; PMARK_WORD: mark the word pointed at by the cursor.  If the cursor is on a
  1241. ; space, the word at the right is marked.  If there is no word on the right, the
  1242. ; word on the left is marked.
  1243. defproc pmark_word
  1244.    if marktype()<>'' then
  1245.       sayerror -279  -- 'Text already marked'
  1246.       stop
  1247.    endif
  1248.    call pend_word()
  1249.    mark_block
  1250.    call pbegin_word()
  1251.    mark_block
  1252. compile if EVERSION > 5
  1253.   'Copy2SharBuff'       /* Copy mark to shared text buffer */
  1254. compile endif
  1255.  
  1256.  
  1257. ; PRESTORE_MARK: restore the current marks (cannot be used as a stack) See also
  1258. ; psave_mark
  1259. defproc prestore_mark(savemark)
  1260.    unmark
  1261.    parse value savemark with savefirstline savelastline savefirstcol savelastcol savemkfileid savemt
  1262.    if savemt<>'' then
  1263.       call pset_mark(savefirstline,savelastline,savefirstcol,savelastcol,savemt,savemkfileid)
  1264.    endif
  1265.  
  1266.  
  1267. ; PRESTORE_POS: restore the cursor position (cannot be used as a stack) See
  1268. ; also psave_pos()
  1269. defproc prestore_pos(save_pos)
  1270.    parse value save_pos with svline svcol svcx svcy
  1271.    .cursory = svcy                          -- set .cursory
  1272.    min(svline, .last)                       -- set .line
  1273.    .col = MAXCOL; .col = svcol - svcx + 1   -- set left edge of window
  1274.    .col = svcol                             -- set .col
  1275.  
  1276.  
  1277. ;  Printer_ready( printer_number ) tests whether printer is ready.
  1278. ;
  1279. ;  Enter with printer_number = 1 for the first printer (LPT1), 2 for LPT2.
  1280. ;  No argument at all defaults to LPT1.
  1281. ;
  1282. ;  Returns 1 (true)  for printer attached and ready.
  1283. ;  Returns 0 (false) for printer not attached or not ready.
  1284. ;
  1285. ;  Note:  Assumes the standard BIOS responses for an IBM PC.
  1286. ;  The BIOS responds with AH=90 hex for printer ready.
  1287. ;  Might not work on clones and other strange machines.
  1288. ;
  1289. ;  If we're on OS/2 we don't check because the spooler protects us from
  1290. ;  a hang if the printer's off-line.  We always return "ready" on OS/2.
  1291. ;
  1292. defproc printer_ready
  1293. compile if EVERSION >= 4
  1294.    return 1
  1295. compile else
  1296.    if arg(1)='' then
  1297.       printer_number=1
  1298.    elseif not isnum(arg(1)) then
  1299.       sayerror 'Printer_ready:  'INVALID_NUMBER__MSG
  1300.       return 0
  1301.    else
  1302.       printer_number = arg(1)
  1303.    endif
  1304.    /* Call BIOS interrupt 17 hex with AH=2, printer status query. */
  1305.    parse value int86x(23,512 0 0 printer_number-1,'') with printer_status .
  1306. ;    IBM PC family returns '90' for printer ready (not busy + selected).
  1307. ;    Some clones return 'D0' (not busy + acknowledge + selected).
  1308. ;    Here, we'll accept either value.
  1309. ;                    hex2dec('9000'):              hex2dec('D000'):
  1310.    return (printer_status == -28672) or (printer_status == -12288)
  1311. compile endif
  1312.  
  1313.  
  1314. ; PSAVE_MARK: save the current marks (cannot be used as a stack) See also
  1315. ; prestore_pos()
  1316. defproc psave_mark(var savemark)
  1317.    savemt=marktype()
  1318.    if savemt then
  1319.       getmark  savefirstline,savelastline,savefirstcol,savelastcol,savemkfileid
  1320.       unmark
  1321.       savemark=savefirstline savelastline savefirstcol savelastcol savemkfileid savemt
  1322.    else
  1323.       savemark=''
  1324.    endif
  1325.  
  1326.  
  1327. ; PSAVE_POS: save the cursor position (cannot be used as a stack) See also
  1328. ; prestore_pos()
  1329. defproc psave_pos(var save_pos)
  1330.    save_pos=.line .col .cursorx .cursory
  1331.  
  1332.  
  1333. defproc pset_mark(firstline,lastline,firstcol,lastcol,mt,fileid)
  1334. compile if EVERSION >= '5.50'
  1335.    setmark firstline,lastline,firstcol,lastcol,wordpos(mt,'LINE CHAR BLOCK CHARG BLOCKG')-1,fileid
  1336. compile else
  1337.    getfileid actfileid    /* preserve current active fileid */
  1338.    rc = 0
  1339.    activatefile fileid
  1340.  compile if not E3
  1341.    if rc=sayerror('Invalid fileid') then stop; endif
  1342.  compile endif
  1343.    call psave_pos(save_pos)
  1344.    unmark
  1345.    if lastcol then
  1346.       .col=lastcol; lastline
  1347.    else
  1348.       lastline-1; .col=MAXCOL
  1349.    endif
  1350.    call  pmark(mt)
  1351.    .col=firstcol; firstline
  1352.    call pmark(mt)
  1353.    call prestore_pos(save_pos)
  1354.    activatefile actfileid         /* restore the initial active file */
  1355. compile endif
  1356.  
  1357. ; PTABS: return the current tabs setting. (Uses pcommon_tab_margin)
  1358.  
  1359. defproc ptabs
  1360. compile if EVERSION < 5
  1361.    return pcommon_tab_margin('tabs')
  1362. compile else
  1363.    return .tabs
  1364. compile endif
  1365.  
  1366.  
  1367. ; PUPPERCASE: force to uppercase the marked area
  1368.  
  1369. defproc puppercase
  1370.    call checkmark()
  1371.    /* invoke pinit_extract, pextract_string, pput_string_back to do the job */
  1372.    call psave_pos(save_pos)
  1373.    call pinit_extract()
  1374.    do forever
  1375.       code = pextract_string(string)
  1376.       if code = 1 then leave endif
  1377.       if code = 0 then
  1378.          string = upcase(string)
  1379.          call pput_string_back(string)
  1380.       endif
  1381.    end
  1382.    call prestore_pos(save_pos)
  1383.  
  1384. ;defproc remove_trailing_spaces
  1385. ;   /* This is no longer used by any file in standard E.  Use strip()  */
  1386. ;   /* instead.  But left here for compatibility with older procs.     */
  1387. ;   return strip(arg(1),'T')
  1388.  
  1389. compile if EPM
  1390. ; In E3 and EOS2, we can use a_X to enter the value of any key.  In EPM,
  1391. ; we can't, so the following routine is used by KEY and LOOPKEY to convert
  1392. ; from an ASCII key name to the internal value.  It handles shift or alt +
  1393. ; any letter, or a function key (optionally, with any shift prefix).  LAM
  1394. defproc resolve_key(k)
  1395.    kl=lowcase(k)
  1396.    suffix=\2                           -- For unshifted function keys
  1397.    if length(k)>=3 & pos(substr(k,2,1),'_-+') then
  1398.       if length(k)>3 & substr(kl,3,1)='f' then     -- Shifted function key
  1399.          suffix=substr(\10\34\18,pos(leftstr(kl,1),'sac'),1)  -- Set suffix,
  1400.          kl=substr(kl,3)             -- strip shift prefix, and more later...
  1401.       else                        -- alt+letter or ctrl+letter
  1402.          k=substr(kl,3,1) || substr(' ',pos(leftstr(kl,1),'ac'),1)
  1403.       endif
  1404.    endif
  1405.    if leftstr(kl,1)='f' & isnum(substr(kl,2)) then
  1406.       k=chr(substr(kl,2)+31) || suffix
  1407.    endif
  1408.    return k
  1409. compile endif
  1410.  
  1411. compile if EVERSION < 5
  1412. defproc restore_command_state(cstate)
  1413.    if command_state()<>cstate then
  1414.       command_toggle
  1415.    endif
  1416.  
  1417. defproc save_command_state(var cstate)
  1418.    cstate=command_state()
  1419.    cursor_data
  1420.    refresh            /* Force E to update the cursor position */
  1421. compile endif
  1422.  
  1423.  
  1424. -- 4.10:  Saving with tab compression is built in now.  No need for
  1425. -- the make-do proc savefilewithtabs().  DOS version still needs it for
  1426. -- people editing MAKE files, but we make it optional via WANT_TABS.
  1427.  
  1428. compile if E3 & WANT_TABS
  1429. ; Note:  This does not tabify the entire file; it just replaces 8 blanks
  1430. ; in the first column with a tab character.
  1431. defproc savefilewithtabs(filename)
  1432.    options=arg(2)
  1433.    call psave_pos(save_pos)
  1434.    getfileid fileid
  1435.    unmark;bottom;markline;top;markline
  1436.    call prestore_pos(save_pos)
  1437.    'xcom e 'argsep'n .';deleteline
  1438.    if rc and rc<>-282 then  -- sayerror("new file")
  1439.       return rc
  1440.    endif
  1441.    rc=0
  1442.    copymark
  1443.    if rc then return rc endif
  1444.    unmark
  1445.    top;.col=1;markblock;bottom;.col=8;markblock
  1446.    .col=1;top
  1447.    'c/        /'\t'/m*'     /* replace first column 8 spaces with tab */
  1448.    sayerror 1  /* Turn off pending messages */
  1449.    unmark
  1450.    savestatus=savefile(filename,options)
  1451.    .modify=0
  1452.    'xcom q'
  1453.    if savestatus then return savestatus endif
  1454.    activatefile fileid
  1455.    if filename=.filename then
  1456.       .modify=0
  1457.    endif
  1458.    return 0
  1459. compile endif
  1460.  
  1461. define
  1462. compile if EVERSION < '5.21'
  1463.    MSGC = '.messagecolor'
  1464. compile elseif EVERSION < '5.50'
  1465.    MSGC = 'vMESSAGECOLOR'
  1466. compile else            -- GPI version
  1467.    MSGC = 'color'
  1468. compile endif
  1469.  
  1470. ; Paste up a message in a box, using SAYAT's.  Useful for "Processing..." msgs.
  1471. defproc sayatbox
  1472. compile if EVERSION >= '5.21'
  1473.    universal vMESSAGECOLOR
  1474. compile endif
  1475. compile if WANT_DBCS_SUPPORT
  1476.    universal ondbcs
  1477. compile endif
  1478.  
  1479. compile if EVERSION >= '5.50'  -- GPI version; doesn't use background color in SAYATs.
  1480.    color = sayat_color()
  1481. compile endif
  1482. compile if WANT_DBCS_SUPPORT
  1483.    if ondbcs then
  1484.       middle = substr('',1,length(arg(1)),\x06)
  1485.       sayat '  '\x01\x06||middle||\x06\x02'  ',1,2, $MSGC
  1486.       sayat '  '\x05' 'arg(1)' '\x05'  ',2,2, $MSGC
  1487.       sayat '  '\x03\x06||middle\x06\x04'  ',3,2, $MSGC
  1488.    else
  1489. compile endif
  1490.       middle = substr('',1,length(arg(1)),'═')
  1491.       sayat '  ╔═'middle'═╗  ',1,2, $MSGC
  1492.       sayat '  ║ 'arg(1)' ║  ',2,2, $MSGC
  1493.       sayat '  ╚═'middle'═╝  ',3,2, $MSGC
  1494. compile if WANT_DBCS_SUPPORT
  1495.    endif
  1496. compile endif
  1497.  
  1498. compile if EVERSION >= '5.50'
  1499. defproc sayat_color =          -- Pick a color for SAYAT that doesn't conflict w/ foreground or background color.
  1500.    universal vMESSAGECOLOR
  1501.    if vMESSAGECOLOR // 16 <> .textcolor // 16 & vMESSAGECOLOR // 16 <> .textcolor % 16 then
  1502.       return vMESSAGECOLOR       -- Preference is the message color.
  1503.    endif
  1504.    if vMESSAGECOLOR // 16 <> LIGHT_RED then
  1505.       return LIGHT_RED           -- Second choice is light red.
  1506.    endif
  1507.    if .textcolor // 16 <> LIGHT_BLUE & .textcolor % 16 <> LIGHT_BLUE then
  1508.       return LIGHT_BLUE          -- If that's used, then how about light blue
  1509.    endif
  1510.    return GREEN                  -- Final fallback is green.
  1511. compile endif
  1512.  
  1513. defproc splitlines()
  1514.    if .line then
  1515.       split
  1516.       oldcol=.col
  1517.       call pfirst_nonblank()
  1518. compile if EPM           -- Can't use REPLACELINE because it wipes out attributes.
  1519.       col1 = .col
  1520.       down
  1521.       if textline(.line)<>'' then
  1522.          call pfirst_nonblank()
  1523.          col2 = .col
  1524.          getsearch savesearch
  1525.          .col = 1
  1526.          if col1 < col2 then       -- Shift new line left
  1527.             'xcom c/'copies(' ',col2-col1)'//'  -- Change first n blanks to null
  1528.          elseif col1 > col2 then   -- Shift new line right
  1529. ;;            c = substr(textline(.line),1,1)  -- LAM: simpler to use GREP
  1530. ;;            if c='/' then d='?'; else d='/'; endif  -- Choose delimiter
  1531. ;;            'xcom c 'd||c||d||substr('',1,col1-col2)||c||d  -- Add blanks before 1st char.
  1532.             'xcom c /^/'copies(' ',col1-col2)'/g'  -- Add blanks before 1st char.
  1533.          endif
  1534.          setsearch savesearch
  1535.       endif
  1536.       up
  1537. compile else           -- E3 and EOS2 can still use the old, simple way.
  1538.       getline line,.line+1
  1539.       replaceline substr('',1,.col-1) ||    -- indent like previous line
  1540.          strip(line,'L'),                   -- (remove leading spaces)
  1541.          .line+1
  1542. compile endif
  1543.       .col=oldcol
  1544.    endif
  1545.  
  1546.  
  1547. ; Note on a speed trick:  subdir_present is initialized to null at start-up.
  1548. ; This causes defproc subdir(), the first time it's called, to execute a
  1549. ; FINDFILE (by way of find_routine) to search the path for the subdir program.
  1550. ; (See DEFC HELP for another example of findfile.)
  1551. ; After that first search the exact path location of subdir is known; it's
  1552. ; remembered in the universal variable subdir_present.  All future calls supply
  1553. ; the exact location (as in "C:\UTIL\SUBDIR.COM") to avoid the path search.
  1554.  
  1555. definit  /* Keep this definit close to the proc it serves. */
  1556.    universal subdir_present
  1557.    subdir_present=''
  1558.  
  1559. defproc subdir
  1560.    universal subdir_present
  1561.    if subdir_present='' then  -- First time; look for the program
  1562.  compile if E3
  1563.       subdir_present=find_routine('SUBDIR /Q')
  1564.  compile else
  1565.       subdir_present=find_routine('FILEFIND')
  1566.  compile endif
  1567.       if subdir_present == -1 then     -- Not found, try ATTRIB
  1568.          subdir_present=find_routine('ATTRIB /S')
  1569.       endif
  1570.    endif
  1571.    if subdir_present == -1 then
  1572.       sayerror CANT_FIND_PROG__MSG 'ATTRIB'
  1573.       stop
  1574.    endif
  1575.    quietshell subdir_present arg(1)
  1576.  
  1577. compile if EVERSION >= 4
  1578. defproc swapwords(num)
  1579.    return substr(num,3,2) || substr(num,1,2)
  1580. compile endif
  1581.  
  1582.  
  1583. compile if E3 or (EPM & not (EVERSION >= '5.17'))
  1584. ;  EOS2 & EPM have a TEXTLINE() function built in.  This is added here so that
  1585. ;  E3 macro programmers can use TEXTLINE also, if they like.
  1586. defproc textline(linenum)
  1587.    getline line,linenum; return line
  1588. compile endif
  1589.  
  1590. ;  A truncate function to maintain compatibility of macros between this
  1591. ;  version and the OS/2 version which will have floating point.  Two
  1592. ;  functions in DOSUTIL.E need this.
  1593. ;
  1594. ;  If we're passed a floating point number with a decimal point in it,
  1595. ;  like "4.0", drop the decimal part.
  1596. ;  If we're passed an exponential-format number like "6E3", fatal error.
  1597. defproc trunc(num)
  1598.    if not verify('E',upcase(num)) then
  1599.       sayerror NO_FLOAT__MSG num
  1600.       stop
  1601.    endif
  1602.    parse value num with whole'.'.
  1603.    return whole
  1604.  
  1605. compile if WANT_LAN_SUPPORT
  1606. defproc unlock(fileid)
  1607.    if fileid.lockhandle = 0 then
  1608.       sayerror fileid.filename NOT_LOCKED__MSG
  1609.       return 1
  1610.    endif
  1611.    result = dynalink('DOSCALLS',
  1612.                      '#59',                    /* dosclose */
  1613.                      atoi(fileid.lockhandle))
  1614.    if result then
  1615.       sayerror 'DOSCLOSE' ERROR_NUMBER__MSG result
  1616.    else
  1617.       fileid.lockhandle = 0
  1618.    endif
  1619.    return result
  1620. compile endif
  1621.  
  1622.