Waybackwhen, I wrote this proposal for a very simple BBS networking protocol. There were several in existence, but the specs were always complicated. I wanted something someone could implement without a Phd ;-)
The following is a proposal for a new CoCo BBS message networking protocol created by Allen Huffman at Sub-Etha Software. This protocol was designed to easily allow the CoCo community to link BBSs together for mass communication within this network.
Background:
Several successful BBS networking protocols are already in existence such as FidoNet and WWIVNet. Although very powerful, these systems require large amounts of disk space to operate and have so far been limited only to systems with hard drives.
Introducing the Sub-Etha Net:
The proposed “Sub-Etha Net”, henceforth known as SENet, will be a low-hardware CoCo specific network designed for the sole purpose of linking the online CoCo community together with one massive public message base.
At this time, no private messages between systems will be supported. This will greatly limit the amount of overhead required by each system. Current protocols have required each system within the net to store a “net list” containing information on ALL systems within the network. SENet will not require such a list and no “hub” systems are needed.
How it Will Work:
In order to link with the network, the Sysop will simply insert the phone number of the system it wishes to net with and configure a few settings which control when and what it will transfer. The system you plan to net with will also add your number to its listing. Once this has been done, no further configuration will be required. A simple message pointer flag stored for each system is all that is required to keep track of messages.
An Example: System A will call System B and transfer messages.
At the specified time, System A dials a number stored in it’s net list.
Upon connection, System A waits for a prompt (such as “Press Return:”) then sends an escape code and it’s phone number (in the form ###-###-####) to System B.
System B will look up that number in it’s net list and either ACKnowledge or request the number to be resent (in case of line noise).
If several unsuccessful attempts are made, System B will disconnect. (If this was caused by line noise, this forces System A to redial and try for a better connection.)
After a successful connection, System A sends a four byte number stored in it’s net list which instructs System B to send all messages it has from that number on.
System B then sends messages (with appropriate error checking).
System A will ACKnowledge the transfer (or request data to be resent).
Depending on System B’s configuration, System B will either send a final ACKnowledgement and disconnect, OR it will send it’s four byte number for a message request.
System A then sends messages (with appropriate error checking).
System B will ACKnowledge the transfer (or request data to be resent).
System A will send a final ACKnowledgemend and disconnect.
Message base structure:
To keep things a simple as possible, the message base will contain only the following information…
From: Name of poster (30 characters)
Subj: Message subject (40 characters)
Date: Date/time posted (6 character packet)
This allows the message “header” to fit in one 80 column line of information. Any other information such as “To:” or “Reply to:” will be contained in the actual message text portion of the file. This allows excellent flexibility for future expansion.
I wonder what else I will find in my archives. I still think something like this was a good idea — low overhead, simple to implement even in BASIC (though requiring an assembly language remote terminal driver), and “just enough to get the basic stuff done.”
Maybe one day we’ll do something like that using a CoCo and a $10 WiFi Modem for it ;-)
It seems I started running a BBS in Lufkin, Texas around 1989 or so. It ran under OS-9 which allowed me to still be programming on my computer and such while a caller was online. Fun times.
Delta, meaning change, was significant here. The BBS would change themes! (This idea came from, I believe, an MC-10 buddy of mine I knew in Houston. Hello, Paul, wherever you are!)
I recently found a few of the themes and thought I’d share them here… Welcome screen, bad password screen, login screen, and goodbye screen.
DeltaBoard (native theme)
____ ____ _____ | \ | | | /\ | ) |--- | | / \ Online Since December, 1991! |___/ |____ |____ | /____\ Originally Online in 1989!
/) The DeltaBoard (\ 3/12/2400 Baud - MNP5 - 8/N/1
Co-SysOps: Axel and OSIRIS
"Online Home for Sub-Etha Software!"
To request a password, press [Return] at the UserName prompt.
Special Login Accounts (type at the UserName prompt):
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
---
The password you have entered is invalid.
Please check your password then try your call again.
If you need assistance, or have forgotten your password, you may call back and logon as "guest" then leave feedback to the SysOp and tell him what you want for a new password that you can remember...
---
Access granted to Allen's Half-Meg 6809 Based Multi-Tasking Timesharing System. ___ ___ ___ ___ ___ / / /__ _ /__/ The DeltaBoard - Lufkin, Texas \___ _\__ \ _ /__/ ___/ ___/ Area (409) Hub for StG Net International __\ \__ \__\
---
[Y)es - End call.\ [N)o - Return to main menu.\ [F)eedback - Leave mail to SysOp.\
King: Allen Huffman of Nothingham Surf: Sire Axel of Oile Chief Peon: Osiris
"It has been a long fortnight for you, I see," says the Greeter. "Well, come inside and chat with the King, or have a tankard of our finest ale. All is well here!" he finishes.
To request a password, press [Return] at the UserName prompt.
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
---
"Halt!" screams the greeter, suddenly not beeing so greetful. "I do not recognize you! Are you the imposter we have heard of in the village? Please call back and knock again when you can remember who you are lest the guards throw you in the dungeon! If you still need help, you may pretend to be "GUEST" and the castle helper will help you...
The doors shut.
Click. ---
The old wooden doors creak open slowly. Inside, you can see that there is a ball in progress with ladies dressed in their finest and gentlemen laughing boisterously. A sense of excitment fills the room as the ladies pause to glance at you and the gentlemen rush to shake your hand.
"Welcome back! So glad to see that the battles have left you none the worse for wear!" someone says.
King Allen himself is here, and is waiting to speak with you about your journeys. But first, you must meet with your beloved mate.
"Tell me about it," your mate requests. "Tell me everything...!"
Of course, your mate cannot hear you over the party so you must write everything down. For your convenience, Castle Delta has a list of options for you to use. Enjoy all we have - all one needs to do is ask, and it shall be given. Enjoy your stay!
---
The time has come for you to depart. Beware the many pitfalls in your path\ and remember: when you need a break from the world, come to Castle Delta.\ We will always welcome you as our most important guest. If you would like\ to leave word with King Allen about your stay, feel free to do so...\ \ [Y)es - Leave the castle.\ [N)o - I forgot something. I gotta go back and get it!\ [F)eedback - Leave the King mail. {Not chain mail, though...}\ [O)ptional - Talk with, or leave a message to, a peon...\
---
As you exit, the castle door slams shut, leaving you to wonder just what lies ahead in this dark, sinister world. But, you take solice in the fact that you may return at your next opportunity. After all...your mate is here behind the walls of Castle Delta!
Manager: Allen Huffman Clerk: Axel Bellhop: Hopsing
[.. VACANCY]
To request a password, press [Return] at the UserName prompt.
Special \\ Guest - Forget your password? Login >> OldDelta - To login to the ORIGINAL DeltaBoard circa 1990. Account // PKZip - To download the latest version of PKZip (2.04G)
"Please sign the register..." the clerk requests.
---
"Are you sure this is your credit card?" the clerk asks.
"Please come back again when you have proper identification and sign in {and make it legible next time, buddy!} or, if you have never stayed with us before or cannot remember if you have, register as a "GUEST" and someone from management will be happy to help you with your luggage...
The clerk dissappears into the back room. No amount of bell ringing will bring him back so you decide to leave...
Click.
---
"Welcome to 'zee Hotel" the clerk says. "Hopsing will take your baggage, not to worry. In the main lobby you will find a comprehensive directory of our services. Since you are a Valued Guest, all services are free of charge! You also have a listing in your room, if you are weary. The hotel manager is at your service. Press the 'C' button at the elevator and you will belifted to his suite! If he is not there, just leave him a message. He will have Hopsing hand deliver it to your door" finished the clerk. {whew!}
"It is encouraged that you talk with other guests and staff so that we all may be to know each other better," starts the clerk again, "therefore making your visit more enjoyable! There are many activities to choose from, and the conversations run from docile to very lively! If you ever need me, just press the 'H' button at any elevator and I will assist you in any way. Thank you for checking into Delta Hotel..." stops the clerk.
---
We hope you have enjoyed your stay at Delta Hotel. If you care to, leave\ comments to the manager!\ \ [Y)es - I gotta run! I have to catch a plane and BOY are my arms gonna\ be tired!\ [N)o - I left something in the room! I'll be back shortly...\ [F)eedback - Leave word with the hotel manager.\ [O)ptional - Express sympathy to Hopsing {he never gets mail}...\
---
Thank you for sleeping with us! Tell your friends! Tell your neighbors! Tell your Uncle Fred in Idaho! The Delta Hotel is open 24 hours a day to serve you, so feel free to drop by any time. Hopsing has loaded your baggage and you are all set to go...
{And bring back those two towels in your suitcase when you return, eh?}
(Hotel Delta script/ideas by Osiris)
Click.
From the way these are numbered, there was at least one more theme but the files were not with the others (odd, that).
Meanwhile, in Iowa…
In 1995, I moved to Iowa. I put my BBS online here, with a set of new themes:
DeltaBoard – “Online in Iowa since last week!”
Star Dreck – The Lost Generation
Castle Delta – with a new look
Hotel Delta
Haunted Mansion – Disney, eh?
Phone # – just showed the phone number, and seemed to have snarky menus
Al’s Den of Iniquity – “Beware: No Furniture”
I had forgotten about most of these. I’ll have to share those sometime. And a few more I have also found (or at least partially found).
I have been going through all my OS-9 hard drive images trying to get everything compiled into one place. During this project I ran across a folder called DECB (Disk Extended Color BASIC). It contained the following files:
I had no recollection of what this was, nor why filenames were in lowercase. That was not normally how files were done from Disk BASIC on a CoCo due to the 32-column screen showing lowercase as inverted video.
The “microwar.txt” was an e-mail response to an inquiry I made to Microware in 1993 about the history of OS-9:
INTERNET# Document Id: UX00f.BUX0039573
Item 6352278 93/08/24 06:03
From: STEVES@MICROWARE.COM@INTERNET# Internet Gateway II
To: COCO-SYSOP Allen C. Huffman
Sub: Re: The History of OS-9
From mcrware!microware.com!steves@uunet.UU.NET Tue Aug 24 17:24:36 1993 Received: from relay1.UU.NET by relay2.geis.com with SMTP (1.37.109.4 /15.6) id AA23578; Tue, 24 Aug 93 17:24:36 +0100 Received: from spool.uu.net (via LOCALHOST) by relay1.UU.NET with SMTP (5T.61/UUNET-internet-primary) id AA11760; Tue, 24 Aug 93 12:24:35 -0400 Received: from mcrware.UUCP by uucp2.uu.net with UUCP/RMAIL (queuweing-rmail) id 122237.10246; Tue, 24 Aug 1993 12:22:37 EDT Received: from yme by microware.com with SMTP id AA00775 (5.67a8/IDA-1.5 for <coco-sysop@genie.geis.com>); Tue, 24 Aug 1993 10:03:08 -0500 From: Steve Simpson <steves@microware.com> Received: by yme id <AA00684@yme>; Tue, 24 Aug 93 10:03:04 CDT Date: Tue, 24 Aug 93 10:03:04 CDT Message-Id: <9308241503.AA00684@yme> To: coco-sysop@genie.geis.com Subject: Re: The History of OS-9
The “Steve” there was Steve “Homer” Simpson, who I would later know when I went to work for Microware two years later. He provide me with a Microware history article, and a Ken Kaplan interview about Microware’s first 15 years. (Note to self: Get this archived somewhere.)
The “TEST.TXT” file was a 300 line text file, obviously created by a program, that was just this:
This is a file of 300 lines or so, and this is line number * 0*... This is a file of 300 lines or so, and this is line number * 1*... This is a file of 300 lines or so, and this is line number * 2*... ...snip... This is a file of 300 lines or so, and this is line number * 298*... This is a file of 300 lines or so, and this is line number * 299*... This is a file of 300 lines or so, and this is line number * 300*...
I was a bit confused at the purpose of these two files. Fortunately, “contents.txt” cleared things up a bit.
Jan '95 #01 Demonstration Issue 1. All About This Program Allen C. Huffman INFO
2. REALLY *BIG* FILE Bob's Big Boy TEST
3. Microware Information Microware Staff MICROWAR
4. Stuff For Sale Various FORSALE
5. Useless File Bob USELESS
6. Nothing Dan NOTHING
7. Something Bob & Dan SOMETHIN
8. Movie Reviews Sis Kehl MOVIES
9. Spam Recipes Mr. Cook SPAMSPAM
F. Another File Another Writer ANOTHER
G. Nothin' Nobody NOTHING
H. Nothin' Again Nobody Again NOTHING
I. More About Flies Spider-Man FLYFILE
J. Jump Text Jumpman Bob JUMPTEXT
K. KeepThisSecret Spy SPYFILE
*. Use Star for This StarMan STAR
Seeing my name in there let me know that this was indeed something I was involved in. But what was it? I needed to move those BAS files over to an emulator and take a look.
Fortunately, one of them was already in ASCII – “reader.asc” – and it was indeed a BASIC program that apparently I wrote back in 1995.
0 REM * 1 REM * Text Viewing Program Thingy V1.00 by Allen C. Huffman 2 REM * Copyright (C) 1995 by Sub-Etha Software 3 REM * Written for Terry Simons and the MI&CC Upgrade Diskletter 4 REM * 5 PALETTE0,0:PALETTE8,63:WIDTH80:CLS1
I had zero recollection of writing this, but I remember the Mid-Iowa & Country CoCo Club (MI&CC) and its organizer, Terry Simons. Sub-Etha Software attended their Middle America Fest held in Des Moines in 1993. Somewhere, I am pretty sure I have photos from this even, but they are not in my online CoCoFest photo gallery for some reason.
I could tell this was something I wrote, since that line 5 of doing the background black, foreground white, width 80, CLS1 line was how I started all my CoCo 3 BASIC programs.
A quick scan of this program, which I will include in full, reveals it would read the “contents.txt” file and display a directory of text files (articles) on the disk and let the user select one. It would then load the file and let them read it, with options to go page to page through the file. A text file reader with a menu system – neat!
0 REM *
1 REM * Text Viewing Program Thingy V1.00 by Allen C. Huffman
2 REM * Copyright (C) 1995 by Sub-Etha Software
3 REM * Written for Terry Simons and the MI&CC Upgrade Diskletter
4 REM *
5 PALETTE0,0:PALETTE8,63:WIDTH80:CLS1
10 CLEAR17000:DIMFL$(15,3),A$(200)
50 REM * Read Index File
55 OPEN"I",#1,"contents.txt":LINEINPUT#1,IS$:LINEINPUT#1,SB$:FL=0
60 FORA=0TO3:LINEINPUT#1,FL$(FL,A):NEXT:IFEOF(1)=0THENFL=FL+1:IFFL<30THEN60
65 CLOSE
100 REM * Table of Contents
105 CLS:LOCATE28,0:PRINT"Mid Iowa & Country CoCo":LOCATE40-LEN(IS$)/2,1:PRINTIS$;:LOCATE0,3:ATTR0,7:PRINT:ATTR0,0:LOCATE0,22:ATTR0,7:PRINT:ATTR0,0
110 GOSUB1155:LOCATE35,2:PRINT"Main Menu";:GOSUB1130:LOCATE23,23:PRINT"Select File to View or [Q] to Quit";
115 FORA=0TOFL:LOCATE40*ABS(A>7)+5,(A AND7)*2+5:PRINTFL$(A,0):LOCATE40*ABS(A>7)+23,(A AND7)*2+6:PRINTFL$(A,1):NEXT
120 GOSUB1055:A=0:IFA$="Q"THEN450
125 IFA$=LEFT$(FL$(A,0),1)THENFL$=FL$(A,2):A$=FL$(A,0)+" by "+FL$(A,1):GOTO205ELSEA=A+1:IFA<16THEN125
130 SOUND100,1:GOTO120
200 REM * View a File (FL$)
205 LOCATE40-LEN(A$)/2,2:PRINTA$;:GOSUB1130:LOCATE2,23:PRINT"[UP] Next Page [DN] Prev Page [J]ump to Page [P]rint File [Q]uit to Menu";:LN=0:
210 GOSUB1105:ONERR GOTO245:OPEN"I",#1,FL$+".TXT":ONERR GOTO
215 LOCATE32,13:ATTR0,0,B:PRINT"Loading File ...":ATTR0,0:MX=0
220 IFEOF(1)=0THENLINEINPUT#1,A$:A$(MX)=LEFT$(A$,65):MX=MX+1:IFMX<200THEN220
225 CLOSE:LOCATE68,2:PRINT"Lines:";MX;:LN=0:LOCATE0,12:PRINT
230 LOCATE0,2:PRINT"Page"INT(LN/18)+1"of"INT(MX/18)+1" ";:FORA=0TO17:LOCATE8,A+4:IFLN+A<MX THENPRINTA$(LN+A)ELSEPRINT
235 NEXT
240 GOSUB1055:A=INSTR(CHR$(94)+CHR$(10)+"JPQ",A$):IFA<1ORA>5THENSOUND100,1:GOTO240 ELSEONA GOTO255,305,355,405,430
245 FORA=12TO14:LOCATE15,A:PRINT"* File Not Found - Press Any Key for Main Menu *":NEXT:GOSUB1055:GOSUB1105:GOTO110
250 REM * [UP] Next Page
255 IFLN+18<MX THENLN=LN+18
260 GOTO230
300 REM * [DN] Prev Page
305 IFLN-18=>0THENLN=LN-18
310 GOTO230
350 REM * [J]ump to Page
355 LOCATE0,11:PRINT:PRINT:PRINT:LOCATE29,12:PRINT"Jump to Page 1 -"INT(MX/18)+1":";:GOSUB1005:A=VAL(A$)-1:IFA<0ORA>INT(MX/18)THENSOUND100,1:GOTO230ELSELN=A*18:GOTO230
360 IFPG>1THENPG=PG-1
365 GOTO230
400 REM * [P]rint Article
405 LOCATE0,11:PRINT:PRINT:PRINT:LOCATE13,12:PRINT"Ready Printer. Press [ENTER] to Print or [Q] to Quit";
410 GOSUB1055:IFA$="Q"THEN230ELSEIFA$=CHR$(13)THEN415ELSESOUND100,1:GOTO410
415 REM --- if printer is not online, beep and go back to 201... <- check here
420 A=0
425 PRINT#-2,TAB(8)A$(A):A=A+1:IFA<MX THEN425ELSE230
430 GOTO110
450 REM * Quit
455 CLOSE:CLS:STOP
460 END
1000 REM * Line Input
1005 LINEINPUTA$:RETURN
1050 REM * Inkey$
1055 A$=INKEY$:IFA$=""THEN1055
1060 CH=ASC(A$):IFCH>95THENA$=CHR$(CH-32)
1065 RETURN
1100 REM * Clear Text Area
1105 FORA=4TO21:LOCATE0,A:PRINT:NEXT:RETURN
1125 REM * Clear Bottom Line
1130 LOCATE0,23:PRINTSTRING$(79,32);:RETURN
1150 REM * Clear Top Line (well, third one actually...)
1155 LOCATE0,2:PRINTSTRING$(79,32);:RETURN
I used the Toolshed (new GitHub home) decb command line tool to create a blank 32-track DSK image, and then then copy the “reader.BAS” file over to it. I also copied the “contents.txt” file, since that was needed.
I booted up the Xroar emulator, mounted my new disk image, and loaded the program. When I ran it, it went to a black screen momentarily, then I saw this:
I assumed the file might be corrupted, so I then tried to CLOAD the ASCII file in Xroar. That is a neat feature that lets you “Load” a text file, then when you type CLOAD it simulates loading an ASCII file form tape, using the input text file as that ASCII file.
Same problem.
I visually inspected the program. Maybe there was some EXEC to an assembly routine that needed to loaded before RUNing this BASIC.
Nothing.
Was Xroar defective? I went to the Xroar Online Emulator and tried it there, loading my DSK image through the web page.
Crash.
I then posted to the CoCo e-mail list sharing a Dropbox link to a folder containing these files, as well as the DSK image. I asked if anyone could test it and see if it crashed for them, as well. Michael Kline was the first to respond:
Alan,
I tested all BASIC programmes on a CC3. They all lock up.
Michael
This at least let me know it was not an Xroar-specific issue. But what was this issue?
I experimented with the TRON command to see how far the program would get before locking up. It would print some quick values [0][1][2][3][4][5] before the screen cleared and things crashed, but this time to a blank green screen. The output to the 32-column screen was changing behavior.
I commented out line 5 so it would stay on the 32 column screen, and ran it again. I saw it spew out line numbers, before clearing the screen and printing an “?HP ERROR IN 105”. That is the error you get when you do CoCo 3 40/80 column screen commands on the 32 column screen. From the looks of things, removing the WIDTH80 line allowed it to get to around line 60 or so before one of those commands was used and it errored out.
Why would WIDTH 80 crash a program? I did more experiments. After this error, with the system not locked up, I typed “5 WIDTH 40” just to add a screen width, but no PALLETEs or CLS command.
According to TRON, the program was crashing at WIDTH 40… Huh???
Each time a crash like this happened, the virtual CoCo had to be restarted (power cycle). Just a virtual reset would not work. You might get “OK” back but things were not working.
Very, very odd.
I finally got my program to run by changing the value of the CLEAR command in line 10. (Initially, I deleted the whole line after the WIDTH line just to see what happened, and narrowed it down to something to do with the CLEAR.)
I shared my results on the CoCo list, and William “Lost Wizard” Astle, one of the great minds at understanding how the BASIC ROMs operate, replied with this tidbit:
It won’t be a string space bug – handling that didn’t change in the Coco3.
Have you been running it from the 40 or 80 column screen? If so, that’s probably why. The driver for handling output to the 40/80 column screen doesn’t properly manage the memory map and if the stack ends up too low in memory, it gets swapped out while the 40/80 column screen is mapped in, leading to a system crash. String space and the address parameter to CLEAR are both above the stack.
This crash happens if the stack ends up below $4000 if memory serves.
If you aren’t running from the 40/80 column screen, it may be some other weirdness triggering it.
– William Astle, via the CoCo List
Light has been shedded, and I knew all I would have to do is look up the Super Color BASIC Unraveled book to find a clear and concise explanation of this bug. But, before I got there, William added more details:
The only solution as far as I can tell is do no output on the 40/80 column screen or clear less string space. Given that a lot of the numbers used for CLEAR for string space are effectively random with no real understanding of how big they need to be, it’s entirely possible that 17000 is way more than it needs to be. Something most programmers don’t know is that a string constant in the program that is never modified doesn’t use up any string space so often the CLEAR number is massively larger than it needs to be.
Having the WIDTH before the CLEAR should prevent WIDTH from crashing but any subsequent PRINT, LOCATE, INPUT (from keyboard), or HSTAT probably would crash.
– William Astle, via the CoCo List
My confusion continued, and finally a third response form him added this:
It’s not that straight forward and unravelled doesn’t mention it. I only know because I tripped on it hard back in “the day” and it left me scratching my head for quite a while.
Basically, the stack has to stay above $4000 (the screen gets mapped in the $2000 to $3FFF range) so that would probably put the absolute limit somewhere just under 16K (16384). You’d want 200 bytes or so room for the stack so 16000 would be a nice round number. On the other hand, if you reserve any memory with the second parameter for CLEAR, that number goes down.
Perversely, if you could get the stack to be *below* $2000, it would also not crash, but that means a very small program with no PMODE graphics, probably.
The size of scalar variables, arrays, or program text doesn’t actually matter for this calculation because the screen is not mapped in except when doing I/O on the screen.
– William Astle, via the CoCo List
A bug the Unraveled folks didn’t know about? William stumbled upon it back then, and if this code was a version I tried to run, I must have, as well. But, why would I have left it in this non-working version? I expect I may find a “fixed” version of this program in my Disk BASIC disk archives, eventually. For all I know, maybe I kept this one around as a “what is wrong with this program” example, copying it to my OS-9 hard drive so I could post it on a BBS or online service (or even to the original CoCo List back then).
Hmm, I wonder if the old Princeton CoCo list archives still exist. Maybe I posted about this 30 years ago (1995!) when I was writing this program? (Note to self: Look that up…)
But I digress.
If you CLEAR a big enough number, then do a WIDTH 40 or 80, the CoCo 3 crashes hard. I toyed with that value, and you can get to a spot where it works, then a bit higher and you get some different types of crashes with the screen freaking out in different ways, but all end up the same way: crashed CoCo, must hard-reset/power cycle to recover.
Have you ever run into this bug on your CoCo 3? Please leave a comment with your story…
Until next time…
One more thing…
Oh yeah… Here is what the program looks like when it runs.
2025-02-27 – Corrected use of “hard links” to be “symbolic,” per William A. in the comments. Thanks!
NOTE: I am posting this as a plea for help. If you understand this problem, and know of solution, please leave a comment. I would really appreciate some input and clarification on my “understanding” of this issue.
TL:DNR: Symbolic links are a workaround.
The year is 2025, and open source projects can still be broken by having a space in a path name.
According to a robot, “Windows has allowed spaces in filenames and directory names since Windows NT 3.1, which was released in 1993.”
I have not fact checked this. My first PC was a Toshiba laptop I purchased at the end of 1995. (Not counting my DOS-based Tandy 1400LT I had years earlier.) At that point, it was Windows 3.1 that followed the 8.3 filename format that CP/M used.
FILENAME.TXT
It was the late Steve Bjork that convinced me to upgrade to the new Windows 95 when it came out. This upgrade allowed filenames up to 255 characters, if my quick web search is correct. I recall having a DOS C compiler (“Power C” – wow, they still sell this???) and it did not support the long filenames. Windows did provide some level of backwards compatibility by having any long filename still represented by a short name, which would have the first part of the filename then a “~1”, so something like “really long filename.txt” might also exist as “REALLY~1.TXT”.
Side note: There was a quirk with this implementation. Even filenames that could have fit in the 8 characters seemed to get this “~1” added to them. BUT, you could rename those to the normal 8 characters and is till worked. i.e. “filename.txt” would create “FILENA~1.TXT” but you could then “RENAME FILENA~1.TXT FILENAME.TXT” and it would show up as FILENAME.TXT. I actually wrote a C program that would go through the directory and rename any files like this. Fun times. And yikes, that was 30 years ago!?!?!
So basically, for three decades we could have spaces in filenames and directories on Windows.
Unix, back when it started, had short filenames and did not allow spaces initially. But, as long as I have been using it (my first exposure was 1995 on SunOS) I believe it did.
In the late 1980s I began using Microware’s OS-9 for the 6809 (on a Radio Shack Color Computer 3). While it had longer filenames than DOS (28 characters?), it did not allow spaces in filenames or directory names. I am unsure if the modern OS-9000 (renamed to just “OS-9 for x86” or whatever architecture, waybackwhen) has ever updated to allow spaces.
But I digress.
I still run across open source projects that fail if they are built from a path that has a space anywhere in it. For example, if you have this:
/usr/allenh/github downloads/
…and you “git” your project there, the build might break because of that space. Scripts may just see it as “/usr/allenh/github” and fail. This seems to be the case for the NitrOS9 Project, a fantastic effort to recreate OS-9/6809 with tons of enhancements.
From my experience, I think these problems can be solved by simply adding quotes around paths in the build scripts. For example, if you have this:
DISCLAIMER: Just examples. I know about escaping spaces as “\ ” in *nix filesystems, and maybe something like that exists for Windows (let me know in the comment).
But, again, this is 2025. I run into projects that fail with spaces in the path multiple times a year.
Just don’t put spaces, duh.
“Hey doctor, it hurts when I do this.”
“Then don’t do that.”
Why not just remove the spaces? In olden days, you were in control of directories because you made them. I came from a “no spaces allowed” OS background so I never used spaces. “SOURCECODE” or, if underscore was allowed, maybe “SOURCE_CODE” to be more readable (but I hate typing two extra keypresses to generate that underscore).
But, Windows may not agree. Once I did a fresh Windows install, and let it do all the defaults (Microsoft account to login, enable OneDrive, etc.) and the path it created had a space in it. Anything that I put in “my” home folder (Documents, etc.) had a space somewhere earlier in the path.
Likewise, on macOS, if you use iCloud, some default directories get links that make them look “normal”:
…but if you decide to make your own directory on your “iCloud Drive”, you see the true long path — which has a space in it!
allenh@Mac Development % pwd /Users/allenh/Library/Mobile Documents/com~apple~CloudDocs/Others/Development
That “Mobile Documents” path is the cause of so many problems.
My workaround was to simply move these folders outside of my self-created directory and put them into one of the defaults, like “~/Documents/Development”.
Symbolic links, anyone?
On macOS (a Unix-type operating system), and Linux (if such a problem exists there?), you can create symbolic-links to folders. You create a new name and then tell it where it points to.
Now in my home folder, I have a directory called “Development-iCloud” that has no space in it, but points to the real spot with a space:
allenh@Mac ~ % cd Development-iCloud allenh@Mac Development-iCloud % pwd /Users/allenh/Development-iCloud
Now I can change into that folder and build scripts that were failing will work. Nice.
But what about Windows?
I have not tried it myself, mostly because I didn’t have A.I. to ask for a solution the last time I ran into this on Windows, but there is a “mklink.exe” command that appears similar, and may solve the problem there:
mklink /D "C:\path\to\link" "D:\path\to\actual"
It feels like this workaround should work there.
But is this what developers do? Most smart computer folks I know run away from anything cloud (and for good reason). I have been drinking the Kool-Aid for awhile and love having access to non-private files on all my devices, via syncing on Dropbox (mostly) or iCloud or OneDrive or Google Drive. I use all of them, for different purposes.
You, of course, already knew this. But I learn from your comments, so please leave some. Thanks!
This may be the next “old dog, new trick” I adapt too.
When I started learning C in the late 1980s, I had a compiler manual (not very useful for learning the language) and a Pocket C Reference book — both for pre-ANSI K&R C. I may have had another “big” C book, but I mostly remember using the Pocket C Book.
Looking back at some of my early code, I find I was declaring “fixed” strings like this:
And this shows us:
char version[5]="0.00"; /* Version number... */
Odd. Did I really count the bytes (plus 0 at the end) for every string like that? Not always. I found this one:
char filename[28]="cocofest3.map";
…but I think I remember why 28. In the OS-9/6809 operating system, directory entries were 32 bytes. The first 28 were the filename (yep, back in the 80s there were operating systems with filenames longer than FILENAME.EXT), and then three at the end were the LSN (logical sector number) where the File ID sector was. (More or less accurate.)
At some point in my C history, I just started using pointers to strings like this:
char *version = "1.0.42b-delta";
I guess I got tired of [brackets]. I mean, “they work the same way”, don’t they?
void function (char *line)
{
if (NULL != line)
{
printf ("Line: '%s'\n", line);
}
}
…and…
void function (char line[])
{
if (NULL != line)
{
printf ("Line: '%s'\n", line);
}
}
…both end up with line pointing to the start of wherever the bytes to that string are in memory. I’ve seen main() done the same ways:
int main (int arc, char *argv[] )
…and…
int main ( int argc, char **argv )
For years, I’ve been doing it the second way, but all my early code was *argv[] so I suspect that is how I learned it from my early K&R C books.
I have no idea why I changed, or when, but probably in the mid-to-late 1990s. I started working for Microware Systems Corporation in Des Moines, Iowa in 1995. This was the first place I used an ANSI-C compiler. In code samples from the training courses I taught, some used “*argv[]” but ones I wrote used “**argv”.
Does it matter?
Not really. But let’s talk about it anyway…
There was a comment left on one my articles last year that pointed out something different I had no considered: sizeof
If you have “char *line” you cannot use sizeof() to give you anything but the size of the pointer (“sizeof(line)”) or the size of a character (or whatever data type used) that it points to (“sizeof(*line)”).
If you have “char line[]”, you can get the size of the array (number of characters, in this case) or the size of one of the elements in it:
sizeof(line1) = 8 <- size of a 64-bit pointer sizeof(*line1) = 1 <- size of a char
sizeof(line2) = 11 <- size of the character array sizeof(*line2) = 1 <- size of a char
I cannot remember ever using sizeof() on a string constant. You may recall I was surprised it worked when I learned about it a few months ago.
But, now that I am aware, I think I may start moving myself back to where I started and using the [brackets] when I have constant strings. Using sizeof() in the program just embeds a constant value, while strlen() is a function that walks through each byte looking for the end zero, thus adding more code space and more execution time.
If I wanted to copy some constant string into a buffer, I could try these two approaches:
// Copy message into buffer.
char *line1 = "This is a message.";
strncpy (buffer, line1, strlen(line1)); // strlen
printf ("Buffer: '%s'\n", buffer);
char line2[] = "This is a message.";
strncpy (buffer, line2, sizeof(*line2)); // sizeof
printf ("Buffer: '%s'\n", buffer);
And the results are the same:
Buffer: 'This is a message.' Buffer: 'This is a message.'
I would use the second version since using sizeof(*line2) avoids the overhead of strlen() scanning through each byte in the string looking for the end zero.
NOTE: As was pointed out in the comments, strlen() returns the number of characters up to the zero. “Hello” is a strlen() of 5. But sizeof() is the full array or characters including the 0 at the end so “Hello” would have a sizeof() of 6.
If you wanted them to be the same, it would be “sizeof(line)-1”.
It’s all fun and games until you pass a parameter…
This “benefit” of sizeof() is not useful if you are passing the string in to a function. It just ends up like a pointer to wherever the string is stored:
Above, I create a “*line” pointer to a string then pass it in to two functions. The first expects a *line as the parameter, and the second expects a line[].
Then I do a “line[]” array and pass it to the same two functions.
And, if you use a “good compiler,” you may get a warning about doing sizeof() like this:
main.c: In function ‘function2’:
main.c:16:44: warning: ‘sizeof’ on array function parameter ‘line’ will return size of ‘char *’ [-Wsizeof-array-argument]
16 | printf ("sizeof(line) = %zu\n", sizeof(line));
Notice that warning was from function2(), and not from function1(). This is one difference in using “*line” versus “line[]” in the functions. For function1(), no warning is given:
Since the function takes a “pointer to one or more chars”, doing sizeof() what that pointer points to makes sense. It is what you asked for. The “C gibberish” website says:
…a warning is given about the “sizeof(line)” because it cannot tell us the size of a line[] array — it became a pointer to the character memory when it went into the function. But because the function parameter was “line[]”.
Doing sizeof() an “array of char” is valid. But it was passed into the function, even though the parameter was a line[] it is passed as a pointer to the data. I guess this is one of those “I’m sorry, Dave. I’m afraid I can’t do that” moments ;-)
Is this useful? It certainly will let you use sizeof() instead of strlen() on a string if you have direct access to the string variable. But passing strings into functions? Not so much. (Or am I mistaken?)
But I do think I am going to try to go back to using “line[]” for my string declarations. I like retro.
Juan Castro strikes again, this time providing a short program for me to try on a CoCo 3 (I used the Xroar Online emulator) that shows another quirk in the handling of 16-bit values on the CoCo.
The reason this requires a CoCo 3 is because it makes use of the ONERR GOTO command that was added for Super Extended Color BASIC.
“Goes to the line number if an error occurs during program execution.”
There are two special variables that get set when an error is trapped by “ON ERR”.
ERNO
“Returns an error number that corresponds to the error that occurred.”
ERLIN
“Returns the line number where the error occurred.”
So in this simple program, with a mis-spelled “PRINT” command…
10 ON ERR GOTO 50000 20 PRUNT "I TYPE POORLY" 30 END 50000 PRINT "ERROR";ERNO;"IN LINE";ERLIN
When I run that, I see:
ERROR 1 IN LINE 20
1 must be the value of ?SN ERROR. The manual says to look for “BASIC Error Messages” in the back of this book, but the page is titled ERROR CODES. It is on page 321. It lists errors 1 to 39.
But that is not important for this post.
ERLIN, which you see reported the error was in line 20, has a problem.
If the line number with the error has the high bit set (higher than 32767), it gets reported as a negative number! Changing the program to make the PRUNT typo happen on a later line shows this:
10 ON ERR GOTO 50000 32768 PRUNT "I TYPE POORLY" 32769 END 50000 PRINT "ERROR";ERNO;"IN LINE";ERLIN
If I run this version, I see:
ERROR 1 IN LINE-32768
If the error line is moved to 32767, you will it it report properly.
The book Super Extended BASIC Unraveled II mentions this bug on page 33:
“The ERLIN function will return a negative number if the line number in which the error occurred is greater than 32767. This is caused by the fact that the ERLIN function returns the line number as a two-byte integer instead of a floating point number, as it should.”
– Super Extended BASIC Unraveled II, page 33
I did not know there was a 2-byte integer routine in the ROMs. Always learning something new! (Or, re-learning in case I actually did learn this decades ago.)
Thanks, Juan, for getting my dusty brain thinking.
There is something wonderful about having a poor memory. Whether I knew something before or not, I do not remember it now, so I get the pleasure of “learning something new” even if I previously knew the new thing.
In a reply to my Color BASIC and octal post, Juan Castro mentioned another quirk about how BASIC sees numbers represented as decimals versus hex or octal.
AND, OR, AND NOT demand signed 16-bit integers as input, whereas the &H/&O expressions (and consequantly my &B extension) return UNsigneded integers. That is VERY annoying:
PRINT &H8001 AND &H0007 ?FC ERROR OK
Come the %#&*£ ON!
– Juan Castro
I am unsure about this, since after the parser reads through the code, it turns any hex or octal or decimal value intothe internal 5-byte floating point representation of the value. “A=65535” turns into exactly the same type of variable as “A=&HFFFF”.
AND and OR should deal with them exactly the same way. In Juan’s example, decimal values will generate the same ?FC ERROR. But there is a workaround…
I stumbled upon this when playing around with using AND and OR to set or test bits. My Color BASIC and 16-bits and AND and OR and NOT article explains what I was trying to do, and how I ultimately ended up achieving it.
In Juan’s example, &H8001 is 32769 in decimal. &H0007 is 7. Having the “high bit” (bit 15) set of the first value effectively makes it a negative number:
1000000000000001 = &H8001 (32769) ^ ^ bit15 bit0
Any value with that bit set will not work with AND or OR, regardless if you represented it in decimal, hex or octal. You can go up to &H7FFF (32767) using AND or OR, but past that, you get the ?FC ERROR:
Juan has been working on some BASIC enhancements, adding new features (like a method of representing values in binary — which I would find quite useful). But seeing numbers in binary not work would be even more frustrating:
PRINT &B100000000000000 AND &H1 ?FC ERROR
…at least, that is my assumption about what is “&B” binary representation would do.
Here is how to make Juan’s code work:
PRINT (&H8007-65536) AND &H0007 1
Any value that has that high bit set needs to have 65536 subtracted from it, then you get the results you would expect.
But unfortunately, you cannot use AND to test for that high bit to be set ;-) so instead you have to do silly things like this:
V=&H8007 IF V>&H7FFF THEN V=V-65536 PRINT V AND &H0001
And it’s just that easy!
Though, if you print V, you will see it is a negative number, as you might have guessed. If you don’t need to PRINT V, doing something as simple as this will let you AND and/or OR on values that have the high bit set.
A followup from my previous post… This box, which appeared in Rainbow magazine, was called Rainbow Check Plus:
Rainbow Magazine checksums
It first appeared in the February 1984 issue, and was even featured on the cover:
The article “Rainbow Check Plus for the CoCo and MC-10” appears on page 21, and was written by H. Allen Curtis. (Why is that name so familiar?) I did not realize it was available for the MC-10 as well. Here is the listing for the CoCo version:
10 CLS:X=256*PEEK(35)+178
20 CLEAR25,X-1
30 X=256*PEEK(35)+178
40 FOR Z=X TOX+77
50 READ Y:W=W+Y:PRINT Z,Y;W
60 POKE Z,Y:NEXT
70 IFW=7985THEN80ELSEPRINT"DATA ERROR":STOP
80 EXEC X:END
90 DATA 182,1,106,167,140,60,134
100 DATA 126,183,1,106,190,1,107
110 DATA 175,140,50,48,140,4,191
120 DATA 1,107,57,129,10,38,38
130 DATA 52,22,79,158,25,230,129
140 DATA 39,12,171,128,171,128
150 DATA 230,132,38,250,48,1,32
160 DATA 240,183,2,222,48,140,14
170 DATA 159,166,166,132,28,254
180 DATA 189,173,198,53,22,126,0
190 DATA 0,135,255,134,40,55
200 DATA 51,52,41,0
But wait … there’s more. As I was looking into this, I learned that “Rainbow Check Plus” was a follow-up to “Rainbow Check” which appeared in January 1983. It seems the original “Rainbow Check” would not catch some key items:
Incorrect line numbers. “300 CLS” and “390 CLS” would provide the same check value.
Incorrect variables. It would not catch a wrong variable. The example given is that “F” would be the same as “E”.
Incorrect command words. SGN or SIN would provide the same checksum.
Now I really wonder what it was doing to generate the numbers, if it wasn’t looking at the actual line data ;-)
The original version appeared on page 95 as part of the “Assembly Corner” column by Dennis L. Lewandoski. The column was called “Let’s End Those Typing Errors Once and For All.” This version appeared in the form of an assembly language program listing, as well as a BASIC loader with DATA statements.
Here is the BASIC program listing for the original 1983 “Rainbow Check” version:
10 CLS:IFPEEK(116)=127 THEN X=32688 ELSE X=16304
20 CLEAR25,X-1
30 IFPEEK(116)=127 THENX=32688 ELSE X=16304
40 FORZ=X TO X+77
50 READY:W=W+Y:PRINTZ,Y;W
60 POKE Z,Y : NEXT
70 IFW=5718 THEN80 ELSE PRINT"DATA ERROR":STOP
80 EXEC X:END
90 DATA 182,1,106,167,141,0,68
100 DATA 134,126,183,1,106,190
110 DATA 1,107,175,141,0,57,48
120 DATA 141,0,4,191,1,107,57
130 DATA 129,10,38,44,52,22,220
140 DATA 27,147,25,142,4,0,141
150 DATA 6,31,152,141,2,32,25
160 DATA 52,2,68,68,68,68
170 DATA 141,4,53,2,132
180 DATA 15,129,9,46,4,139,112
190 DATA 32,2,139,55,167,128,57
200 DATA 53,22,126,0,0
Unfortunately, the assembly was not provided on Rainbow on Tape, so I would have to type it all in by hand.
I suspect I will have to do just that, as well as disassemble the 1984 version and see how both worked, which might explain the limitations of the original.
Over on YouTube, user @ms-ex8em pointed me to the November 1988 issue of Dragon User magazine and a little program that helps you type in machine code program listings accurately.
I recall spending countless hours typing in machine code programs from Rainbow Magazine “back in the day”. These programs would be a few lines of BASIC followed by dozens or hundreds of lines of DATA statements with numbers that represented the bytes of the machine language program.
One such program I specifically remember was Zonx, a cool game with background sound effects. It appeared in the October 1985 issue. You can see what I typed in by checking out page 65. And page 67. And page 68. And page 70. And page 71.
And, somehow, I managed to type all of those numbers in and get a working program!
Rainbow did have one thing to help — and perhaps I used it. They had a small program you could run, then as you typed in your program listing, when you got to specific lines you could hit a key and it would spit out a number (a checksum?) and see if it matched their numbers:
Above, you can see what number should be expected when you got to line 150, 310, 440 and so on. After all the code was typed in, the final number it should give you was 238. This required you to type in the program exactly as it appeared including spaces and any other formatting.
It was not optimal, but it was better than nothing.
I also saw some BASIC loaders for machine language that took matters into their own hands, and had built-in checksum values in their DATA statements. For example, they would put a specific amount of numbers on each line, with a checksum of those numbers at the end. Say that amount of numbers was five. A line might look like this:
1500 DATA 1,1,1,1,1,5
In that silly example, you could add up ever five bytes you READ and then compare that to the 6th byte in each line. If it matched, continue. If it didn’t, the loader code would print some kind of message, hopefully indicating what line had a mismatch.
I always appreciated program listings that did that.
Now, back to @ms-ex8em… The code they shared was quite different. You can find it on page 12:
10 REM HEX LOADER
20 CLEAR 200,31599
30 INPUT"START";ST
40 INPUT"END";ED
50 FOR J=ST to ED STEP 8
60 PRINT USING"##### : ";J;
70 INPUT A$
80 CS=0
90 FOR K=1 TO LEN(A$)
100 CS=CS+K*VAL("&H"+MID$(A$,K,1))
110 NEXT K
120 INPUT" = ";C
130 IF S<>CS THEN PRINT"CHECKSUM ERROR-TRY AGAIN":SOUND 1,1:GOTO 60
140 FOR K=0 TO 7
150 POKE J+K,VAL("&H"+MID$(K*2+1,2)
160 NEXT K,J
First comment… There appears to be a mistake in line 150. It should have two closing parens at the end of the line.
Now let’s see what this code is doing.
In line 10, the CLEAR reserves memory (so BASIC cannot use it) starting at 31599. This is because the machine language program will load starting at 31600.
In line 40, the user is asked to input the start and end of the program they will be typing in.
In line 50, there is a FOR/NEXT that goes from start to end, stepping by 8. This tells me they expect 8 bytes of data on each line the user types in. The first input should be at 31600, then the next at 31608 and so on.
The user types in the 16 characters (representing 8 hex bytes) shown in the box below. They look like this:
31600 : 8E7B6F9F74Be012B = 1016
In line 80, a checksum is calculated by adding up the value of each character typed in that line.
In line 120, the user is asked to type in the checksum shown in the data listing.
In line 130, if the number the user typed in (from the data listing) does not match value the program calculated, an error message prints and it goes back to let the user retype the entire line.
If it matched, line 140 will then go through those 16 characters and create the byte value for each of the 8 data bytes and POKE them into memory at the proper place.
This repeats until the end address is reached. At that point, some new assembly language program has been loaded into memory starting at 31600.
Pretty cool!
The problem @ms-ex8em was seeing with this program was a ?TM ERROR. That is most likely showing up in line 150 because of the missing paren. Fix that, then maybe the rest will work ;-)
I thought this was a neat way to enter in machine code. What other neat ways did you see back then?
UPDATE: A support person with FTDI reached out to me, and confirms their static library can only be used with Microsoft’s compiler. It will not work with GCC, etc. That is the root of my issue. My next question is going to be: Can I do C code with Visual Studio? More to come…
This should be a simple problem to solve, and this problem may be related to using the wrong compiler (a very old Clang 3.3).
FTDI provides device drivers for things like RS232 interfaces. FTDI drivers typically come with Windows, Linux and Mac. When writing a program to use the FTDI device, they provide header files, DLLs and .libs. These come in a .zip file:
Inside this zip are two header files. One is for the common FTDI stuff (Open, Close, etc.). The second is for the FT4222 which is a USB-to-I2C chipset.
Both are provided as .libs for DLLs, or static libraries. They also provide 32-bit and 64-bit versions of each.
There are defines for each of the libraries that are supposed to be set before including the corresponding header file:
#define FTD2XX_STATIC #define FT4222_STATIC
#ifndef FTD2XX_STATIC #error FTD2XX_STATICmust be defined to use static libs. #endif
#ifndef FT4222_STATIC #error FT4222_STATIC must be defined to use static libs. #endif
…though I would normally set it in my project settings.
This “should” be simple, but on LabWindows/CVI 2017 (which uses Clang 3.3), it has a two sets of linker errors to some Windows library stuff that I do not know how to resolve.
When I make a project in Code::Blocks which uses GCC, I only get one set of six mangled references.
GCC errors:
..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\FTD2XX.obj):(.text$mn+0xec)||undefined reference to `??3@YAXPEAX_K@Z'| ..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\FTD2XX.obj):(.text$mn+0x16d)||undefined reference to `??3@YAXPEAX_K@Z'| ..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\FTD2XX.obj):(.text$mn+0x1e5)||undefined reference to `??3@YAXPEAX_K@Z'| ..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\FTD2XX.obj):(.text$mn+0x25d)||undefined reference to `??3@YAXPEAX_K@Z'| ..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\FTD2XX.obj):(.text$mn+0x2d5)||undefined reference to `??3@YAXPEAX_K@Z'| ..\..\LibFT4222-v1.4.7\imports\ftd2xx\lib\amd64\ftd2xx.lib(x64\Release\fteepd.obj):(.data$r+0x0)||undefined reference to `??_7type_info@@6B@'| ||error: ld returned 1 exit status| ||=== Build failed: 7 error(s), 20 warning(s) (0 minute(s), 1 second(s)) ===|
Since GCC gets further, I am going to try to use it.
This sample project is just a test to link to Open and Close functions in the FTD2XX library. Nothing is being used in the FT4222 library, so it really is not part of this test, but ultimately I will need it.
My test program is:
#define FTD2XX_STATIC #define FT4222_STATIC
// -lsetupapi -ladvapi32 -luser32
#ifndef FT4222_STATIC #error FT4222_STATIC must be defined to use static libs. #endif
#include <windows.h>
#include <stdio.h> #include <stdlib.h>
#include "ftd2xx.h" // Add to include path. #include "LibFT4222.h" // Add to include path.
int main (void) { FT_STATUS ftStatus = 0; FT_HANDLE ftHandle;
I am posting this to my blog in case someone else is searching for a solution for this.
Meanwhile, if you think you know how to get this to work, please let me know.
IMPORTANT INFO: The FTDI readme says it works in Visual Studio. They have one example they provide that does static linking and it builds just fine. I have not tested it to see if it actually works, and do not know how to tell if it truly is using the static libraries. (We have always used the DLL version of the libraries, and those work fine.)
Is is possible they made a library that will not work in Clang or GCC, but does work in Microsoft’s compiler?