How should I use ByVal in VBScript functions? - asp-classic

I am running into a bit of a problem with ByVal in VBScript. Here's a quick sample script that I wrote to illustrate the issue:
<%
Option Explicit
dim PublicDict
Set PublicDict = createobject("Scripting.Dictionary")
PublicDict.Add "MyKey", "What's up doc?"
response.write OutputStringFromDictionary( PublicDict ) & "<br />"
response.write PublicDict("MyKey")
Set PublicDict = nothing
Function OutputStringFromDictionary( ByVal DictionaryParameter )
DictionaryParameter("MyKey") = replace(DictionaryParameter("MyKey"), "'", "''")
OutputStringFromDictionary = DictionaryParameter("MyKey")
end Function
%>
This script outputs these lines to the browser:
What''s up doc?
What''s up doc?
I was hoping to get:
What''s up doc?
What's up doc?
How do I make it so that OutputStringFromDictionary doesn't modify the original dictionary?

You'd have to clone the actual data somehow. Passing the dictionary by value prevents the dictionary itself from being modified, but you still have pointers to the same items that the dictionary references. You can't modify the dictionary, but you can modify the items it contains.

Related

How to insert a " into sqlite3 text

I want to insert a string ,like Hello ,I am "Tmacy"!,into a sqlite3 table.But I can't find a way to insert the ".(ps.I tried to use \" instead of ", but it doesn't word.). Note:I use the C/C++ API function sqlite3_exec to insert the string into sqlite table.If you insert it with the sqlite3 command , it may works .
like that:
sprintf(sqlcmd,"insert into dict values('%s','%s')",word,meaning);
if(sqlite3_exec(data,sqlcmd,NULL,NULL,&errmsg) != SQLITE_OK){
printf("insert error!:%s\n",errmsg);
}else{
printf("insert success!\n");
}
Thanks!
The sqlite3_mprintf function has formats like %Q that allow you to format strings correctly:
char *sql = sqlite3_mprintf("INSERT INTO dict VALUES(%Q,%Q)", word, meaning);
err = sqlite3_exec(data, sql, NULL, NULL, &errmsg);
sqlite3_free(sql);
Try repeating the quote instead of escaping it :-
http://www.sqlite.org/faq.html#q14
You'd be better off using parameters here, it's safer then simply making slight changes to the text strings so that " and such don't cause a crash. Some sample code of using parameters in one of my own projects, in VB .net.
Public Sub RunSQLiteCommand(ByVal CommandText As String, Optional ByVal ReadDataCommand As Boolean = False, Optional ByVal ParameterList As Hashtable = Nothing)
SQLcommand.Parameters.Clear()
SQLcommand.CommandText = CommandText
If ParameterList IsNot Nothing Then
For Each key As String In ParameterList.Keys
SQLcommand.Parameters.Add(New SQLite.SQLiteParameter(key, ParameterList(key)))
Next
End If
SQLcommand.ExecuteNonQuery()
If ReadDataCommand Then
SQLreader = SQLcommand.ExecuteReader()
End If
End Sub
If you really want to avoid using parameters though, then "" (two of them) would be the way to go. If I'm ever not using parameters I run all string values I'm inserting into the database through a function that replaces " with "" everywhere in the string value.
Edit: Oh yeah, I almost forgot. For using parameters, your key value should be '#FieldName', and your SQL Query should say '#FieldName' wherever you use that parameter.
So for example if you call your field 'Name' that you want to insert the " in, you'd have something like this for insert query.
insert into dict values(#Name, #OtherField)
You could call your parameter anything you want, it's just easier if you name it the same thing as the field you're loading the value into.

Msaccess 2010 -base on a report on a recordsource

I have looked at a previous example of yours detailed below. However I have a problem:
Heres my code it runs off a button on a form called Reports:
Dim dbs As Database
Dim qdf As QueryDef
Dim varitem As Variant
Set dbs = CurrentDb()
Set qdf = dbs.QueryDefs("Qry_rpt_cr")
qdf.Parameters(0) = Forms!frm_reports.rmselectfilter.Column(1, varitem)
qdf.Parameters(4) = Forms!frm_reports.rmselectperiod.Column(0, 0)
qdf.Parameters(3) = Forms!frm_reports.rmselectperiod.Column(0, 1)
qdf.Parameters(2) = Forms!frm_reports.rmselectperiod.Column(0, 2)
qdf.Parameters(1) = Forms!frm_reports.rmselectperiod.Column(0, 3)
Set grst = CurrentDb.OpenRecordset("Select * from Qry_rpt_cr")
DoCmd.OpenReport "rpt_cr_test", acPreview
grst.Close
Set grst = Nothing
End Sub
The question is the query needs five parameters to be passed to it and then open the recordset using the defined parameters and then open the report. But the code does not open. Its says an error on this line Set grst = CurrentDb.OpenRecordset("Select * from Qry_rpt_cr") asking for 5 parameters but I have passed them earlier in the code. Any suggestions would be welcomed. HAppy to make a donation for a correct answer. ED
Example from your archives
From Access Web you can use the "name" property of a recordset. You resulting code would look something like this:
In the report
Private Sub Report_Open(Cancel As Integer)
Me.RecordSource = gMyRecordSet.Name
End Sub
In the calling object (module, form, etc.)
Public gMyRecordSet As Recordset
'...
Public Sub callMyReport()
'...
Set gMyRecordSet = CurrentDb.OpenRecordset("Select * " & _
"from foo " & _
"where bar='yaddah'")
DoCmd.OpenReport "myReport", acViewPreview
'...
gMyRecordSet.Close
Set gMyRecordSet = Nothing
'...
End Sub
I've not used Access for a while , but i think you are setting the params for a query, and then running a different query. Access is asking for params to be provided for the query you are asking ("select * from ..."), not the (named) query that your query references, if that makes sense.
This should be easily fixed, just run OpenRecordset from the QueryDef:
Set grst = qdf.OpenRecordSet
and then Access will include the query's params correctly.
Edit: Thx Remou

ASP.NET Replacing Line Break with HTML br not working

Hi
I am trying to submit some information into a database using an ASP.NET multiline textbox.
I have the following code:
Dim noteContent As String = Replace(txtNoteContent.InnerText.ToString(), vbCrLf, "<br />")
Shop.Job.Notes.addNote(Request.QueryString("JobID"), ddlNoteFrom.SelectedValue, ddlNoteTo.SelectedValue, noteContent)
The addNote's function code is:
Public Shared Sub addNote(ByVal JobID As Integer, ByVal NoteFrom As Integer, ByVal NoteTo As Object, ByVal NoteContent As String)
Dim newNote As New Job_Note
newNote.Date = DateTime.Now()
newNote.JobID = JobID
newNote.NoteByStaffID = NoteFrom
If Not NoteTo = Nothing Then
newNote.NoteToStaffID = CInt(NoteTo)
End If
newNote.NoteContent = NoteContent
Try
db.Job_Notes.InsertOnSubmit(newNote)
db.SubmitChanges()
Catch ex As Exception
End Try
End Sub
When it submit's the compiler does not seem to detect that line breaks have been entered into the textbox. I have debugged and stepped through the code, and sure enough, it just ignores the line breaks. If I try and replace another character instead of a line break, it works fine.
It doesn't seem to be anything to do with my function, the LINQ insert or anything like that, it simply just doesn't detect the line breaks. I have tried VbCr, and also chr(13) but they do not work either.
Can someone help me? I have been trying ad searching for over an hour trying to sort this.
Thanks
When you do your replace, you should check for VbCrLf (Windows Line Break), VbLf (Unix Line Break) and VbCr (Mac Line Break). If memory serves correct, the standard newline in a HTML textarea element is "\n" (aka VbLf), so you might just get away with replacing VbCrLf with VbLf in your code, but personally I always check for them all just to be safe.
Example
Dim htmlBreakElement As String = "<br />"
Dim noteContent As String = txtNoteContent.Text _
.Replace(vbCrLf, htmlBreakElement) _
.Replace(vbLf, htmlBreakElement) _
.Replace(vbCr, htmlBreakElement)
Shop.Job.Notes.addNote(Request.QueryString("JobID"), ddlNoteFrom.SelectedValue, ddlNoteTo.SelectedValue, noteContent)

Can a VBScript function return a dictionary?

I have a dictionary of form data that I want to modify using a function.
function queryCleanForm(myDictForm)
dim arrayKeys
arrayKeys = myDictForm.keys
for i=0 to myDictForm.count-1
myDictForm(arrayKeys(i)) = replace(myDictForm(arrayKeys(i)), "'", "''")
response.write myDictForm(arrayKeys(i))
next
queryCleanForm = myDictForm
end function
The problem is the line queryCleanForm = myDictForm errors as
Wrong number of arguments or invalid property assignment
Is there a way to do this in VBScript?
Try this:
SET queryCleanForm = myDictForm
With objects you need to use SET to tell VBScript that it is an object reference you are assigning not a value type.
Yes, you need to use the SET command:
Set queryCleanForm = myDictForm
You can also use the ByRef or ByVal values in the function. ByVal, the object you sent to a function or sub is copied into private memmory to be used inside the function and discarded after the function is completed. ByRef, the object you sent to a function is referenced to and all manipulations you make, removing keys, setting the object etc, is directly done to the object you sent.
E.g.
Sub test
DIM testDict as variant
call setdict(testDict)
testDict.Add "test", "value"
call addValue(testDict, "test2","another value")
msgbox testDict.Count
Set testDict = Nothing
End Sub
Sub setdict(ByRef in_Dict as Variant)
If Typename(in_Dict) <> "Dictionary" Then
SET in_Dict = CreateObject("Scripting.Dictionary")
end if
end sub
sub addValue(ByRef in_Obj as Variant, ByVal in_Key as String, ByVal in_Value as String)
if not in_Obj.Exists(in_Key) then
in_Obj.Add in_Key, in_Value
end if
end sub
The test sub calls with a variable of type variant to the sub setdict. In the function I validate the type of the object sent to the sub. If the object type is not a dictionary object (which it is not) then the object in_Dict which is actually the testDict object declared in the sub test, will be set to a dictionary object.
To demonstrate the reference better I also included the second sub called addvalue. I pass the object to the function again as reference and add another key to the dictionary object. In the main test sub ill then post the count. In this case there are 2 keys present.

vbscript / Classic ASP - Is there any way to get your own file name programmatically?

I was just reviewing some old code and found the following (inside foo.asp):
Const ASP_FILENAME = "foo.asp" ' TODO: Update this to the name of this file (if changed)
The variable is only used for logging errors. (ie. "Error in foo.asp - Could not create xxxxx object.") Is there any way to avoid this?
Thanks!
You could parse Request.ServerVariables("url") to get the filename portion. A google search found this code, to which i don't claim credit, which uses the SCRIPT_NAME server variable which seems to make more sense indeed, also taking any url rewriting in to account that might be in place:
function getFileName(fpath, returnExtension)
tmp = fpath
if instrRev(tmp,"/") > 0 then
tmp = mid(tmp, instrRev(tmp,"/")+1)
end if
if returnExtension = false then
if instrRev(tmp,".") > 0 then
tmp = left(tmp, instrRev(tmp,".")-1)
end if
end if
getFileName = tmp
end function
filename = request.ServerVariables("SCRIPT_NAME")
Const ASP_FILENAME = getFileName(filename, true)
From the now-defunct Aspfaq.com (thanks to Archive.org):
How do I get the name of the current URL / page?
This one is pretty easy, but there are two parts.
To retrieve the name of the current file, you can use any of these:
<%
Response.Write Request.ServerVariables("SCRIPT_NAME") & "<br>"
Response.Write Request.ServerVariables("PATH_INFO") & "<br>"
Response.Write Request.ServerVariables("URL") & "<br>"
%>
To make that path local (for example, to use with FileSystemObject), just apply the server.mappath() method to the result.
To get the entire URL, including the http:// or https:// prefix, you can do this:
<%
prot = "http"
https = lcase(request.ServerVariables("HTTPS"))
if https <> "off" then prot = "https"
domainname = Request.ServerVariables("SERVER_NAME")
filename = Request.ServerVariables("SCRIPT_NAME")
querystring = Request.ServerVariables("QUERY_STRING")
response.write prot & "://" & domainname & filename & "?" & querystring
%>
To get the page name ONLY, use something like this:
<%
scr = Request.ServerVariables("SCRIPT_NAME") & "<br>"
if instr(scr,"/")>0 then
scr = right(scr, len(scr) - instrRev(scr,"/"))
end if
response.write scr
%>
Or, without the IF logic:
<%
scr = Request.ServerVariables("SCRIPT_NAME") & "<br>"
loc = instrRev(scr,"/")
scr = mid(scr, loc+1, len(scr) - loc)
response.write scr
%>
Now. If your file is an #INCLUDE within another file, the above scripts will produce the name of the CALLING file (since the included file is first integrated into the calling script, then the ASP within it is all executed in the context of the 'parent' file). One way you can work around this is to re-populate a current_filename variable before loading each include file, for example:
<%
current_filename = "filetoinclude.asp"
%>
<!--#include file='filetoinclude.asp'-->
(And no, don't try passing current_filename as a variable to the #INCLUDE directive; see Article #2042.)
Then, in filetoinclude.asp:
<%
Response.Write "Current file: " & current_filename
%>
Of course, you could just as easily hard-code the filename inside of each include file. But I suppose that solution would somewhat defeat the purpose of retrieving that information at least somewhat dynamically.
I dont know if server.mappath exists on traditional asp, but if so you could use if to know the page filename.
Not saying that anyone here [insert discrete throat clearing cough here] still uses Classic ASP for maintaining and supporting legacy applications, but I recently had the need to do something similar. Refusing to settle for the "it's impossible with Classic ASP" responses out there, I set out to find a way and came up with the following solution.
This approach basically leverages underlying OS commands to literally determine the current filename (whose result is equivalent to using the __FILE__ magic constant in PHP) regardless of whether it's a file include (*.inc) or the script itself (*.asp).
First, to support some sanitization (you can do this some other more "optimal" way if you wish):
'Regex helpers
Function NewRegex(ByVal pattern, ByVal ignore_case, ByVal global)
Set NewRegex = New RegExp
NewRegex.Pattern = pattern
NewRegex.IgnoreCase = ignore_case
NewRegex.Global = global
End Function
Function RegexMatch(ByVal pattern, ByVal subject)
RegexMatch = RegexMatches(subject, pattern, True, False)
End Function
Function RegexMatches(ByVal subject, ByVal pattern, ByVal ignore_case, ByVal global)
RegexMatches = NewRegex(pattern, ignore_case, global).Test(subject)
End Function
And now for a time of "reflection:"
Function GetCurrentFilename(ByVal uniqueId)
'1. Enforce uniqueId format
If Not RegexMatch("^[0-9a-f]+$", uniqueId) Then
Exit Function
End If
'2. Use findstr to scan "readable" files in current directory for uniqueId
Dim shell, cmd, process, fs, filename
Set shell = Server.CreateObject("WScript.Shell")
'See findstr /? for details on switches used below
'cmd = C:\Windows\system32\cmd.exe /c findstr /P /M /C:"uniqueId" "C:\Inetpub\wwwroot\includes\*"
cmd = shell.ExpandEnvironmentStrings("%COMSPEC%") & " /c findstr /P /M /C:""" & uniqueId & """ """ & Server.MapPath(".") & "\*"""
Set process = shell.Exec(cmd)
'3. Use Scripting.FileSystemObject to return the filename portion of the first result returned
Set fs = Server.CreateObject("Scripting.FileSystemObject")
GetCurrentFilename = fs.GetFileName(process.StdOut.ReadLine())
Set fs = Nothing
Set process = Nothing
Set shell = Nothing
End Function
Then, inside whatever file you want to "inspect" the current filename, simply drop the following line, passing in some unique identifier that should not exist in any other file in the current directory but this one:
'myfile.inc
Response.Write "This is in " & GetCurrentFilename("908ab098c")
The result:
This is in somefile.inc
Oh, and if you're interested in what I needed to use this for, here's what it looks like used in a simple breakpoint function:
Function Breakpoint(ByVal line_no, ByVal uniqueId, ByVal msg)
Dim fn
fn = GetCurrentFilename(uniqueId)
Response.Write "[!] Breakpoint hit at Line " & CLng(line_no) & " in " & fn & ": " & Server.HtmlEncode(msg) & vbNewLine
Response.End
End Function
Such that on Line 20 of my code, if I wanted to add my own breakpoint, it would look like this:
Breakpoint 20, "B0001", "Some debug output here"
Output:
[!] Breakpoint hit at Line 20 in somefile.inc: Some debug output here
Happy coding!

Resources