When attempting to load the iTunes XML/plist file, I get "internal table overflow." After Googling, it looks like Applescript has run out of memory. The file is 18 meg on disk, so while on the larger side of things, it should still work on a Mac with 2 gigs.
How can I resolve this?
Obviously, since it's created by iTunes, I can't control the generate of it much.
Update: The relevant snippet:
tell application "System Events"
tell property list file (itunes_xml_file as string)
tell contents
set my_tracks to value of property list item "Tracks"
repeat with t in items of my_tracks
I guess that AppleScript is simply not made to handle this amount of data. I tried to use AppleScript a while back as well and tried to do something similar (reading an iTunes library). AppleScript's original intention was to automate applications by sending AppleEvents to them - which in combination with the weird syntax of AppleScript, confuses a lot and makes it difficult to do a lot of simple things.
After some frustrating time I decided to use Python instead, as it provides a simple module for reading the plist files: http://docs.python.org/dev/library/plistlib.html
Possibly not what you wanted to hear, but the problem with AppleScript is that it is easily overloaded with data, as the abstraction of data it works with is rather bulky and takes up lot of memory.
I'm sure if you give Python a try, you'll have something up and running in less than a hour. Python is installed on all Macs by default and is really easy to learn.
OS version 10.6.8
Update: Confirmation of validity
After initially writing the below I tried to revert the code at hand but could not reproduce the error and hid the post by "deleting" it.
Just now the error happened when loading one non-existant and one existent file-path in an options-parsing script loaded with a load script call, initially handled by run handler, called by the CLI osascript(1) program. This time it is revertible and I feel confident to un-"delete" it.
In short, my solution is to change anyone_else's POSIX file path_posix to AppleScript's POSIX file path_posix
Some relation
After writing the below I now realize that i first only saw "iTunes" and missed the relevant first line with tell app "system events" and the use of it's property list file which perhaps/actually/somehow could be related to my issue with info for a POSIX file.
A note related to OP/question: file or alias as string gives a colon-separated "HFS"-path. System Events handles both.
My issue
In a script-loading script i got error "Internal table overflow." number -2707 from the block below.
It was issued when i called the block's handler using ~IPC~ (app app_name's handler_name()) (when i investigated it more thoroughly but, i had come across it before - without IPC).
try
set file_modified_date to (info for my POSIX file file_path_posix)'s modification date
true
on error error_message number error_number from error_source partial result error_result to error_class
if {error_number} is not in {-43, -37} then error error_message number error_number from error_source partial result error_result to error_class
false
end try
A (the(?)) parent (used for my) of this script, worth mentioning, is current application (with some levels in between) (compiled and bundled in "AppleScript Editor" to be run as a stand-alone .app)
My solution
Changing
set file_modified_date to (info for my POSIX file file_path_posix)'s modification date
to
set file_modified_date to (info for AppleScript's POSIX file file_path_posix)'s modification date
solved the issue - for now.
Thoughts
I'm guessing different ~modules~ has different "tables" (don't now much C) for handling a thing like POSIX file and info for (open "Scripting Addition" / extension (OSAX) "Standard Additions", as it (both) still is, is it not?).
Hope this helps, and that my level of detail (and parentheses) didn't loose or confuse you :) Good night.
Diggin' 'round the cradles
Around the AS memory grave: (Spam prevention made me downgrade all but 2 hyperlinks - give me some rep. and i'll fix it :p)
• The eminent ~has [on this error code] (http://lists.apple.com/archives/applescript-users/2005/Jul/msg00166.html) with a related but perhaps other source (and mentioning his library loader) via list.apple.com.
• Some [good questioning] (http://lists.apple.com/archives/applescript-implementors/2005/Jun/msg00104.html), some to which the below might be a slightly yawning answer:
• cs.cmu.edu provides (120625) a pascal source from 1992 that defines the same limits as my local /System/Library/Frameworks/Carbon.framework/Versions/A/Frameworks/OpenScripting.framework/Versions/A/Headers/AppleScript.h
• And finally a more distantly related [issue with large scripts] (http://macscripter.net/viewtopic.php?id=11760) from macscripter.net - a good forum of knowledge and collection of resources around applescript.
Related
I've compiled my first web crawler script with AppleScript and I'm at the point now where I've gained a lot of knowledge and tricks from what I've written. I want to parse down the script now and disable some things that I thought would be helpful (for example: I coded it so the script completely quits Excel after entering the data in some workbooks from web pages because I noticed when you didn't start Excel fresh running the code it would return an error. But now I have the script running every 15 minutes so I worry that I will be working in Excel on some forecasting or formatting and the script will run and kick me out of Excel while I'm working and interrupt me or worse, quit without the option of saving). I vaguely remember C++ coding there was the ability to mark some text with a certain character that disabled it from running in the environment but made it so you could still see the original code before editing out stuff you decided wasn't necessary. Is there a way to mark a certain statement with a symbol so that AppleScript doesn't run the commands? I haven't experimented at all but I don't know what to guess that would do it. I may be mistaken that you can blank out or "white out" text while leaving it in the original position, still readable and able to be put back in when you want it or left for you so you have a collection of all the research you put into the process of building a script for a project. Well I suppose I'll just wonder a while and find something else to burn hours on.
In applescript there are three ways to "comment" out text in your code.
--A line beginning with two dashes is a comment.
#In applescript 2.+, the number sign also works as a comment symbol.
(* Multi-line text
can be commented out
using these symbols. *)
We have a PDF document processing system, implemented in AppleScript (where we call the scripts from the shell using osascript). In some of the scripts, we call Acrobat Preflight Droplets from the Applescript.
This does usually work without problems. However, in some cases, where the processed document is big or/and complex. the droplet returns control to the script before the report is written and the document is moved to the "success" or "failure" folder. The consequence is that the process continues, but without the moved file, it eventually fails.
The workaround so far has been to add a delay after those droplet calls. This does help, but it is a waste of time for small documents, and there will always be a document big and complex enough to take longer than the delay.
We also found out that the time needed for finishing writing the report and moving the document depends on the speed of the system (had to be expected…).
The workaround would be to calculate the delay from the document size, its number of pages, and a machine-dependent parameter. Document size, and number of pages are no big deal; they can be retrieved in the Applescript.
The problem is the machine-dependent parameter, which can be determined experimentally. But how do I make that parameter available to all the scripts needing it?
Incorporating it into the scripts is not an option, because we have a number of systems installed, and if we would do that, we'd end up in a maintenance nightmare. Passing it as an argument in the initial system call is also not possible, because the calls are many, and again would lead to a maintenance nightmare.
So, is there a way to set up a place where that machine parameter can be stored and easily called from any Applescript, no matter how it itself is called.
Thanks a lot for your advice.
You might find the Property List Suite in System Events useful. It’s a standard means of storing and then retrieving such information. Property List files themselves are simply XML files, so you can even create them outside of AppleScript and then read them within your scripts.
There’s a description with examples at https://apple.stackexchange.com/questions/58007/how-do-i-pass-variables-values-between-subsequent-applescript-runs-persistent
A simple suggestion if you only have one paramater to keep track of would be to just have a text file in a known location on each machine. The only content of the text file would be the machine paramater. I like to use the Application Support folder this kind of thing.
Assuming your machine parameter is CPU speed. You can save a text file in /Library/Application Support/Preflight Scripts/machinecpu.txt with the contents:
2.4
Then in Applescript, you would just read the text file.:
set machineParam to read file "Macintosh HD:Library:Application Support:Preflight Scripts:machinecpu.txt"
I have an applescript xcode project in xcode 3.2 and am trying to change the system volume...however it doesn't work...it either stops the nstimer or doesnt do anything at all...
Is there a way to log the errors so that I can pinpoint the issue?
Here is my code
set newVolume to 50
set volume output volume newVolume
textName's setStringValue_(currentVolume)
set currentVolume to newVolume
obv this is a much more condense version but this literally does not work...it is inside of an NSTimer but, even when not within an NSTimer it still does not work...newVolume, currentVolume, and textName are all declared...do I need to declare something for the set volume line?
So, your actual question was simply how to log errors from AppleScriptObjC:
AppleScriptObjC will log any errors thrown in your script to the console -- just look in the bottom pane in Xcode. For instance, in your case you should see something like “«script» doesn’t understand the «aevtstvl» message.” (This isn’t terribly clear, but it’s telling you that your script sent a set volume command to a script object, which didn’t have a handler for it.) If you want to capture and log errors yourself, you can put troublesome sections inside a try/on error block, and deal with it yourself in the error handler.
If you’re feeling extra inquisitive, you can also turn on the NSScriptingDebugLogLevel preference, like this:
defaults write com.me.myapp NSScriptingDebugLogLevel 1
...and AppleScriptObjC will log information about every message sent either way across the bridge. (Set it to 0 or use defaults delete to turn it off.)
That’s error logging. Now, what you didn’t actually ask, but I’m going to answer anyway, was “How do I fix my set volume command?”
Short version: add tell current application to:
tell current application to set volume output volume 50
And yes, the range for the “new” volume parameters is 0 to 100. The old compatibility one goes from 0 to 7. (Why? The old Control Panel volume slider had 8 stops.)
Long version:
There’s a bad interaction between the default direct parameter and set volume’s handling of it. When using AppleScriptObjC, “it”, and therefore the default direct parameter, unless you say otherwise, is the current script, and set volume chokes on that. You can force “it” to be nothing by saying tell current application to. (Alternatively, you could give it an explicit direct parameter by using the old-fashioned form set volume x where x is a real number from 0 to 7. However, this doesn’t match the numbers you get from get volume settings, only lets you set the output volume, and doesn’t let you set things like “muted” correctly.)
And by the way, if your AppleScriptObjC project is sufficiently simple (in particular, if you don’t need any interface), you can write it directly in AppleScript Editor: choose File > New from Template > Cocoa-AppleScript Applet, and use the normal AppleScript on run and on open handlers, except that you can now also invoke anything from Cocoa.
Let's take for example notepad. How can I in my application be 100% sure whether notepad is running or not?
By 100% I mean, if there is another process whose name is "notepad.exe" which in fact is not a real notepad but for example an imitation, I don't want to detect it. Only real notepads.
I've already thought about reading the process memory but it's more difficult than it appears to be, because of memory displacements etc.
The standard way is by name, right? But for me it is really important, that it is not any other program since I want to interact with it what would critical fail if I found a wrong process.
Does anyone know a good way of doing this?
PS: There is no specific programming language to do it in. If possible I would prefer an indipendent solution. But if required, I specifically use .Net/C#.
The only way to be 99.9%1 sure you're looking at the right executable is to validate the file's digital signature. For example, you'd ensure that the notepad.exe in question was signed by "Microsoft Corporation".
I'd do something like this:
Get the list of running processes.
Filter down to name of interest (notepad.exe)
Get each process' image [executable] path.
Validate that the Authenticode signature is valid and trusted.
Compare the name of the signer to the expected value.
Success! You can be very certain this is the correct file.
This method avoids issues like having to know ahead of time where the file should be located (which is nearly impossible – Notepad is installed in two locations), what its hash value should be (obviously bound to change), or strange user behavior (replacing Notepad with some other text editor).
1 - of course, it's impossible to be 100% sure. Someone really determined could self-sign an executable with the expected signer name and add the certificate to their machine's root store, causing the signature to appear valid.
Well, I haven't been confronted to that kind of problem, but you can first check if the process is running by searching by name (in your case, that would be notepad.exe), parse the Process.GetProcesses() list for that, then get
Process.StartInfo.FileName
and see if this is the path to the Notepad executable, that would do the deal, right ?
What exactly do you know of the executable we want to be running? If you knew the filesize that could work as a "hack". Use #josh3736 's method, but replace point 4 and 5 by comparing the filesize with the one you know [different versions will have different sizes, but if there are not too many you can hardcode them]. Calculation a Md5-Hashtag would look more professional, but would do basicly the same thing.
**
If your process has a GUI: you could use EnumWindows for the children to get Edit-Boxes etc. Find something destinctive for your "notepad.exe" and check if it's there.
This is so wrong.
I want to perform a large copy operation; moving 250 GB from my laptop hard drive to an external drive.
OSX lion claims this will take about five hours.
After a couple of hours of chugging, it reports that one particular file could not be copied (for whatever reason; I cannot remember and I don't have the patience to repeat the experiment at the moment).
And on that note it bails.
I am frankly left aghast.
That this problem persists in this day and age is to me scarcely believable. I remember hitting up against the same scenario 20 years back with Windows 3.1.
How hard would it be for the folks at Apple (or Microsoft for that matter) to implement file copying in such a way that it skips over failures, writing a list of failed operations on-the-fly to stderr? And how much more useful would that implementation be? (both these questions are rhetorical by the way; simply an expression of my utter bewilderment; please don't answer them unless by means of comments or supplements to an answer to the actual question, which follows:).
More to the point (and this is my actual question), how can I implement this myself in OS X?
PS I'm open to all solutions here: programmatic / scripting / third-party software
I hear and understand your rant, but this is bordering on being a SuperUser-type question and not a programming question (saved only by the fact you said you would like to implement this yourself).
From the description, it sounds like the Finder bailed when it couldn't copy one particular file (my guess is that it was looking for admin and/or root permission for some priviledged folder).
For massive copies like this, you can use the Terminal command line:
e.g.
cp
or
sudo cp
with options like "-R" (which continues copying even if errors are detected -- unless you're using "legacy" mode) or "-n" (don't copy if the file already exists at the destination). You can see all the possible options by typing in "man cp" at the Terminal command line.
If you really wanted to do this programatically, there are options in NSWorkspace (the performFileoperation:source:destination:files:tag: method (documentation linked for you, look at the NSWorkspaceCopyOperation constant). You can also do more low level stuff via "NSFileManager" and it's copyItemAtPath:toPath:error: method, but that's really getting to brute-force approaches there.