home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 5 Edit / 05-Edit.zip / epmmac.zip / STDPROCS.E < prev    next >
Text File  |  1996-01-23  |  65KB  |  1,892 lines

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