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