home *** CD-ROM | disk | FTP | other *** search
/ Crawly Crypt Collection 1 / crawlyvol1.bin / program / compiler / m2posx14 / src / lib.ipp < prev    next >
Encoding:
Modula Implementation  |  1994-05-05  |  21.5 KB  |  712 lines

  1. IMPLEMENTATION MODULE lib;
  2. __IMP_SWITCHES__
  3. __DEBUG__
  4. #ifdef HM2
  5. #ifdef __LONG_WHOLE__
  6. (*$!i+: Modul muss mit $i- uebersetzt werden! *)
  7. (*$!w+: Modul muss mit $w- uebersetzt werden! *)
  8. #else
  9. (*$!i-: Modul muss mit $i+ uebersetzt werden! *)
  10. (*$!w-: Modul muss mit $w+ uebersetzt werden! *)
  11. #endif
  12. #endif
  13. (*****************************************************************************)
  14. (* Die Funktion "rand()" ist eine direkte Umsetzung aus der GnuLib/MiNTLib.  *)
  15. (*---------------------------------------------------------------------------*)
  16. (* 05-Mai-94, Holger Kleinschmidt                                            *)
  17. (*****************************************************************************)
  18.  
  19. VAL_INTRINSIC
  20. CAST_IMPORT
  21. PTR_ARITH_IMPORT
  22.  
  23. FROM SYSTEM IMPORT
  24. (* TYPE *) ADDRESS,
  25. (* PROC *) ADR, TSIZE;
  26.  
  27. FROM PORTAB IMPORT
  28. (* CONST*) MAXINT, MAXUNSIGNEDLONG, MINSIGNEDLONG, MAXSIGNEDLONG,
  29. (* TYPE *) UNSIGNEDLONG, SIGNEDLONG, UNSIGNEDWORD;
  30.  
  31. FROM ctype IMPORT
  32. (* PROC *) todigit, tocard, toupper, isspace;
  33.  
  34. FROM types IMPORT
  35. (* CONST*) NULL, EOS,
  36. (* TYPE *) StrPtr, StrPPtr, sizeT, int, unsigned, long, unsignedlong;
  37.  
  38. IMPORT e;
  39.  
  40. FROM MEMBLK IMPORT
  41. (* PROC *) memswap;
  42.  
  43. (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
  44.  
  45. VAR
  46.   Seed : SIGNEDLONG;
  47.  
  48. (*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
  49.  
  50. PROCEDURE lfind ((* EIN/ -- *) key     : ADDRESS;
  51.                  (* EIN/ -- *) base    : ADDRESS;
  52.                  (* EIN/ -- *) nelems  : sizeT;
  53.                  (* EIN/ -- *) size    : sizeT;
  54.                  (* EIN/ -- *) compare : CompareProc  ): ADDRESS;
  55. (*T*)
  56. VAR last : ADDRESS;
  57.  
  58. BEGIN
  59.  IF   (key = NULL)
  60.    OR (base = NULL)
  61.    OR (size = VAL(sizeT,0))
  62.    OR (nelems = VAL(sizeT,0))
  63.  THEN
  64.    RETURN(NULL);
  65.  END;
  66.  
  67.  last := ADDADR(base, (nelems - VAL(sizeT,1)) * size);
  68.  
  69.  (* Indem das letzte zu vergleichende Feldelement
  70.   * mit dem zu suchenden ausgetauscht wird, wirkt
  71.   * es als Endemarke fuer das Suchen.
  72.   *)
  73.  memswap(key, last, size);
  74.  
  75.  WHILE compare(base, last) <> 0  DO
  76.    base := ADDADR(base, size);
  77.  END;
  78.  
  79.  (* Das Vertauschen muss natuerlich wieder rueckgaengig gemacht werden. *)
  80.  memswap(key, last, size);
  81.  
  82.  (* Wenn das gesamte Feld durchsucht wurde, muss noch
  83.   * der Vergleich mit dem letzten Element erfolgen,
  84.   * ansonsten wurde schon vorher ein Element mit dem
  85.   * gesuchten Wert gefunden.
  86.   *)
  87.  IF (base = last) AND (compare(last, key) <> 0) THEN
  88.    RETURN(NULL);
  89.  ELSE
  90.    RETURN(base);
  91.  END;
  92. END lfind;
  93.  
  94. (*---------------------------------------------------------------------------*)
  95.  
  96. PROCEDURE bsearch ((* EIN/ -- *) key     : ADDRESS;
  97.                    (* EIN/ -- *) base    : ADDRESS;
  98.                    (* EIN/ -- *) nelems  : sizeT;
  99.                    (* EIN/ -- *) size    : sizeT;
  100.                    (* EIN/ -- *) compare : CompareProc  ): ADDRESS;
  101. (*T*)
  102. VAR __REG__ left  : sizeT;
  103.     __REG__ right : sizeT;
  104.     __REG__ mid   : sizeT;
  105.  
  106. BEGIN
  107.  IF   (key = NULL)
  108.    OR (base = NULL)
  109.    OR (size = VAL(sizeT,0))
  110.    OR (nelems = VAL(sizeT,0))
  111.  THEN
  112.    RETURN(NULL);
  113.  END;
  114.  
  115.  left  := 0;
  116.  right := nelems - VAL(sizeT,1);
  117.  
  118.  WHILE left < right DO
  119.    mid := (left + right) DIV VAL(sizeT,2);
  120.    (* left <= mid < right *)
  121.    IF compare(ADDADR(base, mid * size), key) < 0 THEN
  122.      left  := mid + VAL(sizeT,1);
  123.    ELSE
  124.      right := mid;
  125.    END;
  126.  END;
  127.  
  128.  base := ADDADR(base, left * size);
  129.  IF compare(base, key) = 0 THEN
  130.    RETURN(base);
  131.  ELSE
  132.    RETURN(NULL);
  133.  END;
  134. END bsearch;
  135.  
  136. (*---------------------------------------------------------------------------*)
  137.  
  138. PROCEDURE qsort ((* EIN/ -- *) base    : ADDRESS;
  139.                  (* EIN/ -- *) nelems  : sizeT;
  140.                  (* EIN/ -- *) size    : sizeT;
  141.                  (* EIN/ -- *) compare : CompareProc  );
  142. (*T*)
  143. CONST direct = LC(8);
  144.  
  145. VAR cmpP : ADDRESS;
  146.  
  147. VAR rP : ADDRESS;
  148.     (* wird bei Selectionsort benutzt, und ist hier deklariert,
  149.      * damit er keinen Stackplatz beim rekursiven Aufruf von "sort()"
  150.      * belegt. Er braucht keine lokale Variable von "sort()" zu sein,
  151.      * da er nur vom Selectionsort benutzt werden, aus dem heraus kein
  152.      * weiterer rekursiver Aufruf mehr stattfindet.
  153.      *)
  154.  
  155. (* Das Prinzip von Quicksort ist an sich recht einfach:
  156.  
  157.    Als erstes wird ein beliebiges Element des Feldes ausgewaehlt, dann
  158.    werden von beiden Enden des Feldes zur Mitte hin Elemente gesucht, die
  159.    groesser bzw. kleiner oder gleich dem Vergleichselement sind - diese
  160.    beiden Elemente werden ausgetauscht; das Austauschen wird solange
  161.    wiederholt, bis sich die beiden Suchzeiger ueberschneiden; In der linken
  162.    Haelfte befinden sich dann die Elemente, die kleiner oder gleich dem
  163.    Vergleichselement sind, in der rechten Haelfte befinden sich die Elemente,
  164.    die groesser oder gleich dem Vergleichselement sind.
  165.    Diese Prozedur wird jetzt mit den beiden Haelften erneut ausgefuehrt
  166.    usw. bis die zu sortierenden Teilfelder nur noch ein Element gross sind,
  167.    dann ist das gesamte Feld sortiert. Die wiederholte Ausfuehrung gleicher
  168.    Taetigkeiten schreit natuerlich nach Rekursion.
  169.  
  170.    Der Aufwand:
  171.  
  172.    Den Partitionierungsvorgang kann man sich als das Suchen eines bestimmten
  173.    Elementes, naemlich das mit dem naechstgroesseren Wert, vorstellen.
  174.    Angenommen, das Vergleichselement ist immer das wertemaessig mittlere
  175.    Element: in diesem Fall wird die Suche zur Binaersuche, da immer die
  176.    Haelfte der Werte beim naechsten Suchvorgang ausgeschlossen wird. Der
  177.    Aufwand des binaeren Suchens betraegt  O( ld( n )); da wir n Elemente
  178.    haben, betraegt der Sortieraufwand O( n * ld( n )).
  179.    Das waere der Idealfall.
  180.  
  181.    Im schlechtesten Fall ist das ausgewaehlte Vergleichselement immer das
  182.    wertemaessig groesste bzw. kleinste; in diesem Fall wird die Suche zur
  183.    linearen Suche, deren mittlerer Aufwand  n/2 betraegt; der Aufwand des
  184.    Sortierens betraegt dann  O( n * n ). Ein Beispiel waere ein bereits
  185.    sortiertes Feld, bei dem man als Vergleichselement immer das erste
  186.    auswaehlt.
  187.  
  188.    Den schlechtesten Fall kann man zwar nicht ganz ausschliessen, aber
  189.    doch sehr unwahrscheinlich machen: die einfachste Methode ist, als
  190.    Vergleichselement das positionsmaessig mittlere zu nehmen; die
  191.    Wahrscheinlichkeit hierbei haeufig die Extremwerte zu erwischen ist
  192.    gering. Noch unwahrscheinlicher wird es, wenn als Vergleichselement das
  193.    wertemaessig mittlere aus dreien genommen wird (z.B. dem positionsmaessig
  194.    ersten, mittleren und letzten).
  195.  
  196.    Abgesehen von der Wahl des Vergleichselementes gibt es weitere
  197.    Moeglichkeiten zur Optimierung:
  198.  
  199.     - Zuerst die kleinere Haelfte weitersortieren.
  200.       Hierdurch betraegt die Stackbelastung nur  ~ld(n).
  201.  
  202.     - Hinter dem rekursiven Aufruf zur Sortierung der zweiten, groesseren
  203.       Haelfte folgt kein Ausdruck, der vom Ergebnis dieses Aufrufs abhaengt;
  204.       die Sortierung der groesseren Feldes kann deswegen iterativ geschehen.
  205.  
  206.     - Wie alle hoeheren Sortiermethoden ist auch bei Quicksort die Leistung
  207.       bei kleinem  n  schwach, da der Verwaltungsaufwand relativ gross ist.
  208.       Unterschreitet daher die Groesse des zu sortierenden Teilfeldes ein
  209.       hinreichend kleines  n, kann das Feld durch eine einfachere Methode
  210.       (direktes Einfuegen, direkte Auswahl...) zuende sortiert werden.
  211. *)
  212.  
  213. PROCEDURE sort ((* EIN/ -- *) bot : sizeT;
  214.                 (* EIN/ -- *) top : sizeT );
  215.  
  216. VAR         left   : sizeT;
  217.             right  : sizeT;
  218.     __REG__ leftP  : ADDRESS;
  219.     __REG__ rightP : ADDRESS;
  220.  
  221. BEGIN (* sort *)
  222.  WHILE bot < top DO
  223.    left   := bot;
  224.    right  := top;
  225.    leftP  := ADDADR(base, bot * size);
  226.    rightP := ADDADR(base, top * size);
  227.  
  228.    IF top - bot < direct THEN
  229.      (* Direktes Sortieren durch Auswaehlen.
  230.       * 'SelectionSort' ist bei so wenigen Elementen
  231.       * (< 10) schneller als 'InsertionSort'.
  232.       *
  233.       * Funktionsweise:
  234.       * Der Reihe nach vom ersten bis zum vorletzten
  235.       * Element wird ein Vergleichselement gewaehlt,
  236.       * das mit allen Elementen rechts von ihm verglichen
  237.       * wird; das Minimum und das Vergleichselement
  238.       * werden ausgetauscht.
  239.       *)
  240.  
  241.      WHILE DIFADR(leftP, rightP) < VAL(SIGNEDLONG,0) DO
  242.        cmpP := leftP;
  243.        rP   := ADDADR(leftP, size);
  244.        WHILE DIFADR(rP, rightP) <= VAL(SIGNEDLONG,0) DO
  245.          IF compare(rP, cmpP) < 0 THEN
  246.            cmpP := rP;
  247.          END;
  248.          rP := ADDADR(rP, size);
  249.        END; (* WHILE *)
  250.  
  251.        IF cmpP <> leftP THEN
  252.          memswap(cmpP, leftP, size);
  253.        END;
  254.        leftP := ADDADR(leftP, size);
  255.      END;
  256.      RETURN; (* fertig *)
  257.  
  258.    ELSE
  259.  
  260.      (* Es wird kein groesserer Aufwand bei der Auswahl des
  261.       * mittleren Elementes betrieben, da dies in den allermeisten
  262.       * Faellen mehr Zeit kostet, als es Zeit einspart, wenn das
  263.       * Feld wirklich so unguenstig belegt ist, dass das
  264.       * positionsmaessig mittlere immer das Extremelement ist.
  265.       *)
  266.  
  267.      cmpP := ADDADR(base, ((left + right) DIV VAL(sizeT,2)) * size);
  268.  
  269.      REPEAT
  270.  
  271.        (* Bei der Suche nach den auszutauschenden Elementen gibt es
  272.         * zwei Moeglichkeiten:
  273.         *
  274.         *  - Vom jeweiligen Rand ausgehend wird ein Element gesucht,
  275.         *    dass groesser/kleiner ODER GLEICH dem Vergleichselement
  276.         *    ist. Durch die Gleichbedingung wirkt das Vergleichselement
  277.         *    als Endemarke der Iteration, da auf jeden Fall dieses
  278.         *    Element gefunden wird.
  279.         *    Der Nachteil: Kommt der Wert des Vergleichselementes
  280.         *    haufig in dem Feld vor, so finden entsprechend viele
  281.         *    unnoetige Austauschoperationen statt.
  282.         *
  283.         *  - Vom jeweiligen Rand her wird ein Element gesucht, dass
  284.         *    ECHT groesser (kleiner) als das Vergleichselement ist.
  285.         *    Das vermeidet die unnoetigen Austauschoperationen bei
  286.         *    Elementen, die gleich dem Vergleichselement sind;
  287.         *    allerdings wirkt das Vergleichselement nun nicht mehr
  288.         *    als Marke (es kann sein, dass kein Element gefunden
  289.         *    wird, das echt groesser/kleiner als das Vergleichselement
  290.         *    ist), sodass zusaetzlich der Laufindex als Endebedingung
  291.         *    abgefragt werden muss.
  292.         *
  293.         * Es wird die erste Methode benutzt, da eine grosse Anzahl
  294.         * von Elementen mit gleichem Schluessel sicher selten vorkommt,
  295.         * und bei der zweiten Methode dafuer an anderer Stelle mehr
  296.         * Aufwand getrieben werden muss.
  297.         *)
  298.  
  299.        WHILE compare(leftP, cmpP) < 0 DO
  300.          leftP := ADDADR(leftP, size);
  301.          INC(left);
  302.        END;
  303.  
  304.        WHILE compare(cmpP, rightP) < 0 DO
  305.          rightP := SUBADR(rightP, size);
  306.          DEC(right);
  307.        END;
  308.  
  309.        IF left <= right THEN
  310.          memswap(leftP, rightP, size);
  311.          (* Falls das Vergleichselement beim Austausch beteiligt war,
  312.           * muss auch der Zeiger auf das Vergleichselement entsprechend
  313.           * neu gesetzt werden.
  314.           *)
  315.          IF cmpP = leftP THEN
  316.            cmpP := rightP;
  317.          ELSIF cmpP = rightP THEN
  318.            cmpP := leftP;
  319.          END;
  320.  
  321.          IF left < top THEN
  322.            INC(left);
  323.            leftP := ADDADR(leftP, size);
  324.          END;
  325.          IF right > bot THEN
  326.            DEC(right);
  327.            rightP := SUBADR(rightP, size);
  328.          END;
  329.        END;
  330.      UNTIL left > right;
  331.  
  332.      (* (bot<=i<left)->(x[i]<=x[cmpP]) & (right<i<=top)->(x[i]>=x[cmpP]) *)
  333.  
  334.      IF (right - bot) < (top - left) THEN
  335.        (* Nur das kleinere Teilfeld wird rekursiv
  336.         * weitersortiert, das groessere wird durch
  337.         * die darauffolgenden Zuweisungen in der
  338.         * Schleife weiter zerlegt.
  339.         *)
  340.        IF bot < right THEN
  341.          (* Rekursionsbasis: Teilfeld ist sortiert,
  342.           * wenn es nur noch ein Element enthaelt.
  343.           *)
  344.          sort(bot, right);
  345.        END;
  346.        (* Die Elemente left von <left> sind jetzt sortiert,
  347.         * die groessere Haelfte wird in der Schleife
  348.         * weiterbearbeitet.
  349.         *)
  350.        bot := left;
  351.      ELSE
  352.        IF left < top THEN
  353.          sort(left, top);
  354.        END;
  355.        top := right;
  356.      END; (* IF (right ..*)
  357.  
  358.    END; (* IF (top ..*)
  359.  END; (* WHILE *)
  360. END sort;
  361.  
  362. BEGIN (* qsort *)
  363.  IF   (base = NULL)
  364.    OR (size = VAL(sizeT,0))
  365.    OR (nelems <= VAL(sizeT,1))
  366.  THEN
  367.    RETURN;
  368.  END;
  369.  sort(0, nelems - VAL(sizeT,1));
  370. END qsort;
  371.  
  372. (*---------------------------------------------------------------------------*)
  373.  
  374. PROCEDURE ValToStr ((* EIN/ -- *) val    : UNSIGNEDLONG;
  375.                     (* EIN/ -- *) signed : BOOLEAN;
  376.                     (* EIN/ -- *) base   : int;
  377.                     (* -- /AUS *) buf    : StrPtr       );
  378.  
  379. VAR         basis  : UNSIGNEDLONG;
  380.     __REG__ len    : UNSIGNEDWORD;
  381.     __REG__ i      : UNSIGNEDWORD;
  382.     __REG__ b      : StrPtr;
  383.             sign   : BOOLEAN;
  384.             digits : ARRAY [0..33] OF CHAR;
  385.  
  386. BEGIN
  387.  IF (base < 2) OR (base > 36) THEN
  388.    basis := 10;
  389.  ELSE
  390.    basis := VAL(UNSIGNEDLONG,base);
  391.  END;
  392.  
  393.  sign := signed AND (base = 10) AND (CAST(SIGNEDLONG,val) < VAL(SIGNEDLONG,0));
  394.  IF sign THEN
  395.    IF val <> CAST(UNSIGNEDLONG,MINSIGNEDLONG) THEN
  396.      (* Abfrage verhindert Ueberlauffehler, da MINSIGNEDLONG im
  397.       * Zweierkomplement nicht als positive Zahl darstellbar ist
  398.       * und unveraendert bleibt.
  399.       *)
  400.      val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,val));
  401.    END;
  402.  END;
  403.  
  404.  (* Die Zahl von hinten nach vorne in String wandeln;
  405.   * durch die REPEAT-Schleife wird auch die Null
  406.   * dargestellt.
  407.   *)
  408.  len := 0;
  409.  REPEAT
  410.    digits[len] := toupper(todigit(VAL(CARDINAL,val MOD basis)));
  411.    val    := val DIV basis;
  412.    INC(len);
  413.  UNTIL val = LC(0);
  414.  IF sign THEN
  415.    digits[len] := '-';
  416.    INC(len);
  417.  END;
  418.  
  419.  (* Jetzt wird die Zahlendarstellung in umgekehrter
  420.   * Reihenfolge aus dem Hilfsstring in den eigentlichen
  421.   * String uebertragen. Ausserdem werden Prefix und fuehrende
  422.   * Nullen hinzugefuegt.
  423.   *)
  424.  
  425.  b := buf;
  426.  IF b <> NULL THEN
  427.    i := 0;
  428.    WHILE len > 0 DO
  429.      DEC(len);
  430.      b^[i] := digits[len];
  431.      INC(i);
  432.    END;
  433.    b^[i] := 0C;
  434.  END;
  435. END ValToStr;
  436.  
  437. (*---------------------------------------------------------------------------*)
  438.  
  439. PROCEDURE itoa ((* EIN/ -- *) n    : int;
  440.                 (* EIN/ -- *) buf  : StrPtr;
  441.                 (* EIN/ -- *) base : int    );
  442. BEGIN
  443.  ValToStr(CAST(UNSIGNEDLONG,VAL(SIGNEDLONG,n)), TRUE, base, buf);
  444. END itoa;
  445.  
  446. (*---------------------------------------------------------------------------*)
  447.  
  448. PROCEDURE ltoa ((* EIN/ -- *) n    : long;
  449.                 (* EIN/ -- *) buf  : StrPtr;
  450.                 (* EIN/ -- *) base : int    );
  451. BEGIN
  452.  ValToStr(CAST(UNSIGNEDLONG,n), TRUE, base, buf);
  453. END ltoa;
  454.  
  455. (*---------------------------------------------------------------------------*)
  456.  
  457. PROCEDURE ultoa ((* EIN/ -- *) n    : unsignedlong;
  458.                  (* EIN/ -- *) buf  : StrPtr;
  459.                  (* EIN/ -- *) base : int           );
  460.  
  461. BEGIN
  462.  ValToStr(n, FALSE, base, buf);
  463. END ultoa;
  464.  
  465. (*---------------------------------------------------------------------------*)
  466.  
  467. PROCEDURE StrToVal ((* EIN/ -- *)     str     : StrPtr;
  468.                     (* EIN/ -- *)     max     : UNSIGNEDLONG;
  469.                     (* EIN/ -- *)     basis   : int;
  470.                     (* EIN/ -- *)     signed  : BOOLEAN;
  471.                     (* -- /AUS *) VAR nextIdx : UNSIGNEDWORD;
  472.                     (* -- /AUS *) VAR val     : UNSIGNEDLONG  );
  473.  
  474. VAR __REG__ idx          : UNSIGNEDWORD;
  475.     __REG__ digit        : CHAR;
  476.     __REG__ s            : StrPtr;
  477.             neg          : BOOLEAN;
  478.             maxDivBase   : UNSIGNEDLONG;
  479.             maxLastDigit : UNSIGNEDLONG;
  480.             num          : UNSIGNEDLONG;
  481.             base         : UNSIGNEDLONG;
  482.  
  483. BEGIN
  484.  val := 0;
  485.  idx := 0;
  486.  neg := FALSE;
  487.  s   := str;
  488.  IF s = NULL THEN
  489.    nextIdx := 0;
  490.    RETURN;
  491.  END;
  492.  
  493.  (* Fuehrende Leerzeichen tun nichts zur Sache *)
  494.  WHILE isspace(s^[idx]) DO
  495.    INC(idx);
  496.  END;
  497.  
  498.  (* Moegliches Vorzeichen feststellen, bei negativer Zahl ist der
  499.   * maximale Wert um eins groesser (im Zweierkomplement).
  500.   *)
  501.  IF signed THEN
  502.    digit := s^[idx];
  503.    neg   := digit = '-';
  504.    IF digit = '+' THEN
  505.      INC(idx);
  506.    ELSIF neg THEN
  507.      (* Negative Zahlen haben einen um eins groesseren
  508.       * Wertebereich als positive Zahlen (die Null ausgenommen).
  509.       *)
  510.      INC(idx);
  511.      INC(max);
  512.    END;
  513.  END;
  514.  
  515.  digit := s^[idx];
  516.  IF digit = 0C THEN
  517.    (* Keine Zahl folgt => Fehler *)
  518.    nextIdx := idx;
  519.    RETURN;
  520.  END;
  521.  
  522.  IF (basis < 2) OR (basis > 36) THEN
  523.    basis := 0;
  524.  END;
  525.  base := VAL(UNSIGNEDLONG,basis);
  526.  
  527.  IF basis = 0 THEN
  528.    (* Die Basis der Zahl soll aus der Zeichenfolge hervorgehen *)
  529.    INC(idx);
  530.    IF digit = '%' THEN
  531.      (* Zahl in Binaerdarstellung *)
  532.      base := 2;
  533.    ELSIF digit = '0' THEN
  534.      (* Zahl in Sedezimal- oder Oktaldarstellung oder einzelne Null *)
  535.      IF toupper(s^[idx]) = 'X' THEN
  536.        base := 16;
  537.        INC(idx);
  538.      ELSE
  539.        base := 8;
  540.      END;
  541.    ELSIF digit = '$' THEN
  542.      base := 16;
  543.    ELSE
  544.      base := 10;
  545.      DEC(idx);
  546.    END;
  547.  
  548.  (* Die Basis ist angegeben, zusaetzliche Angabe in Repraesentation
  549.   * ueberlesen (Oktalnull stoert nicht).
  550.   *)
  551.  ELSIF (basis = 2) AND (digit = '%') THEN
  552.    (* Binaerdarstellung *)
  553.    INC(idx);
  554.  ELSIF basis = 16 THEN
  555.    (* Sedezimaldarstellung *)
  556.    IF digit = '$' THEN
  557.      INC(idx);
  558.    ELSIF (digit = '0') AND (toupper(s^[idx+1]) = 'X') THEN
  559.      INC(idx, 2);
  560.    END;
  561.  END;
  562.  
  563.  maxDivBase   := max DIV base;
  564.  maxLastDigit := max MOD base;
  565.  
  566.  LOOP
  567.    (* Abbrechen, sobald der String zuende ist, oder ein Zeichen gefunden
  568.     * wurde, das keine gueltige Ziffer ist, oder ein Ueberlauf stattfinden
  569.     * wuerde.
  570.     *)
  571.    nextIdx := idx;
  572.    digit   := s^[idx];
  573.    IF digit = 0C THEN
  574.      EXIT;
  575.    END;
  576.  
  577.    num := VAL(UNSIGNEDLONG,tocard(digit));
  578.    IF num >= base THEN
  579.      EXIT;
  580.    END;
  581.  
  582.    (* Da <val> mit jedem neuen Digit um eine Stelle erweitert wird,
  583.     * wird fuer die Ueberlaufpruefung der bisherige <val> vor der
  584.     * Erweiterung mit einem Zehntel des Maximalwerts verglichen;
  585.     * wuerde nach der Erweiterung verglichen, waere der Ueberlauf
  586.     * ja womoeglich schon passiert, und dabei koennte auch ein
  587.     * UNSIGNEDLONG-Ueberlauf auftreten -- ein Vergleich wuerde dann
  588.     * nur Unsinn produzieren.
  589.     * Ist der bisherige Wert kleiner als ein Zehntel des Maximums,
  590.     * kann kein Ueberlauf auftreten, ist der bisherige Wert gleich
  591.     * dem Maximumszehntel, muss geprueft werden, ob das neue Digit
  592.     * den Wert des letzten Digits des Maximums ueberschreitet.
  593.     *)
  594.    IF    (val < maxDivBase)
  595.       OR (val = maxDivBase) AND (num <= maxLastDigit)
  596.    THEN
  597.      val := val * base + num;
  598.      INC(idx);
  599.    ELSE (* Ueberlauf *)
  600.      e.errno := e.ERANGE;
  601.      IF neg AND (max <> CAST(UNSIGNEDLONG,MINSIGNEDLONG)) THEN
  602.        val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,max));
  603.      ELSE
  604.        val := max;
  605.      END;
  606.      RETURN;
  607.    END;
  608.  END; (* LOOP *)
  609.  
  610.  IF neg AND (val <> CAST(UNSIGNEDLONG,MINSIGNEDLONG)) THEN
  611.    (* Wenn vor der Zahl ein '-' stand und negative Zahlen erlaubt
  612.     * sind, den bisher positiven Zahlenwert in einen negativen wandeln.
  613.     * Abfrage auf MINSIGNEDLONG verhindert Ueberlauf.
  614.     *)
  615.    val := CAST(UNSIGNEDLONG,-CAST(SIGNEDLONG,val));
  616.  END;
  617. END StrToVal;
  618.  
  619. (*---------------------------------------------------------------------------*)
  620.  
  621. PROCEDURE strtol ((* EIN/ -- *) str  : StrPtr;
  622.                   (* EIN/ -- *) end  : StrPPtr;
  623.                   (* EIN/ -- *) base : int      ): long;
  624.  
  625. VAR val  : UNSIGNEDLONG;
  626.     next : UNSIGNEDWORD;
  627.  
  628. BEGIN
  629.  StrToVal(str, MAXSIGNEDLONG, base, TRUE, next, val);
  630.  IF end <> NULL THEN
  631.    end^ := ADR(str^[next]);
  632.  END;
  633.  RETURN(CAST(long,val));
  634. END strtol;
  635.  
  636. (*---------------------------------------------------------------------------*)
  637.  
  638. PROCEDURE strtoul ((* EIN/ -- *) str  : StrPtr;
  639.                    (* EIN/ -- *) end  : StrPPtr;
  640.                    (* EIN/ -- *) base : int      ): unsignedlong;
  641.  
  642. VAR val  : UNSIGNEDLONG;
  643.     next : UNSIGNEDWORD;
  644.  
  645. BEGIN
  646.  StrToVal(str, MAXUNSIGNEDLONG, base, FALSE, next, val);
  647.  IF end <> NULL THEN
  648.    end^ := ADR(str^[next]);
  649.  END;
  650.  RETURN(val);
  651. END strtoul;
  652.  
  653. (*---------------------------------------------------------------------------*)
  654.  
  655. PROCEDURE atol ((* EIN/ -- *) str : StrPtr ): long;
  656.  
  657. VAR val  : UNSIGNEDLONG;
  658.     next : UNSIGNEDWORD;
  659.  
  660. BEGIN
  661.  StrToVal(str, MAXSIGNEDLONG, 10, TRUE, next, val);
  662.  RETURN(CAST(long,val));
  663. END atol;
  664.  
  665. (*---------------------------------------------------------------------------*)
  666.  
  667. PROCEDURE atoi ((* EIN/ -- *) str : StrPtr ): int;
  668.  
  669. VAR val  : UNSIGNEDLONG;
  670.     next : UNSIGNEDWORD;
  671.  
  672. BEGIN
  673.  StrToVal(str, MAXINT, 10, TRUE, next, val);
  674.  RETURN(INT(val));
  675. END atoi;
  676.  
  677. (*---------------------------------------------------------------------------*)
  678.  
  679. PROCEDURE rand ( ): int;
  680.  
  681. CONST
  682.   A = LIC(16807);
  683.   M = LIC(2147483647);
  684.   Q = LIC(127773);
  685.   R = LIC(2836);
  686.  
  687. BEGIN
  688.  Seed := A * (Seed MOD Q) - R * (Seed DIV Q);
  689.  IF Seed < VAL(SIGNEDLONG,0) THEN
  690.    INC(Seed, M);
  691.  END;
  692.  
  693.  IF TSIZE(int) < TSIZE(SIGNEDLONG) THEN
  694.    RETURN(VAL(int,CAST(UNSIGNEDLONG,Seed) MOD VAL(UNSIGNEDLONG,8000H)));
  695.  ELSE
  696.    RETURN(CAST(int,Seed));
  697.  END;
  698. END rand;
  699.  
  700. (*---------------------------------------------------------------------------*)
  701.  
  702. PROCEDURE srand ((* EIN/ -- *) seed : unsigned );
  703. BEGIN
  704.  Seed := CAST(SIGNEDLONG,VAL(UNSIGNEDLONG,seed));
  705. END srand;
  706.  
  707. (*===========================================================================*)
  708.  
  709. BEGIN (* lib *)
  710.  Seed := 1;
  711. END lib.
  712.