ABS383A            ; Read the Data Dictionary and produce an M tree describing a FileMan file [ 12/05/1999  5:01 PM ]

            ; For CECS 383: The Science and Technology of the World Wide Web by Arthur B. Smith (754104)

       

MkTree(FileNum)         ; Construct the tree for the file with file number FileNum in ^ABS383(FileNum)

            ; This result global will have a physical structure corresponding to the logical structure of the

            ; data file, i.e., each depth of subfile is a separate subscript level in the result global.

            ;

            ; The first subscript of the result global is the file number.  Each subsequent subscript is a

            ; field number (hierarchically so that nested subfiles add additional field number subscripts).

            ;

            ; The data stored in each node is: FILE,FIELD^LABEL^TYPE^REQUIRED[^INDEX]

            ; where FILE,FIELD is the file and field numbers (uniquely identifies this entry)

            ; and LABEL is the field label

            ; and TYPE is the field type ("Short Text"|"Numeric"|POINTER|"Date"|"Set of Codes"|

            ;                                         "Computed"|"M Code"|"Variable Pointer"|"Unknown Type"|

            ;                                         "FILE"|"Multi-line Text")

            ;          where POINTER is "Pointer to " FileNum " (" FileName ")"

            ; and REQUIRED is the optionality ("Required"|"Optional") of the field

            ; and INDEX is a comma separated list of cross references on this field.

            ;

            ; The result global also contains a cross reference in ^ABS383("FNUM",FILE) (where

            ; FILE is the file number) which contains the root of the (sub)file in the result global.

            ;

            ; The result global also contains a cross reference in ^ABS383("XREF",SFF,FILE,XREF)

            ; where SFF is the (Sub)File Number, comma, Field Number of the cross-referenced field

            ; and FILE is the File Number where the cross reference is found (may be any ancestor of SFF)

            ; and XREF is the name (subscript) of the cross reference.

       

        Set U="^"

        Quit:'$$VFILE^DILFD(FileNum)  ; Make sure the file exists!

        Set ^ABS383(FileNum)=FileNum_U_$Order(^DD(FileNum,0,"NM",""))_U_"FILE"

            ; Recursively process this file and all subfiles

        Do SubTree(FileNum,"^ABS383("_FileNum_")") 

        Quit

       

SubTree(FNum,Root) ; Process all the fields in (sub)file FNum, adding them to the tree at Root

             ; NOTE: Root should already exist from a previous call or before the first call

             ; NOTE: This processes subfiles by recursive calls

         New Sub,Flags

         Set ^ABS383("FNUM",FNum)=Root  ; Add the cross reference so we can find subfiles!

         Set Sub=0

         For  Set Sub=$Order(^DD(FNum,Sub)) Quit:Sub=""  Quit:Sub]]"@"  Do

         . Set @Root@(Sub)=FNum_"z"_Sub_U_$Piece($Get(^DD(FNum,Sub,0)),U,1)

         . Set Flags=$Piece($Get(^DD(FNum,Sub,0)),U,2)

         . If $Piece($Piece($Get(^DD(FNum,Sub,0)),U,4),";",2)="0"  Do 

             . . ; This is a subfile or a word-processing field -- can't tell yet!

         . . New SubFile

         . . Set SubFile=+Flags ; This is the subfile number

         . . If $Piece($Get(^DD(SubFile,.01,0)),U,2)["W" Do  ; This is a word-processing field!

         . . . Set $Piece(@Root@(Sub),U,3)="Multi-line Text"

         . . Else  Do  ; This is a subfile!

         . . . Set $Piece(@Root@(Sub),U,3)="FILE"

         . . . Do SubTree(SubFile,$Name(@Root@(Sub)))  ; RECURSIVE CALL!

         . Else  Do  ; This is an ordinary (non-multiple) field

         . . Set $Piece(@Root@(Sub),U,3)=$Select(Flags["F":"Short Text",Flags["N":"Numeric",Flags["P":"Pointer",Flags["D":"Date",Flags["S":"Set of Codes",Flags["C":"Computed",Flags["K":"M Code",Flags["V":"Variable Pointer",1:"Unknown Type")

         . . If Flags?.E1"P"1.N0.1(1"."1.N).E Do  ; This is a pointer -- find out to what!

         . . . New Dest

         . . . Set Dest=+$Extract(Flags,$Find(Flags,"P"),$Length(Flags))

         . . . Set $Piece(@Root@(Sub),U,3)="Pointer to "_Dest

         . . . If $Data(^DD(Dest,0,"NM"))=10 Do

         . . . . Set $Piece(@Root@(Sub),U,3)="Pointer to "_Dest_" ("_$Order(^DD(Dest,0,"NM",""))_")"

             . . . ; This should (optionally?) DO MkTree^ABS383A(Dest) here... (or should that be Dest\1?)

         . Set $Piece(@Root@(Sub),U,4)=$Select(Flags["R":"Required",1:"Optional")

             ; Now catalog all the cross references

         New XRName,XFile,XField,XRoot

         Set XRName=""

         For  Set XRName=$Order(^DD(FNum,0,"IX",XRName)) Quit:XRName=""  Do

         . Set XFile=""

         . For  Set XFile=$Order(^DD(FNum,0,"IX",XRName,XFile)) Quit:XFile=""  Do

         . . Set XField=""

         . . For  Set XField=$Order(^DD(FNum,0,"IX",XRName,XFile,XField))  Quit:XField=""  Do

         . . . Set ^ABS383("XREF",XFile_","_XField,FNum,XRName)=""

         . . . Set XRoot=$Get(^ABS383("FNUM",XFile))

         . . . If $Length(XRoot) Do

         . . . . Set Existing=$Piece(@XRoot@(XField),U,5)

         . . . . If $Length(Existing) Set Existing=Existing_","

         . . . . Set $Piece(@XRoot@(XField),U,5)=Existing_XRName

         Quit