Retro Coding: Crafting a Vi Text Editor in BASIC
A nostalgic journey into building a Vi-inspired text editor from scratch using the BASIC programming language.

You’ve just finished writing some critical data to a file – maybe configuration settings, image data, or serialized objects. You check the file, and it’s corrupted. What happened? The most likely culprit is how you told Windows to handle that data, particularly if you weren’t explicit about it being binary.
Windows, at its lowest level, treats all files as raw sequences of bytes. It doesn’t inherently know or care if you’re writing text or a compiled executable. The confusion arises from higher-level libraries, especially the C Runtime (CRT), which introduce modes that can automatically alter your data. The default behavior on Windows is often to assume text files, and this assumption can silently corrupt binary data.
The primary transformations that wreak havoc on binary files are:
\n) into the Windows-specific carriage return and line feed sequence (\r\n) when writing. Conversely, it converts \r\n back to \n when reading. For non-textual data, this insertion and deletion of bytes will corrupt the file’s integrity.0x1A (ASCII/UTF-8 for Ctrl+Z) is often treated as an End-Of-File (EOF) marker in text mode. If your binary data happens to contain this byte, the file write operation might prematurely terminate, leading to truncated files.To avoid these silent corruptions, you must explicitly tell your file I/O functions to treat the file as a stream of raw bytes.
Using the C Runtime (CRT) with fopen:
When using the standard C library functions like fopen, fprintf, fread, etc., you must append the b flag to your mode string.
Incorrect (Default Text Mode - Potentially Corrupts Binary):
FILE *fp = fopen("mydata.bin", "w"); // Opens in default text mode
if (fp) {
// Writing raw bytes here might get corrupted by \n to \r\n conversion
fwrite("some\ndata", 1, 9, fp);
fclose(fp);
}
Correct (Explicit Binary Mode):
FILE *fp = fopen("mydata.bin", "wb"); // 'b' signifies binary mode
if (fp) {
// Writes exactly the bytes provided, no transformations
fwrite("some\ndata", 1, 9, fp);
fclose(fp);
}
Similarly, for reading, use "rb", and for appending, use "ab" or "a+b".
You can also change the default mode for all subsequent fopen calls by using _set_fmode( _O_BINARY ); at the start of your program, or alter the mode of an already opened file descriptor using _setmode(fileno(fp), _O_BINARY);. However, explicit "b" is generally clearer and safer.
Using the Win32 API with CreateFile:
The lower-level Win32 API functions, like CreateFile and WriteFile, operate directly on bytes and do not perform any automatic text transformations. They have no concept of “text” or “binary” modes. When you use these functions, you are inherently working with binary data.
HANDLE hFile = CreateFile(
L"mydata.bin", // File name
GENERIC_WRITE, // Desired access
0, // Share mode
NULL, // Security attributes
CREATE_ALWAYS, // Creation disposition
FILE_ATTRIBUTE_NORMAL, // Flags and attributes
NULL // Template file
);
if (hFile != INVALID_HANDLE_VALUE) {
const char* dataToWrite = "some\ndata";
DWORD bytesWritten;
WriteFile(hFile, dataToWrite, strlen(dataToWrite), &bytesWritten, NULL);
CloseHandle(hFile);
}
CreateFile and its related functions are the most direct way to interact with files on Windows without intermediary interpretations.The need to specify b for binary mode is a convention that helps bridge the gap between POSIX-style I/O (where the b flag is often ignored by the OS but recognized by some C libraries for compatibility) and the Windows CRT’s specific behavior. Languages and libraries built on top of these, like Python (open("file.bin", "wb")), often adopt similar explicit modes for clarity and cross-platform consistency.
While the Win32 API offers the most direct byte-level control, the CRT functions with explicit binary modes are sufficient and often more convenient for many common programming tasks.
The notion of “informing Windows” about file types is a misnomer. The operating system fundamentally deals in bytes. The responsibility for interpreting and potentially transforming those bytes into “text” lies squarely with the application and its runtime libraries.
For any file that is not plain text, or when exact byte control, precise file size, or reliable seeking is paramount, always use explicit binary mode. For CRT functions, this means appending 'b' to your mode string (e.g., "wb"). For the Win32 API, recognize that its functions are inherently binary. Failing to be explicit about binary mode is a recipe for silent data corruption, leading to hours of debugging for problems that could have been avoided with a single, simple flag. Don’t let the default text-mode assumptions of the Windows CRT sneakily destroy your data. Be explicit.