Apple Script to Count File Progress During Copying

Hello.

I think you always had void *, but it used to be the same as an int, or an int served as a void * in the beginning. Pointer arithmetic and all. Maybe people at some time started to use it more than just “int” since it made the purpose clearer, like the type bool.

But the main thing is that an int is the default return value of a function, so when the compiler doesn’t see a return value, due to laziness from a programmer, it bluntly assumes that it returns an int. So, when you don’t include a header file for that function that returns a void * and doesn’t cast it to a return type. :slight_smile:

And for the record, if the ints had increased in size with the adddress space, we’d use 64-bit ints and we’d be all good.

But that’s really spoiling a lot of bits, so that was never an option, and hence the problem.

In K&R you don’t “need” to declare the functions you use, so when people doesn’t follow the warning about no including the declaration . “missing declaration” then the compiler will assume K&R standard, I think it will do that whatever standard you have specified on the command line, falling back to something that works.

Void pointers were new since ANSI C, not before. Read K&R second edition about pointers, which is about ANSI C.

But that only applies for pre-ANSI compilers.

Hello.

About not having void * in pre-Ansi seems right, it used to be char * as far as I can tell from old declarations of malloc.

The whole point is that, if you haven’t set up the compiler to fail, even if you have specified -ansi or stdc99 or what not, it is liable to fall back take it as K&R if your code doesn’t fulfill the ansi standard. :slight_smile:

Some last rants about pointers to void…

The concept of a void pointer never thrilled me, as it is just a formalized construction of something that alwas was there, whether you wrote void * or char *, as long as both expressions denoted a pointer to the smallest storage allocation unit, and semantically meant the same.

What is interesting, is the size of that pointer, in K&R the size of the pointer was an int, and the default return type of a function was an int. This provided for a “wholesomeness” in the anarchy. Later on, with the formalism and development of larger arcitechtures, we had to let go of this “unity”, so when a compiler falls back to K&R due to a programmers sloppyness, he may experience unexplainable errors. :slight_smile:

Hello.

With the example in post #9 here is a much better scheme:

The shell script just writes the number to the file for each file it has copied, without any pause.

The Applescript just reads the number from the file each second, and updates the progressbar accordingly.

This should be a bullet proof protocol, as long as the shell script doesn’t hang, The applescript should check for increments, and just pass if the value hasn’t incremented since last time. The first thing the shell script should do is writing “0” to the file.

This leads to a much more “fuzzy” update of the progress bar, but should prove more efficient for the computer.

I’ll post some snippets here later.

I stopped already because my experience in pre-ANSI is mostly from books and what I hear from engineers (which I hire and who are older than me) who explained me and can tell me stories like “that wasn’t always possible you know.”. It’s simply because I’m too young, I can only speak for ANSI C.

Well, having an special type for it is better than working with cumbersome solutions that aren’t standardizes. It’s not rocket science but I think it’s an good improvement. Now an real generic pointer can be created while an char is certainly an type and not typeless like void. In my opinion they should therefore not be considered the same.

More obvious to me. In processor terms a pointer size is equal to an word size till today. What is interesting is that for more than 20 Years the Integer was equal to the processor’s word until 64-bit. The integers are half-words now and didn’t grow parallel with the processor, for Mac, Windows and Linux. The second interesting thing is why Apple keeps the NS(U)Integer (C type in Cocoa) equal to the processor’s word. The size of an pointer and integer is in Cocoa still the same till today.

My description about simulating callbacks, here’s an small example.


property appName : "backupTest" --same as you save this application without the .app extension
property sourceFolder : missing value
property targetFolder : missing value
property theItems : missing value
property currentItem : missing value

on run argv
	--application initialize
	do shell script "[ -e /dev/ttys000 ] || open -a terminal" --open the terminal and send stdout and stderr to terminal
	set sourceFolder to (choose folder with prompt "Choose Source Folder or Disk") as string
	set targetFolder to (choose folder with prompt "Choose Target Folder or Disk") as string
	set theItems to every paragraph of (do shell script "ls " & quoted form of POSIX path of sourceFolder)
	set currentItem to 1
	start()
end run

on start()
	if currentItem = (count theItems) then
		display dialog "Backup complete"
		quit me
		return
	end if
	set sourceFile to quoted form of POSIX path of (sourceFolder & item currentItem of theItems)
	set targetFile to quoted form of POSIX path of (targetFolder & item currentItem of theItems)
	set currentItem to currentItem + 1
	do shell script "(ditto --rsrc " & sourceFile & space & targetFile & " &>/dev/ttys000; osascript -e 'tell application \"" & appName & "\" 
start()
end tell')&>dev/null &"
end start

on quit
	continue quit
end quit

It’s only important that you save the script as an application with the same name as in property appName and that the application is ‘stay-open’.

What it does is using run handler as the application initializer. Then function start is called and an subshell, in the background, is doing an ditto (dopy) command. When the ditto command is done a callback is made to the function start again in application appName. Between these copies you can do an update of your interface and other stuff.

Hello.

I am sorry for all the confusion around this. In C you can do pretty much anything. But the char * construct, I think they did it like that deliberately. I oppose to this, because a showel is a showel not matter what you call it, on the other hand, there are some subtle differences somewhere, which I can’t remember, nor are willing to look up in the two annoted copies of the C-Standard I have. :slight_smile:

Just lets agree upon that Objective-C with its id, and isa, runtime and reflection is so much more pleasant to deal with, comparing to whatever. And with strongly typed languages, though it is weakly typed in its underpinnings, the likelihood of getting into trouble like those rants has been about, are far less. :slight_smile:

I like C, but I find it hard to write something bigger than say 5000 lines with it as you have to figure out your own encapsulating principles and such, and know where you broke them. Key to success with C is to have the modules form an acyclic graph more or less (To avoid too much spaghetti code).

Here are some routines I use in C for dealing with memory that can be useful.

[code]void *
yrealloc( void *ptr, size_t sz, const char *fromHandler, const char * forVariable )
{
void *p = realloc(ptr, sz ) ;
if (p == NULL ) {
yerror( YREALLOC_ERR, fromHandler, forVariable, YX_EXTERNAL_CAUSE ) ;
}
return p ;
}

/* allocates memory.
if the request for memory can’t be satisified
then depending on whether we are in the ui or not,
a failure message will be printed there.
A failure message will be printed at exit anyway.
*/

void *
ymalloc( size_t sz,const char *fromHandler, const char *forVariable )
{
void *p = malloc(sz ) ;
if (p == NULL ) {
yerror( YMALLOC_ERR, fromHandler, forVariable, YX_EXTERNAL_CAUSE ) ;
}
return p ;
}[/code]
The yerror formats a string with the handler using a string from an error strings table (YMALLOC_ERR and YREALLOC_ERR) , and the variable, before it prints it to stderr, maybe prints it on screen first, if a screen is active. Then a global “cleanup” routine is called before we exit.(YX_EXTERNAL_CAUSE=1) So we kind of sidestep the normal flow, but cleans up when we are done with the fatal error.

This is an idiom that works very well. You get proper error handling while your code reads like a text book example. I use y as prefix since everybody else uses x. And hahaha, I have included stdlib.h and mem.h in the file where those are declared, so I doesn’t fall into the previously described trap even if I don’t cast malloc and realloc internally in the routines. :slight_smile:

To stay on track with the TS here an implementation of my script using Stefan’s SKProgressBar:

property appName : "backupTest" --same as you save this application without the .app extension
property sourceFolder : missing value
property targetFolder : missing value
property theItems : missing value
property currentItem : missing value

on run argv
	--application initialize
	do shell script "[ -e /dev/ttys000 ] || open -a terminal" --open the terminal and send stdout and stderr to terminal
	set sourceFolder to (choose folder with prompt "Choose Source Folder or Disk") as string
	set targetFolder to (choose folder with prompt "Choose Target Folder or Disk") as string
	set theItems to every paragraph of (do shell script "ls " & quoted form of POSIX path of sourceFolder)
	set currentItem to 1
	tell application "Finder" to set b to bounds of window of desktop
	tell b to set {xRes, yRes} to {item 3, item 4}
	set w to 500
	set xpos to (xRes - w) / 2
	set ypos to (yRes + 200) / 2
	
	
	tell application "SKProgressBar"
		activate
		-- main window properties
		set position to {xpos, ypos}
		set width to w
		set title to appName
		
		-- header / footer properties
		set header to "From	: " & sourceFolder & return & "To		: " & targetFolder
		set header alignment to left
		
		
		-- image path can be HFS or POSIX path, default is missing value (no image)
		set image path to "/Applications/Utilities/Disk Utility.app/Contents/Resources/RAID.tiff"
		
		tell progress bar
			set minimum value to 0
			set maximum value to count theItems
			set current value to 0
		end tell
		
		set show window to true
		tell progress bar
			set indeterminate to false
			start animation
		end tell
	end tell
	start()
end run

on start()
	if currentItem = (count theItems) then
		display dialog "Backup complete"
		quit me
		return
	end if
	
	set sourceFile to quoted form of POSIX path of (sourceFolder & item currentItem of theItems)
	set targetFile to quoted form of POSIX path of (targetFolder & item currentItem of theItems)
	set currentItem to currentItem + 1
	tell application "SKProgressBar"
		set footer to "Copying	: " & item currentItem of theItems
		set footer alignment to right
		tell progress bar to set current value to currentItem
	end tell
	
	do shell script "(ditto --rsrc " & sourceFile & space & targetFile & " &>/dev/ttys000; osascript -e 'tell application \"" & appName & "\" 
start()
end tell')&>dev/null &"
end start

on quit
	tell application "SKProgressBar"
		stop animation
		set show window to false
	end tell
	continue quit
end quit

This needs to be saved as an Application with the option ‘stay-open’ and give it the same name as property ‘appName’.

Nice!

Your solution is much simpler, and more elegant than what I had in mind, so I abstain from creating/posting what I had in mind, which was more complicated, but not better.

Do that redirection of the shell to /dev/ttys000 really stick? and does it work like rsync believes it operating on a real terminal? that is, can you do that in a first do shell script, then do a do shell script with a test -z (something in it later), and the shell believes it is connected to a real terminal?

If it is not so, could you please describe the rationale behind it? :slight_smile:

You got me :). It doesn’t really, because when I open (let’s assume after an clean boot) the terminal the first window’s tty is /dev/ttys000. When you open an second window, this window’s tty is /dev/ttys001. If you close the first window the second window will keep it’s tty. Then when opening another window (officialy the third window), it’s tty will be ttys000 again. So when opening an new terminal window it will gets the first available tty.

Proper code would be something like below to check first the existence of an terminal window but also using the correct tty. You could for instance have another sort of terminal open at the same time.

tell application "Terminal"
	activate
	if (count of windows) = 0 then do script " "
	set frontTTY to tty of tab 1 of window 1
end tell

--just some to code to show you that it works
do shell script "date >" & quoted form of frontTTY

I’m not sure but I’m redirecting my output to tty’s output. Commands are normally obtained by input. It’s input is normally directly printed to the output so you can read what you’ve typed (except for passwords like login). But if I get it right you want to execute bash code with do shell script through an terminal without using the terminal application right?

You could take a look here, because I think C is already your middle name. This code will echo the given arguments to the input of the given tty so they will be executed.

Hello DJ.

I was just curious if you had discovered that you could “configure” the “shell” behind do shell script. What is inside there is “Black Magic” to me.

That is, that you could “set” stuff and have it persist between do shell script calls, I was not into “getting” you.
Pure curiousity, that’s all.

Your idea is very cool: show the output from an applet or applescript in a terminal window!

C is a long way from my middle name! If was to get a tag, it should have been Applescript, because that is the language I really prefer.

C is just the early AppleScript for *nix. :slight_smile: A stone-age toolbox.

Edit

Thanks for the code example, though I like your way much better, for a number of reasons, security being one of them. I don’t setuid stuff to root, I’d rather have less stuff with the setuid root set. I imagine that this can be used to automate debugging/ build processes for a variety of languages (anything that writes to stderr/stdout) by using Applescript.
:smiley:

And you can make solutions that looks good too, if you excert some control over the terminal window. Window handling of Terminal windows by Applescript, is slightly painful when dealing with Terminal app directly, so it is much better to do it with System events (as far as I remember).

Edit++
(But of course, if using the tool provided in the link to make this work, then that pretty much justifies it. (I haven’t tried your code yet.) I think I tried something similar some years ago, but then I didn’t have that tool, and I would have to “sudo” for security reasons.)

If I understand you correctly, it’s so that NSUIntegerMax is the same in 32-bit and 64-bit.

NS(U)Integers are long types, their bit sizes equals the bit mode so they should have different values in in each bit-mode.

Don’t mind me…

The association, is a bit weak, but the pace of the locate command has annoyed me for years! Since we are dealing with terminal output in this thread, I’ll just post this.

You’ll need to have the developer tools installed. Create a file called readslow.c with the contents of the code below, move to that directory in a terminal window, and type “make readslow”, then copy it to somewhere in your path. now you can type locate python |readslow -n 1 for instance.

The original was printed in the Unix Programming Language.

/* readslow:  keep reading, waiting for more */
#define	SIZE	2048	/* arbitrary */
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
void usage( void ) ;
int main(int argc, char *argv[] )
{
	char buf[SIZE];
	int n, waiting=0,t=2;

		if (argc > 1 ) {
			if (argc > 2 ) {
				if (strstr(argv[argc-2],"-n")) {
					t=atoi(argv[argc-1]) ;
				} else {
					usage() ;
				}
			} else {
				usage() ;
			}
		} else { 
			t=2;
		}
		for (;;) {
			while ((n = read(0, buf, sizeof buf)) > 0) {
				waiting=0;
				write(1, buf, n);
				sleep(t);
			}	
			if (!waiting) {
				waiting++;
				sleep(t);
			} else if (waiting){
				waiting++;
				if (waiting>2) {
					break;
				}
			}
		}

	return 0 ;
}
void usage( void ) {
	fprintf(stderr,"Usage: readslow -h|-n <seconds>\n") ;
	exit(1) ;
}

@DJ Bazzie Wazzie

I can’t remember exactly where (which thread) we discussed what the Mac Kernel consisted of with regards to BSD 5, but you were right and I were wrong for I was sure it was derived from BSD 4.4, and you stated it was BSD 5. I am currently reading Amit Singh’s excellent book: Mac Os X Internals, and he states that Mac Os X has an xnu kernel, that consists of Mach 3 kernel, (but not fully microkernel, as it shares memory space with ”>) and BSD 5. I even learned that there are stuff there from mklinux.

Well if you take a good look at the history in time you’re right. The first Darwin version was based on BSD 4.4 (lite) just like the first version of FreeBSD (version 2 had to be rewritten). So at the beginning FreeBSD and Darwin were both based on BSD 4.4. During the process of different BSD-based operating systems FreeBSD 4 was considered as the best operating stable and secure operating system and popular by ISPs. Apple decided to ‘synchronize’ Darwin with FreeBSD 5 and launch Mac OS X 10.3 as the world’s best operating system. So since then it’s in my opinion not longer based on BSD 4.4 anymore but more on FreeBSD 5 and it seems that Mac OS X internals agree with me :smiley:

Hello.

It is interesting, now I have to figure out the differences, between BSD 4.4 and freeBSD 5. Now, to my defense, it isn’t really that many references to freeBSD 5 in any kind of Apple documentation, and the ones that must be there have slipped me by for some reason.

Happy Friday!

Well it’s not much of an difference though. FreeBSD version 1 can be considered as equal to the latest version of BSD (version 4.4). BSD never continued developing and the latest release was in '95. The distance between the two projects in development and time is too big to compare them. It’s like comparing the first word perfect with the latest Word 2013. So in my opinion there isn’t much to compare, FreeBSD should be in any way superior to it’s predecessor.