PofoWiki

Die ultimative Informationsquelle zum ATARI Portfolio

Benutzer-Werkzeuge

Webseiten-Werkzeuge


software:diy:assembler:dosbugs

Bekannte DIP DOS Bugs, Besonderheiten und Undokumentiertes

Was sind eigentlich Bugs? Streng genommen handelt es sich dabei um Programmfehler - zumeist solche, die nur unter bestimmten Randbedingungen auftreten und deshalb schwer auffindbar sind. Gewöhnlich gibt es solche Käferchen in jedem größeren Programm und mit Sicherheit auch in jedem Betriebssystem (siehe Anhang E des Technischen Referenzhandbuches und die FAQs des PofoWiki). Was DIP-DOS anbelangt, so waren sie die Motivation für das Erscheinen mehrerer (jeweils fehlerbereinigter) Versionen und einiger installierbarer Patches wie UPDATE.COM oder PORTDIV.COM.

Neben solchen „echten“ Bugs gibt es mitunter Verhalten, das nicht unbedingt dem Erwarteten entspricht. Gerade beim Pofo, der ja im Prinzip ein PC zu sein versucht, gleichzeitig aber mit sehr stark davon abweichender Hardware auskommen muss, ist dies nicht besonders erstaunlich, bringt aber die eine oder andere Falle mit sich.

Die dritte Kategorie, um die es hier gehen soll, beinhaltet schlicht Undokumentiertes, wovon es schon beim Original-DOS eine Menge gibt und beim Pofo mit Sicherheit nicht weniger. Oftmals lässt sich solche undokumentierte Funktionalität recht nützlich verwenden (und wird intern auch verwendet). Beim Pofo gibt es außerdem weniger Betriebssystemversionen als etwa bei MS-DOS, so dass die Gefahr, dass solch undokumentierte Dinge sich ändern, weitaus geringer ist.

Das Versions-Dilemma

Denken sie daran, dass … Portfolios DOS zu DOS 2.11 kompatibel ist, mit ein paar Verbesserungen um es kompatibler zu DOS 3.XX zu machen.

So ist es im Anhang D des Technischen Referenzhandbuchs zu lesen. Im Kapitel 3.4 dieser Referenz sind darüber hinaus genau vier Abweichungen dokumentiert, wobei DOS 2.11 als Ausgangspunkt dient. Bei näherer Betrachtung zeigt sich allerdings, dass es solcher Abweichungen weitaus mehr gibt - größtenteils sind dies Erweiterungen, so dass DIP-DOS eigentlich DOS 3.x ähnlicher als 2.x ist. Andererseits gibt es aber offenbar einige Dinge nicht, die eigentlich für alle DOS-Versionen >= 2.0 existieren sollten. Hinzu kommt, dass DIP-DOS teilweise (oder überall ??) die internen Datenstrukturen von DOS 3.x verwendet, was zumindest zur Verwirrung führt, wenn man die der gemeldeten Version annimmt.

DOS-Version und Hochsprachen

Oder: Wie bekommt ein Programm heraus, unter welchen Namen (bzw. Pfad) es aufgerufen wurde?

In Hochsprachen wie C/C++ oder (Turbo-)Pascal ist dies eigentlich eine triviale Angelegenheit. Man erhält den Namen als „nulltes“ Kommandozeilen-Argument, also argv[0] in C/C++ bzw. ParamStr(0) in Turbo-Pascal. Leider jedoch nicht auf dem Pofo - hier bekommt man eine leere Zeichenkette. Der Grund dafür ist einfach: In den MS-DOS-Versionen ab 3.x wird der der DOS-EXEC-Funktion (4B00/01) übergebene Programmpfad im Environment-Segment des gestarteten Prozesses, und zwar hinter dem die eigentlichen Umgebungsvariablen abschließenden Leerstring (zwei aufeinanderfolgende Null-Bytes) abgelegt. Hinter diesen Null-Bytes folgt zunächst ein 16-Bit-Wort, das offenbar immer den Wert 1 hat und unmittelbar dahinter der Programmpfad als ASCIIZ-String.
In den erwähnten Hochsprachen wird nun das „nullte“ Argument ganz einfach von dort ausgelesen und - damit es keinen Unfall gibt - vorher geprüft, ob die aktuelle DOS-Version >=3 ist.

Wäre DIP-DOS wirklich ein DOS 2.x, gäbe es tatsächlich keinen auch nur halbwegs offiziellen Weg, an den Aufrufnamen heranzukommen - lediglich einen ziemlich üblen Hack unter Ausnutzung der System File Table (SFT), dazu aber später …
Glücklicherweise benimmt sich die EXEC-Funktion im POFO aber genau wie die von DOS 3+, so dass der Programmpfad auch hier im Environment-Segment landet. Was zu tun bleibt ist also, eine Funktion zu schreiben, die den Wert besorgt und in Turbo-C ungefähr so aussehen kann:

   #include <dos.h>
   #include <dir.h>
 
   char _arg0[MAXPATH];
   const char* getProgName()
   {
      int intvar;
      char far* penv;
      intvar = *(int far*) MK_FP(_psp,0x2c);      /* get environment segment */
      penv = (char far*) MK_FP(intvar,0);         /* make environment pointer */
      while ((penv != NULL) && ((*penv) != '\0')) /* find end of environment */
      {
          while ((*penv) != '\0') ++penv;
          ++penv;
      }
      penv += 3;   /* adjust pointer to start of program name */         
      for (intvar = 0; intvar < MAXPATH; ++intvar, ++penv) /* copy path */
      {
         _arg0[intvar] = *penv;
         if ((*penv) == '\0') break;
      }
      return _arg0;
    }

Die hier verwendete globale Variable _psp wird von Turbo-C bei der Initialisierung gesetzt und beinhaltet die Segment-Adresse des Programm Segment Prefixes (PSP) des aktuellen Programms. Zu erklären sind sicher auch noch die etwas umständlichen Test- und Kopieroperationen. Sie sind leider nötig, da der Zeiger in das Environment-Segment immer ein FAR-Zeiger ist. String-Funktionen wie strlen oder strcpy arbeiten in den „kleinen“ Speichermodellen, wie sie für den Pofo meist verwendet werden, mit NEAR-Zeigern.

Ein anderer möglicher Weg wäre es, dem aufgerufenen Programm eine andere DOS-Version (3.x) vorzugaukeln. Da die Betriebssystem-Version nirgends als Variable gespeichert ist, bleibt dafür nur, einen eigenen Handler für die DOS-Funktion 30H (Get Version Number) zu installieren, der das Setzen einer beliebigen Versionsnummer erlaubt.

software/diy/assembler/dosbugs.txt · Zuletzt geändert: 19/09/2010 00:09 (Externe Bearbeitung)