May 08, 2024, 03:04:25 PM

News:

Own IWBasic 2.x ? -----> Get your free upgrade to 3.x now.........


How to insert a NULL into a string

Started by Pip1957, January 22, 2007, 06:10:14 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Pip1957

I am using SHFileOperation to copy some files, on single files all works ok you pass a pointer to the string containing the file and full path.
To copy more than one file in one call to the function you delimit each filepath in the string with a NULL character but I get an error cannot read source fiile
example String: Source="C:\\Test1.txt"+chr$(0)+chr$(0) Works Ok
example multi-file String: Source="C:\\Test1.txt"+chr$(0)+"C:\\Test2.txt"+chr$(0)+chr$(0) error cannot read source fiile
Is this the right way to insert a Null into a string.

sapero

Try with inline nulls :
c:\\file1.ext\x00c:\\file2.txt\x00c:\\file3.ext\x00
The last \x00 is required to ensure that the string is terminated with two nulls; second null is automatically added by the compiler.

In your example, chr$(0) works like empty string, so the second string is appended to the first one, and the result is "C:\\Test1.txtC:\\Test2.txt"

Pip1957

Does not give any error but only copies first file in list

' // Shell File Operations
' const for wFunc
CONST FO_MOVE = 0x1
CONST FO_COPY = 0x2
CONST FO_DELETE = 0x3
CONST FO_RENAME = 0x4
' constants for fFlags
CONST FOF_MULTIDESTFILES = 0x1
CONST FOF_CONFIRMMOUSE = 0x2
CONST FOF_SILENT = 0x4 :rem don't create progress/report
CONST FOF_RENAMEONCOLLISION = 0x8
CONST FOF_NOCONFIRMATION = 0x10             :rem Don't prompt the user.
CONST FOF_WANTMAPPINGHANDLE = 0x20          :rem Fill in SHFILEOPSTRUCT.hNameMappings  Must be freed using SHFreeNameMappings
CONST FOF_ALLOWUNDO = 0x40 :rem Uses Recycle bin for deletion if set
CONST FOF_FILESONLY = 0x80                  :rem on *.*, do only files
CONST FOF_SIMPLEPROGRESS = 0x100            :rem means don't show names of files
CONST FOF_NOCONFIRMMKDIR = 0x200            :rem don't confirm making any needed dirs

TYPE SHFILEOPSTRUCT
DEF hwnd AS INT
DEF wFunc AS INT
DEF pFrom AS pointer
DEF pTo AS pointer
DEF fFlags AS WORD
DEF fAnyOperationsAborted AS INT
DEF hNameMappings AS INT
DEF lpszProgressTitle AS POINTER :'  only used if FOF_SIMPLEPROGRESS
ENDTYPE

DECLARE IMPORT, _SHFileOperation ALIAS SHFileOperationA(lpFileOp AS SHFILEOPSTRUCT),INT
' pointers for source and destination
def s,d:pointer
' strings for source and destination
def source,destination as string

' Source string use path to your sources here
source="C:\\test.mpg\x00C:\\test2.mpg\x00c:\\test.avi\x00"

' Destination string use path to your destination here
destination="d:\\\x00"

' Pointer to Source string
s=source

' Pointer to Destination string
d=destination

' define our structure
def SHFileOp:SHFILEOPSTRUCT

' Fill in our structure for copy function
SHFileOp.wFunc=FO_COPY :'copyfile
SHFileOp.pFrom=s :' pointer for source
SHFileOp.pTo=d :' pointer for destination

' call function
_SHFileOperation(SHFileOp)

'delete pointers
delete s
delete d
end

Ionic Wind Support Team

Some bad stuff in there ;)

You shouldn't be deleting the pointers.  Just because they are pointers doesn't qualify them for a DELETE operation.   It is only when you are using NEW.  You don't need those pointers anyway.

Strings in Emergence are NULL terminated so trying to copy the string will only copy up to the first NULL.  So  you have a few choices.  The easiest method is just a substition of another character, and a loop before the function is called.



STRING src,dst
src = "C:\\Test1.txt|C:\\Test2.txt|"
dst = "D:\\|"

for i = 0 to len(src)
   if src[i] = '|' THEN src[i] = 0
next i

for i = 0 to len(dst)
   if dst[i] = '|' THEN dst[i] = 0
next i

' define our structure
def SHFileOp:SHFILEOPSTRUCT

' Fill in our structure for copy function
SHFileOp.wFunc=FO_COPY :'copyfile
SHFileOp.pFrom=src :' pointer for source
SHFileOp.pTo=dest :' pointer for destination
...


Since the strings are already NULL terminated only one | is needed at the end, which gives you two terminating nulls after the loop.

Paul.
Ionic Wind Support Team

Pip1957

Used your code paul and just get error cannot copy file: Cannot read from source file or disk

Ionic Wind Support Team

Do you have a test1.txt and test2.txt file in the root directory?

Just typed the code out of my head, so it may need tweaking.  Can't test it at the moment as I am working in Linux.  But have used the same technique many times before.  FILEREQUEST uses it for substituing the | character in the extensions string.

Paul.
Ionic Wind Support Team

Ionic Wind Support Team

Try it this way ;)


src = "C:\\Test1.txt|C:\\Test2.txt|"
dst = "D:\\|"

ln = len(src)
for i = 0 to ln
   if src[i] = '|' THEN src[i] = 0
next i

ln = len(dst)
for i = 0 to ln
   if dst[i] = '|' THEN dst[i] = 0
next i


Ionic Wind Support Team

Pip1957

The substitution works ok because if I print the string it just prints the first filename upto the null

Ionic Wind Support Team

Yes, however, that would have been the case in my first snippet as well.  The second snippet gets the length of the string before the loop since substituting the | for a NULL will change the value returned bye LEN.

Which is why I posted again ;)
Ionic Wind Support Team

Pip1957

Thank you Paul second version works a treat thank you very much ::)

Parker

I wasn't aware you could use single quotes in EB, it does work?

Ionic Wind Support Team

No, but again it was off the top of my head and he understood ;)
Ionic Wind Support Team

JoaoAfonso

Hmm... But if I really want to set a string into NULL, how can I do it? In my program I tried the chr$(0) and worked as intended, but as I learn after reading this post, it is not a true null.
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900

barry

I can't speak specifically about EBasic but my guess is that this applies:  traditionally the problem with 0 terminated strings is that they can't contain binary 0s.  Some languages offer other counted strings; strings that begin with a length count, as an alternative since they can contain 0s but they have the drawback of limited length and that in a lot of cases dealing with them is slower.  Some languages offer both types of strings.

But in general the answer to how to include a true 0 in a 0 terminated string is that you can't, by definition.  The string consists of those characters preceding the 0.

Traditional Basics used counted strings or fixed length strigs.  Ebasic doesn't, I guess, partly because it's written in C, which uses 0 terminated strings, and partly because it's efficent and probably mostly because that's what Paul chose to do.  It's probably faster this way for most things and it's rarely a problem once you get used to it.

When I've had to deal with something that could contain a 0 in C in the past I've (usually) used some untyped memory and a pointer to it instead of making it a string.  I haven't done anything in Ebasic that's required that so I'm not sure how I'd deal with it in Ebasic.

Barry

Ionic Wind Support Team

It's not too hard.   Remember a string can be accessed as a character array

str = "put a null here >|< passed the null"
pos = instr(str, "|")
str[pos-1] = NULL

Generally I just use a pointer to a string, and derference it as a character, replacing | with nulls before sending it to archaic windows API functions that don't know how to handle string arrays ;)


string temp
pointer p
str   = "file1.txt|file2.txt|file3.txt||"
temp = str
p = temp
while #<char>p <> 0
   if #<char>p = ASC("|") then #<char>p = 0
   p++
endwhile
SomeAPIFunction(temp)


As long as you immediately pass the string to the API function that expects embedded nulls then you are fine, if you try to copy the resulting string to another string it will only copy up to the first embedded NULL.  I used the temp string just because it could be a reusable section of code.

Paul

Ionic Wind Support Team

JoaoAfonso

Thanks for the information. Was more easy if string=NULL could be understud by EB :P
JoÃÆ'ƒÂÃ,£o Afonso
Viriato
-----------------
Iberia MUD
www.iberiamud.com
iberiamud.com:5900