#include <exec/types.h>
#include <exec/memory.h>
#include <intuition/intuition.h>
#include <libraries/gadtools.h>
#include <dos/dosasl.h>
#include <dos/dosextens.h>
#include <libraries/asl.h>

#include <stdlib.h>
#include "amigan.h"

/* This module is quite large; it compiles to about 39K unoptimized.
   Mainly because it uses Printf(). */

#define AMIGA             0
#define MAC               1
#define IBM               2

MODULE void eolconvert(ABOOL gui);
MODULE void eachwildcard(STRPTR subpattern);
MODULE void updatedetabulate(void);

MODULE struct Gadget *MX71_Source         = NULL,
                     *TE71_SourceTitle    = NULL,
                     *MX71_Dest           = NULL,
                     *TE71_DestTitle      = NULL,
                     *ST71_Pathname       = NULL,
                     *BU71_PathnameASL    = NULL,
                     *CB71_Detabulate     = NULL,
                     *IN71_TabSize        = NULL;

// from rp.c
IMPORT ABOOL               fillwindows;
IMPORT SBYTE               page;
IMPORT SWORD               y;
IMPORT TEXT                asldir[VLONGFIELD + 1];
IMPORT ULONG               fillcolour;
IMPORT struct NewGadget*   Gadget;
IMPORT struct Gadget      *BU99_Left,
                          *BU99_Right,
                          *PrevGadPtr;
IMPORT struct Window*      MainWindowPtr;
IMPORT struct Screen*      ScreenPtr;
IMPORT struct SharedStruct shared;

MODULE ABOOL               stop;

AGLOBAL struct EOLStruct eol =
{   FALSE, IBM, AMIGA, 8, "", "", "", ""
};

// EOL/tab converter
MODULE  STRPTR EOLOptions[4] =
{   (STRPTR) "LF    (Amiga)",
    (STRPTR) "CR    (Macintosh)",
    (STRPTR) "LF+CR (IBM-PC)",
    NULL
};

AGLOBAL void eol1(void)
{   verynewwindow
    (   EOL1WIDTH, EOL1HEIGHT,
        "Report+: EOL/Tab Converter",
        BUTTONIDCMP | STRINGIDCMP | MXIDCMP
    );

    /* source title */
    setgadget(52, 44, 100, 12, "_Source:", PLACETEXT_ABOVE);
    TE71_SourceTitle = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* source format */
    setgadget(50, 50, 0, 0, NULL, PLACETEXT_RIGHT);
    MX71_Source = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
        PrevGadPtr,
        &Gadget,
        GTMX_Labels, &EOLOptions,
        GTMX_Active, eol.source,
        TAG_DONE
    );
    /* dest title */
    setgadget(422, 44, 100, 12, "_Destination:", PLACETEXT_ABOVE);
    TE71_DestTitle = PrevGadPtr = (struct Gadget *) CreateGadget
    (   TEXT_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* destination format */
    setgadget(400, 50, 0, 0, NULL, PLACETEXT_RIGHT);
    MX71_Dest = PrevGadPtr = (struct Gadget *) CreateGadget
    (   MX_KIND,
        PrevGadPtr,
        &Gadget,
        GTMX_Labels, &EOLOptions,
        GTMX_Active, eol.dest,
        TAG_DONE
    );

    /* pathname */
    setgadget(132, 88, 440, 12, "_Pathname(s):", NULL);
    ST71_Pathname = PrevGadPtr = (struct Gadget *) CreateGadget
    (   STRING_KIND,
        PrevGadPtr,
        &Gadget,
        GTST_String, &(eol.pathname),
        GTST_MaxChars, LONGESTFIELD,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* pathname... */
    setgadget(574, 88, 28, 12, "_...", NULL);
    BU71_PathnameASL = PrevGadPtr = (struct Gadget *) CreateGadget
    (   BUTTON_KIND,
        PrevGadPtr,
        &Gadget,
        GT_Underscore, '_',
        TAG_DONE
    );

    // 'convert tabs to spaces?'
    setgadget(294, 110, 0, 0, "C_onvert tabs to spaces?", NULL);
    CB71_Detabulate = PrevGadPtr = (struct Gadget *) CreateGadget
    (   CHECKBOX_KIND,
        PrevGadPtr,
        &Gadget,
        GTCB_Checked, eol.detabulate,
        GT_Underscore, '_',
        TAG_DONE
    );
    /* tab size */
    setgadget(408, 110, 32, 12, "_Tab size:", NULL);
    IN71_TabSize = PrevGadPtr = (struct Gadget *) CreateGadget
    (   INTEGER_KIND,
        PrevGadPtr,
        &Gadget,
        GTIN_Number, eol.tabsize,
        GTIN_MaxChars, 2,
        GA_TabCycle, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    /* There are 17 gadgets:
       BU99_Right       1
       BU99_Left        1
       TE71_SourceTitle 1
       MX71_Source      3
       TE71_DestTitle   1
       MX71_Dest        3
       ST71_Pathname    2
       BU71_PathnameASL 1
       CB71_Detabulate  2
       IN71_TabSize     2 */
    drawgadgets(17);

    ActivateGadget(ST71_Pathname, MainWindowPtr, NULL);
    if (eol.detabulate)
    {   GT_SetGadgetAttrs
        (   IN71_TabSize,
            MainWindowPtr, NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   IN71_TabSize,
            MainWindowPtr, NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
    }
    loop();
    strcpy
    (   eol.pathname,
        ((struct StringInfo *) ST71_Pathname->SpecialInfo)->Buffer
    );
    stcl_d
    (   eol.tabsize,
        ((struct StringInfo *) IN71_TabSize->SpecialInfo)->LongInt
    );
    closewindow();
}

AGLOBAL void eol2(void)
{   verynewwindow
    (   EOL2WIDTH, EOL2HEIGHT,
        "Report+: EOL/Tab Converter",
        BUTTONIDCMP | STRINGIDCMP
    );
    drawgadgets(2);

    GT_SetGadgetAttrs // the `stop' button
    (   BU99_Left,
        MainWindowPtr, NULL,
        GA_Disabled, FALSE,
        GT_Underscore, '_',
        TAG_DONE
    );
    GT_SetGadgetAttrs // the `menu' button
    (   BU99_Right,
        MainWindowPtr, NULL,
        GA_Disabled, TRUE,
        GT_Underscore, '_',
        TAG_DONE
    );

    eol_do(TRUE);
    y = 46;
    if (!stop)
    {   say("All done.", WHITE);
    }

    GT_SetGadgetAttrs // the `stop' button
    (   BU99_Left,
        MainWindowPtr, NULL,
        GA_Disabled, TRUE,
        TAG_DONE
    );
    GT_SetGadgetAttrs // the `next' button
    (   BU99_Right,
        MainWindowPtr,
        NULL,
        GA_Disabled, FALSE,
        TAG_DONE
    );

    loop();
    closewindow();
}

MODULE void eolconvert(ABOOL gui)
{   ULONG                gap, i, j, cursorx   = 0;
    struct FileInfoBlock InputInfoBlock;
    UBYTE*               InputBufferPtr;
    /* APTRs cause trouble when you try to use maths on them. */
    BPTR                 FileHandle;
    TEXT                 temp[LONGFIELD + 1];
    ABOOL                ok                   = FALSE;
    struct Gadget*       addr;
    struct IntuiMessage* MsgPtr;
    ULONG                class, signals;

    strcpy(temp, "Converting ");
    strcat(temp, eol.thisfile);
    strcat(temp, "...");
    if (gui)
    {   getfillcolour();
        SetAPen(MainWindowPtr->RPort, fillcolour);
        RectFill(MainWindowPtr->RPort, 8, 22, EOL2WIDTH - 8, 32); /* clear the text area */
        y = 30;
        say(temp, WHITE);
    } else
    {   Printf("%s", temp);
        Flush(Output());
    }

    if (FileHandle = (BPTR) Lock(eol.thisfile, ACCESS_READ))
    {   if (Examine(FileHandle, &InputInfoBlock))
        {   UnLock(FileHandle);
            // FileHandle = NULL;
            if (InputInfoBlock.fib_DirEntryType == -3) // if a file
            {   // if it is a directory, we would ideally like to convert all
                // files in that directory. We also should support links.
                if (InputBufferPtr = AllocMem(InputInfoBlock.fib_Size, MEMF_ANY | MEMF_PUBLIC))
                {   if (FileHandle = (BPTR) Open(eol.thisfile, MODE_OLDFILE))
                    {   if (Read(FileHandle, InputBufferPtr, InputInfoBlock.fib_Size) != -1)
                        {   Close(FileHandle);
                            if (FileHandle = (BPTR) Open(eol.thisfile, MODE_NEWFILE))
                            {   for (i = 0; i < InputInfoBlock.fib_Size; i++)
                                {   if (*(InputBufferPtr + i) == LF)
                                    {   cursorx = 0;
                                        if (eol.source == eol.dest)
                                            FPutC(FileHandle, LF); // pass it through
                                        elif (eol.source == AMIGA && eol.dest == IBM)
                                        {   FPutC(FileHandle, CR); // add this
                                            FPutC(FileHandle, LF); // and pass this through
                                        } elif (eol.source == AMIGA && eol.dest == MAC)
                                            FPutC(FileHandle, CR); // convert from LF to CR
                                        elif (eol.source == IBM && eol.dest == AMIGA)
                                            FPutC(FileHandle, LF); // pass it through
                                        elif (eol.source == IBM && eol.dest == MAC)
                                            ; // do nothing
                                        else ; // mac as source: we never expect LFs
                                    } elif (*(InputBufferPtr + i) == CR)
                                    {   cursorx = 0;
                                        if (eol.source == eol.dest)
                                            FPutC(FileHandle, CR); // pass it through
                                        elif (eol.source == IBM && eol.dest == AMIGA)
                                            ; // do nothing
                                        elif (eol.source == IBM && eol.dest == MAC)
                                            FPutC(FileHandle, CR); // pass it through
                                        elif (eol.source == MAC && eol.dest == AMIGA)
                                            FPutC(FileHandle, LF); // convert from CR to LF
                                        elif (eol.source == MAC && eol.dest == IBM)
                                        {   FPutC(FileHandle, CR); // pass this through
                                            FPutC(FileHandle, LF); // and add this
                                        } else ; // amiga as source: we never expect CRs
                                    } elif (*(InputBufferPtr + i) == TAB)
                                    {   if (eol.detabulate)
                                        {   gap = (((cursorx / eol.tabsize) + 1) * eol.tabsize) - cursorx;
                                            for (j = 1; j <= gap; j++)
                                                FPutC(FileHandle, ' ');
                                            cursorx += gap;
                                        } else FPutC(FileHandle, TAB); // no point to cursorx in non-detabulate
                                    } else
                                    {   FPutC(FileHandle, *(InputBufferPtr + i));
                                        cursorx++;
                                }   }
                                /* Note that FPutC() returns EOF for errors; this is not currently
                                checked. */
                                ok = TRUE;
                                Close(FileHandle);
                        }   }
                        else
                        {   Close(FileHandle);
                    }   }
                    FreeMem(InputBufferPtr, InputInfoBlock.fib_Size);
        }   }   }
        else
        {   UnLock(FileHandle);
    }   }

    if (gui)
    {   getfillcolour();
        SetAPen(MainWindowPtr->RPort, fillcolour);
        RectFill(MainWindowPtr->RPort, 8, 22, EOL2WIDTH - 8, 32); /* clear the text area */
        if (ok)
            strcat(temp, "done.");
        else strcat(temp, "failed!");
        y = 30;
        say(temp, WHITE);
    } else
    {   if (ok)
            Printf("done.\n");
        else Printf("failed!\n");
    }

    signals = SetSignal(0L, 0L);
    if (signals & SIGBREAKF_CTRL_C)
    {   stop = TRUE;
        SetSignal(0L, SIGBREAKF_CTRL_C); // clear the Ctrl-C signal
        strcpy(temp, "Aborted by user!");
        if (gui)
        {   say(temp, WHITE);
        } else
        {   Printf("%s\n", temp);
            Flush(Output());
    }   }

    while (MsgPtr = (struct IntuiMessage *) GT_GetIMsg(MainWindowPtr->UserPort))
    {   class  = MsgPtr->Class;                       
        addr   = MsgPtr->IAddress;
        GT_ReplyIMsg(MsgPtr);
        switch(class)
        {
        case IDCMP_CLOSEWINDOW:
            cleanexit(EXIT_SUCCESS);
        break;
        case IDCMP_GADGETUP:
            if (addr == BU99_Left)
            {   strcpy(temp, "Aborted by user!");
                say(temp, WHITE);
                stop = TRUE;
            }
        break;
        default:
        break;
}   }   }

AGLOBAL void eolasl(void)
{   struct FileRequester* ASLRqPtr;
    ULONG                 i;
    TEXT                  quotestring[2];

    quotestring[0] = QUOTE;
    quotestring[1] = 0;

    /* It would also be good to correctly
    handle selection of directories. */

    if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, "~(#?.info)", ASL_Window, MainWindowPtr, TAG_DONE)))
        rq("Can't create ASL request!");
    if (AslRequestTags(ASLRqPtr, ASL_Dir, asldir, ASL_Hail, "Report+ file multiselector", ASL_FuncFlags, FILF_PATGAD | FILF_MULTISELECT, TAG_DONE) && *(ASLRqPtr->rf_File) != 0)
    {   if (ASLRqPtr->rf_NumArgs)
        {   /* rf_ArgList is an array of WBArg structures. Each entry in
            this array corresponds to one of the files the user selected
            (in alphabetical order). The user multiselected; step through
            the list of selected files. */

            strcpy(asldir, ASLRqPtr->rf_Dir);
            strcpy(eol.pathname, quotestring);
            strcat(eol.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(eol.pathname, (ASLRqPtr->rf_ArgList)[0].wa_Name, VLONGFIELD))
                rq("Can't add filename to pathname!");
            strcat(eol.pathname, quotestring);
            strcat(eol.pathname, " ");
            for (i = 1; i < ASLRqPtr->rf_NumArgs; i++)
            {   strcat(eol.pathname, quotestring);
                strcat(eol.pathname, ASLRqPtr->rf_Dir);
                if (!AddPart(eol.pathname, (ASLRqPtr->rf_ArgList)[i].wa_Name, VLONGFIELD))
                   rq("Can't add filename to pathname!");
                strcat(eol.pathname, quotestring);
                if (i < ASLRqPtr->rf_NumArgs - 1)
                    strcat(eol.pathname, " ");
        }   }
        else
        {   /* The user didn't multiselect; use the normal way to get the
            filename. */

            strcpy(eol.pathname, quotestring);
            strcat(eol.pathname, ASLRqPtr->rf_Dir);
            if (!AddPart(eol.pathname, ASLRqPtr->rf_File, VLONGFIELD))
                rq("Can't add filename to pathname!");
            strcat(eol.pathname, quotestring);
    }   }
    if (ASLRqPtr)
        FreeAslRequest(ASLRqPtr);
}

void eol_do(ABOOL gui)
{   ABOOL flag = FALSE, quoted = FALSE;
    ULONG i, j = 0;

    /* At this point we have a list of pathnames, separated by spaces and
    NULL-terminated. If they came from ASL, they will be quoted, otherwise,
    they may not. We need to parse this. flag is a boolean value
    representing whether or not we have at least part of a pathname in
    construction; ie. it's to prevent problems from adjacent spaces. */

    if (!gui)
    {   eol.source     = IBM;
        eol.dest       = AMIGA;
        eol.detabulate = FALSE;
    }
    stop = FALSE;

    /* Names which match more than one of the wildcards are processed
    twice (or more). This is unnecessary. */

    wildcard(eol.pathname);
    for (i = 0; i <= strlen(eol.finallist); i++)
    {   if (eol.finallist[i] == 0)
        {   if (flag && !quoted)
            {   // if we're in the middle of an unquoted name
                {   eol.thisfile[j] = 0; // then it is ended
                    eolconvert(gui);
                    j = 0;
                    flag = FALSE;
        }   }   }
        elif (eol.finallist[i] == ' ' && (flag && !quoted))
        {   // if we're in the middle of an unquoted name
            {   eol.thisfile[j] = 0; // then it is ended
                eolconvert(gui);
                j = 0;
                flag = FALSE;
        }   }
        elif (eol.finallist[i] == QUOTE)
        {   if (!flag && !quoted)
            {   flag = TRUE; /* we've started on a name. */
                quoted = TRUE;
            } elif (flag && quoted)
                quoted = FALSE;
        } else
        {   eol.thisfile[j++] = eol.finallist[i];
            flag = TRUE;
        }
        if (stop)
        {   break;
}   }   }

AGLOBAL void eol_loop(ULONG class, struct Gadget* addr, UWORD code, UWORD qual)
{   if (page == 71)
    {   if (class == IDCMP_VANILLAKEY)
        {   code = toupper(code);
            if (code == 'S')
            {   if (!(qual & IEQUALIFIER_LSHIFT) && !(qual & IEQUALIFIER_RSHIFT))
                {   if (eol.source < 2)
                        eol.source++;
                    else eol.source = 0;
                } else
                {   if (eol.source > 0)
                        eol.source--;
                    else eol.source = 2;
                }
                GT_SetGadgetAttrs
                (   MX71_Source,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, eol.source,
                    TAG_DONE
                );
            } elif (code == 'D')
            {   if (!(qual & IEQUALIFIER_LSHIFT) && !(qual & IEQUALIFIER_RSHIFT))
                {   if (eol.dest < 2)
                        eol.dest++;
                    else eol.dest = 0;
                } else
                {   if (eol.dest > 0)
                        eol.dest--;
                    else eol.dest = 2;
                }
                GT_SetGadgetAttrs
                (   MX71_Dest,
                    MainWindowPtr,
                    NULL,
                    GTMX_Active, eol.dest,
                    TAG_DONE
                );
            } elif (code == 'O')
            {   if (CB71_Detabulate->Flags & GFLG_SELECTED)
                {   eol.detabulate = FALSE;
                } else eol.detabulate = TRUE;
                updatedetabulate();
            } elif (code == 'T')
            {   ActivateGadget(IN71_TabSize, MainWindowPtr, NULL);
            } elif (code == 'C')
            {   page = 72;
            } elif (code == 'P')
            {   ActivateGadget(ST71_Pathname, MainWindowPtr, NULL);
            } elif (code == ESCAPE)
            {   page = 0;
            } elif (code == '.')
            {   eolasl();
                GT_SetGadgetAttrs
                (   ST71_Pathname,
                    MainWindowPtr,
                    NULL,
                    GTST_String, eol.pathname,
                    TAG_DONE
                );
        }   }
        elif (class == IDCMP_GADGETDOWN)
        {   // radio gadgets
            if (addr == MX71_Source)
                eol.source = code;
            elif (addr == MX71_Dest)
                eol.dest = code;
        } elif (class == IDCMP_GADGETUP)
        {   // button, etc. gadgets
            if (addr == BU99_Left)
                page = 0;
            elif (addr == BU99_Right)
                page = 72;
            elif (addr == BU71_PathnameASL)
            {   eolasl();
                GT_SetGadgetAttrs
                (   ST71_Pathname,
                    MainWindowPtr,
                    NULL,
                    GTST_String, eol.pathname,
                    TAG_DONE
                );
            } elif (addr == CB71_Detabulate)
            {   if (CB71_Detabulate->Flags & GFLG_SELECTED)
                {   eol.detabulate = TRUE;
                } else eol.detabulate = FALSE;
                updatedetabulate();
    }   }   }
    else
    {   // assert(page == 72);
        if (class == IDCMP_GADGETUP)
        {   if (addr == BU99_Right)
                page = 0;
        } elif (class == IDCMP_VANILLAKEY)
        {   if (code == ESCAPE)
                page = 0;
}   }   }

MODULE void updatedetabulate(void)
{   GT_SetGadgetAttrs
    (   CB71_Detabulate,
        MainWindowPtr, NULL,
        GTCB_Checked, eol.detabulate,
        TAG_DONE
    );
    if (eol.detabulate)
    {   GT_SetGadgetAttrs
        (   IN71_TabSize,
            MainWindowPtr, NULL,
            GA_Disabled, FALSE,
            TAG_DONE
        );
    } else
    {   GT_SetGadgetAttrs
        (   IN71_TabSize,
            MainWindowPtr, NULL,
            GA_Disabled, TRUE,
            TAG_DONE
        );
}   }

AGLOBAL void wildcard(STRPTR pattern)
{   ULONG i, j = 0;
    ABOOL flag = FALSE, quoted = FALSE;

    eol.finallist[0] = 0;

    for (i = 0; i <= strlen(eol.pathname); i++)
    {   if (eol.pathname[i] == 0)
        {   if (flag && !quoted)
            {   // if we're in the middle of an unquoted name
                {   eol.thatfile[j] = 0; // then it is hereby ended
                    eachwildcard(eol.thatfile);
                    j = 0;
                    flag = FALSE;
        }   }   }
        elif (eol.pathname[i] == ' ' && flag && !quoted)
        {   // if we're in the middle of an unquoted name
            {   eol.thatfile[j] = 0; // then it is ended
                eachwildcard(eol.thatfile);
                j = 0;
                flag = FALSE;
        }   }
        elif (eol.pathname[i] == QUOTE)
        {   if (!flag && !quoted)
            {   flag = TRUE; /* we've started on a name. */
                quoted = TRUE;
            } elif (flag && quoted)
                quoted = FALSE;
        } else
        {   eol.thatfile[j++] = eol.pathname[i];
            flag = TRUE;
}   }   }

MODULE void eachwildcard(STRPTR subpattern)
{   struct AnchorPath* AnchorPathPtr;
    BPTR               OldDir;
    TEXT               dirbuffer[VLONGFIELD + 1];
    BOOL               result;
    ABOOL              done;

    dirbuffer[0] = NULL;
    if (!(AnchorPathPtr = AllocMem(sizeof(struct AnchorPath), MEMF_ANY | MEMF_PUBLIC)))
        return;

    AnchorPathPtr->ap_BreakBits = NULL;
    AnchorPathPtr->ap_Flags = NULL;
    AnchorPathPtr->ap_Strlen = 0;
    result = MatchFirst(subpattern, AnchorPathPtr);
    if (result == 0)
    {   OldDir = CurrentDir(AnchorPathPtr->ap_Current->an_Lock);
        if (!NameFromLock(AnchorPathPtr->ap_Current->an_Lock, dirbuffer, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        if (!AddPart(dirbuffer, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
        {   MatchEnd(AnchorPathPtr);
            return;
        }
        CurrentDir(OldDir);
        strcat(eol.finallist, "\"");
        strcat(eol.finallist, dirbuffer);
        strcat(eol.finallist, "\" ");
    } elif (result != ERROR_NO_MORE_ENTRIES)
    {   MatchEnd(AnchorPathPtr);
        return;
    }

    done = FALSE;
    while (!done)
    {   result = MatchNext(AnchorPathPtr);
        if (result == 0)
        {   OldDir = CurrentDir(AnchorPathPtr->ap_Current->an_Lock);
            if (!NameFromLock(AnchorPathPtr->ap_Current->an_Lock, dirbuffer, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            if (!AddPart(dirbuffer, AnchorPathPtr->ap_Info.fib_FileName, VLONGFIELD))
            {   MatchEnd(AnchorPathPtr);
                return;
            }
            CurrentDir(OldDir);
            strcat(eol.finallist, "\"");
            strcat(eol.finallist, dirbuffer);
            strcat(eol.finallist, "\" ");
        } elif (result != ERROR_NO_MORE_ENTRIES)
        {   MatchEnd(AnchorPathPtr);
            return;
        } else done = TRUE;
    }
    MatchEnd(AnchorPathPtr);
    FreeMem(AnchorPathPtr, sizeof(struct AnchorPath));
}
