home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 16 / 16.iso / w / w055 / 4.ddi / SOURCES.LIF / NUCLEUS.PEL < prev    next >
Encoding:
Text File  |  1990-09-27  |  25.8 KB  |  1,104 lines

  1. # $Header:   P:/source/ppee/macros/nucleus.pev   1.160   27 Sep 1990 09:58:58   skipr  $
  2.  
  3. ##############################################################################
  4. #
  5. #           Sage Software - POLYTRON Division
  6. #             1700 NW 167th Place
  7. #               Beaverton, OR 97006
  8. #
  9. #   Copyright 1990, Sage Software, Inc.
  10. #
  11. #   Permission is hereby granted for licensed users of Sage Professional
  12. #   Editor and PolyAwk to copy and modify this source code for their own
  13. #   personal use.  These derivative works may be distributed only to other
  14. #   licensed Sage Professional Editor and PolyAwk users.  All other usage
  15. #   is prohibited without express written permission from Sage Software.
  16. #
  17. ##############################################################################
  18.  
  19. #### $Workfile:   nucleus.pel  $: manifest constants and core utilities
  20.  
  21.  
  22. # reserved global variables
  23.  
  24. global TRUE    = 1
  25. global FALSE    = 0
  26.  
  27. global emulation_mode
  28. global backup_files_enabled;
  29.  
  30.  
  31.     ## DOS file attributes:
  32. global FILEMODE_NORMAL        = 0
  33. global _READ_ONLY        = 1
  34. global _HIDDEN            = 2
  35. global _SYSTEM            = 4
  36. global _VOL_ID            = 8
  37. global _SUBDIR            = 16
  38. global _ARCHIVE            = 32
  39. global _NORMAL            = 64
  40.  
  41.     ## Event numbers:
  42. global EVENT_EMULATION_CHANGED    = 9
  43. global EVENT_IDLE_TIME        = 10
  44. global EVENT_CTRL_BREAK        = 11
  45. global EVENT_INVALID_PCHAR    = 12
  46. global EVENT_UNASSGN_KEY    = 13
  47. global EVENT_NEW_EDIT_FILE    = 14
  48. global EVENT_NEW_CURNT_BUFFER    = 15
  49. global EVENT_NEW_CURNT_WINDOW    = 16
  50. global EVENT_HELP_INVOKED    = 17
  51. global EVENT_IDLE_THRESHOLD    = 18
  52. global EVENT_EXIT_EDITOR    = 19
  53. global EVENT_TEMP_SPACE_OVFLW    = 20
  54. global EVENT_EDIT_FILE_SAVE    = 21
  55. global EVENT_KEYPRESS        = 22
  56. global EVENT_FIRST_MOD        = 23
  57. global EVENT_NEW_SCREEN_SIZE    = 24
  58. global EVENT_DISPLAY_UPDATE    = 26
  59. global EVENT_PROCESS_COMPLETE    = 27
  60. global EVENT_MOUSE_LEFT_DOWN    = 28
  61. global EVENT_MOUSE_RIGHT_DOWN    = 29
  62. global EVENT_MOUSE_MID_DOWN    = 30
  63. global EVENT_MOUSE_LEFT_UP    = 31
  64. global EVENT_MOUSE_RIGHT_UP    = 32
  65. global EVENT_MOUSE_MID_UP    = 33
  66. global EVENT_MOUSE_LEFT_CLICK1    = 34
  67. global EVENT_MOUSE_RIGHT_CLICK1    = 35
  68. global EVENT_MOUSE_MID_CLICK1    = 36
  69. global EVENT_MOUSE_LEFT_CLICK2    = 37
  70. global EVENT_MOUSE_RIGHT_CLICK2    = 38
  71. global EVENT_MOUSE_MID_CLICK2    = 39
  72. global EVENT_INSERT_KEY        = 40
  73. global EVENT_INSERT_STRING    = 41
  74. global EVENT_DELETE_CHARS    = 42
  75. global EVENT_INSERT_NEWLINE    = 43
  76. global EVENT_SHELL_EXIT        = 44
  77. global EVENT_FUNCTION_CHANGED    = 45
  78. global EVENT_DELETING_BUFFER    = 46
  79.  
  80.  
  81.     ## System file numbers:        (see locate_sageedit_file)
  82. global SAGEEDIT_FILE_CONFIG    = 1    # sageedit.cfg
  83. global SAGEEDIT_FILE_AE        = 2    # sageedit.ae
  84. global SAGEEDIT_FILE_HELP    = 3    # help.txt
  85. global SAGEEDIT_FILE_BINDINGS    = 4    # bindings.txt
  86. global SAGEEDIT_FILE_REFMAN    = 5    # refman.txt
  87.  
  88.  
  89. ## process_command_line()
  90. #
  91. # handle command line options and invoke edit_file on filenames
  92. #
  93. global function process_command_line() {
  94.  
  95.     local    cmd_line_error
  96.     local    arg, iarg, i, option
  97.     local    poe
  98.     local    recordKeysFile
  99.     local    playbackKeysFile
  100.  
  101.     # process command line arguments one at a time
  102.  
  103.     for ( iarg=1; iarg<ARGC; iarg++ ) {
  104.  
  105.         arg = ARGV[iarg]
  106.  
  107.         # process switches from left to right
  108.  
  109.         if ( substr(arg,1,1) == "-" ) {
  110.             arg = substr(arg,2)
  111.  
  112.             while ( arg ) {
  113.  
  114.                 option = substr(arg,1,1)
  115.                 arg = substr(arg,2)
  116.  
  117.                 #
  118.                 # invoke startup Function
  119.                 #
  120.                 if ( option == "f" || option == "F" ) {
  121.                     if ( arg == "" )
  122.                         arg = ARGV[ ++iarg ]
  123.  
  124.                     arg = trim( ltrim( arg ));
  125.                     arg = trim( ltrim( arg, "\"" ), "\"" );
  126.  
  127.                     execute_function( arg )
  128.                     arg = ""
  129.  
  130.  
  131.                 #
  132.                 # Readonly option
  133.                 #
  134.                 } else if ( option == "r" ) {
  135.                     set_default_buffer_flag( \
  136.                         BUFFER_READ_ONLY, \
  137.                         TRUE )
  138.                     set_buffer_flag( \
  139.                         BUFFER_READ_ONLY, \
  140.                         TRUE )
  141.  
  142.                 #
  143.                 # control-Z is eof option
  144.                 #
  145.                 } else if ( option == "z" || option == "Z" ) {
  146.                     default_buffer_eof_string = buffer_eof_string = chr( 26 )
  147.  
  148.                 #
  149.                 # playback keys stored in key file
  150.                 #
  151.                 } else if ( option == "P" ) {
  152.                     playbackKeys = TRUE
  153.                     if ( arg == "" )
  154.                         arg = ARGV[ ++iarg ]
  155.                     playbackKeysFile = arg
  156.                     arg = ""
  157.  
  158.                 #
  159.                 # save all keys to playback file
  160.                 #
  161.                 } else if ( option == "R" ) {
  162.                     recordKeys = TRUE
  163.                     if ( arg == "" )
  164.                         arg = ARGV[ ++iarg ]
  165.                     recordKeysFile = arg
  166.                     arg = ""
  167.  
  168.                 #
  169.                 # invoke awk function Library
  170.                 #
  171.                 # specified .ae filename is processed
  172.                 # in C code so skip to the next argument
  173.                 #
  174.                 } else if (option == "a" || option == "A" ) {
  175.                     if ( arg == "" )
  176.                         iarg++
  177.                     arg = ""
  178.  
  179.                 #
  180.                 # unrecognized switch character
  181.                 #
  182.                 } else {
  183.                     cmd_line_error = "option " option " not recognized"
  184.                     arg = ""
  185.                 }
  186.             }
  187.         } else {
  188.             # treat arguments not beginning with "-" as filenames
  189.             edit_file(arg)
  190.         }
  191.     }
  192.  
  193.     # make the first buffer in the list the current buffer
  194.     next_buffer()
  195.  
  196.     # ============================================================= #
  197.  
  198.     if ( emulation_mode == "" ) {
  199.         poe = pause_on_error
  200.         pause_on_error = 1
  201.         warning( "no emulation mode defined - <Alt-Q> to exit" )
  202.         pause_on_error = poe
  203.     }
  204.  
  205.     # record/playback session support
  206.     if ( playbackKeys ) {
  207.         playbackKeysInitialize( playbackKeysFile )
  208.     } else if ( recordKeys ) {
  209.         recordKeysInitialize( recordKeysFile )
  210.     }
  211.  
  212.     display_update()    # so following messages show up
  213.     if (cmd_line_error) {
  214.         warning( cmd_line_error )
  215.     } else {
  216.         message( version_label() )
  217.     }
  218. }
  219.  
  220.  
  221. ## display copyright notice and version label
  222. #
  223. global function print_version() {
  224.     warning( version_label() )
  225. }
  226.  
  227. local function version_label() {
  228.     return    "Sage Professional Editor v" version    \
  229.         " - Copyright 1990, Sage Software, Inc."
  230. }
  231.  
  232.  
  233. ## prompt user for filename for edit_file() and read_file() operations
  234. #
  235. global function edit_file_key( display_menu ) {
  236.     local    fn
  237.  
  238.     # If optional argument "display_menu" is set to TRUE, we unget a
  239.     # tab key so that prompt_history brings up a menu of files in the
  240.     # current directory.  This enables file selection using a mouse.
  241.     #
  242.     if ( 0+display_menu ){
  243.         flush_keyboard()
  244.         ungetkey( KEYCODE_TAB )
  245.     }
  246.  
  247.     fn = prompt_history( "EDITFILE", "File: ", "" )
  248.  
  249.     if( fn ){
  250.         if( !edit_file( fn ))
  251.             message( "Cannot open file '%s'", fn )
  252.         else
  253.             display_filename()
  254.     }
  255. }
  256.  
  257. global function read_file_key() {
  258.     local    fn
  259.     local    result = FALSE
  260.  
  261.     fn = prompt_history( "EDITFILE", "File to read: ", "" )
  262.  
  263.     if ( fn ) {
  264.         result = read_file( fn )
  265.         if ( !result )
  266.             message( "Cannot read '%s'", fn )
  267.     }
  268.     return result
  269. }
  270.  
  271.  
  272. ## prompt the user for a command, and run it
  273. #
  274. global function system_key() {
  275.     local com, err
  276.  
  277.     com = ltrim( prompt_history( "SYSTEM", "System Command: ", "" ))
  278.  
  279.     if( com && ( err = system( com )))
  280.         warning( "Command exited with %d", err )
  281.     else
  282.         message( "" )
  283. }
  284.  
  285.  
  286. ## string manipulation utilities
  287. #
  288. global function strrepeat( s, n ) {                #PUBLIC #STR
  289.     local    t = ""
  290.  
  291.     while (n-- > 0) {
  292.         t = s t
  293.     }
  294.     return t
  295. }
  296.  
  297. global function compress( s, t ) {                #PUBLIC #STR
  298.     local    repl
  299.     if (s){
  300.         repl = length(t) ? substr(t,1,1) : " "
  301.         gsub( build_cc(t) "+", repl, s )
  302.     }
  303.     return s
  304. }
  305.  
  306. global function ltrim( s, t ) {                    #PUBLIC #STR
  307.     if (s){
  308.         sub( "^" build_cc(t) "*", "", s )
  309.     }
  310.     return s
  311. }
  312.  
  313. global function trim( s, t ) {                    #PUBLIC #STR
  314.     if (s){
  315.         sub( build_cc(t) "*$", "", s )
  316.     }
  317.     return s
  318. }
  319.  
  320. local function build_cc( t ){
  321. #
  322. # Build a regular expression "character class" containing the specified
  323. # list of characters.  If no characters are specified, return the character
  324. # class "[ \t]" (the default pattern used by trim, ltrim and compress)
  325. # which matches either the space or tab characters.
  326. #
  327.     if (t){
  328.         # quote the "\" and "]" characters; also quote "^" only
  329.         # if it is the first character in the list
  330.         gsub( /\\/, "\\\\", t )
  331.         gsub( /\]/, "\\]", t )
  332.         sub( /^\^/, "\\^", t )
  333.         return "[" t "]"
  334.     }
  335.     return "[ \t]"
  336. }
  337.  
  338. global function trans( s, tr, repl ) {                #PUBLIC #STR
  339.     local    len
  340.     local    i
  341.     local    result = ""
  342.     local    ch
  343.  
  344.     if (!tr) {
  345.         return ""
  346.     }
  347.  
  348.     if (!repl) {
  349.         repl = ""
  350.     }
  351.  
  352.     while (s != "") {
  353.         ch = substr( s,1,1 )
  354.         s = substr( s,2 )
  355.  
  356.         len = length( tr )
  357.         i = 1
  358.         while (len--) {
  359.             if (gsub( quote_regex(substr( tr, i, 1 )), substr( repl, i, 1 ), ch ))
  360.                 break
  361.             i++
  362.         }
  363.         result = result ch
  364.     }
  365.     return result
  366. }
  367.  
  368.  
  369. ## goto_line() -- move the cursor to column one of the specified line
  370. #
  371. global function goto_line( line ) {                #PUBLIC #INT
  372.     if ( !(0+line) )
  373.         line = 1
  374.     return goto_pos(0+line, 1)
  375. }
  376.  
  377.  
  378. ## push_keymap and pop_keymap
  379. #
  380. # push the specified keymap id onto the keymap stack. If no keymap
  381. # id is specified, push the current keymap
  382. #
  383. # pop of the top element on the keymap stack and make it the current
  384. # keymap
  385. #
  386. global    keymapStack
  387. global    keymapIndex
  388.  
  389. global function push_keymap( kid ) {                #PUBLIC #INT
  390.     local    oldkmp = current_keymap
  391.  
  392.     keymapStack[ keymapIndex++ ] = current_keymap
  393.  
  394.     if ( argcount() ) {    #  set to new keymap if one was specified
  395.         if (kid != current_keymap) {
  396.             current_keymap = kid
  397.             if (current_keymap == oldkmp) {
  398.                 keymapIndex--
  399.                 return FALSE        # didn't set it
  400.             }
  401.         }
  402.     }
  403.  
  404.     return TRUE
  405. }
  406.  
  407. global function pop_keymap() {                    #PUBLIC #INT
  408.     if( keymapIndex > 0 ) {
  409.         current_keymap = keymapStack[ --keymapIndex ]
  410.         return TRUE
  411.     }
  412.     return FALSE
  413. }
  414.  
  415.  
  416. ## invoke a filter and replace the marked region with the result
  417. #
  418. global function filter( command ) {                #PUBLIC #VOID
  419.  
  420.     local    save_buffer_name,
  421.         first_temp_file,
  422.         second_temp_file,
  423.         block_marked,
  424.         status
  425.  
  426.     first_temp_file  = create_temp_name()
  427.     second_temp_file = create_temp_name()
  428.  
  429.     block_marked = region_type()
  430.     save_position()
  431.  
  432.     #
  433.     # temporarily change the current buffer's file name and write
  434.     # the marked block out to the temp file.
  435.     #
  436.     if (!block_marked) {
  437.         goto_buffer_top()
  438.         drop_anchor( LINE_SELECTION )
  439.         goto_buffer_bottom()
  440.     } else if (block_marked == COLUMN_SELECTION) {
  441.         # position at tope of column block
  442.         if (current_line >= mark_line()) {
  443.             if (current_line > mark_line())
  444.                 swap_marks();
  445.             else if (current_column > mark_column())
  446.                 swap_marks();
  447.         }
  448.     }
  449.  
  450.     write_marked_block( first_temp_file )
  451.  
  452.     #
  453.     # filter first_temp_file through the "command" to generate
  454.     # second_temp_file and then read in the file.
  455.     #
  456.     if (system( command " <" first_temp_file " >&" second_temp_file) != -1) {
  457.         delete_chars()            # delete the selection
  458.  
  459.         if (block_marked == LINE_SELECTION)
  460.             goto_bol();
  461.         else if ( and(buffer_flags, BUFFER_IN_VIRTUAL_SPACE) )
  462.             prev_char();
  463.  
  464.         read_file( second_temp_file )
  465.         restore_position( status = FALSE )
  466.     } else {
  467.         if (!block_marked)
  468.             raise_anchor()
  469.         restore_position( status = TRUE )
  470.     }
  471.  
  472.     unlink( second_temp_file )
  473.     unlink( first_temp_file )
  474.     return status
  475. }
  476.  
  477.  
  478. #-------------- code to record and playback an edit session ---------------#
  479.  
  480. local    recordFileHandle
  481. local    playbackFileHandle
  482. local    recordKeys
  483. local    playbackKeys
  484. local    playbackMacroId
  485. local    recordMacroId
  486.  
  487. local function recordKeysInitialize( keyfname ) {
  488.  
  489.     recordFileHandle = fopen( keyfname, 1 )    # open file for write only
  490.  
  491.     if ( recordFileHandle >= 0 ) {
  492.         recordMacroId = function_id( "recordkeys" )
  493.         attach_event_handler( EVENT_KEYPRESS,  recordMacroId )
  494.         return TRUE
  495.     } else {
  496.         warning( "Can't open '%s.'", keyfname )
  497.         return FALSE
  498.     }
  499. }
  500.  
  501. local function playbackKeysInitialize( keyfname ) {
  502.  
  503.     playbackFileHandle = fopen( keyfname, 0 ) # open file for read only
  504.  
  505.     if ( playbackFileHandle >= 0 ) {
  506.         playbackMacroId = function_id( "playbackkeys" )
  507.         attach_event_handler( EVENT_IDLE_TIME, playbackMacroId )
  508.         return TRUE
  509.     } else {
  510.         warning( "Can't open '%s.'", keyfname )
  511.         return FALSE
  512.     }
  513. }
  514.  
  515. global function recordkeys() {
  516.     local ch1 = shiftr( and( current_key, 0x0FF00), 8)
  517.     local ch2 = and( current_key, 0x00FF )
  518.  
  519.     fputc( (ch1 == 0) ? 255 : ch1, recordFileHandle )
  520.     fputc( (ch1 == 0) ? 255 : ch2, recordFileHandle )
  521.  
  522.     if ( and( ch1, 0xF0 ) == 0xF0 ) {
  523.         fputc( mouse_event_x, recordFileHandle )
  524.         fputc( mouse_event_y, recordFileHandle )
  525.     }
  526.  
  527. }
  528.  
  529.  
  530. local    prevMouseButtons
  531.  
  532. global function get_mouse_buttons() {
  533.     local    buttons
  534.  
  535.     if (playbackKeys) {
  536.         buttons = and(shiftl(fgetc( playbackFileHandle ),8),0xFF00) + \
  537.             and(fgetc( playbackFileHandle ), 0x00FF)
  538.         mouse_display_x = fgetc( playbackFileHandle )
  539.         mouse_display_y = fgetc( playbackFileHandle )
  540.         if (buttons != prevMouseButtons) {
  541.             mouse_event_x = fgetc( playbackFileHandle )
  542.             mouse_event_y = fgetc( playbackFileHandle )
  543.         }
  544.     } else if (recordKeys) {
  545.         buttons = mouse_buttons
  546.         fputc(shiftr( and( buttons, 0x0FF00), 8), recordFileHandle )
  547.         fputc( and( buttons, 0x000FF), recordFileHandle )
  548.  
  549.         fputc( mouse_display_x, recordFileHandle )
  550.         fputc( mouse_display_y, recordFileHandle )
  551.         if (buttons != prevMouseButtons) {
  552.             fputc( mouse_event_x, recordFileHandle )
  553.             fputc( mouse_event_y, recordFileHandle )
  554.         }
  555.     } else {
  556.         buttons = mouse_buttons
  557.     }
  558.     prevMouseButtons = buttons
  559.     return buttons
  560.  
  561. }
  562.  
  563.  
  564.  
  565. local reload_count = 1        # 0 => free run
  566.  
  567. ## reload keys from a saved key file
  568. #
  569. #    this function allows the user to interrupt the playback and
  570. #    intervene manually with the restoration.
  571. #
  572. #    Recommendations:
  573. #    1. rename your original file to *.old
  574. #    2. rename your reckeys.__$ to *.rec
  575. #    3. save the file at useful points during the recovery.
  576. #    4. you may ESC out of a playback session, do some cleanup
  577. #       and then resume playback via <F10>reloadkeys<Enter>
  578. #    5. while single-stepping, be careful not to type too fast
  579. #       else some spaces will be processed as input.  This is most
  580. #       likely to happen on slow commands.  It's always safe to type
  581. #       when the prompt appears.
  582. #
  583. global function playbackkeys() {
  584.     local    key, ch, ch1, ch2
  585.  
  586.     # first obey playback controls:
  587.  
  588.     if( and( keyboard_flags, 0x7F )                \
  589.             ||( reload_count > 0 && reload_count-- == 1 )){
  590.         delete_event( EVENT_IDLE_TIME, playbackMacroId )
  591.  
  592.         for(;;){
  593.             message( "press ESC to stop playback; SPACE to single step; ENTER to resume.." )
  594.             ch = and( getkey(), 255 )
  595.  
  596.             if( ch == 13 || ch == 10 ){
  597.                 reload_count = 0
  598.                 break
  599.  
  600.             } else if( ch == 27 ){
  601.                 message( "" )
  602.                 delete_event( EVENT_IDLE_TIME, playbackMacroId )
  603.                 return
  604.  
  605.             } else if( ch == 32 ){
  606.                 reload_count = 1
  607.                 break
  608.  
  609.             } else if( 48 <= ch && ch <= 57 ){
  610.                 reload_count = prompt( "Enter playback count: ", chr( ch ))
  611.                 if( reload_count > 0 )
  612.                     break
  613.             } else if( key == 18432 ){
  614.                 up()
  615.             } else if( key == 20480 ){
  616.                 down()
  617.             } else if( key == 19200 ){
  618.                 left()
  619.             } else if( key == 19712 ){
  620.                 right()
  621.             } else
  622.                 beep()
  623.         }
  624.         attach_event_handler( EVENT_IDLE_TIME, playbackMacroId )
  625.         message( "" )
  626.     }
  627.  
  628.     # now playback the next character:
  629.  
  630.     ch1 = fgetc( playbackFileHandle )
  631.     ch2 = fgetc( playbackFileHandle )
  632.  
  633.     ch1 = (ch1==255) ? 0 : ch1
  634.     ch2 = (ch2==255) ? 0 : ch2
  635.  
  636.     if ((ch1 == -1) && (ch2 == -1)) {
  637.         delete_event( EVENT_IDLE_TIME, playbackMacroId )
  638.         return
  639.     } else if (and(ch1,0xF0) == 0xF0) {
  640.         mouse_event_x = mouse_display_x = fgetc( playbackFileHandle )
  641.         mouse_event_y = mouse_display_y = fgetc( playbackFileHandle )
  642.     }
  643.     ungetkey( or( shiftl( ch1,8 ), ch2 ))
  644. }
  645.  
  646. # -------------------------------------------------------------------------- #
  647.  
  648. ## attach_cleanup_handler()
  649. #
  650. # If the sageedit.ae file is changed while the editor is running (typically
  651. # by recompiling a .pel file), the error "Currently executing function has
  652. # been changed" may result.  In this case, an event is triggered upon 
  653. # return from the system command.  Here, we use that event to finish up
  654. # whatever function was running at the time.  The "cleanup_handler" function
  655. # must reside in a different file than that from which it was called to be
  656. # effective.  (See also the comments within the system_window_command()
  657. # function in system.pel).
  658.  
  659. local    function_to_call
  660.  
  661. global function attach_cleanup_handler( handler_name ) {
  662.     if (( function_to_call = function_id( handler_name ))) {
  663.         attach_event_handler( EVENT_FUNCTION_CHANGED,
  664.                 "cleanup_handler" )
  665.     }
  666. }
  667.  
  668. global function cleanup_handler() {
  669.     delete_event( EVENT_FUNCTION_CHANGED, "cleanup_handler" )
  670.     execute_function( function_to_call )
  671. }
  672.  
  673. # -------------------------------------------------------------------------- #
  674.  
  675. ## insert whole lines
  676. #
  677. global function paste_lines(){
  678.     goto_bol()
  679.     insert_scrap()
  680. }
  681.  
  682.  
  683. ## delete whole lines
  684. #
  685. global function cut_lines(){
  686.     if( region_type() != LINE_SELECTION )
  687.         drop_anchor( LINE_SELECTION )
  688.     delete_to_scrap()
  689. }
  690.  
  691. ## toggle insert mode
  692. #
  693. global function toggle_insert_mode( on ) {
  694.  
  695.     if( argcount() < 1 )
  696.         on = and( buffer_flags, BUFFER_OVERTYPE_MODE )
  697.     else
  698.         on = 0+on
  699.  
  700.     if ( on ) {
  701.         buffer_flags = and(buffer_flags, not(BUFFER_OVERTYPE_MODE ))
  702.         message( "Insert Mode" )
  703.     } else {
  704.         buffer_flags = or(buffer_flags, BUFFER_OVERTYPE_MODE )
  705.         message( "Overtype Mode" )
  706.     }
  707. }
  708.  
  709.  
  710. ## toggle tabs to spaces
  711. #
  712. global function toggle_tabs_to_spaces( on ){
  713.  
  714.     if( argcount() < 1 )
  715.         on = !and( buffer_flags, BUFFER_TABS_TO_SPACES )
  716.     else
  717.         on = 0+on
  718.  
  719.     set_buffer_flag( BUFFER_TABS_TO_SPACES, on )
  720.     message( "Tabs to spaces " ( on ? "enabled." : "disabled." ))
  721. }
  722.  
  723.  
  724. ## toggle pause on error flag
  725. #
  726. global function toggle_pause( on ){                #PUBLIC #VOID
  727.     if (argcount())
  728.         pe( on )
  729.     else
  730.         pe()
  731. }
  732.  
  733. global function pe( on ){                    #PUBLIC #VOID
  734.  
  735.     if( argcount() < 1 )
  736.         pause_on_error = !pause_on_error
  737.     else
  738.         pause_on_error = !!(0+on) != 0
  739.  
  740.     if( pause_on_error )
  741.         message( "pause_on_error Enabled" )
  742.     else
  743.         message( "pause_on_error Disabled" )
  744. }
  745.  
  746.  
  747. ## arrays containing the names of the sageedit system files
  748. #
  749. global    sageedit_filename
  750. local    existing_sageedit_file
  751. local    primary_sageedit_dir
  752.  
  753. ## return the name of an existing file using the SAGEEDIT path
  754. #
  755. # valid argument values are:
  756. #    SAGEEDIT_FILE_CONFIG    # sageedit.cfg
  757. #    SAGEEDIT_FILE_AE    # sageedit.ae
  758. #    SAGEEDIT_FILE_HELP    # help.txt
  759. #    SAGEEDIT_FILE_BINDINGS    # bindings.txt
  760. #    SAGEEDIT_FILE_REFMAN    # refman.txt
  761. #
  762. global function locate_sageedit_file( sageedit_id ) {
  763.     local    fn
  764.     local    element
  765.     local    path
  766.     local    result
  767.  
  768.     # initialize filename array if necessary
  769.     if ( !sageedit_filename ) {
  770.         sageedit_filename[SAGEEDIT_FILE_CONFIG]        = "sageedit.cfg"
  771.         sageedit_filename[SAGEEDIT_FILE_AE]        = "sageedit.ae"
  772.         sageedit_filename[SAGEEDIT_FILE_HELP]        = "help\\help.txt"
  773.         sageedit_filename[SAGEEDIT_FILE_BINDINGS]    = "help\\bindings.txt"
  774.         sageedit_filename[SAGEEDIT_FILE_REFMAN]        = "help\\refman.txt"
  775.     }
  776.  
  777.     # has the file already been located?
  778.     if ( sageedit_id in existing_sageedit_file ) {
  779.         return existing_sageedit_file[sageedit_id]
  780.     }
  781.  
  782.     if ( sageedit_id in sageedit_filename ) {
  783.  
  784.         fn = sageedit_filename[sageedit_id]
  785.         do {
  786.             # look first in the current directory
  787.             if ( filemode( fn ) >= 0 ) {
  788.                 existing_sageedit_file[sageedit_id]    \
  789.                         = fn            \
  790.                         = buildpath( fn )
  791.                 return fn
  792.             }
  793.  
  794.             # search the sageedit path
  795.             path = ENV[ "SAGEEDIT" ]
  796.             while ( path ) {
  797.  
  798.                 # extract a directory from the semicolon separated list
  799.                 if ( match( path, /;/ )) {
  800.                     element = trim( substr( path, 1, RSTART-1 ))
  801.                     path = ltrim( substr( path, RSTART+1 ))
  802.                 } else {
  803.                     element = path
  804.                     path = 0
  805.                 }
  806.  
  807.                 # treat path elements consisting only of a
  808.                 # drive letter as the cwd on that drive
  809.                 if ( match( element, /:$/ )) {
  810.                     element = element "."
  811.                 }
  812.  
  813.                 # assemble filename (multiple backslashes are ok)
  814.                 result = buildpath( element "\\" fn )
  815.  
  816.                 # check existence
  817.                 if ( filemode( result ) >= 0 ) {
  818.                     existing_sageedit_file[sageedit_id] \
  819.                             = result
  820.                     return result
  821.                 }
  822.             }
  823.  
  824.             # try ARGV[0]
  825.             if ( match( ARGV[0], /.*\\/ )) {
  826.                 result = buildpath( \
  827.                     substr( ARGV[0], RSTART, RLENGTH ) fn )
  828.                 if ( filemode( result ) >= 0 ) {
  829.                     existing_sageedit_file[sageedit_id] \
  830.                             = result
  831.                     return result
  832.                 }
  833.             }
  834.  
  835.             # if all of that failed, try again after removing
  836.             # the "help\" part of the name, before giving up
  837.             if ( substr(fn,1,5) != "help\\" )
  838.                 break
  839.             fn = substr( fn, 6 )
  840.         } while ( fn )
  841.     }
  842.     # return null
  843. }
  844.  
  845. ## return the first directory given in the SAGEEDIT path
  846. #
  847. global function editor_path( sageedit_id ) {
  848.     # sageedit_id is an optional argument containing the id of
  849.     # one of the editor support files (e.g. SAGEEDIT_FILE_CONFIG).
  850.     # If specified, the name of the file will be appended
  851.  
  852.     local    path
  853.     local    fmode
  854.  
  855.     if ( primary_sageedit_dir ) {
  856.         # sageedit path has already been processed
  857.         path = primary_sageedit_dir
  858.  
  859.     } else if (( path = ENV[ "SAGEEDIT" ] )) {
  860.  
  861.         # handle a semicolon separated list of directories
  862.         if ( match( path, /;/ )) {
  863.             path = substr( path, 1, RSTART-1 )
  864.         }
  865.  
  866.         # treat path elements consisting only of a
  867.         # drive letter as the cwd on that drive
  868.         if ( match( path, /:$/ )) {
  869.             path = path "."
  870.         }
  871.  
  872.         path = buildpath( path "\\" )
  873.  
  874.         # handle root as a special case since filemode of
  875.         # root is unreliable on certain networks
  876.         if ( path !~ /:[\\/]$/ ) {
  877.  
  878.             # if the directory doesn't exist, use the cwd
  879.             fmode = substr( path, length( path )) == "\\"    \
  880.                     ? filemode( substr( path,    \
  881.                         1,            \
  882.                         length( path )-1 ))    \
  883.                     : -1
  884.             if ( (fmode <= 0) || !and( fmode, _SUBDIR )) {
  885.                 path = buildpath( "." )
  886.             }
  887.         }
  888.         primary_sageedit_dir = path
  889.     }
  890.  
  891.     # if an optional file argument was specified, append the name of the
  892.     # appropriate file
  893.     if ( sageedit_id in sageedit_filename ) {
  894.         return path sageedit_filename[sageedit_id]
  895.     }
  896.  
  897.     return path
  898. }
  899.  
  900. ## path_path
  901. #
  902. # return the drive:path of a filespec, trailing slash/backslash
  903. # is included.
  904. #
  905. global function path_path(fspec) {
  906.     local len;
  907.  
  908.      if ((len = length(fspec)) == 0)
  909.         return "";
  910.  
  911.     len -= length(path_ext(fspec));
  912.     len -= length(path_fname(fspec));
  913.  
  914.     return substr(fspec, 1, len);
  915. }
  916.  
  917.  
  918. ## bld_fnam
  919. #
  920. # build a filename out of its components
  921. #
  922. global function bld_fnam(path, name, suffix) {
  923.     local name1, name2, name3, name4;
  924.  
  925.     name1 = path_path(path);
  926.     name2 = path_fname(name);
  927.     name3 = path_ext(suffix);
  928.     if (length(name3) == 0)
  929.         name3 = "." suffix;
  930.  
  931.     name4 = name1 name2 name3
  932.     return name4
  933.  
  934. }
  935.  
  936.  
  937. ## quit from editor
  938. #
  939. global function done(){
  940.     local    buf
  941.     local    priorMessageLevel
  942.     local    i = buffers_modified
  943.  
  944.     if ( i ) {
  945.         buf = sprintf( "%d %s been modified, Exit[ynw]? ", \
  946.             i, i > 1 ? "buffers have" : "buffer has")
  947.         begin_dialog()
  948.         i = tolower( confirm(buf, "yYnNwW") )
  949.         if (i == "w") {
  950.             priorMessageLevel = message_level
  951.             message_level = 0
  952.             if ( !write_all_buffers() ) {
  953.                 message_level = priorMessageLevel
  954.                 end_dialog()
  955.                 return
  956.             }
  957.         } else if (i != "y") {
  958.             end_dialog()
  959.             return
  960.         }
  961.     }
  962.     quit( 0, 0 )
  963. }
  964.  
  965.  
  966.  
  967.  
  968. ## write all buffers and exit
  969. #
  970. global function write_and_exit(){
  971.     if (write_all_buffers()) {
  972.         quit(0,0)
  973.     }
  974. }
  975.  
  976. ## set_flag_bits() - set the value of one or more bits in a flag
  977. #
  978. #
  979. # arguments:
  980. #
  981. #    srcFlag - the value of the input flag
  982. #
  983. #    mask    - which bits in the input flag are to be changed
  984. #
  985. #    newBits - what the new flag should be (only those bits specified
  986. #        in the mask will be affected)
  987. #
  988. # function result: new flag
  989. #
  990. #
  991. # example:
  992. #    window_flags = set_flag_bits( window_flags, WINDOW_CHARS, WINDOW_HEX )
  993. #
  994. global function set_flag_bits( srcFlag, mask, newBits ) {    #PUBLIC #INT
  995.     return or(                \
  996.         and( srcFlag, not(mask) ),    \
  997.         and( newBits, mask) )
  998. }
  999.  
  1000.  
  1001. ## toggle_file_backup()
  1002. #
  1003. global function toggle_file_backup( on ){
  1004.  
  1005.     if ( argcount() < 1 )        # no argument specified
  1006.         backup_files_enabled = !backup_files_enabled;
  1007.     else
  1008.         backup_files_enabled = 0+on   # use the argument specified
  1009.  
  1010.     message( backup_files_enabled           \
  1011.         ? "Backup files will be created."    \
  1012.         : "Backup files will not be created.")
  1013. }
  1014.  
  1015.  
  1016. ### push_dir()
  1017. # Push the name of the current working directory on a stack and change to
  1018. # the specified directory.
  1019. #
  1020. ### pop_dir()
  1021. # Change back to a previously pushed directory and pop the element off the
  1022. # stack.  Returns TRUE if successful, FALSE if there is no directory element
  1023. # on the stack.
  1024. #
  1025.  
  1026. local    cwd_stack
  1027. local    cwd_stack_size
  1028.  
  1029. global function push_dir( new_dir ) {
  1030.     cwd_stack[ ++cwd_stack_size ] = getcwd()
  1031.     if ( new_dir ) {
  1032.         chdir( new_dir )
  1033.     }
  1034. }
  1035.  
  1036. global function pop_dir() {
  1037.     if ( cwd_stack_size in cwd_stack ) {
  1038.         chdir( cwd_stack[ cwd_stack_size ] )
  1039.         delete cwd_stack[ cwd_stack_size-- ]
  1040.         return TRUE
  1041.     } else {
  1042.         return FALSE
  1043.     }
  1044. }
  1045.  
  1046. ## support for functions in optional .PEL files
  1047. #
  1048. function optional_function( fn_name ){
  1049.     local    fid
  1050.     local    filename
  1051.     if (( fid = function_id( fn_name ))){
  1052.         execute_function( fid );
  1053.     } else {
  1054.         if ( fn_name == "local_setup" ) {
  1055.             return        # no warning if not present
  1056.         } else if ( fn_name == "read_config_file" ) {
  1057.             return        # no warning if not present
  1058.         } else if ( fn_name == "native" ) {
  1059.             filename = "NATIVE.PEL"
  1060.         } else if ( fn_name == "display_ascii_table" ) {
  1061.             filename = "ASCII.PEL"
  1062.         } else if ( fn_name == "routines" ) {
  1063.             filename = "ROUTINES.PEL"
  1064.         } else {
  1065.             filename = ".PEL file"
  1066.         }
  1067.         warning( "function \"%s\": %s is not in current function library",
  1068.                 fn_name, filename )
  1069.     }
  1070. }
  1071.  
  1072.  
  1073.  
  1074.  
  1075.  
  1076.  
  1077. ## create_semaphore_fname()
  1078. #
  1079. #  Create a new extension for the file name specified.  The extension needs
  1080. #  to be unique or else conflicts may occur and files will be reported as 
  1081. #  locked when they actually aren't.
  1082. #
  1083. #  All extensions will appear in the form xxx.__! or xxx.x_! or xxx.xx!
  1084. #
  1085. global function create_semaphore_fname( fname, lastchar ){
  1086.     local bname;
  1087.     local ext;
  1088.     local ppath;
  1089.     local count;
  1090.  
  1091.     fname = buildpath( fname );
  1092.     bname = path_fname( fname );
  1093.     ext   = path_ext( fname );
  1094.     ppath = substr( fname, 1, length( fname ) - length( bname ) - length( ext ));
  1095.     if (ext == "")
  1096.         ext = ".";
  1097.  
  1098.     ext = substr(substr( ext "___", 1, 3) lastchar, 1, 4);
  1099.  
  1100.     return ppath bname ext;
  1101. }
  1102.  
  1103.  
  1104.