Using shell

New to FreeBASIC? Post your questions here.
Post Reply
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Using shell

Post by newbieforever »

Another newbie question:

A DOS batch command like this works perfectly:

Code: Select all

echo Hello > "Сергeй Сергeевич.txt"
Is it impossible to do the same via shell?*

Code: Select all

dim as wstring * 100 fi = """Сергeй Сергeевич.txt"""
'dim as wstring * 100 fi = """Hans Peter.txt"""
dim as wstring * 100 te = "Hello"
dim as wstring * 100 st

st = "echo " & te & " > " & fi     
shell st
No file is created...
(Hans Peter would work!)

* I mean here shell, not other possible methods.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Using shell

Post by jj2007 »

Code: Select all

Inkey Launch$(Cat$("cmd.exe /C chcp 65001 & echo Добро пожаловать ... it works "+Chr$(62)+" Добро.txt"))
This works, but it's not FreeBasic. I tried the same with FB:

Code: Select all

Dim s As String
shell("chcp 65001")
s="cmd.exe /C echo Добро пожаловать > Добро.txt"
print s
shell(s)
Sleep()
... but apparently FB doesn't use the correct encoding. Any help from the experts?
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Using shell

Post by newbieforever »

A simplified testing code:

Code: Select all

' DOS batch command works:
' echo Hello > "Сергeй.txt"
' The file is created.

dim as wstring * 4 DQ = wchr(34)
   
shell "echo Hello > " & DQ & "Сергeй.txt" & DQ

Print "echo Hello > " & DQ & "Сергeй.txt" & DQ
' Print shows that shell sends to cmd:
' echo Hello > "Сергeй.txt".
' But no file is created. Error message:
' "The syntax for file name, directory name, or volume label is incorrect."

' This works:
shell "echo Hello > " & DQ & "Sergej.txt" & DQ
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Using shell

Post by caseih »

SHELL takes a normal string as a parameter and calls the C runtime system() function, which is the ANSI version. So passing any WSTRING or unicode literal to SHELL is going to get converted to ANSI (whatever 8-bit character set your Windows is set to use).

What you probably want to do is directly use the Win32 API, or use Microsoft's non-standard _wshell() call in the C runtime.

On operating systems that are natively UTF-8 such as Linux and Mac, the FB SYSTEM should work fine with unicode literals since they'll be UTF-8. And in fact your example code runs fine on my Linux machine. This is because the source code file with the string literal is UTF-8 encoded, so the string literals are just taken, well, literally, so they become normal STRINGs with UTF-8 bytes in them. This is one big advantage of UTF-8 over UTF-16.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Using shell

Post by dodicat »

Does this work?
Cannot test on this box, the second console window is broken.

Code: Select all

#include "crt.bi"
#include "file.bi"

sub far(s as wstring,f as wstring,r as wstring) 'find and replace
    for n as long=0 to len(s)-1
  if s[n]=f then s[n]=r
next
end sub

'extract from another post

sub save overload(filename as wstring,content as wstring)
     dim as wstring * 10 tempname="VT.txt"
     Dim As Long n=Freefile
    Open tempname For Output Encoding "utf16" As #n
    Print #n,content
    Close #n
    _wrename(@tempname,@filename)
    if fileexists(tempname) then kill tempname
end sub

sub load overload(filename as wstring, text as string)
     dim as wstring * 10 tempname="VT.txt"
     _wrename(@filename,@tempname)
   var  f=freefile
    Open tempname For Binary Access Read As #f
    If Lof(1) > 0 Then
      text = String(Lof(f), 0)
      Get #f, , text
    End If
    Close #f
     _wrename(@tempname,@filename)
     if fileexists(tempname) then kill tempname
end sub



dim as wstring * 200 s="echo Hello * "+ chr(34)+"Сергeй Сергeевич.txt" +chr(34)'+ "> tmp.bat"
print s
shell "echo " + s + "> tmp.bat"
dim as wstring * 200 f
load ("tmp.bat",s)

far(s,"*",">")

save("tmp2.bat",s)
shell "type tmp2.bat"
shell " tmp2.bat"
kill "tmp.bat"
kill "tmp2.bat"




sleep  
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Using shell

Post by jj2007 »

caseih wrote:SHELL takes a normal string as a parameter and calls the C runtime system() function, which is the ANSI version. So passing any WSTRING or unicode literal to SHELL is going to get converted to ANSI (whatever 8-bit character set your Windows is set to use).
I wish FB would do that; but apparently, even a perfectly valid 8-bit character set like "UTF-8" is being garbled:

Code: Select all

#include "Windows.bi"

Function Utf8String(src as wstring) as String
  Dim As integer slen=Len(src)
  Dim As String sret=String(slen*2, 0)
  slen=WideCharToMultiByte(65001, 0, @src, -1, sret, 0, 0, 0)
  WideCharToMultiByte(65001, 0, @src, -1, sret, slen, 0, 0)
  return sret
End Function

shell("chcp 65001")
Dim ws As wString*100="cmd.exe /C echo Добро пожаловать > Добро.txt"
Dim s As String=Utf8String(ws)
' asm int 3
' asm mov eax, [s]	' this is a perfectly valid UTF-8 string!
print s
shell(s)
Sleep()
Neither print nor shell use this string "as is".
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Using shell

Post by newbieforever »

Just a footnote:
@dodicat: I think the line shell " tmp2.bat" must fail because your tmp2.bat is a unicode file; bat must be ansi...
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Using shell

Post by dodicat »

indeed.
copy and paste directly to a shell window runs OK (AS YOU HAVE SAID)
Funny that dos commands handle unicode, but not via a file (batch)
What about powershell?
I'll try later.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Using shell

Post by Josep Roca »

This works:

Code: Select all

#define unicode
#include once "windows.bi"
#include once "win/shellapi.bi"

'ShellExecuteW(0, "open", "cmd.exe", "/u /c echo Добро пожаловать > Добро.txt", 0, SW_HIDE)
ShellExecuteW(0, "open", "cmd.exe", "/u /c echo Добро пожаловать > ""Сергeй Сергeевич.txt""", 0, SW_HIDE)
newbieforever
Posts: 117
Joined: Jun 21, 2018 11:14

Re: Using shell

Post by newbieforever »

@Josep Roca: YES, THIS WORKS, HALLELUJAH!
caseih
Posts: 2157
Joined: Feb 26, 2007 5:32

Re: Using shell

Post by caseih »

jj2007 wrote:I wish FB would do that; but apparently, even a perfectly valid 8-bit character set like "UTF-8" is being garbled:
Hmm wonder what's going on here. The code works fine on Linux with UTF-8 being passed straight through.
Neither print nor shell use this string "as is".
They do on Linux, and I presume Mac. On Windows there must be something else going on. In any case the Win32 API is the way to go, although it's definitely not portable.
Josep Roca
Posts: 564
Joined: Sep 27, 2016 18:20
Location: Valencia, Spain

Re: Using shell

Post by Josep Roca »

Windows does not speak utf-8 but utf-16.
jj2007
Posts: 2326
Joined: Oct 23, 2016 15:28
Location: Roma, Italia
Contact:

Re: Using shell

Post by jj2007 »

Right, but the console can print UTF-8.
dodicat
Posts: 7983
Joined: Jan 10, 2006 20:30
Location: Scotland

Re: Using shell

Post by dodicat »

Using the c runtime again

Code: Select all



declare function wsystem_ cdecl alias "_wsystem" (byval as wstring ptr) as long


print "echo Hello everybody > " + chr(34)+"Сергeй Сергeевич.txt" + chr(34)

wsystem_("echo Hello everybody > " + chr(34)+"Сергeй Сергeевич.txt" + chr(34))
sleep
  
Note: wsystem is not in crt.bi, but it is in msvcrt.dll.
So I had to declare.
Post Reply