Bool DirNew(CDrive *drive, U8 *cur_dir, CDirEntry *tmpde, Bool free_old_chain=TRUE)
{//Makes a directory entry in the directory from a CDirEntry node.
        switch (drive->fs_type)
        {
                case FSt_REDSEA:
                        return RedSeaDirNew(drive, cur_dir, tmpde, free_old_chain);

                case FSt_FAT32:
                        return FAT32DirNew(drive, cur_dir, tmpde, free_old_chain);

                default:
                        PrintErr("File System Not Supported\n");
                        return FALSE;
        }
}

U0 DirEntryDel(CDirEntry *tmpde)
{//Free node returned from FilesFind().  Doesn't Free user_data.
//Does not change the directory on disk.
        if (tmpde)
        {
                Free(tmpde->full_name);
                Free(tmpde);
        }
}

U0 DirEntryDel2(CDirEntry *tmpde)
{//Free node returned from FilesFind().  Frees user_data
//Does not change the directory on disk.
        if (tmpde)
        {
                Free(tmpde->full_name);
                Free(tmpde->user_data);
                Free(tmpde);
        }
}

U0 DirTreeDel(CDirEntry *tmpde)
{//Free tree returned from FilesFind().  Doesn't Free user_data.
//Does not change the directory on disk.
        CDirEntry *tmpde2;

        while (tmpde)
        {
                tmpde2 = tmpde->next;
                if (tmpde->sub)
                        DirTreeDel(tmpde->sub);
                DirEntryDel(tmpde);
                tmpde = tmpde2;
        }
}

U0 DirTreeDel2(CDirEntry *tmpde)
{//Free tree returned from FilesFind().  Frees user_data
//Does not change the directory on disk.
        CDirEntry *tmpde2;

        while (tmpde)
        {
                tmpde2 = tmpde->next;
                if (tmpde->sub)
                        DirTreeDel2(tmpde->sub);
                DirEntryDel2(tmpde);
                tmpde = tmpde2;
        }
}

I64 DirEntryCompareName(CDirEntry *e1, CDirEntry *e2)
{
        U8  buf1[CDIR_FILENAME_LEN], buf2[CDIR_FILENAME_LEN], buf3[CDIR_FILENAME_LEN], buf4[CDIR_FILENAME_LEN];
        I64 d1 = 0, d2 = 0;

        if (e1->attr & RS_ATTR_DIR)
                d1 = 1;
        if (e2->attr & RS_ATTR_DIR)
                d2 = 1;
        if (d1 != d2)
                return d2-d1;
        else
        {
                StrCopy(buf1, e1->name);
                StrCopy(buf2, e2->name);
                FileExtRemove(buf1, buf3);
                FileExtRemove(buf2, buf4);
                if (d1 = StrCompare(buf3, buf4))
                        return d1;
                return StrCompare(buf1, buf2);
        }
}

I64 DirEntryCompareClus(CDirEntry *e1, CDirEntry *e2)
{
        return e1->clus - e2->clus;
}

#define SK_NAME 0
#define SK_CLUS 1

U0 DirFilesSort(CDirEntry **_tmpde, I64 key)
{
        I64                      i, count;
        CDirEntry       *tmpde = *_tmpde, *tmpde1, **sort_buf;

        if (tmpde)
        {
                count = LinkedListCount(tmpde);
                if (count > 1)
                {
                        sort_buf = MAlloc(count * sizeof(U8 *));
                        i = 0;
                        tmpde1 = tmpde;
                        while (tmpde1)
                        {
                                sort_buf[i++] = tmpde1;
                                tmpde1 = tmpde1->next;
                        }
                        switch [key]
                        {
                                case SK_NAME:
                                        QuickSortI64(sort_buf, count, &DirEntryCompareName);
                                        break;

                                case SK_CLUS:
                                        QuickSortI64(sort_buf, count, &DirEntryCompareClus);
                                        break;
                        }
                        tmpde = sort_buf[0];
                        *_tmpde = tmpde;
                        for (i = 0; i < count - 1; i++)
                        {
                                tmpde1 = sort_buf[i];
                                tmpde1->next = sort_buf[i + 1];
                        }
                        tmpde1 = sort_buf[i];
                        tmpde1->next = NULL;
                        Free(sort_buf);

                        tmpde1 = tmpde;
                        while (tmpde1)
                        {
                                if (tmpde1->sub)
                                        DirFilesSort(&tmpde1->sub, key);
                                tmpde1 = tmpde1->next;
                        }
                }
                else
                        if (tmpde->sub)
                                DirFilesSort(&tmpde->sub, key);
        }
}

CDirEntry *DirFilesFlatten(CDirEntry *tmpde, CDirEntry **_res, I64 fuf_flags)
{//Returns last node
        CDirEntry       *tmpde1;
        Bool             del;

        if (tmpde)
                while (TRUE)
                {
                        tmpde1 = tmpde->next;
                        if (!(tmpde->attr & RS_ATTR_DIR) || !(fuf_flags & FUF_JUST_FILES))
                        {
                                _res = *_res = tmpde;
                                del = FALSE;
                        }
                        else
                                del = TRUE;
                        if (tmpde->sub)
                        {
                                _res = DirFilesFlatten(tmpde->sub, _res, fuf_flags);
                                tmpde->sub = NULL;
                        }
                        if (del)
                                DirEntryDel(tmpde);
                        if (tmpde1)
                                tmpde = tmpde1;
                        else
                                break;
                }
        *_res = NULL;
        return _res;
}

U0 PutFileLink(U8 *filename, U8 *full_name=NULL, I64 line=0, Bool plain_text=FALSE)
{//Put DolDoc file,line link to StdOut, DocPut.
        U8 *st;

        if (!filename)
                return;
        if (IsRaw)
        {
                if (line)
                        "%s,%04d", filename, line;
                else
                        "%s", filename;
        }
        else
        {
//LK_DOC,LK_DOC_ANCHOR,LK_DOC_FIND,LK_DOC_LINE
                if (filename[0] == 'A'&&filename[2] == ':')
                {
                        if (line) //See SpriteEdText()
                                "$LK,\"%s,%04d\",A=\"AL:%s,%d\"$", filename + 3, line, filename + 3, line;
                        else
                                "$LK,\"%s\",A=\"AI:%s\"$", filename + 3, filename + 3;
                }
                else
                {
                        if (!full_name)
                                full_name = st = FileNameAbs(filename);
                        else
                                st = NULL;
                        if (plain_text)
                        {
                                if (line)
                                        "$LK,\"%s,%04d\",A=\"PL:%s,%d\"$", filename, line, full_name, line;
                                else
                                        "$LK,\"%s\",A=\"PI:%s\"$", filename, full_name;
                        }
                        else
                        {
                                if (line)
                                        "$LK,\"%s,%04d\",A=\"FL:%s,%d\"$", filename, line, full_name, line;
                                else
                                        "$LK,\"%s\",A=\"FI:%s\"$", filename, full_name;
                        }
                        Free(st);
                }
        }
}

U0 PutDirLink(U8 *dirname, U8 *full_name=NULL)
{//Put DolDoc dir macro to StdOut, DocPut.
        U8 *st;

        if (!dirname)
                return;
        if (IsRaw)
                "%s", dirname;
        else
        {
                if (!full_name)
                        full_name = st = DirNameAbs(dirname);
                else
                        st = NULL;
                "$MA,T=\"%s\",LM=\"Cd(\\\"%s\\\");Dir;\n\"$", dirname, full_name;
                Free(st);
        }
}