cancel
Showing results for 
Search instead for 
Did you mean: 
cancel
Showing results for 
Search instead for 
Did you mean: 

Buffers

nick_raphael
1-Newbie

Buffers

Greetings:

This is my first post to this list. Please answer me directly as well as to
the list, as I only get the digest, and this is somewhat urgent.

Thank you. Here is my question:

How do I get the contents of the paste buffer into a variable for
examination and manipulation, or how would I directly modify its contents?

I need to change certain attributes and values. Next, should I process the
contents just as a string, or does it make sense to parse the string to
build a document fragment. Note that I cannot always guarantee a single
root node.

Thanks for any advice you can give me.

Sincerely,

Nick
6 REPLIES 6


Nick,

There are numerous functions that you can use to work with buffers. As I
am not sure how long you've been "lurking" :), I'll explain the help
numbers just in case. From the command line, if you type in the command
help followed by a number (several to follow), you will be taken to the
corresponding help topic. You can find these numbers by placing the mouse
pointer over the help (not the topics) window, right clicking and selecting
properties. The help number is the string that says help###.html. Just
use the number for the topic.

Anyway, you can create a named buffer (help 97-1) that you can use in other
buffer commands/functions. To assign a buffer value to a variable take a
look at the insert_string (help 9014-1) function. The next line is from
one of my old early ACL attempts, but you can see what it should (sic) look
like ("is" is short for insert_string).

is -buffer asgnids "$idnum"

Just don't forget to create the buffer you want to use (which I believe
you've already done).

I'd also look at the insert_buffer (help 664-1) regarding what tagging will
or will not be evaluated.

Rather rushed and cryptic, but I hope this helps a bit.

Lynn

You can manipulate buffer contents by using the write command. Type
"help 9061" on the Epic command line and see the parts about the -paste
and -buffer arguments for the write command.

Hi Nick,

I'm afraid I can't really see a straight and simple answer to your question,
so I'm sending a little information that I gathered while I was resolving
the problem of how to manipulate the contents of paste buffers in Epic.
It's perhaps a more narrative and descriptive response than you were
expecting, but that's because I think you might need to develop your own
solution based on what you find out can be done, so I've provided a little
more background than I would usually.

>From your e-mail, I assume that you're talking about the default paste
buffer (which is also generally the system clipboard) rather than a named
buffer which was created in Epic (the process is slightly simpler for named
paste buffers). The main consideration of working with the default paste
buffer is that the contents have not necessarily been copied from within
Epic. I worked on a solution for this problem for quite some time and I ran
into various minor problems until I eventually decided to split the code
based on whether or not the buffer had been copied in Epic or in an external
application. You can use the buffer_is_clipboard function to find out
whether the last paste operation was conducted in Epic or not. If the text
in the default buffer comes from outside of Epic, then I use the following
code to return its contents as a string:
#
function getClipboardContents() {
# This function returns the contents of the clipboard as a string.
local $doc = doc_open('',0x100);
local savedoc = current_doc($doc);
local savecaret = oid_caret()
local savepos = oid_caret_pos()
paste;
clear_mark
goto_oid( oid_null() )
mark -noinvert -noselection begin
goto_oid( oid_null(), -1 )
mark end
local s = main::selection
doc_close($doc);
goto_oid( savecaret, savepos )
current_doc(savedoc)
return s
}

If the text in the default paste buffer was copied out of Epic
(buffer_is_clipboard returns false) then I don't use the function above
because I found that it was vulnerable to certain user settings and I didn't
want to have to set and restore all of the settings that could possibly
cause a problem. Instead I used to use the following function:
#
function getBufferDocContents() {
# This function returns the contents of the default paste buffer. It
cycles through all the
# possible values of doc ids and returns the id for the clipboard (default
buffer) if found.
local y, output;
# Set an arbitrary limit of 1000 to the possible values of doc id.
for (y=-1;y<1000;y++) {
if (doc_valid(y)) {
if (doc_name(y) == 'default') {
# This is the clipboard's id.
local savedoc = current_doc(y)
local savecaret = oid_caret()
local savepos = oid_caret_pos()
clear_mark
goto_oid( oid_null() )
mark -noinvert -noselection begin
goto_oid( oid_null(), -1 )
mark end
local s = main::selection
goto_oid( savecaret, savepos )
current_doc(savedoc)
return s
}
}
}
# No default paste buffer could be found: the clipboard contents could not
be returned, so
# we return the null string.
return '';
}

The function above unfortunately has certain problems, for instance it
sometimes doesn't include closing tags. I included the code for it though
because it can be used to return an ID for the document that represents the
default paste buffer which may be useful to you if you want to manipulate
the paste buffer as a document.

I eventually decided to change to the following method which I find to be
very effective, though it may not be possible in your environment. Rather
than figuring out what the contents of the default paste buffer are after
the text has been copied, I decided it would be easier to simply copy the
contents of the buffer to a string variable at the same time as they were
copied. To do this, I decided to declare a global variable to house the
contents of the buffer and then to just create a function that would copy
the selection into this variable whenever text was cut or copied. At first
I tried to add this function as a copy and cut callback, but unfortunately I
found that these callbacks are sometimes fired by certain other Epic
functions (like the oid_select function and the mark command). The final
solution that I adopted was simply to create the following function:
# gstrClipboard is the name of the global variable that we use to house the
contents of the clipboard
function storeCopiedMarkup(cut, append) {
# If the cut parameter is set to one, then the function needs to cut (copy
and delete) the text;
# if the cut parameter is off, then the function simply copies the text.
# If the append parameter is on, then the function appends instead of
overwriting (obviously).
if ($cut) {
if ($append) {
$selectedText = selection_markup();
delete_mark;
$gstrClipboard .= $selectedText;
} else {
$selectedText = selection_markup();
delete_mark;
$gstrClipboard = $selectedText;
}
} else {
if ($append) {
$gstrClipboard .= selection_markup();
copy_mark -append -noclm
} else {
$gstrClipboard = selection_markup();
copy_mark -noclm;
}
}
}

Keeping things simple, I simply remapped the various Copy and Cut shortcuts
(keys, Edit menu, and toolbar buttons) to this function with the appropriate
parameters. In this way, I can always calculate the contents of the default
paste buffer by the following method:
$strPasteBuffer =
buffer_is_clipboard()?getClipboardContents():$gstrClipboard;

>Next, should I process the
> contents just as a string, or does it make sense to parse the string to
> build a document fragment. Note that I cannot always guarantee a single
> root node.
Unfortunately I think that it will entirely depend on what you're trying to
do. In my experience, if you have some fairly complicated manipulations to
do or if you use repeating attribute names or a recursive content model then
the best thing to do is to create a named paste buffer and insert the
contents of the string you want to manipulate into this new buffer. If you
save the docID of this buffer when you create it then you can use all of the
document manipulation functions that are part of ACL (including the XPath
and oid functions) in order to make any changes that you need to the
document. Also, since you mentioned the possibility of multiple root nodes,
then it might be worth knowing that you can use the Epic "Well-formed XML"
DTD as the document type of the named buffer when you create it - that way
you have maximum flexibility in the new buffer. Once you've manipulated the
contents of your buffer as necessary, you can paste them back into your
document simply by using the paste command with the name of the buffer you
created. Once again, I'm sorry I can't provide more specific exmaples, but
of course it entirely depends on what you're trying to do. If you just want
to globally switch some attribute names and values, then it might be better
simply to use the string parsing ACL functions (like gsub and match) on the
contents of the buffer and then insert the altered buffer back into the
default paste buffer with the insert_buffer function.

Cheers,

Dugald Topshee

Hi Lynn--

Maybe I misunderstood the question, but I think your code does the opposite of what Nick wants. Your code (unless I'm reading it wrong) puts the value of a variable *into* a buffer, but I think Nick is trying to get the value *from* the buffer so he can massage it before it gets pasted.

I had a similar problem, which I solved by invoking Java (via Javascript!) to get the clipboard contents as a string. It's kind of awkward, I admit, but no more so than using ACL to create a new phantom document and pasting into it as Dugald recommends. 🙂

--Clay


Hi Dugald:

Thanks again for your help. I have a follow-up question.

In digging around in Epic's own packages, I came across the _buffer
package, which includes a function buffer_content. Are you familiar with
that?

I have not been able to pass use it entirely successfully, however, as I
can't seem to figure out how to pass in the default paste buffer.

Of course, it is probably best, also, not to avail oneself of Epic's
private utilities, which are probably subject to change.

Thanks,

Nick

I am familiar with the buffer_content function, I find it's really useful to
poke around in the packages folder because there is a lot of good code in
there. However like yourself, I'm reluctant simply to call in any code from
there since you never know if they will change it in an upcoming release.
When I use a function from _buffer, _doc, _array or one of the other Epic
packages, I always rewrite the function definition in my own code with a new
name just to be safe.

As for the buffer_content function, I have tried to use it with the default
paste buffer but I found that it wasn't all that useful in the end. I think
that behind the scenes, Epic plays around a little bit with the default
paste buffer in a way that's inaccessible programmatically. I only say that
because I know that all the other paste buffers are associated with a
particular DTD or are treated as plain text. For the default paste buffer,
Epic seems to treat it in a slightly different way (to be slightly more
specific, I suspect that Epic stores information about the markup within the
default paste buffer differently from how it stores information about markup
in other buffers). I don't really know of course, I'm just speculating.
What I do know is that I found that the doc_content function (called by
buffer_content) doesn't behave consistently with the default paste buffer.
If you want to try it out though, you can do what I did which is to bypass
the buffer_content function and go straight to doc_content (since all
buffer_content does is call doc_content on the right buffer) passing it the
docID of the default paste buffer. My rather clumsy way to get the docID of
the default paste buffer is just to cycle through an arbitrary number of
integers, call doc_name() on each one and, when you get to one called
'default', then use that docID as the parameter for doc_content.

BTW, you'll find doc_content, along with some other interesting bits of
code, in _doc in the main subfolder of packages.

Good luck,

Dugald
Announcements