Hello, cyberpals. I am extremely tired
and it's very cold outside. So I
made a big mistake with the
design of my Amend revision control system.
I thought that using resource forks as like a database
would work well.
And like many things, it worked well right up until it didn't.
And the problem is that resource forks are not
well suited for writing new
resources,
especially adding new ones or changing the size of existing resources.
So if you have an existing resource for your settings
or something where each setting in the resource is
like, a fixed size, and you're periodically updating that
I think that usage is okay. But if you're adding new
resources at the end or deleting
ones or changing the size of them, like growing them or whatever,
you run into the issue that I ran into, which is
when the toolbox routines add a new resource
that is larger than the current resource, like you're
expanding its size or you're adding a new one, it writes
the new resource at the end of the file, and then the map
that keeps track of the index of where each
resource is in the file is put at the end
of that. And the problem is that
if you have some kind of issue,
like a bug in your program that causes it to crash or some
other issue, it can write the new
stuff and then before it gets to
the writing the map, it crashes. So you have no
map in the resource file then. And so the issue that I ran into
with Amend is that I was making a commit in
a repo, and some bug in Amend caused
it to crash, and then the resource-- the repo file,
was left with no index, and a whole bunch of things
were overwritten. And I don't know if that's because it's trying to
update like a resource in the middle of the file. And to
do that, it rewrites every
resource after that or whatever it was
doing. But it basically corrupted the whole most
of the file and especially the index. So I
was unable to recover that file.
Luckily, I had some backups from a week prior,
but I lost a few commits in between,
and because the actual source code files are not stored in the I
mean, they are stored in the repo, but they're just copies. So my actual code
wasn't lost. But then I just had to basically make a commit because
Amend doesn't have, like, a "git add -p"
function where you can interactively add certain chunks of the file,
I basically just had to make one commit on
top of the backup repo, and it was like a
whole bunch of changes that were unrelated. But because the
files had changed so much, I couldn't pick them apart.
So anyway,
since I was using that same kind of database format
for my BBS project,
I thought that that's probably something that I need to fix,
because I'm not going to be able to rely on that, especially because the BBS
code is going to be doing a lot more writing than Amend,
like every time a user logs in or updates their last
log in time or posts a new message on a message board,
it's going to have to write all those things to a file somewhere.
I decided to come up with this new file format,
and it's called bile because it was originally like "blocky file"
where each-- it would be one
file, but it would be split up into chunks of 512 bytes,
and then it would basically manage it like a file system
would where you can write data in each block,
and then you just keep a map of which block is tied to which file.
And it was getting kind of overly complicated. So I just kind of
reduced it down to each object
in the file is just written out whole
in the file. So there's no
blocks or anything. And then there's just a map object that keeps
track of where each file is, where each object is in the
file, which is basically just how resource files work.
Except the way that I'm doing it is I'm never overriding
an object and the
map is never overwriting map object.
What it does is it allocates a new one at the end of the file.
So like if you want to write a new resource-- er, a new object to
the file, it allocates a new object puts it
at the end of the file and then marks
the old object in its map
that's maintained in memory-- it marks that object as
purgeable. And when
it builds the new map, it excludes that reference to that
old object, and then it only has the reference to the new object.
And then that map is then put at the end of the
file after that new object.
And then once it knows that all of that has been written out properly,
it then updates the pointer object at the
beginning of the file and just says that the map is now at the
far end of the file. And then
if you reopen the file or just go forward from that point that
old object that was referenced that is now at the end
of the file, it was purged from the map. So the map doesn't
know anything about that object. So then
the next time when you go to allocate or when you want to create a
new object or write it into the file,
it scans its map and finds where the holes are.
And if there's a hole big enough to fit that object, it can put it
in that earlier position in the file.
So the file doesn't keep just growing forever.
It will keep trying to overwrite purged data
in the file earlier.
So basically you're never left without a map because you either
have the old map that the pointer is still pointing to
and you have a new map somewhere else in the file. And if you get
corrupted anywhere after that, after it starts writing the new data,
if it would crash, whatever. And then the next time you open the file, the pointer
object is still pointing at the old map, which has not been overwritten. So you're
basically never left without a map.
And then I haven't written this part yet, but there could
be like a compaction routine
that would basically just start a new file, take all the objects out of
the old one, and then write them sequentially to pack them
all in. And then once the entire new file is
written out completely, it would just delete
the old one and rename the new one to the old file
name. So it's like an atomic operation, basically.
So you're never left with without
either your old data or a completely intact new
file. So when I ran into this issue
with amend, I basically added a bunch of code
that has to-- every time you do a commit, it backs up the repo to
a temporary file, and then it writes
the resources to the new file. And then that way, if it crashes, you have
an automatic backup of the repo. But because the repo files are
now quite large, they're like almost a megabyte of data.
Having to rewrite that every time is kind of crazy.
So that's why I came up with this format. I already adapted
the BBS code to use this new file format,
and I basically wrote it like kind of like a library. So you just have
some simple routines to create a
new file, you pass in a creator and a type, it uses that as the
file format on the disk or the file creator and file
type. So you can associate them with your own application.
bile_open just opens a file. And then
in each of these instances,
when you create a new file, it writes out a header that basically just
points to that pointer block-- er pointer object,
is basically just pointing at nothing. And then all the other code.
When it has to rewrite stuff, it knows to
check whether it's pointing at a blank map.
So when you open it, it just opens the file and then checks
the magic string at the beginning of it. So it knows it's a bile file.
It then loads the map pointer object.
It verifies that the location
that it's pointing to is not outside of the bounds of the file,
and then it jumps to that position in the file because the
actual map can be anywhere because it's going to get moved around every time you
write a new object, it jumps to that position in the file, loads the
map, and then it also verifies the size and everything.
You can close the [file] and then you can find an object by
its type and its ID. So it's just like a resource
file. Each object has its own type and ID.
So it kind of works like a database where you can have multiple
types, which would be like in their own separate tables.
And then each object has a type and an ID.
You can get a quick count by those types.
You can ask it for the next ID, which is like an auto-incrementing ID
on a SQL table. It basically just finds
the highest ID of a type, and then it
increments it and gives it to you. bile_alloc is to
allocate an object in the map, which this
is like an internal function. So when you
call bile_write and you just pass a type and
an ID and then a pointer to the data and the length of the data,
bile_write calls bile_alloc and allocates
a new object in the map with that ID and
the type ID and the size.
When you write the old object,
if there is one with that type and ID is that the
type is set to the purgeable type,
and then after you write it calls...
it's a private function. It calls write_map
which goes
through the map of objects, and then
it just discards the old map that is stored
in the map. So the map actually contains a reference
to itself as an object because it's just like every other object in
the file. So it discards the old map
and discards any purgeable objects.
And then it writes the new map to
the end of the file or wherever there's free space,
because the map can be put somewhere in the middle of the file
if there is free space, but it will not overwrite the
old map or any purgeable objects until the
second write. So as it goes through this
path, it's not going to because
it doesn't actually switch to
use that new map that it just built until after it's written everything.
So anyway, all of that is--
and then you can delete which, instead of waiting for
the next write to possibly overwrite that data in the database,
you can just call delete and it will actually forcibly
remove it from the database and then overwrite
it with zeros. read_object
is how you would read--
like you would usually use read_object. You just want to pass it a--
so you would find
the object first, maybe.
And then that would return an object. You could search for a user with
an ID or something, and then you would want to read that object,
and so you can pass it the object and then give it a pointer
and the size, and the size--
the size is usually the size of the object. But you can say
like just give me the first ten bytes or whatever of that object,
and I'm actually using that in the
BBS code because
it has to scan every user in
the bile-- in the map. But it
has to read the first part of
the user record rather than loading the entire user record into memory
and then just picking out that first record. It can say just give me
the first size of-- however many bytes
that field is. And then there's
also just a read so you can pass it a type in an ID and
the same thing as this except if you already have
the object from bile_find,
you can just read directly the object. And then if you call bile_read
and pass it a type in an ID, it just
calls bile_find for you and then read_alloc
is the same thing except instead of passing a pointer,
you pass it a pointer to a pointer and read_alloc will
malloc that much data and then load
that data from the file into that pointer and then pass it back to
you and then writes
a type in ID data and the length and then
it also rewrites the map.
So that's pretty much how this code works.
This is just a little regress test suite I wrote for it
so that I can make sure all the stuff was working. So this
all passes and then the bile.c and .h
I already put into the BBS code and
rewrote all of the resource-- the code that would
touch a resource file and handle resources and
stuff. I already migrated to a bile file.
So what I want to do today is adapt
Amend to this.
This swap disk thing is just something that I came up with.
The way that Finder works in System 6 is,
if you ever drag a file from one folder to another,
it always moves it. You can't copy a file to another folder
directly. You can select
a file and then duplicate it and then move the duplicated
file. Except when you duplicate it, it changes the name
or it makes the name of the new file "Copy of" whatever file.
So then you always have to duplicate move
and then rename. It's very annoying, but if you drag
a file to another disk, it always copies instead of
moves. So I'm using the...
MountImage that I talked about in a previous video and
it's basically just mounting a virtual floppy disk of
1.4 Megs, and then if I want to copy files
around, I just copy them to the disk first and
then copy them from the disk to the folder.
So I don't have to do the whole
move and rename-- er, duplicate and rename
thing anyway.
So what I want to do is make a copy of
Amend because this is
going to be like Amend version 2 because the file format is not
going to be compatible. Although I can probably write something that can migrate
from-- I guess I'm going to have to because I already have a bunch of
code in old resource file repos.
But for now it's just
going to operate as creating
a new file.
And then I'm going to copy the latest
code from here.
I really wish there were easier way to copy files
from the Finder that way. Like I know in newer
versions, you can hold down Alt or Command or whatever-- er, Option
or Command as you're dragging a file and it'll copy
it instead of move it.
These are going to go into 2
This repo file is 472K
so it's getting quite large to make
a backup of it every time you want to do a commit.
Okay.
The other thing that I did recently that I don't think I
talked about yet is that I'm no longer using the ANSI C library.
I'm maintaining my own,
which is because Think C provides the source code for their C library,
it's just that with some small additions.
But it is a modern C library.
So some things that I changed are [memmove] can do overlapping
copies because it just calls the
toolbox function block copy, which already supports overlapping
things. And then I added like strlcat and
snprintf which was a big one that I have
been wanting for a long time. It was actually pretty
easy to implement that due to the way that
sprintf works under the hood anyway.
So this is now Amend 2 and we need to add
the new file code into
the main segment. And then I
guess most of these are going to be in repo-- most of
the changes I mean.
So the templates we're not going to need anymore because
you're not going to be able to edit things in ResEdit anymore.
I will probably need to make like a simple GUI utility to
manage to edit files that
we can use on Amend or BBS
code, but for now
we don't need templates.
Okay, this just calls repo_open.
The other annoying thing with using resource files is like--
as a database-- is that anytime you need to load
or update a resource in the actual
program's resource fork, you have to kind of
swap things around and make sure you swap them back after.
Because anytime you do like a
lookup for a resource, it's going to use the current resource file.
And when you're using a resource file
as a database, that becomes the current resource file. So it's
going to look for things in there that
aren't going to be there. Okay. So I think we can do
all this in repo so far and
delete those templates.
And because the types in a bile
file are the same-- like they're a long integer
to give you four characters. All of the types can be
the same.
Then the repo is going to need to have
a reference to the file.
So a repo file that's a file
in the repo.
These are actually also in the bile object,
so we don't need these are just going to get passed
directly to the bile code.
Ok. So repo_open calls repo_init.
repo_create calls...
We don't need to create a file ourselves here.
I think the way I did it in the BBS code was you
just pass do
the opening here and
then you pass a bile object.
I am very tired today.
My child is not sleeping well.
Just a file name.
We don't have a file name from...
where does reply fName come from?
Okay, so we don't need to do this anymore because we're not
going to pass...
Okay, so we will just pass that.
Actually, no. We probably need to look up the path of
the file that we are passed.
Okay, that will store in a pointer that gets
allocated, and then
we need to convert
it to a Pascal string.
Pass it to file_open.
repo_create kind of does the same thing.
And then it was a file name and
think just a creator and type and
then this returns
null.
Right. Because file create does not handle
deleting an existing file.
So the create will fail with that code.
So if you get a duplicate
error,
we will file
I don't think we need to pass is_new anymore because that...
All right, we'll continue passing that then.
Right. Because this returns a repo
repo_create. We'll pass one.
Okay, so repo in it. Then expect a
file or a file
that bile already has the file name and the
stuff in it. It's already open.
We don't need that.
We don't need to store the file name.
Okay.
Happy new year, everyone.
So this is going to turn into a--
I was getting into the habit of calling them bob
because bobs are fun.
So bob will be fine.
Yes, we do.
So this parses
the file.
So this is not a file object. This becomes
file read alloc because we're actually just reading the entire
file. Right.
And if it returns null,
the object wasn't file the
type, the ID,
some pointer to a file.
Okay, so we're not actually reading the object.
Sorry, bob, we don't need
new path.
I thought about putting every object
of a type in its own file, but on
Mac HFS volumes, there's a maximum of 65,000
files for the whole file system because they're stored as
a short like the file
ID stored as a short. It's kind of small.
Anyway,
we'll read_alloc into fdata.
Otherwise the file will parse the data
and then free that
will sort the files count commits.
This is all just going to do the same thing.
So maybe we can just call this data
to be super generic.
Got to pass the final object that
does that. And then we will say commit
type number
ID into data.
Zero parse
the commit and then free the
data and
we stored the file. Right? Yes, we did.
repo_close.
I need to check that. I don't know if it's trying
to directly to
a resource or not.
Free all of the file data and
free the repo...
repo_parse_file. We'll just take the data.
Yeah, let's pass the size because
we can't look up the size like we can with the resource.
So that comes from the object.
Pass the ID because we already know it.
File ID becomes-- I'm
using size_t as the integer type in bile
or as the ID type.
That's not technically correct,
even though they're the same type. I should probably just make that clear.
That could test as a short. Anyway,
we'll do that just to be because
nfiles can actually be the
count is returned as a size_t,
but we're storing it as
short because we're never going to have that many files anyway. Whatever.
Copy this.
This one manipulates uses data
plus data pause and this one just manipulates
the pointer.
They should probably do the same thing, but I don't want to change that right
now. I'm taking Andreas's advice
and only sticking to what I'm working on.
Okay, so the log is a new handle. It's not a
resource,
so we don't need that.
And then this is not even checking the size.
Probably should.
Okay, so this is loading a diff into memory.
It's the size and
then only
request the text edit size set
handle size.
This is all very weird, but we don't need it anyway.
We don't need to do any of this because we can just read however
much data we want from the object block.
Move into h plus header line.
So this is shifting data down and
then copying.
Okay, so we can actually do this a lot easier.
Okay. And then we will say all
in we
will copy into
the text,
copy into our new buffer. The header that's
done. Why are we even doing that?
Because that has to allocate its own.
We could probably even shrink that and just pass it
dtext and have it write,
because we don't know the size of it is the issue.
And then we would have to realloc the buffer to
grow it. We'll just use two buffers, then copy
into the text buffer the header and
copy the link.
Then we can free buf.
Then we can copy into...
we haven't loaded it yet.
Okay, so now we will do bile_read.
We already have the object, don't we? Do we
have a bob so we will read object.
The size will be all
links, header length and
we will check the return value
the bigger ones. First,
I was like trying to return the error code
and then you'd have to pass a
pointer to the size because that's kind of how the Mac functions
work, but I find it very annoying because when
you want to pass in a size to read and then get a size
back that it actually read the way that Mac
does it. You set a variable to the size,
and then you pass a pointer to that variable, and then it reads
that on the way in as how
much you want to read, and then it overwrites that variable on
the way out and says how much it read. But when you want to error
check, you have to copy the variable ahead of time because it's going to get
overwritten and then you have to compare the two so it doesn't really buy you
anything. I'm sure it makes the toolbox
assembly function smaller. So I'm
having my own kind of errno variable that you can access
with bile_error, which is kind of how the resource functions work.
You call ResError to see if there was like what the actual
error code was. Anyway. So we read
the object of that length and we put it into
the buffer after the header.
Then we copy into
detects plus max text edit size minus trunk,
whatever. And then
we can just insert our text and
then free our text.
No, we don't want to do that anyway.
Okay. So I think that was easier.
All right.
Okay. Add a file repo,
get file find.
It doesn't matter anyway, because bile right handles all that for us.
Yeah, we don't need any of this data.
Avoid having to change that.
Okay. And then we don't need this stuff anymore because right hand
type ID, data length,
type ID data.
That's an annoying way of doing that.
Now we need to let's
do this a better way, shall we?
I like the data pause kind of thing.
I don't want to change the pointer because we need
it.
I haven't converted this project yet, but I like
using the panic function instead of error because
error doesn't make any sense here.
And then we don't need that because rights
always happen when you call bile_write, and then we
can just free our data
there.
Does that make sense?
Get file Editors. I don't think this does anything with a resource check
out file.
Get to use one of these. Sometimes I
don't know why I keep forgetting that file
type ID. If that is null,
copy exists in the repo.
Are we storing the file in the file?
Because the one thing that I just glossed over there
is resources.
You can assign a name to them. And I was using that
as an index, but not index, because you can have the same
resource with the same name. So I would
store the file name as the name of the resource,
and then you can look up a resource by its name the
way that I'm doing it. I don't have that functionality in bile because I don't
often need it.
But what I was doing was putting
in the BBS code where I had to store a username. And then when I
want to find by a username, since I can't just
look up the ID, I have to scan the whole list of users to find
by a username. I was having, like, a username
key as the beginning of the
struct, which is actually a lowercase version of the name, because I need
to find a user by case
insensitive username match.
So I was just storing the username key as the first
part of the struct that gets written into bile,
and then when I want to quickly iterate over them, instead of reading
the entire user record into memory,
I can just say bile_read the size of the
username key, and then it would only have to read, like,
16 bytes or whatever of each username.
So I might put in some
kind of index so that you can look up
by name or store and name, but I
haven't really needed it a lot. So I was trying to avoid it anyway.
So this is finding the object if it finds
the object.
Right.
Okay, so this loads the entire text file into
memory and then writes it to a new file.
But we don't really have to do that with bile, because we don't need
to load the entire resource into memory,
so we can, like, do it in chunks,
read a chunk from the bile file,
load that into memory, and write it to the new file.
Yeah, I like that idea. So we will say
length is greater than let's
call this size,
so I guess I will need that. That's annoying.
So the read doesn't have an offset, so it can only read from the beginning.
All right. Well, we were reading the entire text
thing in the memory before, so I guess that'll work for now,
but oh,
dear, read allocype.
So I have to find it again. It's kind of annoying.
Well, if we have the size, we can just do it ourselves.
Then I
feel like here is the case where I was talking where you pass in a
length as a pointer, and then it returns that pointer or
returns the value in that variable,
but now we need two of them to compare.
I guess it will never fail,
or it will never be.
Not that size if it didn't fail,
but still.
Okay, next,
let's file in
the file code. When you do bile_find,
the object that this returns is a direct
pointer to the object in the map
so that it doesn't have to allocate something,
because like, here, if I just passed directly the
text object size, it would get overwritten in the map.
So I probably shouldn't do that.
So I should probably make file find allocate
it and return it, and then you have to free it to
avoid that problem.
Okay, I'll do that later.
Right. We have to do that again.
Text.
Okay.
Text.
What?
What is this even doing with it?
That's weird.
This is probably copied from the previous function.
That's weird.
Hey, we get to use a Bob.
Oh, I see what it was doing.
I did all that just to get the size of the resource.
We don't have to do that because we have
a yeah,
you know what? Before I forget, I'm going to
make it do that. It's going to allocate.
And this was already in there because when you sort you
can't hang on to.
Okay,
I think I have a constant for that,
even though it is that value.
Okay.
And then anywhere
that we call that, we have to free
it afterwards.
So this is actually doing what we because
it was relying on that because
it needed to manipulate the map.
Is that the only place?
All right. So I guess we have to duplicate that too.
I didn't even write that correctly.
So that will return a direct reference
to the object.
We'll call it like,
okay, I'm back.
I don't know.
So this will return the actual object.
Math finds.
I like that better. So now we need to figure out where we used.
Okay, that looks up a diff.
What is going on here?
Create the file, open it,
truncate it,
write the header into a buffer,
and write the buffer into
a file.
I don't like that pattern of manipulating the even
weird. I've done this like three different.
How about we do so
we can do it that way?
I guess we're going to manage this ourselves.
Store different.
This is not the value. This is the name field
that I was saying that file doesn't support.
We don't have name,
but we do have this
gets past handle,
and then we can start
new versions of each file repo file with ID
file.
So we need to copy that into memory until
we have the file right at an offset.
This is all reading into one file anyway.
It doesn't really matter.
Read into type
file size, the ID, and we have
no file.
I think that's all of it. Except for the migration.
We don't really need the backup stuff anymore,
but we may as well keep it.
I'm just going to say new
version.
This doesn't make sense because it says migration
code, so it all has to read resources.
I'll comment that out for now because we're going to be dealing with empty files
right now. Anyway.
There's a lot of changes without checking
if it worked,
right, because we don't have panic, but we do have an
updated utility from our
other projects.
Before I forget, I'm going to copy the modified bile code.
I'm going to copy the
util code into the
file code into the file and
subtext.
Okay, does that make sense?
And now I just want to rerun the regression tests
on file, make sure I didn't break
anything since
it changed its API.
And then anywhere we do find, we have to free it,
which I have to do in subtext, too.
Oh, no, just realized that I haven't
been wearing my microphone since I got back.
Sorry about that.
Oh, that's weird. You have to flush data after closing a file. It doesn't
do that automatically.
35.
What is this anyway?
That's an unrelated issue.
What was it?
No such value.
Why are you being this way of
a file? How do you get the volume of file?
All right, I will have
to come back to that and require some investigation.
Whatevah!
So now we need to copy the bile code back
to amend 2
and subtext.
All right, because I modified repo.h.
Anyway,
look at all of them arrows.
My Macintosh Plus arrived that
I'm going to be using for my BBS.
I did some work on it yesterday.
If you check my Twitter account, I have a bunch of pictures and
stuff about what I did.
I also adjusted the width of the
screen on this machine a little bit because it seemed like it was too wide.
Once I measured it against
the actual specs of the width that it's supposed to be.
I found it to be a Ted, too wide.
So you may be seeing the screen slightly different today,
right? Because it's a stir
55.
So weird. Why am I even bothering to zero?
That's weird. Why didn't it hit the bomb in
the browser? Because it's the same thing
also, we have,
which is useful because you
should still check that whether it truncated and do something.
But the main point is that
when it does exceed
your buffer, you're no longer just scribbling over random
memory. So there's
that.
All right.
Okay, so converts the file name,
print it to the title, convert the title to
a Pascal string saying here.
So I guess while this is committing, when I was working on the snprintf,
I was looking at the code for it's like vprintf
or whatever-- or vsprintf
something like that.
I always thought that the way that sprintf and friends worked
was like it would compute the value and then check
that, printf would check the value length
against the total
length that it was given.
And if it had room, it would append
it.
But what it actually does is it sets up a fake file handle
that stores--
that has a limited size. And when you try and write
to that file handle and you run
out of room, it gets like an EOF, and then it just
stops,
which is how I implemented snprintf. Like, I just made it so that
when you get an
EOF, it just stops
instead of returning an error.
But I thought that was kind of weird. I think it works that way,
like on normal Unix, too.
It's not just like, appending memory or appending each
variable that it's printing to a block of memory.
It's like writing to a file handle, but the file handle is
like a fake memory
backed file handle.
Oh, because that has to allocate eight Dang it.
This is expecting a Str255.
Can you just tell that
it is?
I don't think that works.
I don't know how
to cast that properly.
I guess it would just be the address, right?
But then the function is expecting,
right?
That's what I thought.
Wait,
because I forgot to change all these prototypes.
I'm back. Let's try this again.
This is not casting because a
Str255 typedef is
just unsigned here. We just
need to cast it to unsigned and
it should work.
I got interrupted and it's Dirk
now. Oh man,
what's the deal here? Get pass, I guess returns
or where is it signed character?
I don't know why this even returns a C
string instead of 255.
It seems like that's
a weird function that I wrote,
but since these are all, I don't want
to change that pointer
to a pointer.
I probably didn't update the prototype for this and
parse commit, I think, was the same thing.
Okay, let's try this.
Of course.
No, bob,
just file signs.
I don't know why I keep forgetting that I
don't know what it says about my API.
If I can't even remember the function names
that I added to it read
object file.
This is the other thing is that the file name in
the bile struct is a Str255
like a Pascal string.
repofname.
That's weird.
It's definitely annoying having to deal with functions that take
Pascal strings in the Mac toolbox, and then all of the C functions handle
strings as character arrays,
but at least in my functions, I'm trying to use
Str255 everywhere,
so I know that it expects Pascal string.
I guess it's nice that I didn't have to change any other files because everything
was contained in Repo acting
weird in file too.
And then I'm going to turn off the automated
backups of commits because
we shouldn't need them anymore and
they're very slow.
The diff does come as a handle.
I don't remember changing that, but. Okay,
file name
copy and the source file name. The file name.
Get the path into path to
source filename path off.
So it's just using source file.
Okay, this whole
converting back and forth between C and Pascal strings is very
annoying.
So we can't use source file name,
right? Because repo bile filename is
Pascal string.
How annoying.
So we have it in PA.
Let's do this because
this takes so
it can just take file name
directly returning it in
path.
We will use that ourselves
in repo file name,
PtoC repo file name copy and a source file name
file name.
I guess it would be helpful to have CtoPstr and--
Oh no, I think
I lost that in util because Amend
had its own problem
with copying
all these files around, so I keep losing which version
is correct,
but when you put them into a library, you lose all the ability
to step through the code and stuff.
Am I missing anything else?
The variable in line, it would
be useful to have one that makes a copy of it and
then returns it
so you could assign it to a new variable and do the copy
and play, and then it would Mem copy it so it
would allocate a new string. Mem copy it, then do
the conversion and then return the copied
string.
This video is going to be very long.
I don't remember if I put sternet. Comp into new
MYC library. I think I did so I can drop these files.
Yeah, I did.
I don't know what's this about.
I think it's because there's
no separate Unix library with my exercise
long. Do we even need that?
I guess I dropped those from the util.
I think that's was a case of, like,
copying files around and not having the latest version.
Weird. They're still in there.
Okay, whatever.
We finally linked,
so it's probably going to try and load the
previous.
Oh, right. It always asks for the file,
so we're going to cancel. We're going to create a new repo,
and we will call it and
we will add a file.
Failed looking up directory.
I must have broken...
Where are you?
repo_add_file can't add path to repo.
Okay,
I updated the vwarn
function that panic and error and warn use so
that it could build the dialog window itself
rather than having to use a dialogue resource
in the resource fork of the program so
that I could use it with like, I could quickly make a new project without
having to add a bunch of resources to it. But I could still use
the panic function and it works the first time, but apparently it's broken
after that, so I'll have to fix that, but it
looks like it's at least linking now,
so I need to go through and see what these specific
issues are here. But this video is getting very long,
so I'll just cut it off here. If you watched
this long...
what is wrong with you? Thank you. And I'll see you in
the next video. Bye.