CLICK 2.03a Index eindeutiger identifizieren ?

Zugriff, Engines, Konvertierung. Von ADS über DBF bis zu SQL.

Moderator: Moderatoren

Antworten

Click für Xbase++

das hab ich schon immer gesucht
1
20%
ich brauche sowas nicht
1
20%
ich weiss nicht was ich damit soll
2
40%
ich traue keinem Programm meinen Source an
1
20%
ich habe was besser für sowas
0
Keine Stimmen
 
Insgesamt abgegebene Stimmen: 5

Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

CLICK 2.03a Index eindeutiger identifizieren ?

Beitrag von AUGE_OHR »

hi,

unter www.combifinanz.de/tools hat Olaf Breslauer eine Xbase++ Version
von Phil Barnett CLICK veröffentlicht (s.h. public.xbase++.generic vom
26. Juni 2007 Thema : CLICK)

CLICK ist ein "Source Code Reformatter for Clipper" der durch Olaf auch
mit Xbase++ CLASS Code zurecht kommt (keine INLINE Methode). Als
Option kann man einen Header vor jeder Funktion schreiben lassen und
auch Cross Referenz Listen von den Funktionen ausgeben lassen.

Das ganze ist original Cl*pper Source Code und wurde nun von Olaf
modifiziert. Beim Debuggen viel mir dann auf das in den Headern
zwar die "Table" (DBF) und Index Angaben standen es aber keine
Cross Referenz Liste dazu gibt. Beim weitern stöbern bin ich dann
auf die Multi-Dim-Array "aTable" und "aIndex" gestossen welche als
STATIC in Click zur Laufzeit erreichbar sind.

Die "Table" (DBF) Listen mit den DBStruct() zu erstellen war kein Problem
und auch die Index (bislang nur NTX) zu "identifizieren" funktioniert im
Prinzip. Ich prüfe dabei die DBStruct() Felder ob die im zerlegten ("+")
ORDKEY() vorhanden sind nachdem ich zuvor bei SET INDEX TO xxx
Erfolg hatte. Leider kommt es trotzdem vor das ein Index zu mehr als
exact eine DBF passt ...
SET INDEX TO LIEF_ALT.NTX
*************************

Index : LIEF_ALT.NTX
Ordkey : FFJAHR+LIEFNR
----------------------

AUFEIN.DBF
FAKTU.DBF
FSICHER.DBF
LIEFALT.DBF
LIEFER.DBF
LIEFTEMP.DBF
SAVEFAKT.DBF
SAVELIEF.DBF

--- Quote 12.50 % ---
tja die FELDer FFJAHR+LIEFNR kommen eben sehr oft vor ... klar gehört
LIEF_ALT.NTX zu LIEFALT.DBF, aber woher soll der Computer das wissen ?

Nun hat eine Index ja auch eine gewisse Länge... komme ich da irgendwie
an sowas wie LASTREC() womit ich sowas wie Anzahl der Indexausdrücke
= OrdKeyCount() ... was es unter Xbase++ nicht gibt ...

Kann ich den Index irgendwie per SEEK(Anfang/Ende) auf FOUND() prüfen
den díe richtige DBF müsste ja beides mal .T. liefen ...

sonst noch jemand eine Idee wie ich mehr als 12,50% Trefferquote raus-
holen kann ?

gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

ich weiss nicht was ich damit soll ...

Beitrag von AUGE_OHR »

hi,

Scheinbar ist nicht bekannt was "Source Code Reformatter" so leisten
und warum ich solche Programme wie SNAP, DFLOW und Click liebe.

Ein solche Programm wie Click reformatiert einem nicht nur den Source
damit er schöner aussieht sondern sammelt gewöhnlich auch weitere
Informationen z.b. über Function/Procedure und "wo" die von "wem"
aufgerufen werden. Dieses kann man sich in den Header vor jede
Function/Procedure schreiben lassen. Damit bekommt man auch sehr
schnell raus welche Function/Procedure evtl. nicht mehr benutzt werden,
weil nicht aufgerufen, und kann die dann entsorgen.

Besonders bei unbekanntem Source, wenn man z.b. ein externes Project
übernimmt, und man überhaupt nicht weiss wo welche Function/Procedure
überhaupt ist und von wem verwendet wird, ist so ein Tool Gold wert.

Desweiteren ist es so ziemlich das einzige neben Cl*pper dem ich traue
das "er" meinen geschriebenen Source Code kapiert ... :)
Klar lief mein Source auch vorher durch den Compiler mit -w ohne zu
meckern, aber wenn Click was zu meckern hatte und man das verbessert
hat so ist es danach meisten "noch schöner" als vorher.

In der jetztigen Version braucht die modifizierte Xbase++ Click Version
für 2.744K Byte in 134 ausgew. Dateien ca. 03:35 min für 98087 lines.
Damit ist auch die Auswertung von 36 DBF Dateien sowie die zuordnung
von 16 "SET INDEX TO" enthalten die meine Xbase++ Application enthält.

Eine Header Datei sieht z.b. so aus :
*+²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
*+
*+ Source Module => D:\ALASKA\CLICK\SRC\FUNCTRAK.PRG
*+
*+ Functions: Procedure init_func_text()
*+ Procedure functrak()
*+ Procedure func_call()
*+ Procedure end_func_text()
*+ Procedure func_text()
*+ Static Function findfunc()
*+ Static Function SubArrySrch()
*+
*+ NEW by Jimmy
*+
*+ Procedure yFUNC_DBFS()
*+ Static Procedure yNTXSTRUC()
*+ Static Procedure ySPLITTEST()
*+ Static Procedure ySEEMORE()
*+ Static Procedure ySEETHIS()
*+ Static Procedure yDBFSTRUC()
*+ Static Procedure ySWUSE()
*+ Static Procedure yTAUSCHMK()
*+ Static Function yBIGARR()
*+ Static Function NtxDump()
*+
*+ Tables: USE (cFile) VIA "FOXCDX"
*+ USE (cFile) VIA "DBFNTX"
*+ USE (cSeek) VIA "FOXCDX" NEW shared
*+ USE (cSeek) NEW shared
*+
*+ Reformatted by Click! 2.03a on Aug-7-2007 at 12:45 am
*+
*+²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²²
...
*+±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
*+
*+ Procedure yFUNC_DBFS()
*+
*+ Called from ( click.prg ) 1 - procedure main()
*+
*+±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
die "y" Funktionen sind übrigens die neuen DBF/NTX Funktionen die ich der
Version von Olaf nun hinzugefügt habe.

Wenn sich noch einige mehr bei der Umfrage des Threads dafür interesse
dafür zeigen würde ich Olaf bitten meine Erweiterrungen zu übernehmen
und eine neue Version zu releasen.

gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Index Problem gelöst, aber ...

Beitrag von AUGE_OHR »

hi,

ich habe was in meiner Cl*pper Sammelung über NTX gefunden was es
mir möglich macht mit 99,99% wahrscheinlichkeit zuh sagen ob eine
NTX Datei zu einer DBF "passt". Dazu muss der Index "aktuell" sein
d.h. man kann es im Prinzip auch dafür verwenden um festzustellen
ob ein Index "defekt" ist.

Geht man nun von meinem ersten Beispiel aus so hatte ich ja 8 DBF
Dateien wo der ORDKEY() zu der DBF passen würde. Da ich nun immer
in meiner NET_USE() alle passenden Index Dateien öffne sollte die
höchste OrdKeyNo() = OrdkeyCount()* = LASTREC() der DBF sein.
(* gibt es leider unter Xbase++ nicht)

Ausnahme : wenn ich einen UNIQUE, FOR, WHILE, NEXT etc. in meinem
INDEX ON Ausdruck habe ...

nun hab ich folgendes gefunden was mir jedes "Element"(=OrdKeyNo())
von einer NTX Datei "dump"t

Code: Alles auswählen

*+±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±
*+
*+    Static Function NtxDump()
*+
*+    Called from ( functrak.prg )   1 - static procedure yseemore()
*+
*+±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±±

/* Programm-Name:    NTXDUMP.PRG
 * Autor:            Isaac Said-Nejad
 * Aufruf:           NTXDUMP <Dateiname>
 * Copyright (c):    Nantucket Corp.
 * Compilieren mit:  /n/w/p             
*/

*#include "NtxDump.CH"
#define PAGE_SIZE 1024
#define UNSIGNED 2
#define SIGNED 2
#define LONG 4
#define LONG2 4
#define STACK_SIZE 4096

±±±±±±±±±±±±±±±±±±±±±±±
*+
STATIC FUNCTION NtxDump(ntx_file)
//
// New by Jimmy
// das ist der Zähler für due Durchläufe
//
LOCAL nZahl         := 0

LOCAL handle
LOCAL stack_pointer
LOCAL READ
LOCAL root
LOCAL key_size
LOCAL item_number
LOCAL down
LOCAL buffer
LOCAL items
LOCAL item_pointer
LOCAL child_page
LOCAL item_at
LOCAL stack[STACK_SIZE]

   *    CLEAR SCREEN

   IF PCOUNT() == 0
      *        ? "Syntax: NTXDUMP <Dateiname>"
      *        QUIT
      RETURN 0

   ENDIF

   handle := FOPEN(ntx_file,0)

   IF FERROR() != 0
      show_out("ERROR "+LTRIM(STR(FERROR()))+" while FOPEN "+ntx_file)
      *        ? "Fehler beim ™ffnen der Datei ", FERROR()
      *        QUIT
      RETURN 0
   ENDIF

   stack_pointer := 1
   buffer        := SPACE(PAGE_SIZE)
   READ          := FREAD(handle,@buffer,PAGE_SIZE)

   IF READ <> PAGE_SIZE
      show_out("ERROR reading Headers")
      *        ? "Fehler beim Lesen des Headers"
      *        QUIT
      RETURN 0
   ENDIF

   *    SET ALTERNATE TO NTXDUMP
   *    SET ALTERNATE ON
   *
   *    ? "Datei-ID: ", BIN2W(SUBSTR(buffer, 1, UNSIGNED))
   *    ? "Index-Version: ", BIN2W(SUBSTR(buffer, 3, UNSIGNED))
   *    root := BIN2L(SUBSTR(buffer, 5, LONG))
   *    ? "Root d. aktiven Pages: ", root
   *    ? "Root d. unbenutzten Pages: ", BIN2L(SUBSTR(buffer, 9, LONG))
   *    ? "Eintrag-GrӇe: ", BIN2W(SUBSTR(buffer, 13, UNSIGNED))
   *    key_size := BIN2W(SUBSTR(buffer, 15, UNSIGNED))
   *    ? "Schl
Benutzeravatar
Armin
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 393
Registriert: Mo, 26. Sep 2005 12:09
Wohnort: 75331 Engelsbrand
Danksagung erhalten: 3 Mal
Kontaktdaten:

Beitrag von Armin »

Hi Jimmy,

ich hätte ja gerne mitabgestimmt - mir fehlt:

x - brauche ich im Moment nicht

Grüsse, Armin
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Beitrag von AUGE_OHR »

hi,
Armin hat geschrieben: ich hätte ja gerne mitabgestimmt - mir fehlt:
x - brauche ich im Moment nicht
ich kann die Umfrage leider nicht nachträglich ändern.

weist du wirklich immer wo welche Function/Procedure ist und von wem
die benutzt wird oder benutzt du ein Datadriven System ( mit Macro ) ?

Eine Macro "Auflösung" für die Table/Index hab ich übrigens auch schon
in meiner "latest" Version eingebaut. Man könnte die sicherlich auch ohne
grosse Probleme das in die Analyse des Source mit einbauen,dort wo auch
die [CMD_LIST] und [OP_LIST] abgearbeitet werden.

gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

CDX Index Dateien.

Beitrag von AUGE_OHR »

hi,

nachdem das identifizieren der NTX Dateien ja nun grundsätzlich gelöst
ist hätte ich gerne auch noch die CDX Index Dateien.

Nun ist mir noch nicht klar ob das bei CDX überhaupt so möglich ist denn
ich kann ja mehrere TAGs haben ...

ich habe bislang gefunden:
http://www.clicketyclick.dk/databases/x ... t/cdx.html

Xbase: Compound Index files (*.cdx)

The Structure of Compound Index files (*.cdx)
by David Kuechler (71202.1315@CompuServe.COM)
A CDX is a compact IDX. The initial IDX contains one key per tag. The key is 10 byte character string which is the tag name. The record number stored with the key is the offset to the root page for that tag. There is no description on the compression algorithm
A compact IDX has the following structure:

... gelöscht weil nicht vernüpftig lesebar ...

The individual list must be ANDed with these masks in order to calculate the original index.
sowie einen FoxPro Code der evtl. das macht was ich suche.

Code: Alles auswählen

#define NODESIZE 512
#define WMASK 65535     &&2^16 -1  0xFFFF
#define IXO_TAG 0x80
#define IXO_MDX   0x40               && Index header is a cdx header
#define IXNROOT         1               &&    /* this is the root node */
#define IXNLEAF         2                &&    /* this is a leaf node */

DecodeIndex("test.cdx") && or any fullpath to a CDX file

PROCEDURE DecodeIndex(cIndexFile as String)
      oRoot=0
      Hndx=0
      TRY 
            hNdx=FOPEN(cIndexFile)
            IF hNdx<=1
                  THROW "error opening "+cIndexFile 
            ENDIF 
            SET PRINT TO tt.txt
            SET PRINTER on
            SET CONSOLE off
            oRoot=CREATEOBJECT("tagnode",0,0)
            ?cIndexFile
            oRoot.Showit()

      CATCH TO oError 
     ?"Err",oError.LineNo,oError.details,oError.LineContents,oError.Message
      ENDTRY
      SET PRINTER off
      SET PRINT to
      SET CONSOLE on
      FCLOSE(hNdx)
      CLEAR all
      MODIFY FILE tt.txt nowait

DEFINE CLASS tagnode as ixnode      && one of these per index tag
      ixKeyLen=0
      IxOptions=0
      Sector2=0
      PROCEDURE init(nAddr as Integer,nDepth as String)
            DODEFAULT(nAddr,nDepth)
            WITH this
                  .fIsTagNode=.t.
                  .IxOptions=ASC(SUBSTR(.buffer,4*3+1+2,1))
                  .IxKeyLen=CTOBIN(substr(.buffer,4*3+1,2),"2rs")
                  RootAddr=CTOBIN(LEFT(.buffer,4),"4rs")
                  IxSignature=ASC(SUBSTR(.buffer,4*3+1+3,1))
                  IF BITAND(.ixOptions,IXO_TAG)>0
                        .oChild=CREATEOBJECT("ixnode",RootAddr,nDepth+1)
                        .oChild.oTag=this && ptr to TAG node
                        .oChild.FillIt()
                  ENDIF 
                  IF BITAND(.ixOptions,IXO_MDX)>0
                        .Sector2=CREATEOBJECT("sector",.nAddr+NODESIZE)
                  && an MDX is a double size node
                  ENDIF 
            ENDWITH 
ENDDEFINE

DEFINE CLASS ixnode as sector
      oTag=0
      nDepth=0
      fIsTagNode=.f.
      oChild=0
      oSiblings=0
      nAttr=0
      nKeys=0
      nLeft=0
      nRight=0
      nAvail=0
      rMask=0
      dMask=0
      tMask=0
      rBits=0
      dBits=0
      tBits=0
      mLen=0

      PROCEDURE showit() && recursive procedure to show the entire tree
            LOCAL cKey,rn,i
            WITH this
                  ?REPLICATE("  ",.nDepth)+TRANSFORM(.nDepth),TRANSFORM(.nAddr,"@0x")+" "+.class+" "
                  IF .fIsTagNode && AND BITAND(.ixOptions,IXO_TAG)=0
                        ??TRANSFORM(.ixOptions,"@0x"),TRANSFORM(CTOBIN(LEFT(.buffer,4),"4rs"),"@0x")+" "
                        nKeyExprLen=CTOBIN(SUBSTR(.buffer,512-2,2),"2s")
                        ??LEFT(.Sector2.buffer,nKeyExprLen-1)
                        nForExprLen=CTOBIN(SUBSTR(.buffer,512-6,2),"2s")
                        IF nForExprLen>1
                           nForExprOffset=CTOBIN(SUBSTR(.buffer,512-8,2),"2s")
??" FOR ",SUBSTR(.Sector2.buffer,nForExprOffset+1,nForExprLen-1)
                        ENDIF 
                  ELSE
??TRANSFORM(.nAttr)+" "+TRANSFORM(.nleft,"@0x"),TRANSFORM(.nRight,"@0x"),padr(.nKeys,3)
                        cKey=""
                        nKeyPoolOff=NODESIZE
                        FOR i = 1 TO .nKeys
                              rn=.GetKey(i,@cKey,@nKeyPoolOff)
                              ??ALLTRIM(cKey)+" "
                              IF BITAND(.nAttr,IXNLEAF)>0 AND .nDepth > 1
                              &&should we output in hex ?
                                    ??padr(rn,5)," "
                              ELSE
                                    ??TRANSFORM(rn,"@0x")," "
                              ENDIF 
                        ENDFOR
                  ENDIF 
                  IF VARTYPE(.oChild)="O"
                        .oChild.Showit()
                  ENDIF 
                  IF VARTYPE(.oSiblings)="O"
                        .oSiblings.Showit()
                  ENDIF 
            ENDWITH 

      PROCEDURE FillIt  && recursive procedure to fill the tree
            LOCAL i,cKey,cClass,dwAddr,oSib
            WITH this
                  IF .fIsTagNode
                        dwAddr=CTOBIN(LEFT(.buffer,4),"4rs")
                        .oChild=CREATEOBJECT("ixnode",dwAddr,.nDepth+1)
                        .oChild.oTag=this && ptr to TAG node
                        .oChild.FillIt()
                  ELSE 
                        IF BITAND(.nAttr, IXNLEAF)=0 OR .nDepth=1 
                        && and  BITAND(.nAttr, IXNROOT)=0
                              cClass=IIF(.nDepth<2,"tagnode","ixnode")
                              cKey=""
                              nKeyPoolOff=NODESIZE
                              FOR i = 1 TO .nKeys
                                    dwAddr = .GetKey(i, @cKey,@nKeyPoolOff)
                                    IF VARTYPE(.oChild)!= 'O'
                               .oChild=CREATEOBJECT(cClass,dwAddr,.nDepth+1) 
                                          .oChild.oTag=.oTag
                                          .oChild.FillIt()
                                    ELSE
                                   oSib=CREATEOBJECT(cClass,dwAddr,.nDepth+1) 
                                          oSib.oTag=.oTag
                                          oSib.FillIt()
                                          oTemp=.oChild.oSiblings
                                          IF VARTYPE(oTemp)!='O'
                                                .oChild.oSiblings=oSib
                                          ELSE 
                                             DO WHILE VARTYPE(oTemp.oSiblings)="O"
                                             && add siblings at the end
                                                      oTemp=oTemp.oSiblings
                                                ENDDO
                                                oTemp.oSiblings=oSib
                                          ENDIF 
                                    ENDIF 
                              ENDFOR
                        ENDIF 
                  ENDIF 
            ENDWITH

      PROCEDURE init(nAddr as Integer,nDepth as Integer) as VOID
            LOCAL i,cKey
            this.nDepth=nDepth
            DODEFAULT(nAddr)
                  IF this.class!="Ixnode"
                        RETURN
                  ENDIF 
                  WITH this
                        .nAttr=CTOBIN(SUBSTR(.buffer,1,2),"2rs")
                        .nKeys=CTOBIN(SUBSTR(.buffer,3,2),"2rs")
                        .nLeft=CTOBIN(SUBSTR(.buffer,5,4),"4rs")
                        .nRight=CTOBIN(SUBSTR(.buffer,9,4),"4rs")
                        IF BITAND(.nAttr, IXNLEAF)=0
                              *interior node
                        ELSE 
                              .nAvail=CTOBIN(SUBSTR(.buffer,13,2),"2rs")
                              .rMask=CTOBIN(SUBSTR(.buffer,15,4),"4rs")
                              .dMask=ASC(SUBSTR(.buffer,19))
                              .tMask=ASC(SUBSTR(.buffer,20))
                              .rBits=ASC(SUBSTR(.buffer,21))
                              .dBits=ASC(SUBSTR(.buffer,22))
                              .tBits=ASC(SUBSTR(.buffer,23))
                              .mLen=ASC(SUBSTR(.buffer,24))
                        ENDIF 
                  ENDWITH 
            
      PROCEDURE GetKey(nKey as Integer, cKey as string @, nKeyPoolOff as Integer @) as Integer
            LOCAL i,kLen,rn,nKeyPoolOff,nKeyOff,val,duplen,traillen,ntmp
            WITH this
                  kLen=.oTag.ixKeyLen
                  IF BITAND(.nAttr, IXNLEAF)=0
                  && interior nodes are not compressed
                        cKey=SUBSTR(.Buffer,13+(nKey-1)*(kLen+8), kLen)
                   rn=CTOBIN(SUBSTR(.Buffer,13+(nKey)*(kLen+8)-4, 4),"4s")
                  ELSE 
                        nKeyOff=25+(nKey-1)*.mLen     
                        && skip the node header bytes
                        rn = CTOBIN(SUBSTR(.buffer,nKeyOff,4),"4rs")
                        rn=BITAND(rn,.rMask)
                      val= CTOBIN(SUBSTR(.buffer,nKeyOff+(.mLen-2),2),"2rs")
                        duplen=0
                        traillen= .RotateLeft(val,@duplen)
                        ntmp=kLen-traillen-duplen
                        nKeyPoolOff = nKeyPoolOff-nTmp
                        cKey=PADR(LEFT(ckey,duplen)+SUBSTR(.buffer,nKeyPoolOff+1 , nTmp),kLen," ")
                  ENDIF
            ENDWITH 
            RETURN rn

    HIDDEN PROCEDURE RotateLeft(nNum as Integer, duplen as Integer @)
    && low level bit manipulation
            LOCAL nval
            nval=BITLSHIFT(nNum,this.tBits)
            nval=BITAND(nval + BITRSHIFT(nNum,16-this.tBits),WMASK)
            nTrailen=BITAND(nval,2^this.tBits-1)

            nval=BITLSHIFT(nNum,this.dBits)
            nval=BITAND(nval + BITRSHIFT(nVal,16-this.dBits),WMASK)
            duplen=BITAND(nval,2^this.dBits-1)

      RETURN nTrailen
ENDDEFINE

DEFINE CLASS sector as session
      buffer=0    && the 512 bytes of raw node data
      nAddr=0           && address of the sector in the file

      PROCEDURE init(nAddr)
            this.ReadBuf(nAddr)

      PROCEDURE ReadBuf(nAddr)
            this.nAddr=nAddr
            FSEEK(Hndx,nAddr,0)
            this.buffer=FREAD(Hndx,NODESIZE)

ENDDEFINE
leider hab ich kein FoxPro und kann den Code deshalb nicht ausprobieren.
Wenn jemand FoxPro installiert hat möge er den Code doch bitte mal
testen ob der funktioniert und was der macht, danke.

Das es grundsätzlich gehen müsste, wenn man den TAG vorher definiert,
zeigt http://linux.die.net/man/1/indexdump

hat jemand vielleicht sonst noch einen Tip ?

gruss by OHR
Jimmy
Zuletzt geändert von AUGE_OHR am Do, 09. Aug 2007 1:26, insgesamt 2-mal geändert.
Günter Beyes
Rekursionen-Architekt
Rekursionen-Architekt
Beiträge: 315
Registriert: Mo, 16. Okt 2006 13:04
Wohnort: Region Stuttgart

Beitrag von Günter Beyes »

Hallo Jimmy,

falls du aus alten Zeiten noch den SIXCDX-RDD von Successware herumliegen hast, dann schau mal nach dem dort beigepackten Utilityprogramm cdxinfo.exe.

Es listet für jeden Index Tag den Namen, Indexschlüssel, FOR-Schlüssel (falls vorhanden) und UNIQUE-Status auf.

Also der Tip wäre, das Rad nicht neu zu erfinden 8)

Viele Grüße
Günter
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Beitrag von AUGE_OHR »

hi,
Günter Beyes hat geschrieben:falls du aus alten Zeiten noch den SIXCDX-RDD von Successware herumliegen hast, dann schau mal nach dem dort beigepackten Utilityprogramm cdxinfo.exe.

Es listet für jeden Index Tag den Namen, Indexschlüssel, FOR-Schlüssel (falls vorhanden) und UNIQUE-Status auf.
Six ... ja CDXINFO eingegeben und siehe da
D:\ALASKA\WMP>cdxinfo wm9mark.cdx

CDXINFO v2.0 - CDX/IDX Information Utility
(c)1992-94 SuccessWare Int'l ♦ THE Data Driver Company ♦ 909-699-9657

File Name..: WM9MARK.CDX
File Type..: CDX
Tag Count..: 4
───────────────────────────────────

Tag Name...: GENRE
Expression.: GENRE
Conditional: No
Unique.....: No
RYO Status.: Normal
───────────────────────────────────

Tag Name...: MARK
Expression.: W9MARK+W9VIDEO+STR(SNIPIN,14,3)
Conditional: No
Unique.....: No
RYO Status.: Normal
───────────────────────────────────

Tag Name...: RATE
Expression.: STR(W9RATE,1)+W9VIDEO+STR(SNIPIN,14,3)
Conditional: No
Unique.....: No
RYO Status.: Normal
───────────────────────────────────

Tag Name...: VIDEO
Expression.: W9VIDEO+STR(SNIPIN,14,3)
Conditional: No
Unique.....: No
RYO Status.: Normal
───────────────────────────────────
leider sage er mir nicht wie viele "Elemente" ein TAG hat was ich ja gerne
wissen würde.

gruss by OHR
Jimmy
Benutzeravatar
AUGE_OHR
Marvin
Marvin
Beiträge: 12909
Registriert: Do, 16. Mär 2006 7:55
Wohnort: Hamburg
Hat sich bedankt: 19 Mal
Danksagung erhalten: 46 Mal

Beitrag von AUGE_OHR »

hi,

so langsam komme ich hinter das "Geheimniss" wie die Index Dateien
nach dem B-Tree aufgebaut werden und wie man darin "navigiert"
To make the searching in this ordered list fast, it's generally organized
as a tree -- it starts with a root page with records that point to
pages at lower level, etc., until leaf pages where the pointer is no
longer a pointer to the index but to the dbf. When you search for a
record in the index file, you fetch the root page and scan it
(lineary) until you find key value that is equal or grater than that you
are looking for. That way you've avoided reading all pages describing
the values that are lower. Here you descend one level, fetch the page
and again search the list of keys in that page. And you repeat this
process until you get to the leaf (lowest) level and here you finaly
find a pointer to the dbf. XBase::Index does this for you.

Some of the formats also support multiple indexes in one file --
usually there is one top level index that for different field values
points to different root pages in the index file (so called tags).
Ich habe versuch das durch einen "Übersetzter" zu jagen, aber dann
kommt nur noch Schrott raus, deshalb versuche ich das ganze mal
zusammen zu fassen:

Also was ein B-TREE ist, mit Stamm / Ästen / Blätter, dürfte wohl grob klar
sein. Zuerst sucht man also im Stamm nach einen Eintrag. Dieser führt
aber noch nicht zum Ergebniss sondern verweist nur auf die "Page" (Ast).
Also muss man den verweis der "Page" dann nehmen und kommt dann
zum Ergebniss (Blatt).
Während man bei NDX/NTX nun hier den Wert für ORDKEY() findet ist das
bei CDX komplizierter weil ja "comprimiert" d.h. gleiche Werte kommen
nur 1x vor.

bei allen muss man gewöhlich auch noch die HEX Werte umrechnen und
genau da hab ich wohl noch ein Problem bei der folgenden Routine:

Code: Alles auswählen

#include "Fileio.ch"

#define PAGE_SIZE 1024
#define UNSIGNED 2
#define SIGNED 2
#define LONG 4
#define LONG2 4
#define STACK_SIZE 4096

/* Programm-Name:    CDXDUMP.PRG
 * Autor:            original NTXdump by Isaac Said-Nejad
 * Aufruf:           CDXDUMP <Dateiname>
 * Copyright (c):    Nantucket Corp.
 * Compilieren mit:  /n/w/p

   Byte offset Description

*** File header (page 0) ***

    00 –  03 Pointer to root node
    04 –  07 Pointer to free node list ( -1 if not present/empty)
       07 -1 if none (FoxPro)
           0 if none (FoxBase)
    08 –  11 Version no. ,Reserved for internal use
       08 (Foxbase, FoxPro 1.x) No. of pages in file. (FoxPro 2.x) Reserved.

    12 –  13 Length of key
       13 Number and date keys are 8 bits long . Character keys are <= 100
       bytes long. Note! Character keys are NOT terminated with 00h
       -1 if none (FoxPro)
        0 if none (FoxBase)

    14 Index options (any of the following numeric values or their sums):
       14 Index options represented as the sum of the following values:
       01 a Unique index
       08 Index has FOR clause
       16 (10h)  Bit vector (SoftC)
       32 (20h)  Compact index format (FoxPro)
       64 (40h)  Compounding index header (FoxPro)
       128 (80h) Structure index (FoxPro)

    15 Index signature

    16 –  19 Reserved for internal use
       16 Reserved

    20 –  23 Reserved for internal use
    24 –  27 Reserved for internal use
    28 –  31 Reserved for internal use
    32 –  35 Reserved for internal use
    36 – 501 Reserved for internal use
       (Currently all NULL's)

   502 – 503 Ascending or descending:
       502 0 Ascending
           1 Descending

   504 – 505 Total expression length (FoxPro 2), Reserved for internal use
   506 – 507 FOR expression pool length1 (binary)
   508 – 509 Reserved for internal use
   510 – 511 Key expression pool length1 (binary)

   512 – 1023 Key expression pool (uncompiled)
       Key first with null terminator, then FOR expression.

   1 This information tracks the space used in the key expression pool.

*** Compact Index Interior Node Record ( Non leaf page ) ***

   Byte offset Description
    00 –  01 Node attributes (any of the following numeric values or their sums):
       Node attributes represented as the sum of the following values:
       0 Index Interior node (branch)
       1 Root page
       2 Leaf page

    02 –  03 Number of keys present
       (0, 1 or many)

    04 –  07 Pointer to node directly to left of current node
       (on same level, -1 if not present)

    08 –  11 Pointer to node directly to right of current node
       (on same level; -1 if not present)

    12 – 511 Up to 500 characters containing the key value for the length of
       the key with a four-byte hexadecimal number (stored in normal left-to-
       right format):

       Key data
       Record number in data file (high order byte first)
       Pointer to child page

       This node always contains the index key, record number and intra-index
       pointer.2

   The key/four-byte hexadecimal number combinations will occur the number of
   times indicated in bytes 02 – 03.

*** Compact Index Exterior Node Record ( Leaf page ) ***

    00 –  01 Node attributes (any of the following numeric values or their sums):
       Node attributes represented as the sum of the following values:
       0 Index Interior node (branch)
       1 Root page
       2 Leaf page

    02 –  03 Number of keys present
       (0, 1 or many)

    04 –  07 Pointer to the node directly to the left of current node
       (on same level; -1 if not present)

    08 –  11 Pointer to the node directly to right of the current node
       (on same level; -1 if not present)

    12 –  13 Available free space in node
    14 –  17 Record number mask
    18       Duplicate byte count mask
       The individual list must be ANDed with these masks in order
       to calculatethe original index.

    19       Trailing byte count mask
       The individual list must be ANDed with these masks in order
       to calculatethe original index.

    20       Number of bits used for record number
       Byte 020 Number of bits for record number

    21       Number of bits used for duplicate count
       Byte 021 Number of bits for duplicate count

    22       Number of bits used for trail count
       Byte 022 Number of bits for trailing count

    23       Number of bytes holding record number,
       duplicate count and trailing count Byte 023: Number of bytes holding
       record number, duplicate count & trailing count (i.e. the total size
       of values in byte 20 - 22).

    24 – 511 Index keys and information2

       0 Recno/supCount/TrailCount
         At the start of this area, the recno/dupCount/trailCount is stored
         (bit compressed). Each entry requires the number of bytes as indicated
         by byte 023.
         The key values are placed at the end of this area (working backwards)
         and are stored by eliminating any duplicates with the previous key and
         any trailing blanks.

       1
       2
       3
       4 Record number in data file
       5
       6
       7
       8 Key data

   2 Each entry consists of the record number, duplicate byte count and
   trailing byte count, all compacted. The key text is placed at the logical
   end of the node, working backwards, allowing for previous key entries.

   Dates are stored as Julian dates and converted to numbers
   Numbers are stored as IEEE doubles (binary values) with the following
   conversion:

   Convert to an IEEE double (8 bytes)
   Swap the order of the bytes
   IF the number was negative:
      Invert all the bits
   ELSE
      Invert only the highest order bit
   ENDIF

*/

FUNCTION MAIN(Cdx_file)
LOCAL handle, stack_pointer, read, root, key_size
LOCAL item_number, down, buffer, items, item_pointer
LOCAL child_page, item_at
LOCAL stack[STACK_SIZE]
LOCAL nZahl := 0
LOCAL hByte

   CLEAR SCREEN

   IF PCOUNT() == 0
       ? "Syntax: CDXDUMP <Dateiname>"
       QUIT
   ENDIF

   handle := FOPEN(Cdx_file, 0)

   IF FERROR() != 0
       ? "Fehler beim ™ffnen der Datei ", FERROR()
       QUIT
   ENDIF

   stack_pointer := 1
   buffer  := SPACE(PAGE_SIZE)
   read    := FREAD(handle, @buffer, PAGE_SIZE)

   IF read <> PAGE_SIZE
       ? "Fehler beim Lesen des Headers"
       QUIT
   ENDIF

   SET ALTERNATE TO CDXDUMP.TXT
   SET ALTERNATE ON

*** File header (page 0) ***

   ? " 00 –  03 Pointer to root node        : ", BIN2L(SUBSTR(buffer,  1, LONG))
   root := BIN2L(SUBSTR(buffer, 1, LONG))

   ? " 04 –  07 Pointer to free node list   : ", BIN2L(SUBSTR(buffer,  5, LONG))
   // ( -1 if not present)
   //
   //     07 -1 if none (FoxPro)
   //         0 if none (FoxBase)
   ? "       07 Header type is              : ", IF(BIN2I(SUBSTR(buffer,  8, 1))=0,"FoxBase","FoxPro")


   ? " 08 –  11 Reserved for internal use   : ", BIN2L(SUBSTR(buffer,  9, LONG))

   key_size := BIN2W(SUBSTR(buffer, 13, UNSIGNED))
   ? " 12 –  13 Length of key               : ", BIN2W(SUBSTR(buffer, 13, UNSIGNED))

   ? " 14       Index options               : ", BIN2I(SUBSTR(buffer, 15, 1))
   // (any of the following numeric values or their sums):
   //   1 –     a unique index
   //   8 –     index has FOR clause
   //  32 –     compact index format
   //  64 –     compound index header

   ? " 15       Index signature             : ", BIN2I(SUBSTR(buffer, 16, 1))

   ? " 16 –  19 Reserved for internal use   : ", BIN2L(SUBSTR(buffer, 17, LONG))
   ? " 20 –  23 Reserved for internal use   : ", BIN2L(SUBSTR(buffer, 21, LONG))
   ? " 24 –  27 Reserved for internal use   : ", BIN2L(SUBSTR(buffer, 25, LONG))
   ? " 28 –  31 Reserved for internal use   : ", BIN2L(SUBSTR(buffer, 29, LONG))
   ? " 32 –  35 Reserved for internal use   : ", BIN2L(SUBSTR(buffer, 33, LONG))
   ? " 36 – 501 Reserved for internal use   : ", SUBSTR(buffer, 37, 465)

   ? "502 – 503 Ascending or descending     : ", BIN2W(SUBSTR(buffer,503, UNSIGNED))
   // 0    = ascending
   // 1    = descending

   ? "504 – 505 Reserved for internal use   : ", BIN2W(SUBSTR(buffer,505, UNSIGNED))
   ? "506 – 507 FOR expression pool length1 : ", BIN2W(SUBSTR(buffer,507, UNSIGNED))
   ? "508 – 509 Reserved for internal use   : ", BIN2W(SUBSTR(buffer,509, UNSIGNED))
   ? "510 – 511 Key expression pool length1 : ", BIN2W(SUBSTR(buffer,511, UNSIGNED))

   ? "512 – 1023 Key expression pool        : ", SUBSTR(buffer,513, 512)
   // (uncompiled)

ALTD()

   item_number := 1
   down := .T.
   DO WHILE .T.
       IF down .AND. root <> 0
           FSEEK(handle, root)
           read := FREAD(handle, @buffer, PAGE_SIZE)
           IF read <> PAGE_SIZE
               ? "Fehler beim Lesen der Page"+STR(read)
               ?? STR( FSEEK(handle, 0 , FS_RELATIVE) )
               QUIT
           ENDIF
           ? ""
           ? "1.) Position"
           ?? STR( FSEEK(handle, 0 , FS_RELATIVE) )
           ? "***********************"

           ? "00 –  01 Node attributes                     : ", BIN2W(SUBSTR(buffer,  1, UNSIGNED))
           // (any of the following numeric values or their sums):

           ? "02 –  03 Number of keys present              : ", BIN2W(SUBSTR(buffer,  3, UNSIGNED))
           // (0, 1 or many)

           ? "04 –  07 Pointer to the node left            : ", BIN2L(SUBSTR(buffer,  5, LONG))
           // directly to the left of current node (on same level; -1 if not present)

           ? "08 –  11 Pointer to the node right           : ", BIN2L(SUBSTR(buffer,  9, LONG))
           // directly to right of the current node (on same level; -1 if not present)

           ? "12 – 511 Index key value for the length      : ", BIN2L(SUBSTR(buffer, 13, 500))
           // Up to 500 characters containing the key value for the length of
           // the key with a four-byte hexadecimal number (stored in normal
           // left-to-right format):


           hByte := SUBSTR(buffer, 13, LONG)
           ? "12       hByte                               : ", hByte
           ? "         BIN2L( hByte )                      : ", BIN2L( hByte )

           hByte := SUBSTR(buffer, 13, LONG*2)
           ? "12       hByte*2                             : ", hByte
           ? "         BIN2L( hByte*2 )                    : ", BIN2L( hByte )

           ? "12       Key data                            : ", BIN2I(SUBSTR(hByte, 1, 1))
           ? "16       Record number in data file          : ", BIN2I(SUBSTR(hByte, 5, 1))
           ? "20       Pointer to child page               : ", BIN2I(SUBSTR(hByte, 8, 1))

           ? "         Index key value                     : ", SUBSTR(buffer, 13, 500)

           hByte := SUBSTR(buffer, 508+18, LONG)
           ? "   – 511 hByte                               : ", hByte
           ? "         BIN2L( hByte )                      : ", BIN2L( hByte )

           hByte := SUBSTR(buffer, 504+18, LONG*2)
           ? "   – 511 hByte*2                             : ", hByte
           ? "         BIN2L( hByte*2 )                    : ", BIN2L( hByte )

           ? "     504 Key data                            : ", BIN2I(SUBSTR(hByte, 1, 1))
           ? "     508 Record number in data file          : ", BIN2I(SUBSTR(hByte, 5, 1))
           ? "     511 Pointer to child page               : ", BIN2I(SUBSTR(hByte, 8, 1))


           // 00 –  01 Node attributes
           items         := BIN2W(SUBSTR(buffer, 1, UNSIGNED))
           item_number   := 1
           item_pointer  := UNSIGNED + 1
           ? ""
           ? "*        items                               : "+STR(items )
           ? "*        item_number                         : "+STR(item_number )
           ? "*        item_pointer                        : "+STR(item_pointer)

           // 02 –  03 Number of keys present
           item_at       := BIN2W(SUBSTR(buffer, item_pointer, LONG ))
           ? "*        item_at                             : "+STR(item_at )

           // 04 –  07 Pointer to the node directly to the left
           child_page    := BIN2W(SUBSTR(buffer, item_at+1, LONG))
           ? "*        child_page is                       : "+STR(child_page)

           stack_pointer := stack_pointer+LONG
           IF stack_pointer > STACK_SIZE
              ? "Programm-Stack-Overflow"+STR(stack_pointer)
              QUIT
           ENDIF

           stack[stack_pointer-4] := root
           stack[stack_pointer-3] := items
           stack[stack_pointer-2] := item_number
           stack[stack_pointer-1] := item_at
           root := child_page
           ? "*        root                                : "+STR(root        )

       ELSEIF item_number <= items

           ? ""
           ? "2.) Position"
           ?? STR( FSEEK(handle, 0 , FS_RELATIVE) )
           ? "***********************"

           ? "00 –  01 Node attributes                         : ", BIN2W(SUBSTR(buffer,  1, UNSIGNED))
           // (any of the following numeric values or their sums):

           ? "02 –  03 Number of keys present                  : ", BIN2W(SUBSTR(buffer,  3, UNSIGNED))
           // (0, 1 or many)

           ? "04 –  07 Pointer to the node directly to the left: ", BIN2L(SUBSTR(buffer,  5, LONG))
           // directly to the left of current node (on same level; -1 if not present)

           ? "08 –  11 Pointer to the node directly to right of: ", BIN2L(SUBSTR(buffer,  9, LONG))
           // directly to right of the current node (on same level; -1 if not present)

           ? "12 –  13 Available free space in node            : ", BIN2W(SUBSTR(buffer, 13, UNSIGNED))
           ? "14 –  17 Record number mask                      : ", BIN2L(SUBSTR(buffer, 15, LONG))
           ? "18       Duplicate byte count mask               : ", BIN2I(SUBSTR(buffer, 19, 1))
           ? "19       Trailing byte count mask                : ", BIN2I(SUBSTR(buffer, 20, 1))
           ? "20       Number of bits used for record number   : ", BIN2I(SUBSTR(buffer, 21, 1))
           ? "21       Number of bits used for duplicate count : ", BIN2I(SUBSTR(buffer, 22, 1))
           ? "22       Number of bits used for trail count     : ", BIN2I(SUBSTR(buffer, 23, 1))

           ? "23       Number of bytes holding record number   : ", BIN2I(SUBSTR(buffer, 24, 1))
           // duplicate count and trailing count

           ? "24       Recno/supCount/TrailCount               : ", BIN2I(SUBSTR(buffer, 25, 1))
           ? "28       Record number in data file              : ", BIN2I(SUBSTR(buffer, 29, 1))
           ? "31       Key data                                : ", BIN2I(SUBSTR(buffer, 32, 1))

           hByte := SUBSTR(buffer, 25, LONG)
           ? "         hByte                                   : ", hByte
           ? "         BIN2L( hByte )                          : ", BIN2L( hByte )

           ? "24 – 511 Index keys and information2             : ", BIN2L(SUBSTR(buffer, 25, (511-24) ))
           ? "         LEN()                                   : ", STR(LEN(SUBSTR(buffer, 25, (511-24) )))
           ? "         Index keys and information2             : ", SUBSTR(buffer, 25, (511-24) )

           LEN(SUBSTR(buffer, 25, (511-24) ))

           ? "     504 Recno/supCount/TrailCount               : ", BIN2I(SUBSTR(buffer,505, 1))
           ? "     508 Record number in data file              : ", BIN2I(SUBSTR(buffer,508, 1))
           ? "     511 Key data                                : ", BIN2I(SUBSTR(buffer,512, 1))
           hByte := SUBSTR(buffer,504, LONG)
           ? "         hByte                                   : ", hByte
           ? "         BIN2L( hByte )                          : ", BIN2L( hByte )

*           ? "2a.) Position"
*           ?? STR( FSEEK(handle, (25+511-24) , FS_RELATIVE) )
*           ? "***********************"
*           ? "2c.) Position"
*           ?? STR( FSEEK(handle, -512 , FS_RELATIVE) )
*           ? "***********************"

           //
           // dump out Element
           //
           ? BIN2L(SUBSTR(buffer, item_at+1+LONG,     LONG)),;
                   SUBSTR(buffer, item_at+  LONG2+5, key_size)


           item_number   := item_number + 1
           stack[stack_pointer-2] := item_number
           item_pointer  := (item_number-1) * 2 + 2 + 1
           ? ""
           ? "*        item_number                             : "+STR(item_number )
           ? "*        item_pointer                            : "+STR(item_pointer)

           // 02 –  03 Number of keys present (0, 1 or many)
           item_at       := BIN2W(SUBSTR(buffer, item_pointer, LONG))
           ? "*        item_at                                 : "+STR(item_at)

           // 04 –  07 Pointer to the node directly to the left of current
           //          node (on same level; -1 if not present)
           child_page    := BIN2W(SUBSTR(buffer, item_at+1, LONG))

           ? "*        child_page is                           : "+STR(child_page)

           stack[stack_pointer-1] := item_at
           stack[stack_pointer-3] := items
           root := child_page
           down := .T.

           ? "*        root                                    : "+STR(root        )

nZahl++

       ELSE
           stack_pointer := stack_pointer-LONG

           IF stack_pointer < 5
               EXIT
           ENDIF
           ? ""
           ? "3.) Position"
           ?? STR( FSEEK(handle, 0 , FS_RELATIVE) )
           ? "***********************"
           root        := stack[stack_pointer-4]
           items       := stack[stack_pointer-3]
           item_number := stack[stack_pointer-2]
           item_at     := stack[stack_pointer-1]
           down        := .F.
           FSEEK(handle, root)
           read := FREAD(handle, @buffer, PAGE_SIZE)
           IF read <> PAGE_SIZE
               ? "Fehler beim Lesen der Page"+STR(read)
               ?? STR( FSEEK(handle, 0 , FS_RELATIVE) )
               QUIT
           ENDIF
           ? "*        root                                        : "+STR(root        )
           ? "*        items                                       : "+STR(items       )
           ? "*        item_number                                 : "+STR(item_number )
           ? "*        item_at                                     : "+STR(item_at     )
       ENDIF
   ENDDO

   ?
   ?
   ? "Anzahl",nZahl
   ?

   SET ALTERNATE TO
   SET ALTERNATE OFF

RETURN NIL
wenn jemand "sieht" wo ich was falsch gemacht habe möge mir doch enen
Tip geben, ich "sehe" es einfach nicht wo ich noch einen Gedanken Fehler
habe.

gruss by OHR
Jimmy
Benutzeravatar
Martin Altmann
Foren-Administrator
Foren-Administrator
Beiträge: 16517
Registriert: Fr, 23. Sep 2005 4:58
Wohnort: Berlin
Hat sich bedankt: 111 Mal
Danksagung erhalten: 48 Mal
Kontaktdaten:

Beitrag von Martin Altmann »

Hallo Jimmy,
ich habe nicht viel Zeit - daher nur kurz:
Da Du meintest, Du hättest Probleme beim Umrechnen von Hex, hier eine Funktion, die ich nutze (Parameter ist ein String in Hex, also z.B. 2A9F) - meine Funktion geht sogar noch weiter - von 0-Z:

Code: Alles auswählen

function code2int( cWert )
local nErg, nI, nJ, nL, nA, lF, nF
local aMap := { { 10, "A" }, { 11, "B" }, { 12, "C" }, { 13, "D" }, { 14, "E" }, { 15, "F" },;
					{ 16, "G" }, { 17, "H" }, { 18, "I" }, { 19, "J" }, { 20, "K" }, { 21, "L" },;
					{ 22, "M" }, { 23, "N" }, { 24, "O" }, { 25, "P" }, { 26, "Q" }, { 27, "R" },;
					{ 28, "S" }, { 29, "T" }, { 30, "U" }, { 31, "V" }, { 32, "W" }, { 33, "X" },;
					{ 34, "Y" }, { 35, "Z" } }
lF := .f.
if ( len( cWert ) == 1 ) .and. ( alltrim( str( val( cWert ) ) ) == cWert )
	nErg := val( cWert )
else
	nErg := 0
	nL := Min( 10, len( cWert ) )
	nL := len( cWert )
	for nA := 1 to nL
		nI := 36^( nL - nA )
		nJ := 0
		if alltrim( str( val( substr( cWert, nA, 1 ) ) ) ) == substr( cWert, nA, 1 )
			nJ := val( substr( cWert, nA, 1 ) )
		else
			nF := ascan( aMap, { |a| a[ 2 ] == upper( substr( cWert, nA, 1 ) ) } )
			if nF > 0
				nJ := aMap[ nF, 1 ]
			else
				lF := .t.
			endif
		endif
		nErg += ( nI * nJ )
	next
endif
if lF
	nErg := 0
endif
return int( nErg )
Viele Grüße,
Martin
:grommit:
Webseite mit XB2.NET und ausschließlich statischem Content in Form von HTML-Dateien: https://www.altem.de/
Webseite mit XB2.NET und ausschließlich dynamischem Content in Form von in-memory-HTML: https://meldungen.altem.de/

Mitglied der XUG Osnabrück
Vorsitzender des Deutschsprachige Xbase-Entwickler e. V.
Antworten