Postscript: know what I need, no clue how to do it - printing

We create printfiles by gluing ps and eps files together and overlay data to print customer forms.. and then send those files to the printer.
As printers have changed we have had to adjust the scripts.. We are now looking at XEROX printers and they are very different animals..
We've built a procedure that sets the tray to print from and it needs a change..
/stray
{
/Pagedv exch def
#ifdef :OK431
/DriverOps /ProcSet 2 copy resourcestatus{pop pop findresource Pagedv exch /setinputslot get exec}{pop pop}ifelse globaldict /OK#_CustTray 0 put
#elif :O4600
/PageSub Pagedv 1 sub def currentpagedevice /InputAttributes get PageSub known{ Pagedv statusdict /setpapertray 2 copy known{ get {exec}stopped {pop}{globaldict /OK#_CustTray PageSub put}ifelse (<<) cvx exec /Policies (<<) cvx exec /PageSize 7 (>>) cvx
exec (>>) cvx exec setpagedevice }{pop pop pop}ifelse }if
#elif :HPPRO
currentpagedevice /InputAttributes get Pagedv <</MediaPosition Pagedv >> setpagedevice
#else
<<currentpagedevice /InputAttributes get Pagedv get {}forall /InputAttributes << /Priority [Pagedv] >> >> setpagedevice
Xerox doesn't use a number according to the PPD it uses a string (ie Tray-1)
Pagedv is an integer so I need to append (concatenate) the literal "Tray-" onto it before we return it to the caller
> #elif :XRX
> currentpagedevice /InputAttributes get Pagedv << (Tray-Pagedv) xerox$MediaInputTray >> setpagedevice
I have a concatenate procedure I'm just not sure how to use it in this case.
/concatstrings % (a) (b) -> (ab)
{ exch dup length
2 index length add string
dup dup 4 2 roll copy length
4 -1 roll putinterval
} bind def

Well if you want to concatenate two strings to produce a new string, and what you have is a string and an integer (Pagedv), then the first thing you need to do is turn the integer into a string.
To do that you'll need an empty string big enough to hold the result, and then pass that and the integer to the cvs operator. So a PostScript fragment like this:
Pagedv % The operand to convert to string
256 string % A 256 element string to receive the result
% stack is now - integer string
cvs % consumes integer and string and returns a substring
% stack is now - substring
So if you had a value of 1 for Pagedv then you would now have a PostScript string (1) of length 1.
If you've already defined your /concatstrings function, and are certain it will be available (ie in a dictionary on the dictionary stack and not concealed by another function of the same name) then you would just do:
(Tray-) exch concatstrings
Which would result in a string of (Tray-1). You might find it simpler to avoid calling a function and just do the whole thing at once locally.
Pagedv 256 string cvs % convert integer to string
dup length 5 add string % copy new string, get length, create final string big enough to hold Tray-result
% The above is probably overkill, very few printers have more than 9 trays! But best to be safe
dup 0 (Tray-) putinterval % copy final string, put Tray- at start of final string
dup 5 4 -1 roll putinterval % copy final string, put converted integer string into final result, starting at position 5.

Related

How do I remove point symbol from the decimal number?

I'm trying to take decimal number as an input and I need output of all numbers but without the point symbol in it.
Example input: 123.4
Wanted output 1234
The problem I have that when converting decimal number into string and trying to remove "." using :gsub('%.', '') its removing the point symbol but outputs 1234 1 .
I have tried :gsub('.', '') as well but it outputs 5.
I'm clueless where those numbers come from, here is the screenshot:
Use this syntax to get what you want and discard/ignore what you dont need...
local y = 123.4
-- Remove decimal point or comma here
local str, matches = tostring(y):gsub('[.,]', '')
-- str holds the first return value
-- The second return value goes to: matches
-- So output only the string...
print(str) -- Output: 1234
-- Or/And return it...
return str
There are two issues at play here:
string.gsub returns two values, the resulting string and the number of substitutions. When you pass the results of gsub to print, both will be printed. Solve this by either assigning only the first return value to a variable (more explicit) or surrounding gsub with parenthesis.
. is a pattern item that matches any character. Removing all characters will leave you with the empty string; the number of substitutions - 5 in your example - will be the number of characters. To match the literal dot, either escape it using the percent sign (%.) or enclose it within a character set ([.]), possibly adding further decimal separators ([.,] as in koyaanisqatsi's answer).
Fixed code:
local y = 123.4
local str = tostring(y):gsub("%.", "") -- discards the number of substitutions
print(str)
this is unreliable however since tostring guarantees no particular output format; it might as well emit numbers in scientific notation (which it does for very large or very small numbers), causing your code to break. A more elegant solution to the problem of shifting the number such that it becomes an integer would be to multiply the number by 10 until the fractional part becomes zero:
local y = 123.4
while y % 1 ~= 0 do y = y * 10 end
print(y) -- note: y is the number 1234 rather than the string "1234" here

send hex variable via TCP socket

Probably it's an easy thing, but I'm a Lua beginner...
I'm creating a very simple QSC QSYS plugin to control a projection server using KVL API. Server API is based on hex strings.
For example this command asks the server to load a the playlist with 9bf5455689ed4c019731c6dd3c071f0e uuid:
Controls["LoadSPL"].EventHandler = function()
sock:Write(
"\x06\x0e\x2b\x34\x02\x05\x01\x0a\x0e\x10\x01\x01\x01\x03\x09\x00\x83\x00\x00\x14\x00\x00\x00\x01\x9b\xf5\x45\x56\x89\xed\x4c\x01\x97\x31\xc6\xdd\x3c\x07\x1f\x0e"
)
end
Now I need to be able to create a string with a variable UUID, according to the text indicated in a textbox (or a list of available UUIDs read from the server) in the user interface.
I will concatenate this string to the fixed part of the command.
How can I correctly make a string like
ad17fc696b49454db17d593db3e553e5 become
\xad\x17\xfc\x69\x6b\x49\x45\x4d\xb1\x7d\x59\x3d\xb3\xe5\x53\xe5?
Try this:
local input = "ad17fc696b49454db17d593db3e553e5"
local output = input:gsub("%w%w", function(s) return string.char(tonumber(s, 16)) end)
Explanation: this takes every pair of characters, interprets them as base 16 numeric string, and then takes the character with that number, and uses that to replace the original characters.
EDIT: To make it clear what's going on, and why the other answers are wrong, backslash escape sequences like \xad are a feature of the Lua source code, in memory it's represented by a byte with value 173, just like A is represented by a byte with value 65. Trying to concatenate a literal backslash character with hexadecimal characters does not create an escape code. So the way to do that is manually with string.char.
#! /usr/bin/env lua
str = 'ad17fc696b49454db17d593db3e553e5'
strx = ''
for i = 1, #str, 2 do -- loop through every-other position in your string
chars = str :sub( i, i+1 ) -- capture every 2 chars
strx = strx ..'\\x' ..chars
end -- append a literal backslash, the letter x, then those 2 chars
target = [[\xad\x17\xfc\x69\x6b\x49\x45\x4d\xb1\x7d\x59\x3d\xb3\xe5\x53\xe5]]
print( x, x == target ) -- print results, and test if it meets expected target
\xad\x17\xfc\x69\x6b\x49\x45\x4d\xb1\x7d\x59\x3d\xb3\xe5\x53\xe5 true
This can be code-golfed into a one-liner
x=''for i=1,#s,2 do x=x..'\\x'..s:sub(i,i+1)end

How to find and replace words containing particular characters in Lua?

I have a string of “words”, like this: fIsh mOuntain rIver. The words are separated by a space, and I added spaces to the beginning and ending of the string to simplify the definition of a “word”.
I need to replace any words containing A, B, or C, with 1, any words containing X, Y, or Z with 2, and all remaining words with 3, e.g.:
the CAT ATE the Xylophone
First, replacing words containing A, B, or C with 1, the string becomes:
the 1 1 the Xylophone
Next, replacing words containing X, Y, or Z with 2, the string becomes:
the 1 1 the 2
Finally, it replaces all remaining words with 3, e.g.:
3 1 1 3 2
The final output is a string containing only numbers, with spaces between.
The words might contain any kind of symbols, e.g.: $5鱼fish can be a word. The only feature defining the beginning and ending of words is the spaces.
The matches are found in order, such that words which might possibly contain two matches, e.g. ZebrA, is simply replaced with 1.
The string is in UTF-8.
How can I replace all of the words containing these particular characters with numbers, and finally replace all remaining words with 3?
Try the following code:
function replace(str)
return (str:gsub("%S+", function(word)
if word:match("[ABC]") then return 1 end
if word:match("[XYZ]") then return 2 end
return 3
end))
end
print(replace("the CAT ATE the Xylophone")) --> 3 1 1 3 2
The slnunicode module provides UTF-8 string functions.
The gsub function/method in Lua is used to replace strings and to check out how times a string is found inside a string. gsub(string old, string from, string to)
local str = "Hello, world!"
newStr, recursions = str:gsub("Hello", "Bye"))
print(newStr, recursions)
Bye, world!    1
newStr being "Bye, world!" because from was change to to and recursions being 1 because "Hello" (from) was only founds once in str.

store string of bytes in table in lua

i need to store a string of bytes in a table in lua, how I can do it
thanks
Jp
Is that what you mean?
s="some string"
t={s:byte(1,#s)}
A Lua string is exactly what you wrote - a string of bytes. Lua is different from C-like languages in that it is 8-bit clean, meaning that you can even store embedded zero '\0' inside strings - the length of the string is held separately and is not based on where '\0' is.
You did not write where you want those bytes from (what is the source), so let's assume you are reading from a file. In the following example, f is a file handle obtained by calling io.open(filename), and t is a table (t = {}).
local str = f:read(100) -- will read up to 100 bytes from file handle f
t[#t + 1] = str -- will append the string to the end of table t
table.insert(t, str) -- alternative way of achieving the same

Getting around the Max String size in a vba function?

The max number of characters you can use in string in a vba function is 255.
I am trying to run this function
Var1= 1
Var2= 2
.
.
.
Var256 =256
RunMacros= "'Tims_pet_Robot """ & Var1 & """ , """ & Var2 & """ , """ ... """ & Var256 """ '"
Runat=TimeValue("15:00:00")
Application.OnTime EarliestTime:=Runat, Procedure:=RunMacros & RunMacros2 ', schedule:=True
It runs a procedure at a certain time and passes a bunch of variables to it. but the string is too long.
Update:
Regrettably I am sure it is not the watch window.
Also, it isn't really the max size of a string that I'm dealing with. It's the max size of
a string in a vba function.
For example this function works.
Sub test()
Dim RunAt As Date
Dim RunWhat As String
RunAt = Now + 0.00001
RunWhat = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & _
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & _
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 'that makes 254 'a''s
Application.OnTime EarliestTime:=RunAt, Procedure:="'" & RunWhat & " 12'"
End Sub
Sub aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(m As Integer)
MsgBox ("it works!" & m)
End Sub
But if you change the 12 to 123 it breaks
Example
Sub test2()
Dim RunAt As Date
Dim RunWhat As String
RunAt = Now + 0.00001
RunWhat = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & _
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" & _
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa" 'that makes 254 'a''s
Application.OnTime EarliestTime:=RunAt, Procedure:="'" & RunWhat & " 123'"
End Sub
Sub aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(m As Integer)
MsgBox ("it works!" & m)
End Sub
This code does not work, I'm pretty sure it's because a vba function cannot handle a string with more than 255 chars.
Even if you're in Excel and call a function and give it a string longer that 255 chars it doesn't work.
Try in cell A1 =vlookup("really long string", A1:Z10, 1) and then put the really long string somewhere in that range. The vlookup will fail (not fail to find it, but you won't actually be able to do it)
Also I am aware that there is a max length to a sub name, I'm just under it. Sorry that it look so ugly.
Update 2: so I just ended up printing the variable to a sheet and getting the function called by ontime to read them off the sheet. :(
I may have missed something here, but why can't you just declare your string with the desired size? For example, in my VBA code I often use something like:
Dim AString As String * 1024
which provides for a 1k string. Obviously, you can use whatever declaration you like within the larger limits of Excel and available memory etc.
This may be a little inefficient in some cases, and you will probably wish to use Trim(AString) like constructs to obviate any superfluous trailing blanks. Still, it easily exceeds 256 chars.
This works and shows more than 255 characters in the message box.
Sub TestStrLength()
Dim s As String
Dim i As Integer
s = ""
For i = 1 To 500
s = s & "1234567890"
Next i
MsgBox s
End Sub
The message box truncates the string to 1023 characters, but the string itself can be very large.
I would also recommend that instead of using fixed variables names with numbers (e.g. Var1, Var2, Var3, ... Var255) that you use an array. This is much shorter declaration and easier to use - loops.
Here's an example:
Sub StrArray()
Dim var(256) As Integer
Dim i As Integer
Dim s As String
For i = 1 To 256
var(i) = i
Next i
s = "Tims_pet_Robot"
For i = 1 To 256
s = s & " """ & var(i) & """"
Next i
SecondSub (s)
End Sub
Sub SecondSub(s As String)
MsgBox "String length = " & Len(s)
End Sub
Updated this to show that a string can be longer than 255 characters and used in a subroutine/function as a parameter that way. This shows that the string length is 1443 characters. The actual limit in VBA is 2GB per string.
Perhaps there is instead a problem with the API that you are using and that has a limit to the string (such as a fixed length string). The issue is not with VBA itself.
Ok, I see the problem is specifically with the Application.OnTime method itself. It is behaving like Excel functions in that they only accept strings that are up to 255 characters in length. VBA procedures and functions though do not have this limit as I have shown. Perhaps then this limit is imposed for any built-in Excel object method.
Update:
changed ...longer than 256 characters... to ...longer than 255 characters...
Are you sure? This forum thread suggests it might be your watch window. Try outputting the string to a MsgBox, which can display a maximum of 1024 characters:
MsgBox RunMacros
This test shows that the string in VBA can be at least 10^8 characters long. But if you change it to 10^9 you will fail.
Sub TestForStringLengthVBA()
Dim text As String
text = Space(10 ^ 8) & "Hello world"
Debug.Print Len(text)
text = Right(text, 5)
Debug.Print text
End Sub
So do not be mislead by Intermediate window editor or MsgBox output.
Couldn't you just have another sub that acts as a caller using module level variable(s) for the arguments you want to pass. For example...
Option Explicit
Public strMsg As String
Sub Scheduler()
strMsg = "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
Application.OnTime Now + TimeValue("00:00:01"), "'Caller'"
End Sub
Sub Caller()
Call aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa("It Works! " & strMsg)
End Sub
Sub aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa(strMessage As String)
MsgBox strMessage
End Sub
Excel only shows 255 characters but in fact if more than 255 characters are saved, to see the complete string, consult it in the immediate window
Press Crl + G and type ?RunWhat in the immediate window and press Enter
One of the main causes of this problem that I’ve run into is the fact that the entire procedure-plus-arguments string is limited to 255 characters, including the procedure's containing Excel file specification (automatically added by Excel), which is aggravated by Excel’s brain-dead default specification of the file's full-path\name. So, if you have very deep folder structures (like I do) combined with long-ish, descriptive file names and descriptive folder names (like I often use), then that factor can be a frequent problem when using OnTime.
WORKAROUND: I always (!) explicitly include the containing workbook’s name, which apparently alleviates Excel from having to automatically do so (in its nonsensical manner):
Sub CallOnTime()
Application.OnTime Now + TimeSerial(0, 0, 1), _
"'" & ThisWorkbook.Name & "'!'TargetMacro 37,""Some really long String parameter…""'"
End Sub
Sub TargetMacro(I As Integer, S As String)
MsgBox "I=" & I & ", S=" & S
End Sub
That buys me a lot of string-length real estate to use for the called procedure's arguments.
IMPORTANT: note the inclusion and position of the single-quoted bang delimiter ('!') in the above example.
My guess is that the original designer chose to include the full file-path along with the procedure's containing file name to avoid identification ambiguity with other workbooks running under the same instance of the Excel application. But that's a nonsensical rationale because Excel doesn't allow multiple workbooks with the same name to be opened under a single instance, even if they exist under different folder paths (which, of course, they would have to).
Some additional space-saving tips:
If the parameters include a worksheet specification, use its numeric
sheet Index property instead of its name.
Eliminate any space characters around the comma delimiters.

Resources