HISTORY.A86
上传用户:xiaogehua
上传日期:2007-01-08
资源大小:1183k
文件大小:15k
源码类别:

操作系统开发

开发平台:

Asm

  1. ;    File              : $HISTORY.A86$
  2. ;
  3. ;    Description       :
  4. ;
  5. ;    Original Author   : DIGITAL RESEARCH
  6. ;
  7. ;    Last Edited By    : $CALDERA$
  8. ;
  9. ;-----------------------------------------------------------------------;
  10. ;    Copyright Work of Caldera, Inc. All Rights Reserved.
  11. ;      
  12. ;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
  13. ;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
  14. ;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
  15. ;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
  16. ;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
  17. ;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
  18. ;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
  19. ;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
  20. ;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
  21. ;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
  22. ;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
  23. ;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
  24. ;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
  25. ;    CIVIL LIABILITY.
  26. ;-----------------------------------------------------------------------;
  27. ;
  28. ;    *** Current Edit History ***
  29. ;    *** End of Current Edit History ***
  30. ;
  31. ;    $Log$
  32. ;    ENDLOG
  33. ;
  34. ;  DOSPLUS Command Line Editor Routines
  35. ;
  36. include pcmode.equ
  37. include i:msdos.equ
  38. include i:char.def
  39. include i:cmdline.equ
  40. PCM_HISTORY CSEG
  41. public init_history, save_history
  42. public del_history_buffers, del_cur_history_buffer
  43. public prev_cmd, next_cmd, match_cmd, search_cmd
  44. public prev_word, next_word, match_word
  45. public goto_eol
  46. public del_bol
  47. public deln_word
  48. extrn next_char:near
  49. extrn save_line:near
  50. extrn space_out:near
  51. extrn bs_out:near
  52. extrn goto_bol:near
  53. extrn del_eol:near
  54. extrn del_line:near
  55. extrn char_info:near
  56. extrn put_string:near
  57. extrn prev_w20:near
  58. extrn deln_w10:near
  59. init_history:
  60. ;------------
  61. ; On Entry:
  62. ; SS:BP -> history structure
  63. ; On Exit:
  64. ; SS:SP filled in with appropriate history buffer
  65. ; Preserve DX
  66. ;
  67. push ds
  68. push es
  69. push ss
  70. pop es
  71. lea di,RL_HIST_SEG ; point at history buffer variables
  72. mov si,offset histbuf1 ; assume root buffer
  73. test RL_FLAGS,RLF_INROOT ; root task after all?
  74.  jnz init_history10 ; if not we need to switch
  75. mov si,offset histbuf2 ;  application buffer
  76. init_history10:
  77. movsw ; copy the seg
  78. lodsw ; get overall length
  79. sub ax,2*WORD ; last two words contain pointers
  80. stosw ; save the working length
  81. xchg ax,si ; SI -> saved buffer positions
  82. mov ds,RL_HIST_SEG ;  in the buffer segment
  83. movsw ; update save and
  84. movsw ;  recall positions
  85. pop es
  86. pop ds
  87. ret
  88. save_history:
  89. ;------------
  90. ; We are exiting from READLINE - if line has been modified save the
  91. ; current line and update our pointers.
  92. ;
  93. test dx,dx ; skip update of sav/recall pointers
  94.  jz save_history30 ;  if empty line
  95. call save_current ; save away current command line
  96. mov di,RL_HIST_SAVE ; start with the old one
  97. call find_current_hist ; wrap it if we need to
  98. call find_next_null ; find end of "new" command
  99. inc di ; onto next character
  100. cmp di,RL_HIST_SIZE ; do we need to wrap ?
  101.  jb save_history10
  102. xor di,di ; wrap the line
  103. save_history10:
  104. mov RL_HIST_SAVE,di ; update "save" pointer
  105. test RL_FLAGS,RLF_DIRTY ; if a line has been changed we'd
  106.  jz save_history30 ;  better update "recall" pointer
  107. mov RL_HIST_RECL,di ;  too
  108. save_history30:
  109. push ds
  110. push es
  111. push ss ! pop ds
  112. lea si,RL_HIST_SAVE ; point at history buffer variables
  113. mov es,RL_HIST_SEG
  114. mov di,RL_HIST_SIZE
  115. movsw ; save the "save" pointer
  116. movsw ;  and the "recall" one
  117. pop es
  118. pop ds
  119. ret
  120. save_current_if_dirty:
  121. ;---------------------
  122. test RL_FLAGS,RLF_DIRTY ; if data is dirty (ie. user modified)
  123.  jz save_current20 ;  then save it
  124. save_current:
  125. ;------------
  126. ; Copy current buffer contents to next free location in history buffer
  127. ;
  128. push si
  129. push di
  130. push dx
  131. cmp dx,RL_HIST_SIZE ; is history buffer big enough ?
  132.  jae save_current10 ;  no, skip saving this line
  133. call find_free_hist ; Find the next bit of space
  134. pop cx ! push cx ; CX = chars to save
  135.  jcxz save_current10 ; none, forget about it
  136. push ds
  137. push es
  138. lds si,RL_BUFPTR
  139. mov es,RL_HIST_SEG
  140. rep movsb ; and save the data.  
  141. xor ax,ax ; Null terminate it.
  142. stosb
  143. pop es
  144. pop ds
  145. push di
  146. call find_next_null ; Find the end of the entry we just
  147. mov cx,di ;  overwrote - if any remains zap it
  148. pop di
  149. cld
  150. xor ax,ax ; Null terminate this entry
  151. sub cx,di ; Figure out number of zeros to write
  152.  jbe save_current10
  153. push es
  154. mov es,RL_HIST_SEG
  155. rep stosb ; and pad to the next entry
  156. pop es
  157. save_current10:
  158. pop dx
  159. pop di
  160. pop si
  161. save_current20:
  162. ret
  163. ;
  164. ; Here is the code to deal with history buffers
  165. ;
  166. ; match_cmd Does a string search based on what the user has typed so far
  167. ; search_cmd Matches string, but doesn't change match state
  168. ; prev_cmd Retrieves the previous command from the history buffer
  169. ; next_cmd       "     "  next       "      "     "    "      "
  170. ;
  171. match_cmd:
  172. mov al,@hist_flg ; is matching enabled ?
  173. and ax,RLF_MATCH
  174.  jz search_cmd ; no, always match
  175. xor RL_FLAGS,ax ; toggle match bit
  176. test RL_FLAGS,ax ; turning matching off ?
  177.  jz match30 ;  then just exit
  178. search_cmd:
  179. mov RL_SAVPOS,si ; any chars to save ?
  180. test si,si
  181.  jz prev_cmd ; blank line - just get previous
  182. call save_current_if_dirty ; save current line if it needs saving
  183. push si ; save current offset in line
  184. push di
  185. push dx ; Save index to end of current line
  186. mov dx,si ; discard rest of line if no match
  187. mov di,RL_HIST_RECL ; Point to the current entry
  188. match_loop:
  189. call find_prev_hist ; DI-> previous cmd in buffer
  190. push di ; save this command position
  191. mov di,RL_HIST_RECL ; get starting position
  192. call find_current_hist ;  handle any wrapping
  193. pop si ; recover previous command
  194. cmp di,si ; have we been all round ?
  195.  je match_error ; YES - We've looped so no match found
  196. push ds
  197. push si ; save this entry
  198. mov ds,RL_HIST_SEG
  199. mov di,RL_BUFOFF ; ES:DI -> match string
  200. mov cx,RL_SAVPOS ; try to match CX characters
  201. repe cmpsb
  202. pop di ; recover this entry
  203. pop ds
  204.  jne match_loop ; try again if we didn't match
  205. call copy_from_hist ; if it did match copy it
  206. match_error:
  207. pop cx ; Get end of displayed line
  208. pop di ; user's buffer
  209. pop si
  210. push si ; save current position in lines
  211. call space_out ; Rub the displayed line out
  212. call bs_out ; And backspace to it's start
  213. call goto_eol ; display the line
  214. call goto_bol ; Move cursor to begining
  215. pop cx ; CX = end of matched portion
  216. mov RL_SAVPOS,cx ; CX = Current position in command
  217.  jcxz match20
  218. match10: ; Move cursor forward to current
  219. push cx ;  position
  220. call next_char ; next_char destroys our loop count
  221. pop cx ;  so keep it
  222. loop match10
  223. match20:
  224. mov cx,RL_SAVMAX ; we can't copy any more
  225. mov RL_SAVPOS,cx
  226. match30:
  227. ret
  228. prev_cmd:
  229. ; Get the previous command from the buffer
  230. test RL_FLAGS,RLF_RECALLED ; is this the 1st recall ?
  231.  jnz prev_cmd10
  232. push cx
  233. push di
  234. mov di,RL_HIST_SAVE ; get existing "save" ptr
  235. call find_current_hist ; wrap it if we need to
  236. mov RL_HIST_RECL,di ;  and update "recall" pointer
  237. pop di
  238. pop cx
  239. prev_cmd10:
  240. call save_current_if_dirty ; save current line if it needs saving
  241. call del_line ;  then delete it
  242. push si
  243. push di
  244. mov di,RL_HIST_RECL ; point to the current entry
  245. call find_prev_hist ; DI -> previous entry
  246. jmps found_cmd ; now go and copy it to the user buffer
  247. next_cmd:
  248. ; Get the next command from the buffer
  249. call save_current_if_dirty ; save current line if it needs saving
  250. call del_line ;  then delete it
  251. push si
  252. push di
  253. mov di,RL_HIST_RECL ; point to the current entry
  254. call find_next_hist ; DI -> next entry
  255. ; jmps found_cmd ; now go and copy it to the user buffer
  256. found_cmd:
  257. call copy_from_hist ; Copy from history to user buffer
  258. pop di
  259. pop si
  260. ; jmp goto_eol ; Display new line.
  261. goto_eol: ; Move the cursor to the end of the
  262. mov cx,dx ! sub cx,si ; displayed line
  263.  jcxz goto_e10 ; Already at the EOL
  264. add si,RL_BUFOFF ; Get the Offset in the buffer
  265. call put_string ; Output the sub_string
  266. add di,cx ; Update the local variables
  267. mov si,dx ; and return
  268. goto_e10:
  269. ret
  270. ; DI-> Current entry in history buffer
  271. ;
  272. copy_from_hist:
  273. or RL_FLAGS,RLF_RECALLED ; remember we have recalled something
  274. and RL_FLAGS,not RLF_DIRTY ; this entry is already in buffers
  275. mov RL_HIST_RECL,di ; update pointer for next time
  276. call find_next_null ; how big is this entry ?
  277. mov cx,di
  278. mov si,RL_HIST_RECL
  279. sub cx,si ; (CX-SI)=No of bytes to copy
  280. cmp cx,RL_MAXLEN ; is the line bigger than our buffer ?
  281.  jb copy_from_hist1 ; if so we want to clip it
  282. mov cx,RL_MAXLEN ; to the maximum possible value
  283. copy_from_hist1:
  284. mov dx,cx
  285. push ds
  286. mov ds,RL_HIST_SEG
  287. mov di,RL_BUFOFF
  288. rep movsb ; copy to line buffer
  289. pop ds
  290. call save_line ; save the line
  291. mov cx,RL_SAVMAX ; we can't copy any more
  292. mov RL_SAVPOS,cx
  293. ret
  294. ; Some primitives for history buffer handling:
  295. ;
  296. ; find_free_hist Find the next free entry in the history buffer
  297. ; find_next_null Finds the end of the current entry
  298. ; find_prev_hist Finds the start of the previous entry
  299. ; find_next_hist Finds the start of the next entry
  300. ; find_current_hist Finds the start of current entry
  301. ;
  302. ; Make DI-> next entry of sufficient length for the current cmd buffer
  303. ; If we can't fit at the end zero the remainder of the buffer then wrap
  304. ; back to the start.
  305. ;
  306. find_free_hist:
  307. mov di,RL_HIST_SAVE ; Point at current last entry
  308. push di ; Will DX bytes fit?
  309. add di,dx
  310. cmp di,RL_HIST_SIZE ; Did we run out of buffer?
  311. pop di
  312.  jb find_free_hist20
  313. xor ax,ax ; doesn't fit, so zero to end of buffer
  314. find_free_hist10:
  315. push es
  316. mov es,RL_HIST_SEG
  317. stosb ; keep on zeroing
  318. pop es
  319. cmp di,RL_HIST_SIZE
  320.  jb find_free_hist10
  321. xor di,di ; wrap back to start of history buffer
  322. find_free_hist20:
  323. ret
  324. ; Entry DI-> entry in the history buffer
  325. ; Make DI-> next NULL in the history buffer ( end of current entry )
  326. ;
  327. find_next_null:
  328. mov cx,RL_HIST_SIZE
  329. sub cx,di ; Calc no of bytes left
  330. xor ax,ax ; Look for next terminator
  331. push es
  332. mov es,RL_HIST_SEG
  333. repnz scasb
  334. dec di ; point at the NUL
  335. pop es
  336. ret
  337. ; Entry DI-> entry in the history buffer
  338. ; Make DI-> previous entry in the history buffer
  339. ; Preserve CX
  340. find_prev_hist:
  341. call find_current_hist ; handle any wrapping
  342. mov ax,di ; AX = entry we want previous for
  343. find_prev_hist10:
  344. push ax ; save current offset
  345. push di ; save initial offset
  346. xchg ax,di ; find next from here until
  347. call find_next_hist ;  we get back where we started
  348. xchg ax,di ; AX = current offset
  349. pop di ; recover initial value
  350. pop bx ; recover previous offset
  351. cmp ax,di ; have we wrapped yet ?
  352.  je find_prev_hist20 ; yes, BX = previous entry
  353.  ja find_prev_hist10 ; we are above target so continue
  354. cmp bx,di ; we are below target - if previous
  355.  jae find_prev_hist10 ;  was above target we are OK
  356. cmp ax,bx ; if new below previous then we
  357.  jnb find_prev_hist10 ;  have ERROR wrap, so stop
  358. find_prev_hist20:
  359. mov di,bx ; DI -> Previous entry
  360. ret
  361. find_next_hist:
  362. call find_current_hist ; handle any wrapping
  363. call find_next_null ; point to end of current entry
  364. ; jmp find_current_hist ; handle any wrapping
  365. find_current_hist:
  366. ; This routine is complicated by the need to handle switchers, where
  367. ;  our buffers and pointers may get out of step
  368. push es
  369. xor ax,ax
  370. mov es,RL_HIST_SEG ; now work backwards to start of line
  371. find_current_hist10:
  372. cmp di,1 ; are we at the start of the buffer
  373.  jb find_current_hist30 ;  then don't wrap
  374. std
  375. scasb ; is previous char a NUL ?
  376. cld ;  (it should be!)
  377.  jne find_current_hist10
  378. inc di ; ES:DI -> 1st char of line
  379. find_current_hist20:
  380. mov cx,RL_HIST_SIZE
  381. sub cx,di ; CX= Remaining no: of bytes in buffer
  382.  jbe find_current_hist30
  383. repe scasb ; skip over zero's
  384.  jne find_current_hist40
  385. find_current_hist30:
  386. mov di,1 ; wrap to start of buffer
  387. find_current_hist40:
  388. dec di
  389. pop es
  390. ret
  391. del_history_buffers:
  392. ;-------------------
  393. ; Delete contents of both history buffers
  394. ;
  395. mov ax,histbuf1 ; Segment of 1st history buffer
  396. mov cx,histsiz1 ; End of 1st history buffer
  397. call zap_buffer
  398. mov ax,histbuf2 ; Segment of 2nd history buffer
  399. mov cx,histsiz2 ; End of 2nd history buffer
  400. jmps zap_buffer
  401. del_cur_history_buffer:
  402. ;----------------------
  403. ; Delete contents of the current history buffer
  404. ;
  405. mov ax,RL_HIST_SEG ; zero the current buffer
  406. mov cx,RL_HIST_SIZE
  407. zap_buffer:
  408. push es ; zero fill CX bytes at AX:0
  409. push di
  410. mov es,ax
  411. xor ax,ax
  412. mov RL_HIST_RECL,ax
  413. mov RL_HIST_SAVE,ax
  414. xor di,di
  415. rep stosb ; zero fill the buffer
  416. pop di
  417. pop es
  418. call del_line ; then delete current line
  419. jmp save_line
  420. next_word:
  421. mov cx,dx ; Calculate the number of bytes
  422. sub cx,si ; left to scan
  423. jcxz next_w10 ; Skip if at the EOL
  424. push si ; Save the current Index
  425. mov si,di ; Scan from the current location
  426. call match_word ; Get the next word boundary
  427. mov cx,si
  428. sub cx,di ; Calculate the string length
  429. mov si,di ; to be displayed from the current
  430. call put_string ; location and output the data
  431. pop si
  432. add si,cx ; Update the Index and Offset pointers
  433. add di,cx
  434. next_w10:
  435. ret
  436. ;
  437. ; MATCH_WORD scans the buffer at ES:SI for word boundaries
  438. ; and returns to the calling routine whenever it detects such
  439. ; a boundary.
  440. ;
  441. ; On Entry: ES:SI Buffer Address
  442. ; CX Maximum No of bytes to Scan
  443. ;
  444. ; On Exit: ES:SI Next Word Boundary
  445. ;
  446. match_word:
  447. call char_info
  448. test ah,CHAR_ALPHAN or CHAR_KANJI
  449. loopnz match_word ; scan the rest of the current word
  450.  jcxz match_w30 ; end of word or kanji ?
  451. push dx
  452. match_w10:
  453. mov dx,si
  454. call char_info
  455. test ah,CHAR_ALPHAN or CHAR_KANJI
  456. loopz match_w10
  457.  jz match_w20
  458. sub si,dx ; Correct the count in CX
  459. add cx,si ; and return the location of the
  460. mov si,dx ; word boundary
  461. match_w20:
  462. pop dx
  463. match_w30:
  464. ret
  465. prev_word:
  466. mov cx,si ! jcxz match_w30 ; Initialize the count
  467. push dx ! push si ! push di
  468. mov si,RL_BUFOFF ; Scan from the begining of the buffer
  469. mov dx,si ; keeping the last match in DX
  470. prev_w10:
  471. call match_word ; Find the next word boundary
  472. jcxz prev_w15 ; Stop when we get to the current offset
  473. mov dx,si ; Save current location
  474. jmps prev_w10 ; and repeat
  475. prev_w15:
  476. jmp prev_w20
  477. del_bol: ; Delete to the begining of the line
  478. or si,si ! jz del_bol10 ; Ignore if at the begining
  479. or dx,dx ! jz del_bol10 ; Or the line is empty
  480. push di ; Save the current index
  481. call goto_bol ; Move to the start of the line
  482. pop cx ; Restore the current offset
  483. jmp deln_w10 ; and jump to common code
  484. del_bol10:
  485. ret
  486. deln_word:
  487. mov cx,dx ; Calculate the number of bytes
  488. sub cx,si ; left to scan
  489. jcxz del_bol10 ; Skip if at the EOL
  490. push si ; Save the current Index
  491. mov si,di ; Scan from the current location
  492. call match_word ; Get the next word boundary
  493. mov cx,si
  494. pop si
  495. jmp deln_w10
  496. PCMODE_DATA DSEG WORD
  497. extrn @hist_flg:byte ; To select between histbufs 1 or 2
  498. GLOBAL_DATA dseg word
  499. extrn histbuf1:word, histsiz1:word, histbuf2:word, histsiz2:word
  500. end