home *** CD-ROM | disk | FTP | other *** search
Text File | 1993-04-23 | 41.3 KB | 1,478 lines |
- Newsgroups: comp.sources.misc
- From: mool@oce.nl (Bram Moolenaar)
- Subject: v37i011: vim - Vi IMitation editor v1.27, Part11/24
- Message-ID: <1993Apr25.013353.22206@sparky.imd.sterling.com>
- X-Md4-Signature: 7dd7d0eb0e36ace8b947b5eeca1077f9
- Date: Sun, 25 Apr 1993 01:33:53 GMT
- Approved: kent@sparky.imd.sterling.com
-
- Submitted-by: mool@oce.nl (Bram Moolenaar)
- Posting-number: Volume 37, Issue 11
- Archive-name: vim/part11
- Environment: UNIX, AMIGA, MS-DOS
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then unpack
- # it by saving it into a file and typing "sh file". To overwrite existing
- # files, type "sh file -c". You can also feed this as standard input via
- # unshar, or by typing "sh <file", e.g.. If this archive is complete, you
- # will see the following message at the end:
- # "End of archive 11 (of 23)."
- # Contents: vim/doc/index vim/src/storage.c
- # Wrapped by mool@oce-rd2 on Mon Apr 19 15:50:10 1993
- PATH=/bin:/usr/bin:/usr/ucb ; export PATH
- if test -f 'vim/doc/index' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/doc/index'\"
- else
- echo shar: Extracting \"'vim/doc/index'\" \(18631 characters\)
- sed "s/^X//" >'vim/doc/index' <<'END_OF_FILE'
- Xindex of vim commands for
- X 1. insert mode
- X 2. VI commands (normal mode)
- X 3. command line editing
- X 4. EX commands
- X
- X(for an overview of options see the end of reference.doc)
- X
- X1. INSERT MODE
- X==============
- X
- Xchar action
- X-----------------------------------------------------------------------
- X^@ insert previously inserted text and stop insert {vi: up to 128
- X chars}
- X^A insert previously inserted text {vi: no ^A}
- X^B <0-9a-z> insert contents of register <0-9a-z> {not in vi}
- X^D delete one shiftwidth of indent in the current line {vi:
- X only after auto-indent}
- X^E insert the character which is below the cursor
- X^H <BS> delete character before the cursor {vi: does not cross lines,
- X does not delete autoindents}
- X^J <LF> begin new line
- X^K {char1} {char2} enter digraph (only when compiled with it) {vi: no digraphs}
- X^O execute a single command and return to insert mode
- X^M <CR> begin new line
- X^R insert the character which is above the cursor
- X^T insert one shiftwidth of indent in current line {vi: only in
- X autoindent}
- X^U delete all entered characters in the current line
- X^V insert next non-digit literally, insert three digit decimal
- X number as a single byte.
- X^W delete word before the cursor
- X^[ <ESC> end insert mode
- X<DEL> same as ^H <BS>
- X<C_UP> cursor one line up
- X<C_DOWN> cursor one line down
- X<C_LEFT> cursor one character left
- X<C_RIGHT> cursor one character right
- X<SC_UP> one screenfull backward
- X<SC_DOWN> one screenfull forward
- X<SC_LEFT> cursor one word left
- X<SC_RIGHT> cursor one word right
- X{char1}<BS>{char2} enter digraph (only when compiled with it and 'digraph'
- X option set) {vi: no digraphs}
- X
- X
- X2. VI COMMANDS
- X==============
- X
- XCHAR means non-blank char
- XWORD means sequences of non-blank chars
- XN is number entered before the command
- X<move> is a cursor movement command
- XNmove is the text that is moved over with a cursor movement command
- XSECTION is a section that possibly starts with '}' instead of '{'
- X
- Xnote: 1 = cursor movement command; 2 = can be undone/redone
- X
- Xchar note vim normal mode (vi: what the unix vi does)
- X------------------------------------------------------------------------------
- X^@ error
- X^A 2 add N to number at/after cursor {vi: no ^A}
- X^B 1 scroll N screens Backwards
- X^C interrupt current (search) command
- X^D scroll Down N lines (default: half a screen)
- X^E scroll N lines upwards (N lines Extra)
- X^F 1 scroll N screens Forward
- X^G display current file name and position
- X^H <BS> 1 cursor N chars to the left
- X^I <TAB> 1 go to N newer entry in jump list
- X^J <LF> 1 cursor N lines downward
- X^K error
- X^L redraw screen
- X^M <CR> 1 cursor to the first CHAR N lines lower
- X^N 1 cursor N lines downward
- X^O 1 go to N older entry in jump list
- X^P 1 cursor N lines upward
- X^Q start blockwise quoting (vi: no quoting)
- X^R 2 redo changes which were undone with 'u' (vi: no redo)
- X^S 2 subtract N from number at/after cursor {vi: no ^S}
- X^T jump to N older Tag in tag list
- X^U scroll N lines Upwards (default: half a screen)
- X^V error
- X^W error
- X^X error
- X^Y scroll N lines downwards
- X^Z suspend program (or start new shell)
- X^[ <ESC> error
- X^\ error
- X^] :ta to ident under cursor
- X^^ edit Nth alternate file (equivalent to :e #N)
- X^_ error
- X
- X<SPACE> 1 cursor N chars to the right
- X!<move><filter> filter Nmove text through the "filter" command
- X!!<filter> filter N lines through the "filter" command
- X"<a-zA-Z0-9.> use buffer <a-zA-Z0-9.> for next delete, yank or put
- X (upper case to append)(<.> only works for put)
- X# 1 search backward for the Nth occurrence of the ident under
- X the cursor {not in vi}
- X$ 1 cursor to the end of line N from the cursor
- X% 1 find the next (curly/square) bracket on this line and go
- X to its match. With count: go to N percentage in the file.
- X& 2 repeat last :s
- X'<a-zA-Z> 1 cursor to the first CHAR on the line with mark <a-zA-Z>
- X'[ 1 cursor to the first CHAR on the line of the start of
- X last operated text or start of putted text
- X'] 1 cursor to the first CHAR on the line of the end of
- X last operated text or end of putted text
- X'' 1 cursor to the first CHAR of the line where the cursor was
- X before the latest jump.
- X( 1 cursor N sentences backward
- X) 1 cursor N sentences forward
- X* 1 search forward for the Nth occurrence of the ident under
- X the cursor {not in vi}
- X+ 1 cursor to the first CHAR N lines lower
- X, 1 repeat latest f, t, F or T in opposite direction N times
- X- 1 cursor to the first CHAR N lines higher
- X. 2 repeat last change with count replaced by N
- X/<pattern> 1 search forward for the Nth occurrence of <pattern>
- X0 1 cursor to the first char of the line
- X1 prepend to command to give a count
- X2 "
- X3 "
- X4 "
- X5 "
- X6 "
- X7 "
- X8 "
- X9 "
- X: Ex command (see below)
- X; 1 repeat latest f, t, F or T N times
- X<<move> 2 shift the Nmove lines one shiftwidth leftwards
- X<< 2 shift N lines one shiftwidth leftwards
- X=<move> 2 filter Nmove lines through "indent" (vi: when option
- X 'lisp' is set autoindent Nmove lines)
- X== 2 filter N lines through "indent"
- X><move> 2 shift Nmove lines one shiftwidth rightwards
- X>> 2 shift N lines one shiftwidth rightwards
- X?<pattern> 1 search backward for the Nth previous occurrence of
- X <pattern>
- X@<a-z> 2 execute the contents of named buffer <a-z> N times
- X@@ 2 repeat the previous @<a-z> N times
- XA 2 append text at the end of the line N times
- XB 1 cursor N WORDS backward
- X<"x>C 2 change from the cursor position to the end of the line,
- X and N-1 more lines [into buffer x]; synonym for c$
- X<"x>D 2 delete the characters under the cursor until the end of
- X the line and N-1 more lines [into buffer x]; synonym for d$
- XE 1 cursor forward to the end of WORD N
- XF<char> cursor to the Nth occurrence of <char> to the left
- XG 1 cursor to line N, default last line
- XH 1 cursor to line N from top of screen
- XI 2 insert text before the first CHAR on the line N times
- XJ 2 Join N lines; default is 2
- XK lookup Keyword under the cursor with "keywordprg"
- XL 1 cursor to line N from bottom of screen
- XM 1 cursor to middle line of screen
- XN 1 repeat the latest '/' or '?' N times in opposite
- X direction
- XO 2 begin a new line above the cursor and insert text, repeat
- X N times (vi: blank N screen lines)
- X<"x>P 2 put the text [from buffer x] before the cursor N times
- XQ start quoting lines (vi: go to Ex mode)
- XR 2 enter replace mode: overtype existing characters, repeat the
- X entered text N-1 times
- X<"x>S 2 delete N lines [into buffer x] and start insert; synonym
- X for ^cc or 0cc, depending on autoindent
- XT<char> 1 cursor till after Nth occurrence of <char> to the left
- XU 2 undo all latest changes on one line (vi: while not moved
- X off of it)
- X While quoting: make lowercase
- XV<move> 2 Join N lines and re-format them
- XW 1 cursor N WORDS forward
- X<"x>X 2 delete N characters before the cursor [into buffer x]
- X<"x>Y yank N lines [into buffer x]; synonym for yy
- XZZ store current file, if modified, and exit
- X[[ 1 cursor N sections backward
- X[] 1 cursor N SECTIONS backward
- X\ error
- X]] 1 cursor N sections forward
- X][ 1 cursor N SECTIONS forward
- X^ 1 cursor to the first CHAR of the line
- X_ 1 cursor to the first CHAR N - 1 lines lower
- X`<a-zA-Z> 1 cursor to the mark <a-zA-Z>
- X`[ 1 cursor to the start of last operated text or start of
- X putted text
- X`] 1 cursor to the end of last operated text or end of
- X putted text
- X`` 1 cursor to the position before latest jump
- Xa 2 append text after the cursor N times
- Xb 1 cursor N words backward
- X<"x>c<move> 2 delete Nmove text [into buffer x] and start insert
- X<"x>cc 2 delete N lines [into buffer x] and start insert
- X<"x>d<move> 2 delete Nmove text [into buffer x]
- X<"x>dd 2 delete N lines [into buffer x]
- Xe 1 cursor forward to the end of word N
- Xf<char> 1 cursor to Nth occurrence of <char> to the right
- Xg error
- Xh 1 cursor N chars to the left
- Xi 2 insert text before the cursor N times
- Xj 1 cursor N lines downward
- Xk 1 cursor N lines upward
- Xl 1 cursor N chars to the right
- Xm<a-z> set mark <a-z> at cursor position
- Xn 1 repeat the latest '/' or '?' N times
- Xo 2 begin a new line below the cursor and insert text, repeat
- X N times (vi: blank N screen lines)
- X While quoting: cursor moves other end
- X<"x>p 2 put the text [from buffer x] after the cursor N times
- Xq start quoting characters
- Xr<char> 2 replace N chars by <char>
- X<"x>s 2 (substitute) delete N characters [into buffer x] and
- X start insert
- Xt<char> 1 cursor till before Nth occurrence of <char> to the right
- Xu 2 undo changes (vi: only one level)
- X While quoting: make uppercase
- Xv<a-zA-Z> record typed characters into named buffer <a-zA-Z>
- X (upper case to append)
- Xv stops recording (vi: no recording)
- Xw 1 cursor N words forward
- X<"x>x 2 delete N characters under and after the cursor [into
- X buffer x]
- X<"x>y<move> yank Nmove text [into buffer x]
- X<"x>yy yank N lines [into buffer x]
- Xz<CR> redraw, cursor line to top of window
- Xz. redraw, cursor line to center of window
- Xz- redraw, cursor line at bottom of window
- X{ 1 cursor N paragraphs backward
- X| 1 cursor to column N
- X} 1 cursor N paragraphs forward
- X~ 2 option notildeop: switch case of N characters under
- X cursor and move the cursor N characters to the right
- X (vi: no count)
- X~<move> option tildeop: switch case of Nmove text (vi: no tildeop
- X option)
- X<DEL> when entering a number: remove the last digit
- X<HELP> show the file vim:vim.hlp page by page (vi: no help)
- X<C_UP> 1 move cursor N lines upwards
- X<C_DOWN> 1 move cursor N lines downwards
- X<C_LEFT> 1 move cursor N chars to the left
- X<C_RIGHT> 1 move cursor N chars to the right
- X<SC_UP> 1 scroll N screens Backwards (same as ^B)
- X<SC_DOWN> 1 scroll N screens Forwards (same as ^F)
- X<SC_LEFT> 1 cursor N words backward (same as b)
- X<SC_RIGHT> 1 cursor N words forward (same as w)
- X
- X
- X3. command line editing
- X=======================
- X
- XGet to the command line with the ':', '!', '/' or '?' commands.
- XNormal characters are inserted at the current cursor position.
- X(vi: can only alter last character in the line)
- X
- X^D list filenames that match the pattern in front of the cursor
- X^H delete the character in front of the cursor
- X^N only after an <ESC> with multiple matches: go to next match
- X^P only after an <ESC> with multiple matches: go to previous match
- X^V insert next non-digit literally, insert three digit decimal
- X number as a single byte. {Vi: type the CTRL-V twice to get one}
- X<ESC> do filename completion on the pattern in front of the cursor
- X@ remove all characters
- X<DEL> delete the character under the cursor
- X<C_UP> recall previous command line from history
- X<C_DOWN> recall next command line from history
- X<C_LEFT> cursor left
- X<C_RIGHT> cursor right
- X<SC_LEFT> cursor one word left
- X<SC_RIGHT> cursor one word right
- X
- X
- X4. EX commands
- X==============
- X
- Xlines that start with " or # are ignored
- X
- X<range> stands for a series of line specifiers, separated with ',' or ';'.
- XWhen separated with ';' the cursor position will be set to that line before
- Xinterpreting the next line specifier.
- XThe default line specifier (for most commands) is the Cursor position.
- Xline numbers may be specified with:
- X <number> the absolute line number
- X . the current line
- X $ the last line in the file
- X % equal to 1,$ (the entire file)
- X 't position of mark t
- X /<pattern> the next line where <pattern> matches
- X ?<pattern> the previous line where <pattern> matches
- XEach may be followed (several times) by '+' or '-' and an optional number.
- XThis number is added or subtracted from the preceding line number.
- Xif the number is omitted, 1 is used.
- XExamples:
- X .+3 three lines below the cursor
- X /that+1 the line below the next line containing "that"
- X .,$ from current line until end of file
- X
- XIn the commands below the characters in square brackets are optional.
- X
- X:<range> set the cursor on the (last) specified line number
- X
- X:a[ppend] {vi: append text}
- X
- X:ar[gs] print the file list, with the current file in []
- X
- X:cc [nr] Display error [nr] (default is same error)
- X
- X:cd print the current directory name {vi: no such command}
- X:cd <path> change the current directory to <path>
- X
- X:cf read error file (from errorfile option)
- X
- X:c[hange] {vi: replace lines}
- X
- X:ch[dir] same as :cd
- X
- X:cn display next error
- X
- X:[range]co[py] {address} copy lines from [range] to {address}
- X
- X:cp display previous error
- X
- X:cq Quit without writing and return an error code
- X
- X:[<range>]d[elete] [x] [count]
- X delete <range> lines (default: current line)
- X
- X:dig[raph] display currently defined digraphs {not in vi}
- X
- X:dig[raph] {char1}{char2} {number} ...
- X define the character pair {char1} {char2} to be the
- X digraph for character {number}. {number} is entered
- X as digits.
- X
- X:di[splay] display the contents of numbered and named buffers
- X {vi: no such command}
- X
- X:e[dit] [file] edit 'file' (default: current file), unless changes have
- X been made {vi: allow +n to start at certain position}
- X:e[dit]! [file] edit 'file' (default: current file) always
- X
- X:ex same as :edit
- X
- X:f[ile] prints the current file name and some more info
- X:f[ile] <name> sets current file name to <name>
- X:files lists the alternate file names
- X
- X:<range>g[lobal]/<pattern>/<cmd>
- X execute the EX command <cmd> on the lines where <pattern>
- X matches
- X:<range>g[lobal]!/<pattern>/<cmd>
- X execute the EX command <cmd> on the lines where <pattern>
- X does not match
- X
- X:h[elp] show the help file page by page {vi: no help}
- X
- X:i[nsert] {vi: insert text}
- X
- X:<range>j[oin] join <range> lines
- X
- X:ju[mps] print jump list {vi: no such command}
- X
- X:[range]k<a-z> set mark without a space
- X
- X:l[ist] {vi: list lines}
- X
- X:map <lhs> <rhs> map the key sequence <lhs> to <rhs> in normal mode
- X:map! <lhs> <rhs> map the key sequence <lhs> to <rhs> in insert mode
- X
- X:[range]ma[rk] <a-z> set mark
- X
- X:marks list all marks {vi: no such command}
- X
- X:mk[exrc] write options to .exrc file
- X:mkv[imrc] write options to .vimrc file {not in vi}
- X
- X:[range]m[ove] {address} move lines from [range] to {address}
- X
- X:n[ext] edit next file, unless changes have been made
- X:n[ext]! edit next file
- X:n[ext] <filelist> define <filelist> as the new list of files and edit
- X the first one, unless changes have been made
- X:n[ext]! <filelist> define <filelist> as the new list of files and edit
- X the first one {vi: +command to start editing at a
- X specified position}
- X
- X:noremap <lhs> <rhs> map the key sequence <lhs> to <rhs> in normal mode,
- X disallow remapping of <rhs> {not in vi}
- X:noremap! <lhs> <rhs> map the key sequence <lhs> to <rhs> in insert mode,
- X disallow remapping of <rhs> {not in vi}
- X
- X:nu[mber] {vi: print specified lines with their line number}
- X
- X:N[ext] edit previous file in file list, unless changes have
- X been made
- X:N[ext]! edit previous file in file list
- X
- X:o[pen] {vi: start editing in open mode}
- X
- X:[count]po[p][!] jump to [count] older tag in tag list {vi: no such command}
- X
- X:pres[erve] {vi: emergency exit}
- X
- X:<range>p[rint] print the specified lines
- X
- X:pu[t] [x] insert text from buffer [x] below current line
- X:pu[t]! [x] insert text from buffer [x] above current line
- X
- X:pr[evious] same as :Next
- X
- X:q[uit] quit, unless changes have been made
- X:q[uit]! quit always, without writing
- X
- X:r[ead] <name> insert the file <name> below the cursor
- X:r[ead]!<cmd> excute <cmd> and insert its standard output below the
- X cursor
- X
- X:rec[over] {vi: recover a file after a crash or :preserve}
- X
- X:rew[ind] start editing the first file in the file list, unless
- X changes have been made
- X:rew[ind]! start editing the first file in the file list
- X
- X:se[t] show all modified options {vi: non-default options}
- X:se[t] all show all options
- X:se[t] <option> set toggle option on, show value of string or number
- X option
- X:se[t] no<option> set toggle option off
- X:se[t] inv<option> invert toggle option
- X:se[t] <option>=<value> set string or number option to <value>
- X:se[t] <option>? show value of <option>
- X
- X:sh[ell] escape to a shell {vi: shell name from option 'shell'}
- X
- X:so[urce] <file> read EX commands from <file>
- X:so[urce]! <file> read VI commands from <file> {vi: no such command}
- X
- X:st[op][!] suspend the editor
- X
- X:<range>s[ubstitute]/<pattern>/<string>/<option>
- X for each line in <range> replace the first occurrence of
- X <pattern> by <string>; with <option> 'g' all occurrences
- X on the line are replaced; with <option> 'c' each
- X replace has to be confirmed
- X:<range>s[ubstitute] repeat last :substitute
- X
- X:t synonym for copy
- X
- X:ta[g] <ident> search for <indent> in the tags file and execute
- X the accompanying command, unless changes have been made
- X:ta[g]! <ident> search for <indent> in the tags file and execute
- X the accompanying command
- X
- X:[count]ta[g][!] jump to [count] newer tag in tag list {vi: no such command}
- X
- X:tags print the tag list {vi: no such command}
- X
- X:una[bbreviate] {vi: remove from abbreviation list}
- X
- X:u[ndo] undo last change
- X
- X:unm[ap] <lhs> remove the mapping of <lhs> for normal mode
- X:unm[ap]! <lhs> remove the mapping of <lhs> for insert mode
- X
- X:ve[rsion] print the version number of the editor
- X
- X:<range>v[global]/<pattern>/<cmd>
- X execute the EX command <cmd> on the lines where <pattern>
- X does not match
- X
- X:vi[sual] {vi: switch from EX or open to visual mode}
- X
- X:wi[nsize] <width> <height>
- X Set effective window size to <width> columns and <height>
- X rows. Does not change actual window size. Should only be
- X used from script files. {vi: no such command}
- X
- X:<range>w[rite][!] write the specified lines to the current file
- X:<range>w[rite] <file> write the specified lines to <file>, unless it
- X already exists
- X:<range>w[rite]! <file> write the specified lines to <file>
- X:<range>w[rite][!] >> append the specified lines to the current file
- X:<range>w[rite][!] >> <file>
- X append the specified lines to <file>
- X:<range>w[rite] !<cmd> execute <cmd> with <range> lines as standard input
- X
- X:wq write the current file and exit if no more files
- X:wq! write the current file and exit
- X:wq <file> write to <file> and exit if no more files
- X:wq! <file> write to <file> and exit
- X
- X:x[it][!] [file] same as :wq, but write only when changes have been made
- X
- X:y[ank] [x] copy lines into buffer [x]
- X
- X:z {vi: print some lines}
- X
- X:@<reg> execute contents of buffer <reg> as an Ex command
- X {only in some versions of vi}
- X
- X:@@ repeat last :@<reg> command.
- X
- X:![!]<cmd> [!][<arg>] execute <cmd> with the shell, replace the optional bangs
- X with the previously given command, append the optional
- X <arg>
- X:<range>![!]<cmd> [!][<arg>]
- X filter <range> lines through <cmd>, replace the optional bangs
- X with the previously given command, append the optional
- X <arg>
- X
- X:< shift left
- X
- X:> shift right
- X
- X:= print the line number
- X
- X:& same as :substitute
- X
- X:~ {vi: do a substitute on the previous regular expression}
- END_OF_FILE
- if test 18631 -ne `wc -c <'vim/doc/index'`; then
- echo shar: \"'vim/doc/index'\" unpacked with wrong size!
- fi
- # end of 'vim/doc/index'
- fi
- if test -f 'vim/src/storage.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'vim/src/storage.c'\"
- else
- echo shar: Extracting \"'vim/src/storage.c'\" \(19504 characters\)
- sed "s/^X//" >'vim/src/storage.c' <<'END_OF_FILE'
- X/* vi:ts=4:sw=4
- X *
- X * VIM - Vi IMitation
- X *
- X * Code Contributions By: Bram Moolenaar mool@oce.nl
- X * Tim Thompson twitch!tjt
- X * Tony Andrews onecom!wldrdg!tony
- X * G. R. (Fred) Walter watmath!watcgl!grwalter
- X */
- X
- X/*
- X * storage.c: allocation of lines and management of them
- X *
- X * part 1: storage allocation for the lines and blocks of the current file
- X * part 2: managing of the pointer blocks
- X */
- X
- X#include "vim.h"
- X#include "globals.h"
- X#include "proto.h"
- X
- X/***************************************************************************
- X * part 1: storage allocation for the lines and blocks of the current file *
- X ***************************************************************************/
- X
- X/*
- X * Memory is allocated in relatively large blocks. These blocks are linked
- X * in the allocated block list, headed by m_ahead. They are all freed
- X * when abandoning a file.
- X *
- X * The available chunks of memory are kept in the free chunk list, headed
- X * by m_fhead. This is a circular list. m_search points to the chunk before the
- X * chunk that was freed/allocated the last time. alloc_line() gets a chunk
- X * from the free list; free_line() returns a chunk to the free list.
- X */
- X
- X /* on the Amiga the blocksize must not be a multiple of 256 */
- X /* with MS-Dos the blocksize must be larger than 255 */
- X /* For Unix it does not really matter */
- X#define MEMBLOCKSIZE 2044
- X
- Xtypedef struct m_info info_t;
- X
- X/*
- X * There are two types of in-use memory chunks:
- X * 1. those that are allocated by readfile(). These are always preceded
- X * by a NUL character and end in a NUL character. The chunk must not
- X * contain other NUL characters. The preceding NUL is used to
- X * determine the chunk type. The ending NUL is used to determine the
- X * end of the chunk. The preceding NUL is not part of the chunk, the
- X * ending NUL is.
- X * 2. the other chunks have been allocated with alloc_line(). They are
- X * preceded by a non-NUL character. This is used to determine the chunk
- X * type. The non-NUL may be part of a size field or may be an extra 0xff
- X * byte. The chunk always ends in a NUL character and may also contain
- X * a NUL character. The size field contains the size of the chunk,
- X * including the size field. The trailing NUL may be used by a possibly
- X * follwing type 1 chunk. The preceding size, the optional 0xff and the
- X * trailing NUL are all part of the chunk.
- X *
- X * When the chunk is not in-use it is preceded with the m_info structure.
- X * The m_next field links it in the free chunk list. It must still end in
- X * a NUL byte, because it may be followed by a type 1 chunk!
- X *
- X * When in-use we must make sure there is a non-NUL byte in front of type
- X * 2 chunks.
- X *
- X * On the Amiga this means that the size must not be a multiple of 256.
- X * This is done by multiplying the size by 2 and adding one.
- X *
- X * On MS-DOS the size must be larger than 255. This is done by adding 256
- X * to the size.
- X *
- X * On Unix systems an extra 0xff byte is added. This costs 4 bytes because
- X * pointers must be kept long-aligned.
- X *
- X * On most unix systems structures have to be longword aligned.
- X * On most other systems they are short (16 bit) aligned.
- X */
- X
- X#ifdef UNIX
- X# define ALIGN_LONG /* 32 bit alignment and use filler byte */
- X#else
- X# ifdef AMIGA
- X# define LOWBYTE /* size must not be multiple of 256 */
- X# else
- X# ifdef MSDOS
- X# define HIGHBYTE /* size must be larger than 255 */
- X# else
- X you must define something!
- X# endif
- X# endif
- X#endif
- X
- Xstruct m_info
- X{
- X#ifdef ALIGN_LONG
- X u_long m_size; /* size of the chunk (including m_info) */
- X#else
- X u_short m_size; /* size of the chunk (including m_info) */
- X#endif
- X info_t *m_next; /* pointer to next free chunk in the list */
- X};
- X
- X#ifdef ALIGN_LONG
- X /* size of m_size + room for 0xff byte */
- X# define M_OFFSET (sizeof(u_long) * 2)
- X#else
- X /* size of m_size */
- X# define M_OFFSET (sizeof(u_short))
- X#endif
- X
- Xstatic char *m_ahead = NULL; /* head of allocated memory block list */
- X
- Xstatic info_t m_fhead = {0, NULL}; /* head of free chunk list */
- X
- Xstatic info_t *m_search = NULL; /* pointer to chunk before previously
- X allocated/freed chunk */
- X
- X#ifdef DEBUG
- X# ifdef AMIGA
- Xm_error()
- X{
- X printf("list error\n");
- X}
- X# endif
- X
- Xcheck_list()
- X{
- X# ifdef AMIGA
- X register info_t *mp;
- X
- X for (mp = &m_fhead; ; )
- X {
- X /*
- X * adjust these addresses for the actual available memory!
- X */
- X if (mp >= 0x080000L && mp < 0x200000L ||
- X mp >= 0x400000L && mp < 0xc00000 ||
- X mp >= 0xc80000 || mp->m_next->m_size > 23000)
- X {
- X m_error();
- X return 1;
- X }
- X mp = mp->m_next;
- X if (mp == &m_fhead)
- X break;
- X }
- X# endif
- X return 0;
- X}
- X#endif /* DEBUG */
- X
- X/*
- X * Allocate a block of memory and link it in the allocated list, so that
- X * the block will be freed when abandoning the file.
- X */
- X char *
- Xm_blockalloc(size, message)
- X u_long size;
- X int message;
- X{
- X char *p;
- X
- X p = lalloc(size + sizeof(char *), message);
- X if (p != NULL)
- X {
- X *(char **)p = m_ahead;
- X m_ahead = p;
- X p += sizeof(char *);
- X }
- X return p;
- X}
- X
- X/*
- X * free all allocated memory blocks
- X */
- X void
- Xm_blockfree()
- X{
- X char *p, *np;
- X
- X for (p = m_ahead; p != NULL; p = np)
- X {
- X np = *(char **)p;
- X free(p);
- X }
- X m_ahead = NULL;
- X m_search = NULL;
- X}
- X
- X/*
- X * Free a chunk of memory which was
- X * 1. inserted with readfile(); these are preceded with a NUL byte
- X * 2. allocated with alloc_line(); these are preceded with a non-NUL byte
- X * Insert the chunk into the free list, keeping it sorted on address.
- X */
- X void
- Xfree_line(ptr)
- X char *ptr;
- X{
- X info_t *mp;
- X register info_t *next;
- X info_t *prev, *curr;
- X long len;
- X
- X#ifdef DEBUG
- X if (check_list())
- X return;
- X#endif
- X if (ptr == NULL || ptr == IObuff)
- X return; /* illegal address can happen in out-of-memory situations */
- X
- X if (*(ptr - 1) == NUL) /* type 1 chunk: no size field */
- X {
- X#ifdef ALIGN_LONG /* use longword alignment */
- X long c;
- X
- X len = strlen(ptr) + 1;
- X if ((c = ((long)ptr & 3)) != 0) /* lose some bytes */
- X {
- X c = 4 - c;
- X ptr += c;
- X len -= c;
- X }
- X#else /* use short (16 bit) alignment */
- X len = strlen(ptr) + 1;
- X if ((long)ptr & 1) /* lose a byte */
- X {
- X ++ptr;
- X --len;
- X }
- X#endif /* ALIGN_LONG */
- X
- X /* we must be able to store size, pointer and a trailing NUL */
- X /* otherwise we can't fit it in the free list */
- X if (len <= (long)sizeof(info_t))
- X return; /* these bytes are not used until you quit the file */
- X mp = (info_t *)ptr;
- X mp->m_size = len;
- X }
- X#ifdef ALIGN_LONG
- X else if ((*(ptr - 1) & 0xff) == 0xff) /* type 2 chunk: has size field */
- X {
- X mp = (info_t *)(ptr - M_OFFSET);
- X }
- X else
- X {
- X emsg("Illegal chunk");
- X return;
- X }
- X#endif
- X#ifdef LOWBYTE
- X else /* type 2 chunk: has size field */
- X {
- X mp = (info_t *)(ptr - M_OFFSET);
- X mp->m_size >>= 1;
- X }
- X#endif
- X#ifdef HIGHBYTE
- X else /* type 2 chunk: has size field */
- X {
- X mp = (info_t *)(ptr - M_OFFSET);
- X mp->m_size -= 256;
- X }
- X#endif
- X
- X curr = NULL;
- X /* if mp is smaller than m_search->m_next we start at m_fhead */
- X if (mp < (m_search->m_next))
- X next = &m_fhead;
- X else
- X next = m_search;
- X do
- X {
- X prev = curr;
- X curr = next;
- X next = next->m_next;
- X }
- X while (mp > next && next != &m_fhead);
- X
- X/* if *mp and *next are concatenated, join them into one chunk */
- X if ((char *)mp + mp->m_size == (char *)next)
- X {
- X mp->m_size += next->m_size;
- X mp->m_next = next->m_next;
- X }
- X else
- X mp->m_next = next;
- X
- X/* if *curr and *mp are concatenated, join them */
- X if (prev != NULL && (char *)curr + curr->m_size == (char *)mp)
- X {
- X curr->m_size += mp->m_size;
- X curr->m_next = mp->m_next;
- X m_search = prev;
- X }
- X else
- X {
- X curr->m_next = mp;
- X m_search = curr; /* put m_search before freed chunk */
- X }
- X#ifdef DEBUG
- X check_list();
- X#endif
- X}
- X
- X/*
- X * Allocate and initialize a new line structure with room for at least
- X * 'size' characters.
- X */
- X char *
- Xalloc_line(size)
- X register unsigned size;
- X{
- X register info_t *mp, *mprev, *mp2;
- X int size_align;
- X
- X#ifdef DEBUG
- X if (m_search != NULL && check_list())
- X return NULL;
- X#endif
- X/*
- X * Add room for size field, optional 0xff byte and trailing NUL byte.
- X * Adjust for minimal size (must be able to store info_t
- X * plus a trailing NUL, so the chunk can be released again)
- X */
- X size += M_OFFSET + 1;
- X if (size < sizeof(info_t) + 1)
- X size = sizeof(info_t) + 1;
- X
- X/*
- X * round size up for alignment
- X */
- X#ifdef ALIGN_LONG /* use longword alignment */
- X size_align = (size + 3) & ~3;
- X#else /* ALIGN_LONG */ /* use short (16 bit) alignment */
- X size_align = (size + 1) & ~1;
- X#endif /* ALIGN_LONG */
- X
- X/* if m_search is NULL we have to initialize the free list */
- X if (m_search == NULL)
- X {
- X m_search = &m_fhead;
- X m_fhead.m_next = &m_fhead;
- X }
- X
- X/* search for space in free list */
- X mprev = m_search;
- X for (mp = m_search->m_next; mp->m_size < size; mp = mp->m_next)
- X {
- X if (mp == m_search)
- X {
- X int n = (size_align > (MEMBLOCKSIZE / 4) ? size_align : MEMBLOCKSIZE);
- X
- X mp = (info_t *)m_blockalloc((u_long)n, TRUE);
- X if (mp == NULL)
- X return (NULL);
- X#ifdef HIGHBYTE
- X mp->m_size = n + 256;
- X#endif
- X#ifdef LOWBYTE
- X mp->m_size = (n << 1) + 1;
- X#endif
- X#ifdef ALIGN_LONG
- X mp->m_size = n;
- X *((u_char *)mp + M_OFFSET - 1) = 0xff;
- X#endif
- X free_line((char *)mp + M_OFFSET);
- X mp = m_search;
- X }
- X mprev = mp;
- X }
- X
- X/* if the chunk we found is large enough, split it up in two */
- X if ((long)mp->m_size - size_align >= (long)(sizeof(info_t) + 1))
- X {
- X mp2 = (info_t *)((char *)mp + size_align);
- X mp2->m_size = mp->m_size - size_align;
- X mp2->m_next = mp->m_next;
- X mprev->m_next = mp2;
- X mp->m_size = size_align;
- X }
- X else /* remove *mp from the free list */
- X {
- X mprev->m_next = mp->m_next;
- X }
- X m_search = mprev;
- X
- X#ifdef HIGHBYTE
- X mp->m_size += 256;
- X#endif
- X#ifdef LOWBYTE
- X mp->m_size = (mp->m_size << 1) + 1;
- X#endif
- X mp = (info_t *)((char *)mp + M_OFFSET);
- X#ifdef ALIGN_LONG
- X *((u_char *)mp - 1) = 0xff; /* mark type 2 chunk */
- X#endif
- X *(char *)mp = NUL; /* set the first byte to NUL */
- X#ifdef DEBUG
- X check_list();
- X#endif
- X
- X return ((char *)mp);
- X}
- X
- X/*
- X * save_line(): allocate memory with alloc_line() and copy the
- X * string 'src' into it.
- X */
- X char *
- Xsave_line(src)
- X register char *src;
- X{
- X register char *dst;
- X register unsigned len;
- X
- X len = strlen(src);
- X if ((dst = alloc_line(len)) != NULL)
- X memmove(dst, src, (size_t)(len + 1));
- X return (dst);
- X}
- X
- X/******************************************
- X * part 2: managing of the pointer blocks *
- X ******************************************/
- X
- Xtypedef struct block block_t;
- X
- X#ifdef BLOCK_SIZE
- X# undef BLOCK_SIZE /* for Linux: is in limits.h */
- X#endif
- X
- X#define BLOCK_SIZE 40
- X
- Xstruct block
- X{
- X u_short b_count; /* current number of pointers in b_ptr */
- X block_t *b_next; /* pointer to next block */
- X block_t *b_prev; /* pointer to previous block */
- X char *b_ptr[BLOCK_SIZE]; /* pointers to the lines */
- X char b_flags[BLOCK_SIZE]; /* see below */
- X};
- X
- X#define B_MARKED 0x01 /* mark for :global command */
- X
- Xstatic block_t *first_block; /* pointer to first block in block list */
- Xstatic block_t *last_block; /* pointer to last block in block list */
- X
- Xstatic block_t *curr_block; /* block used by nr2ptr */
- Xstatic linenr_t curr_count; /* first line number of block curr_block */
- X
- Xstatic block_t *alloc_block __ARGS((void));
- X
- X static block_t *
- Xalloc_block()
- X{
- X block_t *p;
- X
- X p = (block_t *)(alloc_line((unsigned)sizeof(block_t)));
- X if (p != NULL)
- X {
- X memset((char *)p, 0, sizeof(block_t));
- X }
- X return (p);
- X}
- X
- X/*
- X * filealloc() - construct an initial empty file buffer
- X */
- X void
- Xfilealloc()
- X{
- X first_block = last_block = alloc_block();
- X if (first_block == NULL || (first_block->b_ptr[0] = alloc_line(0)) == NULL)
- X getout(1);
- X first_block->b_count = 1;
- X Curpos.lnum = 1;
- X Curswant = Curpos.col = 0;
- X Topline = 1;
- X Botline = 2;
- X line_count = 1;
- X curr_count = 0;
- X clrallmarks();
- X clrtags();
- X}
- X
- X/*
- X * freeall() - free the current buffer
- X *
- X * Free all lines in the current buffer.
- X */
- X void
- Xfreeall()
- X{
- X m_blockfree();
- X line_count = 0;
- X s_ins(0, 0, TRUE); /* invalidate Line arrays */
- X u_clearall();
- X}
- X
- X/*
- X * Get the pointer to the line 'nr'.
- X * This function is used a lot for sequential access (writeit, search),
- X * so that is what it is optimized for.
- X */
- X char *
- Xnr2ptr(nr)
- X register linenr_t nr;
- X{
- X register linenr_t count;
- X register block_t *bp = NULL;
- X
- X if ((count = curr_count) == 0 || nr >= count + (bp = curr_block)->b_count || nr < count)
- X {
- X if (nr < 1 || nr > line_count)
- X {
- X emsg("nr2ptr: illegal nr");
- X return (IObuff); /* always return a valid ptr */
- X }
- X
- X /*
- X * three ways to find the pointer:
- X * 1. first pointer in the next block (fast for sequential access)
- X * 2. search forward
- X * 3. search backward
- X */
- X if (count && nr == count + bp->b_count) /* in next block */
- X {
- X count = nr;
- X bp = bp->b_next;
- X }
- X else if (nr <= (count + line_count) / 2 ||
- X (nr <= count && nr <= count / 2))
- X {
- X /* search forward */
- X if (nr < count || count == 0)
- X {
- X count = 1;
- X bp = first_block;
- X }
- X while (bp != NULL)
- X {
- X count += bp->b_count;
- X if (nr < count)
- X {
- X count -= bp->b_count;
- X break;
- X }
- X bp = bp->b_next;
- X }
- X }
- X else
- X { /* search backward */
- X if (nr < count)
- X bp = bp->b_prev;
- X else
- X {
- X bp = last_block;
- X count = line_count + 1;
- X }
- X while (bp != NULL)
- X {
- X count -= bp->b_count;
- X if (nr >= count)
- X break;
- X bp = bp->b_prev;
- X }
- X }
- X
- X if (bp == NULL)
- X {
- X emsg("nr2ptr: strorage corrupt");
- X curr_count = 0;
- X return (IObuff);
- X }
- X curr_count = count;
- X curr_block = bp;
- X }
- X return (bp->b_ptr[nr - count]);
- X}
- X
- X/*
- X * pos2ptr: get pointer to position 'pos'
- X */
- X char *
- Xpos2ptr(pos)
- X FPOS *pos;
- X{
- X return (nr2ptr(pos->lnum) + pos->col);
- X}
- X
- X/*
- X * set the B_MARKED flag for line 'lnum'
- X */
- X void
- Xsetmarked(lnum)
- X linenr_t lnum;
- X{
- X nr2ptr(lnum);
- X curr_block->b_flags[lnum - curr_count] |= B_MARKED;
- X}
- X
- X/*
- X * find the first line with its B_MARKED flag set
- X */
- X linenr_t
- Xfirstmarked()
- X{
- X register block_t *bp;
- X register linenr_t lnum;
- X register int i;
- X
- X for (bp = first_block, lnum = 1; bp != NULL; bp = bp->b_next)
- X for (i = 0; i < bp->b_count; ++i, ++lnum)
- X if (bp->b_flags[i] & B_MARKED)
- X {
- X bp->b_flags[i] &= ~B_MARKED;
- X return lnum;
- X }
- X return (linenr_t) 0;
- X}
- X
- X/*
- X * clear all B_MARKED flags
- X */
- X void
- Xclearmarked()
- X{
- X register block_t *bp;
- X register int i;
- X
- X for (bp = first_block; bp != NULL; bp = bp->b_next)
- X for (i = bp->b_count; --i >= 0; )
- X bp->b_flags[i] &= ~B_MARKED;
- X}
- X
- X/*
- X * a pointer to a line is converted into a line number
- X * we start at line number 'start'
- X * this is a bit slow, but it is used for marks and undo only
- X */
- X linenr_t
- Xptr2nr(ptr, start)
- X char *ptr;
- X linenr_t start;
- X{
- X block_t *bp;
- X register linenr_t nr;
- X register char **pp;
- X register int i;
- X
- X if (ptr == NULL)
- X return (linenr_t)0;
- X
- X if (start == 0)
- X start = 1;
- X nr2ptr(start); /* set curr_block and curr_count */
- X
- X for (nr = curr_count, bp = curr_block; bp != NULL; bp = bp->b_next)
- X for (pp = bp->b_ptr, i = bp->b_count; --i >= 0; ++nr)
- X if (*pp++ == ptr)
- X return (nr);
- X return (linenr_t)0;
- X}
- X
- X/*
- X * appendline: add a line
- X * return TRUE when succesful
- X */
- X int
- Xappendline(after, s)
- X linenr_t after;
- X char *s;
- X{
- X register block_t *bp;
- X block_t *nbp;
- X linenr_t count;
- X register int i;
- X
- X if (s == NULL) /* don't insert NULL pointers! */
- X return FALSE;
- X if (after == 0) /* insert in front of first line */
- X {
- X bp = first_block;
- X count = 1;
- X if (bufempty()) /* simply replace dummy line */
- X {
- X free_line(bp->b_ptr[0]);
- X bp->b_ptr[0] = s;
- X return TRUE;
- X }
- X curr_count = 0; /* curr_block will become invalid */
- X }
- X else
- X {
- X (void)nr2ptr(after); /* find block */
- X bp = curr_block;
- X count = curr_count;
- X }
- X
- X ++line_count;
- X i = bp->b_count;
- X if (i < BLOCK_SIZE) /* there is place in the current block */
- X/* move ptrs one place forward to make space for new one */
- X {
- X register char **pp;
- X register char *fp;
- X
- X pp = &(bp->b_ptr[i]);
- X fp = &(bp->b_flags[i]);
- X for (i += count - after - 1; --i >= 0; --pp, --fp)
- X {
- X *pp = *(pp - 1);
- X *fp = *(fp - 1);
- X }
- X *pp = s;
- X *fp = 0;
- X ++bp->b_count;
- X return TRUE;
- X }
- X
- X/* need to allocate a new block */
- X nbp = alloc_block();
- X if (nbp == NULL)
- X {
- X --line_count;
- X free_line(s);
- X return FALSE;
- X }
- X
- X/* put new block in linked list */
- X if (after == 0) /* put new block in front of linked list */
- X {
- X bp->b_prev = nbp;
- X nbp->b_next = bp;
- X first_block = nbp;
- X nbp->b_ptr[0] = s;
- X nbp->b_count = 1;
- X return TRUE;
- X }
- X
- X /* insert new block in linked list after bp */
- X nbp->b_next = bp->b_next;
- X bp->b_next = nbp;
- X nbp->b_prev = bp;
- X if (nbp->b_next == NULL)
- X last_block = nbp;
- X else
- X nbp->b_next->b_prev = nbp;
- X
- X if (after - count + 1 == BLOCK_SIZE) /* put s in new block */
- X {
- X nbp->b_ptr[0] = s;
- X nbp->b_count = 1;
- X return TRUE;
- X }
- X
- X /* move some ptrs from full block to new block */
- X {
- X register int j = 0;
- X
- X bp->b_count = after - count + 1; /* number of ptrs remaining */
- X i = BLOCK_SIZE - bp->b_count; /* number of ptrs to be moved */
- X nbp->b_count = i;
- X while (--i >= 0)
- X {
- X j = bp->b_count + i;
- X nbp->b_ptr[i] = bp->b_ptr[j];
- X nbp->b_flags[i] = bp->b_flags[j];
- X }
- X bp->b_ptr[j] = s;
- X bp->b_flags[j] = 0;
- X ++bp->b_count;
- X return TRUE;
- X }
- X}
- X
- X/*
- X * delsline: delete line from storage
- X *
- X * the line is turned over to the caller
- X */
- X char *
- Xdelsline(nr, delmarks)
- X linenr_t nr;
- X int delmarks;
- X{
- X char *ptr;
- X register block_t *bp;
- X register char **pp;
- X register char *fp;
- X register int i;
- X
- X if (nr < 1 || nr > line_count)
- X {
- X emsg("delsline: nr wrong");
- X return (alloc_line(0));
- X }
- X ptr = nr2ptr(nr);
- X if (delmarks)
- X adjustmark(ptr, NULL); /* remove marks for this line */
- X bp = curr_block;
- X if (line_count == 1) /* don't delete the last line in the file */
- X {
- X bp->b_ptr[0] = alloc_line(0);
- X return (ptr);
- X }
- X --line_count;
- X
- X /* move the rest of the ptrs in this block one down */
- X pp = &(bp->b_ptr[nr - curr_count]);
- X fp = &(bp->b_flags[nr - curr_count]);
- X for (i = bp->b_count + curr_count - nr - 1; --i >= 0; ++pp, ++fp)
- X {
- X *pp = *(pp + 1);
- X *fp = *(fp + 1);
- X }
- X if (--bp->b_count == 0) /* the block became empty, remove it from the list */
- X {
- X if (bp->b_prev == NULL)
- X first_block = bp->b_next;
- X else
- X bp->b_prev->b_next = bp->b_next;
- X if (bp->b_next == NULL)
- X last_block = bp->b_prev;
- X else
- X bp->b_next->b_prev = bp->b_prev;
- X free_line((char *)bp);
- X curr_count = 0; /* curr_block invalid */
- X }
- X return (ptr);
- X}
- X
- X/*
- X * replace the line "lnum" with the line "new".
- X * return the old line (which should be freed by the caller)
- X */
- X char *
- Xreplaceline(lnum, new)
- X linenr_t lnum;
- X char *new;
- X{
- X char *old;
- X
- X old = nr2ptr(lnum);
- X if (new == NULL || curr_count == 0) /* we don't want NULL pointers in the list */
- X return (alloc_line(0)); /* be friendly to the caller */
- X
- X curr_block->b_ptr[lnum - curr_count] = new;
- X curr_block->b_flags[lnum - curr_count] = 0;
- X adjustmark(old, new);
- X return (old);
- X}
- X
- X/*
- X * canincrease(n) - returns TRUE if the current line can be increased 'n'
- X * bytes
- X *
- X * This routine returns immediately if the requested space is available. If not,
- X * it attempts to allocate the space and adjust the data structures
- X * accordingly. If everything fails it returns FALSE.
- X */
- X int
- Xcanincrease(n)
- X int n;
- X{
- X register char *old;
- X register char *new; /* pointer to new space */
- X register unsigned newsize;
- X
- X old = nr2ptr(Curpos.lnum);
- X newsize = strlen(old) + n;
- X
- X new = alloc_line(newsize);
- X if (new == NULL)
- X return FALSE;
- X
- X strcpy(new, old);
- X adjustmark(old, new);
- X free_line(old);
- X curr_block->b_ptr[Curpos.lnum - curr_count] = new;
- X curr_block->b_flags[Curpos.lnum - curr_count] = 0;
- X
- X return TRUE;
- X}
- END_OF_FILE
- if test 19504 -ne `wc -c <'vim/src/storage.c'`; then
- echo shar: \"'vim/src/storage.c'\" unpacked with wrong size!
- fi
- # end of 'vim/src/storage.c'
- fi
- echo shar: End of archive 11 \(of 23\).
- cp /dev/null ark11isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 23 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still need to unpack the following archives:
- echo " " ${MISSING}
- fi
- ## End of shell archive.
- exit 0
- -------------8<----------------8<----------------8<---------------8<--------
- Bram Moolenaar | DISCLAIMER: This note does not
- Oce Nederland B.V., Research & Development | necessarily represent the position
- p.o. box 101, 5900 MA Venlo | of Oce-Nederland B.V. Therefore
- The Netherlands phone +31 77 594077 | no liability or responsibility for
- UUCP: mool@oce.nl fax +31 77 595450 | whatever will be accepted.
-
- exit 0 # Just in case...
-