Apple has a new file system, APFS, which will be replacing HFS+ (finally). This is good news, in general,
but I (and others) have a vested interest in some features particular to HFS, including Finder Info and resource forks.
Information is limited, but so far the news is good. Per the WWDC APFS presentation:
So HFS compatibility - if all of you have apps that run on HFS+ just fine, we intend for all of those to continue to run without any changes whatsoever on your side. So Apple File System will support and replace HFS+ functionality. And there’s an asterisk there because there’s three things that we will not support moving forward.
One of them is exchangedata. The other is searchfs. And the third is directory hardlinks for Time Machine.
But every other API and behavior will be supported just as it is on HFS+.
searchfs(2) and exchangedata(2) are system calls to “search a volume quickly” and “atomically exchange data between
two files”, respectively.
So I’m optimistic Finder Info and Resource Forks will continue to work.
While q/k offers all the standard trigonometric functions, it does not include
atan2. A recent project (calculating headings between airports) required
atan2; therefore I needed to implement it.
Wikipedia was my guide and my first
attempt was a pretty straight-forward implementation in k:
This works but the excitement faded when I realized $[] only works with
scalars.
Re-examining the atan2 rules, we can create this chart:
x > 0
x < 0
x = 0
y > 0
atan[y%x]
atan[y%x] + pi
+pi%2
y < 0
atan[y%x]
atan[y%x] - pi
-pi%2
y = 0
atan[y%x]
atan[y%x] + pi
undefined
The most difficult case is x = 0. Fortunately, k’s atan gives the correct
result for +infinity, -infinity, and null, so it can ignore x = 0 and y = 0
x >= 0
x < 0
y >= 0
atan[y%x]
atan[y%x] + pi
y < 0
atan[y%x]
atan[y%x] - pi
Our only concern is adding (or substracting) pi when x < 0:
In March, Lemon received some
performance enhancements in the form of left-hand-side direct optimizations.
As the maintainer (and sole user) of a
c++-compatible lemon fork,
I became intimately familiar with these changes (and even noted a couple bugs).
Previously, you might write code like this:
%type expr {int}
expr(A) ::= expr(B) PLUS expr(C). { A = B + C; }
expr(A) ::= LPAREN expr(B) RPAREN. { A = B; }
(Actual code is uglier due to unions and negative stack offsets.) With
left-hand-side direct, the temporary variable can be eliminated in
some circumstances:
%type expr {int}
expr(A) ::= expr(A) PLUS expr(C). { A += C; }
expr(A) ::= LPAREN expr(B) RPAREN. { A = B; }
stack[0].int_value += stack[2].intValue;
....
stack[0].int_value = stack[1].int_value;
Left-hand-side direct optimization happens in 3 circumstances:
If the left-most right-hand side term has the same name and type.
If the left-most right-hand side term has no name
There is a special `/X-overwrites-Y/ comment.
For lemon++, I had to disable the comment check. However, in the sqlite
grammar, most usage looks like:
lemon++ tracks if the major type (@X) or minor type (X) are used and can
still use left-hand-side direct optimizations in this case.
While left-hand-side direct optimizations are obviously beneficial to lemon,
they are probably more beneficial to lemon++ when used with larger and more
complex datatypes instead of integers and pointers. Previously code like this:
%type list {std::vector<int>}
list(A) ::= list(B) expr(C).
{ A = std::move(B); B.push_back(C.int_value); }
It started off with this line in the MPW Make help file:
-i dirname # additional directory to search for include files
What include files? Normal make has an include directive to do just that,
but MPW Make didn’t support it. Running strings on the resource fork, I
found this error:
No file name following !include
And so I verified that !include filename worked as expected.
However, I couldn’t find !include documented anywhere; not in the help file,
not in the Building and Managing Programs in MPW guide, and Google was
helpless as well. Did !include have any secret siblings?
Running strings again, this time looking just for a !, I found references
to more keywords:
!ifdef
!ifndef
!elseifdef
!elseifndef
!endif
!undef
‘!error’
These also work as expected. !undef undefines a command-line (-d)
variable, allowing it to be re-defined later (similar to the override
directive in normal makes.)
These directives (and using !) are suspiciously similar to Microsoft’s
NMake. I couldn’t tell you what the true origin is, though.
### Link: Error: Out of memory: unable to allocate resource buffer. (Error 27) for largest module
### Link: Errors prevented normal completion.
Well that’s not good. Especially since Link has previously been known to work and increasing the memory size didn’t help. But it’s repeatable and thus debuggable! The first step is running with --trace-tools to see if anything looks suspicious.
a065 StackSpace(093007f0)
-> 32564
a065 StackSpace(093007f0)
-> 32564
a065 StackSpace(093007f0)
-> 32628
a11e NewPtr(00000000)
a11e NewPtr(00000001)
a11e NewPtr(00000001)
a002 Read(00f763ba)
read(0008, 00f763ec, 00000400)
a002 Read(00f763ba)
read(0008, 00f763ec, 00000400)
a9ee DECSTR68K(0000)
NumToString(0000001b, 00fffc6a)
a11e NewPtr(00000064)
### Link: Error: Out of memory: unable to allocate resource buffer. (Error 27) for largest module
### Link: Errors prevented normal completion.
NewPtr with a size of 0. Quite suspicious indeed. Why would anyone do that? Let’s use the --debug debugger shell and investigate further.
So this is glue code to call NewPtr with the pascal calling conventions (parameter passed on stack, return value returned on stack). $971A(A5) is the parameter (size), which is 0.
So it’s set in a routine called ALLOCDATA, which is never executed. Interesting. One thing I didn’t mention is that this error came while linking a Desk Accessory, which is a driver. My previous usage was for normal applications. If we give Link a -P (for progress) flag, we learn this important fact:
Size of global data area: 0
So Link pointlessly allocates 3 pointers when there is no data. When I wrote the NewPtr code, I figured allocating a 0-length pointer was a rather silly thing to do so it just returned NULL in that case. Link was not amused. Updating NewPtr to allocate memory for 0-sized requests fixed the bug.
TCPIPDNRNameToIP initiates a DNS lookup. This includes calling
TCPIPLogin with port 53, building the DNR message, and sending it
with TCPIPSendUDP – all things that could be done with user-level code.
On success, the DNRstatus field is set to DNR_Pending.
Tool Errors
Tool Error
Explanation
terrTCPIPNOTACTIVE
Marinetti has not been started.
terrNOCONNECTION
Marinetti is not connected to the network.
terrNODNSERVERS
No DNS servers have been specified.
terrBUFFERTOOSMALL
Out of memory error trying to increase the size of the DNR request queue.
TCPIPCancelDNR cancels a pending DNR request and sets the DNRstatus
field to DNR_Cancelled (note the British spelling). The address of the
dnrBuffer serves as the identifier.
The cornbread from my childhood was based on a recipe from the back of the cornmeal cannister or perhaps a well-worn Betty Crocker Cookbook. There was more flour than cornmeal and it was cooked in a 9 x 9 pan.
This isn’t the cornbread from my childhood
I think this recipe originated with The Pioneer Woman but it was adjusted a bit since I didn’t have any milk on hand and I prefer a touch of sugar.
Liquid Ingredients
1 egg
1 cup buttermilk
1/4 cup melted butter
Dry Ingredients
3/4 cup corn meal
1/2 cup all purpose flour
1/4 cup sugar or honey
1 tsp salt
1 tbsp baking powder
1/4 tsp baking soda
Preheat oven to 400°. Place a pat of butter in your cast iron skillet and then place your skillet in the oven while it pre-heats. Combine liquid ingredients then mix in dry ingredients. Pour batter into the heated skillet (the bottom should begin to crust up immediately) and cook for 20-25 minutes.
A while ago, I did some research into
MFS,
the original Macintosh File System. At the time, I was considering
trying to implement a GS/OS File System
Translator for it, though nothing ever came of that. MFS uses a 12-bit
linked-list to store file allocation information, in a fashion similar to the
MS-DOS FAT format.
This similarity is no coincidence; Over the weekend, I found this revealing
passage on Andy Hertzfeld’s
Folklore:
Our first file system used a simple data structure that didn’t scale well
to large drives (in fact, it was suggested to us by Bill Gates in July 1981)…
Apple replaced MFS with HFS a year and a half later.
Microsoft extended FAT (FAT 8, FAT 12, FAT 16, FAT 32) as disk and file sizes
grew bigger before replacing it with NTFS. FAT is still in use due to its
simplicity and universal support.