Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/security/nss/cmd/signtool/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 56 kB image not shown  

Quelle  javascript.c   Sprache: C

 
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "signtool.h"
#include <prmem.h>
#include <prio.h>
#include <prenv.h>

static int javascript_fn(char *relpath, char *basedir, char *reldir,
                         char *filename, void *arg);
static int extract_js(char *filename);
static int copyinto(char *from, char *to);
static PRStatus ensureExists(char *base, char *path);
static int make_dirs(char *path, PRInt32 file_perms);

static char *jartree = NULL;
static int idOrdinal;
static PRBool dumpParse = PR_FALSE;

static char *event_handlers[] = {
    "onAbort",
    "onBlur",
    "onChange",
    "onClick",
    "onDblClick",
    "onDragDrop",
    "onError",
    "onFocus",
    "onKeyDown",
    "onKeyPress",
    "onKeyUp",
    "onLoad",
    "onMouseDown",
    "onMouseMove",
    "onMouseOut",
    "onMouseOver",
    "onMouseUp",
    "onMove",
    "onReset",
    "onResize",
    "onSelect",
    "onSubmit",
    "onUnload"
};

static int num_handlers = 23;

/*
 *  I n l i n e J a v a S c r i p t
 *
 *  Javascript signing. Instead of passing an archive to signtool,
 *  a directory containing html files is given. Archives are created
 *  from the archive= and src= tag attributes inside the html,
 *  as appropriate. Then the archives are signed.
 *
 */

int
InlineJavaScript(char *dir, PRBool recurse)
{
    jartree = dir;
    if (verbosity >= 0) {
        PR_fprintf(outputFD, "\nGenerating inline signatures from HTML files in: %s\n",
                   dir);
    }
    if (PR_GetEnvSecure("SIGNTOOL_DUMP_PARSE")) {
        dumpParse = PR_TRUE;
    }

    return foreach (dir, "", javascript_fn, recurse, PR_FALSE /*include dirs*/,
                    (void *)NULL);
}

/************************************************************************
 *
 * j a v a s c r i p t _ f n
 */

static int
javascript_fn(char *relpath, char *basedir, char *reldir, char *filename, void *arg)
{
    char fullname[FNSIZE];

    /* only process inline scripts from .htm, .html, and .shtml*/

    if (!(PL_strcaserstr(filename, ".htm") == filename + strlen(filename) - 4) &&
        !(PL_strcaserstr(filename, ".html") == filename + strlen(filename) - 5) &&
        !(PL_strcaserstr(filename, ".shtml") == filename + strlen(filename) - 6)) {
        return 0;
    }

    /* don't process scripts that signtool has already
     extracted (those that are inside .arc directories) */


    if (PL_strcaserstr(filename, ".arc") == filename + strlen(filename) - 4)
        return 0;

    if (verbosity >= 0) {
        PR_fprintf(outputFD, "Processing HTML file: %s\n", relpath);
    }

    /* reset firstArchive at top of each HTML file */

    /* skip directories that contain extracted scripts */

    if (PL_strcaserstr(reldir, ".arc") == reldir + strlen(reldir) - 4)
        return 0;

    snprintf(fullname, sizeof(fullname), "%s/%s", basedir, relpath);
    return extract_js(fullname);
}

/*===========================================================================
 =
 = D A T A   S T R U C T U R E S
 =
*/

typedef enum {
    TEXT_HTML_STATE = 0,
    SCRIPT_HTML_STATE
}

HTML_STATE;

typedef enum {
    /* we start in the start state */
    START_STATE,

    /* We are looking for or reading in an attribute */
    GET_ATT_STATE,

    /* We're burning ws before finding an attribute */
    PRE_ATT_WS_STATE,

    /* We're burning ws after an attribute.  Looking for an '='. */
    POST_ATT_WS_STATE,

    /* We're burning ws after an '=', waiting for a value */
    PRE_VAL_WS_STATE,

    /* We're reading in a value */
    GET_VALUE_STATE,

    /* We're reading in a value that's inside quotes */
    GET_QUOTED_VAL_STATE,

    /* We've encountered the closing '>' */
    DONE_STATE,

    /* Error state */
    ERR_STATE
}

TAG_STATE;

typedef struct AVPair_Str {
    char *attribute;
    char *value;
    unsigned int valueLine; /* the line that the value ends on */
    struct AVPair_Str *next;
} AVPair;

typedef enum {
    APPLET_TAG,
    SCRIPT_TAG,
    LINK_TAG,
    STYLE_TAG,
    COMMENT_TAG,
    OTHER_TAG
}

TAG_TYPE;

typedef struct {
    TAG_TYPE type;
    AVPair *attList;
    AVPair *attListTail;
    char *text;
} TagItem;

typedef enum {
    TAG_ITEM,
    TEXT_ITEM
}

ITEM_TYPE;

typedef struct HTMLItem_Str {
    unsigned int startLine;
    unsigned int endLine;
    ITEM_TYPE type;
    union {
        TagItem *tag;
        char *text;
    } item;
    struct HTMLItem_Str *next;
} HTMLItem;

typedef struct {
    PRFileDesc *fd;
    PRInt32 curIndex;
    PRBool IsEOF;
#define FILE_BUFFER_BUFSIZE 512
    char buf[FILE_BUFFER_BUFSIZE];
    PRInt32 startOffset;
    PRInt32 maxIndex;
    unsigned int lineNum;
} FileBuffer;

/*===========================================================================
 =
 = F U N C T I O N S
 =
*/

static HTMLItem *CreateTextItem(char *text, unsigned int startline,
                                unsigned int endline);
static HTMLItem *CreateTagItem(TagItem *ti, unsigned int startline,
                               unsigned int endline);
static TagItem *ProcessTag(FileBuffer *fb, char **errStr);
static void DestroyHTMLItem(HTMLItem *item);
static void DestroyTagItem(TagItem *ti);
static TAG_TYPE GetTagType(char *att);
static FileBuffer *FB_Create(PRFileDesc *fd);
static int FB_GetChar(FileBuffer *fb);
static PRInt32 FB_GetPointer(FileBuffer *fb);
static PRInt32 FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end,
                           char **buf);
static unsigned int FB_GetLineNum(FileBuffer *fb);
static void FB_Destroy(FileBuffer *fb);
static void PrintTagItem(PRFileDesc *fd, TagItem *ti);
static void PrintHTMLStream(PRFileDesc *fd, HTMLItem *head);

/************************************************************************
 *
 * C r e a t e T e x t I t e m
 */

static HTMLItem *
CreateTextItem(char *text, unsigned int startline, unsigned int endline)
{
    HTMLItem *item;

    item = PR_Malloc(sizeof(HTMLItem));
    if (!item) {
        return NULL;
    }

    item->type = TEXT_ITEM;
    item->item.text = text;
    item->next = NULL;
    item->startLine = startline;
    item->endLine = endline;

    return item;
}

/************************************************************************
 *
 * C r e a t e T a g I t e m
 */

static HTMLItem *
CreateTagItem(TagItem *ti, unsigned int startline, unsigned int endline)
{
    HTMLItem *item;

    item = PR_Malloc(sizeof(HTMLItem));
    if (!item) {
        return NULL;
    }

    item->type = TAG_ITEM;
    item->item.tag = ti;
    item->next = NULL;
    item->startLine = startline;
    item->endLine = endline;

    return item;
}

static PRBool
isAttChar(int c)
{
    return (isalnum(c) || c == '/' || c == '-');
}

/************************************************************************
 *
 * P r o c e s s T a g
 */

static TagItem *
ProcessTag(FileBuffer *fb, char **errStr)
{
    TAG_STATE state;
    PRInt32 startText, startID, curPos;
    PRBool firstAtt;
    int curchar;
    TagItem *ti = NULL;
    AVPair *curPair = NULL;
    char quotechar = '\0';
    unsigned int linenum;
    unsigned int startline;

    state = START_STATE;

    startID = FB_GetPointer(fb);
    startText = startID;
    firstAtt = PR_TRUE;

    ti = (TagItem *)PR_Malloc(sizeof(TagItem));
    if (!ti)
        out_of_memory();
    ti->type = OTHER_TAG;
    ti->attList = NULL;
    ti->attListTail = NULL;
    ti->text = NULL;

    startline = FB_GetLineNum(fb);

    while (state != DONE_STATE && state != ERR_STATE) {
        linenum = FB_GetLineNum(fb);
        curchar = FB_GetChar(fb);
        if (curchar == EOF) {
            *errStr = PR_smprintf(
                "line %d: Unexpected end-of-file while parsing tag starting at line %d.\n",
                linenum, startline);
            state = ERR_STATE;
            continue;
        }

        switch (state) {
            case START_STATE:
                if (curchar == '!') {
                    /*
                     * SGML tag or comment
                     * Here's the general rule for SGML tags.  Everything from
                     * <! to > is the tag.  Inside the tag, comments are
                     * delimited with --.  So we are looking for the first '>'
                     * that is not commented out, that is, not inside a pair
                     * of --: <!DOCTYPE --this is a comment >(psyche!)   -->
                     */


                    PRBool inComment = PR_FALSE;
                    short hyphenCount = 0; /* number of consecutive hyphens */

                    while (1) {
                        linenum = FB_GetLineNum(fb);
                        curchar = FB_GetChar(fb);
                        if (curchar == EOF) {
                            /* Uh oh, EOF inside comment */
                            *errStr = PR_smprintf(
                                "line %d: Unexpected end-of-file inside comment starting at line %d.\n",
                                linenum, startline);
                            state = ERR_STATE;
                            break;
                        }
                        if (curchar == '-') {
                            if (hyphenCount == 1) {
                                /* This is a comment delimiter */
                                inComment = !inComment;
                                hyphenCount = 0;
                            } else {
                                /* beginning of a comment delimiter? */
                                hyphenCount = 1;
                            }
                        } else if (curchar == '>') {
                            if (!inComment) {
                                /* This is the end of the tag */
                                state = DONE_STATE;
                                break;
                            } else {
                                /* The > is inside a comment, so it's not
                                 * really the end of the tag */

                                hyphenCount = 0;
                            }
                        } else {
                            hyphenCount = 0;
                        }
                    }
                    ti->type = COMMENT_TAG;
                    break;
                }
            /* fall through */
            case GET_ATT_STATE:
                if (isspace(curchar) || curchar == '=' || curchar == '>') {
                    /* end of the current attribute */
                    curPos = FB_GetPointer(fb) - 2;
                    if (curPos >= startID) {
                        /* We have an attribute */
                        curPair = (AVPair *)PR_Malloc(sizeof(AVPair));
                        if (!curPair)
                            out_of_memory();
                        curPair->value = NULL;
                        curPair->next = NULL;
                        FB_GetRange(fb, startID, curPos,
                                    &curPair->attribute);

                        /* Stick this attribute on the list */
                        if (ti->attListTail) {
                            ti->attListTail->next = curPair;
                            ti->attListTail = curPair;
                        } else {
                            ti->attList = ti->attListTail =
                                curPair;
                        }

                        /* If this is the first attribute, find the type of tag
                         * based on it. Also, start saving the text of the tag. */

                        if (firstAtt) {
                            ti->type = GetTagType(curPair->attribute);
                            startText = FB_GetPointer(fb) -
                                        1;
                            firstAtt = PR_FALSE;
                        }
                    } else {
                        if (curchar == '=') {
                            /* If we don't have any attribute but we do have an
                             * equal sign, that's an error */

                            *errStr = PR_smprintf("line %d: Malformed tag starting at line %d.\n",
                                                  linenum, startline);
                            state = ERR_STATE;
                            break;
                        }
                    }

                    /* Compute next state */
                    if (curchar == '=') {
                        startID = FB_GetPointer(fb);
                        state = PRE_VAL_WS_STATE;
                    } else if (curchar == '>') {
                        state = DONE_STATE;
                    } else if (curPair) {
                        state = POST_ATT_WS_STATE;
                    } else {
                        state = PRE_ATT_WS_STATE;
                    }
                } else if (isAttChar(curchar)) {
                    /* Just another char in the attribute. Do nothing */
                    state = GET_ATT_STATE;
                } else {
                    /* bogus char */
                    *errStr = PR_smprintf("line %d: Bogus chararacter '%c' in tag.\n",
                                          linenum, curchar);
                    state = ERR_STATE;
                    break;
                }
                break;
            case PRE_ATT_WS_STATE:
                if (curchar == '>') {
                    state = DONE_STATE;
                } else if (isspace(curchar)) {
                    /* more whitespace, do nothing */
                } else if (isAttChar(curchar)) {
                    /* starting another attribute */
                    startID = FB_GetPointer(fb) - 1;
                    state = GET_ATT_STATE;
                } else {
                    /* bogus char */
                    *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
                                          linenum, curchar);
                    state = ERR_STATE;
                    break;
                }
                break;
            case POST_ATT_WS_STATE:
                if (curchar == '>') {
                    state = DONE_STATE;
                } else if (isspace(curchar)) {
                    /* more whitespace, do nothing */
                } else if (isAttChar(curchar)) {
                    /* starting another attribute */
                    startID = FB_GetPointer(fb) - 1;
                    state = GET_ATT_STATE;
                } else if (curchar == '=') {
                    /* there was whitespace between the attribute and its equal
                     * sign, which means there's a value coming up */

                    state = PRE_VAL_WS_STATE;
                } else {
                    /* bogus char */
                    *errStr = PR_smprintf("line %d: Bogus character '%c' in tag.\n",
                                          linenum, curchar);
                    state = ERR_STATE;
                    break;
                }
                break;
            case PRE_VAL_WS_STATE:
                if (curchar == '>') {
                    /* premature end-of-tag (sounds like a personal problem). */
                    *errStr = PR_smprintf(
                        "line %d: End of tag while waiting for value.\n",
                        linenum);
                    state = ERR_STATE;
                    break;
                } else if (isspace(curchar)) {
                    /* more whitespace, do nothing */
                    break;
                } else {
                    /* this must be some sort of value. Fall through
                     * to GET_VALUE_STATE */

                    startID = FB_GetPointer(fb) - 1;
                    state = GET_VALUE_STATE;
                }
            /* Fall through if we didn't break on '>' or whitespace */
            case GET_VALUE_STATE:
                if (isspace(curchar) || curchar == '>') {
                    /* end of value */
                    curPos = FB_GetPointer(fb) - 2;
                    if (curPos >= startID) {
                        /* Grab the value */
                        FB_GetRange(fb, startID, curPos,
                                    &curPair->value);
                        curPair->valueLine = linenum;
                    } else {
                        /* empty value, leave as NULL */
                    }
                    if (isspace(curchar)) {
                        state = PRE_ATT_WS_STATE;
                    } else {
                        state = DONE_STATE;
                    }
                } else if (curchar == '\"' || curchar == '\'') {
                    /* quoted value.  Start recording the value inside the quote*/
                    startID = FB_GetPointer(fb);
                    state = GET_QUOTED_VAL_STATE;
                    PORT_Assert(quotechar == '\0');
                    quotechar = curchar; /* look for matching quote type */
                } else {
                    /* just more value */
                }
                break;
            case GET_QUOTED_VAL_STATE:
                PORT_Assert(quotechar != '\0');
                if (curchar == quotechar) {
                    /* end of quoted value */
                    curPos = FB_GetPointer(fb) - 2;
                    if (curPos >= startID) {
                        /* Grab the value */
                        FB_GetRange(fb, startID, curPos,
                                    &curPair->value);
                        curPair->valueLine = linenum;
                    } else {
                        /* empty value, leave it as NULL */
                    }
                    state = GET_ATT_STATE;
                    quotechar = '\0';
                    startID = FB_GetPointer(fb);
                } else {
                    /* more quoted value, continue */
                }
                break;
            case DONE_STATE:
            case ERR_STATE:
            default:; /* should never get here */
        }
    }

    if (state == DONE_STATE) {
        /* Get the text of the tag */
        curPos = FB_GetPointer(fb) - 1;
        FB_GetRange(fb, startText, curPos, &ti->text);

        /* Return the tag */
        return ti;
    }

    /* Uh oh, an error.  Kill the tag item*/
    DestroyTagItem(ti);
    return NULL;
}

/************************************************************************
 *
 * D e s t r o y H T M L I t e m
 */

static void
DestroyHTMLItem(HTMLItem *item)
{
    if (item->type == TAG_ITEM) {
        DestroyTagItem(item->item.tag);
    } else {
        if (item->item.text) {
            PR_Free(item->item.text);
        }
    }
}

/************************************************************************
 *
 * D e s t r o y T a g I t e m
 */

static void
DestroyTagItem(TagItem *ti)
{
    AVPair *temp;

    if (ti->text) {
        PR_Free(ti->text);
        ti->text = NULL;
    }

    while (ti->attList) {
        temp = ti->attList;
        ti->attList = ti->attList->next;

        if (temp->attribute) {
            PR_Free(temp->attribute);
            temp->attribute = NULL;
        }
        if (temp->value) {
            PR_Free(temp->value);
            temp->value = NULL;
        }
        PR_Free(temp);
    }

    PR_Free(ti);
}

/************************************************************************
 *
 * G e t T a g T y p e
 */

static TAG_TYPE
GetTagType(char *att)
{
    if (!PORT_Strcasecmp(att, "APPLET")) {
        return APPLET_TAG;
    }
    if (!PORT_Strcasecmp(att, "SCRIPT")) {
        return SCRIPT_TAG;
    }
    if (!PORT_Strcasecmp(att, "LINK")) {
        return LINK_TAG;
    }
    if (!PORT_Strcasecmp(att, "STYLE")) {
        return STYLE_TAG;
    }
    return OTHER_TAG;
}

/************************************************************************
 *
 * F B _ C r e a t e
 */

static FileBuffer *
FB_Create(PRFileDesc *fd)
{
    FileBuffer *fb;
    PRInt32 amountRead;
    PRInt32 storedOffset;

    fb = (FileBuffer *)PR_Malloc(sizeof(FileBuffer));
    fb->fd = fd;
    storedOffset = PR_Seek(fd, 0, PR_SEEK_CUR);
    PR_Seek(fd, 0, PR_SEEK_SET);
    fb->startOffset = 0;
    amountRead = PR_Read(fd, fb->buf, FILE_BUFFER_BUFSIZE);
    if (amountRead == -1)
        goto loser;
    fb->maxIndex = amountRead - 1;
    fb->curIndex = 0;
    fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;
    fb->lineNum = 1;

    PR_Seek(fd, storedOffset, PR_SEEK_SET);
    return fb;
loser:
    PR_Seek(fd, storedOffset, PR_SEEK_SET);
    PR_Free(fb);
    return NULL;
}

/************************************************************************
 *
 * F B _ G e t C h a r
 */

static int
FB_GetChar(FileBuffer *fb)
{
    PRInt32 storedOffset;
    PRInt32 amountRead;
    int retval = -1;

    if (fb->IsEOF) {
        return EOF;
    }

    storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);

    retval = (unsigned char)fb->buf[fb->curIndex++];
    if (retval == '\n')
        fb->lineNum++;

    if (fb->curIndex > fb->maxIndex) {
        /* We're at the end of the buffer. Try to get some new data from the
         * file */

        fb->startOffset += fb->maxIndex + 1;
        PR_Seek(fb->fd, fb->startOffset, PR_SEEK_SET);
        amountRead = PR_Read(fb->fd, fb->buf, FILE_BUFFER_BUFSIZE);
        if (amountRead == -1)
            goto loser;
        fb->maxIndex = amountRead - 1;
        fb->curIndex = 0;
    }

    fb->IsEOF = (fb->curIndex > fb->maxIndex) ? PR_TRUE : PR_FALSE;

loser:
    PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
    return retval;
}

/************************************************************************
 *
 * F B _ G e t L i n e N u m
 *
 */

static unsigned int
FB_GetLineNum(FileBuffer *fb)
{
    return fb->lineNum;
}

/************************************************************************
 *
 * F B _ G e t P o i n t e r
 *
 */

static PRInt32
FB_GetPointer(FileBuffer *fb)
{
    return fb->startOffset + fb->curIndex;
}

/************************************************************************
 *
 * F B _ G e t R a n g e
 *
 */

static PRInt32
FB_GetRange(FileBuffer *fb, PRInt32 start, PRInt32 end, char **buf)
{
    PRInt32 amountRead;
    PRInt32 storedOffset;

    *buf = PR_Malloc(end - start + 2);
    if (*buf == NULL) {
        return 0;
    }

    storedOffset = PR_Seek(fb->fd, 0, PR_SEEK_CUR);
    PR_Seek(fb->fd, start, PR_SEEK_SET);
    amountRead = PR_Read(fb->fd, *buf, end - start + 1);
    PR_Seek(fb->fd, storedOffset, PR_SEEK_SET);
    if (amountRead == -1) {
        PR_Free(*buf);
        *buf = NULL;
        return 0;
    }

    (*buf)[end - start + 1] = '\0';
    return amountRead;
}

/************************************************************************
 *
 * F B _ D e s t r o y
 *
 */

static void
FB_Destroy(FileBuffer *fb)
{
    if (fb) {
        PR_Free(fb);
    }
}

/************************************************************************
 *
 * P r i n t T a g I t e m
 *
 */

static void
PrintTagItem(PRFileDesc *fd, TagItem *ti)
{
    AVPair *pair;

    PR_fprintf(fd, "TAG:\n----\nType: ");
    switch (ti->type) {
        case APPLET_TAG:
            PR_fprintf(fd, "applet\n");
            break;
        case SCRIPT_TAG:
            PR_fprintf(fd, "script\n");
            break;
        case LINK_TAG:
            PR_fprintf(fd, "link\n");
            break;
        case STYLE_TAG:
            PR_fprintf(fd, "style\n");
            break;
        case COMMENT_TAG:
            PR_fprintf(fd, "comment\n");
            break;
        case OTHER_TAG:
        default:
            PR_fprintf(fd, "other\n");
            break;
    }

    PR_fprintf(fd, "Attributes:\n");
    for (pair = ti->attList; pair; pair = pair->next) {
        PR_fprintf(fd, "\t%s=%s\n", pair->attribute,
                   pair->value ? pair->value : "");
    }
    PR_fprintf(fd, "Text:%s\n", ti->text ? ti->text : "");

    PR_fprintf(fd, "---End of tag---\n");
}

/************************************************************************
 *
 * P r i n t H T M L S t r e a m
 *
 */

static void
PrintHTMLStream(PRFileDesc *fd, HTMLItem *head)
{
    while (head) {
        if (head->type == TAG_ITEM) {
            PrintTagItem(fd, head->item.tag);
        } else {
            PR_fprintf(fd, "\nTEXT:\n-----\n%s\n-----\n\n", head->item.text);
        }
        head = head->next;
    }
}

/************************************************************************
 *
 * S a v e I n l i n e S c r i p t
 *
 */

static int
SaveInlineScript(char *text, char *id, char *basedir, char *archiveDir)
{
    char *filename = NULL;
    PRFileDesc *fd = NULL;
    int retval = -1;
    PRInt32 writeLen;
    char *ilDir = NULL;

    if (!text || !id || !archiveDir) {
        return -1;
    }

    if (dumpParse) {
        PR_fprintf(outputFD, "SaveInlineScript: text=%s, id=%s, \n"
                             "basedir=%s, archiveDir=%s\n",
                   text, id, basedir, archiveDir);
    }

    /* Make sure the archive directory is around */
    if (ensureExists(basedir, archiveDir) != PR_SUCCESS) {
        PR_fprintf(errorFD,
                   "ERROR: Unable to create archive directory %s.\n", archiveDir);
        errorCount++;
        return -1;
    }

    /* Make sure the inline script directory is around */
    ilDir = PR_smprintf("%s/inlineScripts", archiveDir);
    scriptdir = "inlineScripts";
    if (ensureExists(basedir, ilDir) != PR_SUCCESS) {
        PR_fprintf(errorFD,
                   "ERROR: Unable to create directory %s.\n", ilDir);
        errorCount++;
        return -1;
    }

    filename = PR_smprintf("%s/%s/%s", basedir, ilDir, id);

    /* If the file already exists, give a warning, then blow it away */
    if (PR_Access(filename, PR_ACCESS_EXISTS) == PR_SUCCESS) {
        PR_fprintf(errorFD,
                   "warning: file \"%s\" already exists--will overwrite.\n",
                   filename);
        warningCount++;
        if (rm_dash_r(filename)) {
            PR_fprintf(errorFD, "ERROR: Unable to delete %s.\n", filename);
            errorCount++;
            goto finish;
        }
    }

    /* Write text into file with name id */
    fd = PR_Open(filename, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777);
    if (!fd) {
        PR_fprintf(errorFD, "ERROR: Unable to create file \"%s\".\n",
                   filename);
        errorCount++;
        goto finish;
    }
    writeLen = strlen(text);
    if (PR_Write(fd, text, writeLen) != writeLen) {
        PR_fprintf(errorFD, "ERROR: Unable to write to file \"%s\".\n",
                   filename);
        errorCount++;
        goto finish;
    }

    retval = 0;
finish:
    if (filename) {
        PR_smprintf_free(filename);
    }
    if (ilDir) {
        PR_smprintf_free(ilDir);
    }
    if (fd) {
        PR_Close(fd);
    }
    return retval;
}

/************************************************************************
 *
 * S a v e U n n a m a b l e S c r i p t
 *
 */

static int
SaveUnnamableScript(char *text, char *basedir, char *archiveDir,
                    char *HTMLfilename)
{
    char *id = NULL;
    char *ext = NULL;
    char *start = NULL;
    int retval = -1;

    if (!text || !archiveDir || !HTMLfilename) {
        return -1;
    }

    if (dumpParse) {
        PR_fprintf(outputFD, "SaveUnnamableScript: text=%s, basedir=%s,\n"
                             "archiveDir=%s, filename=%s\n",
                   text, basedir, archiveDir,
                   HTMLfilename);
    }

    /* Construct the filename */
    ext = PL_strrchr(HTMLfilename, '.');
    if (ext) {
        *ext = '\0';
    }
    for (start = HTMLfilename; strpbrk(start, "/\\");
         start = strpbrk(start, "/\\") + 1)
        /* do nothing */;
    if (*start == '\0')
        start = HTMLfilename;
    id = PR_smprintf("_%s%d", start, idOrdinal++);
    if (ext) {
        *ext = '.';
    }

    /* Now call SaveInlineScript to do the work */
    retval = SaveInlineScript(text, id, basedir, archiveDir);

    PR_Free(id);

    return retval;
}

/************************************************************************
 *
 * S a v e S o u r c e
 *
 */

static int
SaveSource(char *src, char *codebase, char *basedir, char *archiveDir)
{
    char *from = NULL, *to = NULL;
    int retval = -1;
    char *arcDir = NULL;

    if (!src || !archiveDir) {
        return -1;
    }

    if (dumpParse) {
        PR_fprintf(outputFD, "SaveSource: src=%s, codebase=%s, basedir=%s,\n"
                             "archiveDir=%s\n",
                   src, codebase, basedir, archiveDir);
    }

    if (codebase) {
        arcDir = PR_smprintf("%s/%s/%s/", basedir, codebase, archiveDir);
    } else {
        arcDir = PR_smprintf("%s/%s/", basedir, archiveDir);
    }

    if (codebase) {
        from = PR_smprintf("%s/%s/%s", basedir, codebase, src);
        to = PR_smprintf("%s%s", arcDir, src);
    } else {
        from = PR_smprintf("%s/%s", basedir, src);
        to = PR_smprintf("%s%s", arcDir, src);
    }

    if (make_dirs(to, 0777)) {
        PR_fprintf(errorFD,
                   "ERROR: Unable to create archive directory %s.\n", archiveDir);
        errorCount++;
        goto finish;
    }

    retval = copyinto(from, to);
finish:
    if (from)
        PR_Free(from);
    if (to)
        PR_Free(to);
    if (arcDir)
        PR_Free(arcDir);
    return retval;
}

/************************************************************************
 *
 * T a g T y p e T o S t r i n g
 *
 */

char *
TagTypeToString(TAG_TYPE type)
{
    switch (type) {
        case APPLET_TAG:
            return "APPLET";
        case SCRIPT_TAG:
            return "SCRIPT";
        case LINK_TAG:
            return "LINK";
        case STYLE_TAG:
            return "STYLE";
        default:
            break;
    }
    return "unknown";
}

/************************************************************************
 *
 * e x t r a c t _ j s
 *
 */

static int
extract_js(char *filename)
{
    PRFileDesc *fd = NULL;
    FileBuffer *fb = NULL;
    HTMLItem *head = NULL;
    HTMLItem *tail = NULL;
    HTMLItem *curitem = NULL;
    HTMLItem *styleList = NULL;
    HTMLItem *styleListTail = NULL;
    HTMLItem *entityList = NULL;
    HTMLItem *entityListTail = NULL;
    TagItem *tagp = NULL;
    char *text = NULL;
    char *tagerr = NULL;
    char *archiveDir = NULL;
    char *firstArchiveDir = NULL;
    char *basedir = NULL;
    PRInt32 textStart;
    PRInt32 curOffset;
    HTML_STATE state;
    int curchar;
    int retval = -1;
    unsigned int linenum, startLine;

    /* Initialize the implicit ID counter for each file */
    idOrdinal = 0;

    /*
     * First, parse the HTML into a stream of tags and text.
     */


    fd = PR_Open(filename, PR_RDONLY, 0);
    if (!fd) {
        PR_fprintf(errorFD, "Unable to open %s for reading.\n", filename);
        errorCount++;
        return -1;
    }

    /* Construct base directory of filename. */
    {
        char *cp;

        basedir = PL_strdup(filename);

        /* Remove trailing slashes */
        while ((cp = PL_strprbrk(basedir, "/\\")) ==
               (basedir + strlen(basedir) - 1)) {
            *cp = '\0';
        }

        /* Now remove everything from the last slash (which will be followed
         * by a filename) to the end */

        cp = PL_strprbrk(basedir, "/\\");
        if (cp) {
            *cp = '\0';
        }
    }

    state = TEXT_HTML_STATE;

    fb = FB_Create(fd);

    textStart = 0;
    startLine = 0;
    while (linenum = FB_GetLineNum(fb), (curchar = FB_GetChar(fb)) != EOF) {
        switch (state) {
            case TEXT_HTML_STATE:
                if (curchar == '<') {
                    /*
                     * Found a tag
                     */

                    /* Save the text so far to a new text item */
                    curOffset = FB_GetPointer(fb) - 2;
                    if (curOffset >= textStart) {
                        if (FB_GetRange(fb, textStart, curOffset,
                                        &text) !=
                            curOffset - textStart + 1) {
                            PR_fprintf(errorFD,
                                       "Unable to read from %s.\n",
                                       filename);
                            errorCount++;
                            goto loser;
                        }
                        /* little fudge here.  If the first character on a line
                         * is '<', meaning a new tag, the preceding text item
                         * actually ends on the previous line.  In this case
                         * we will be saying that the text segment ends on the
                         * next line. I don't think this matters for text items. */

                        curitem = CreateTextItem(text, startLine,
                                                 linenum);
                        text = NULL;
                        if (tail == NULL) {
                            head = tail = curitem;
                        } else {
                            tail->next = curitem;
                            tail = curitem;
                        }
                    }

                    /* Process the tag */
                    tagp = ProcessTag(fb, &tagerr);
                    if (!tagp) {
                        if (tagerr) {
                            PR_fprintf(errorFD, "Error in file %s: %s\n",
                                       filename, tagerr);
                            errorCount++;
                        } else {
                            PR_fprintf(errorFD,
                                       "Error in file %s, in tag starting at line %d\n",
                                       filename, linenum);
                            errorCount++;
                        }
                        goto loser;
                    }
                    /* Add the tag to the list */
                    curitem = CreateTagItem(tagp, linenum, FB_GetLineNum(fb));
                    if (tail == NULL) {
                        head = tail = curitem;
                    } else {
                        tail->next = curitem;
                        tail = curitem;
                    }

                    /* What's the next state */
                    if (tagp->type == SCRIPT_TAG) {
                        state = SCRIPT_HTML_STATE;
                    }

                    /* Start recording text from the new offset */
                    textStart = FB_GetPointer(fb);
                    startLine = FB_GetLineNum(fb);
                } else {
                    /* regular character.  Next! */
                }
                break;
            case SCRIPT_HTML_STATE:
                if (curchar == '<') {
                    char *cp;
                    /*
                     * If this is a </script> tag, then we're at the end of the
                     * script.  Otherwise, ignore
                     */

                    curOffset = FB_GetPointer(fb) - 1;
                    cp = NULL;
                    if (FB_GetRange(fb, curOffset, curOffset + 8, &cp) != 9) {
                        if (cp) {
                            PR_Free(cp);
                            cp = NULL;
                        }
                    } else {
                        /* compare the strings */
                        if (!PORT_Strncasecmp(cp, "", 9)) {
                            /* This is the end of the script. Record the text. */
                            curOffset--;
                            if (curOffset >= textStart) {
                                if (FB_GetRange(fb, textStart, curOffset, &text) !=
                                    curOffset - textStart + 1) {
                                    PR_fprintf(errorFD, "Unable to read from %s.\n",
                                               filename);
                                    errorCount++;
                                    goto loser;
                                }
                                curitem = CreateTextItem(text, startLine, linenum);
                                text = NULL;
                                if (tail == NULL) {
                                    head = tail = curitem;
                                } else {
                                    tail->next = curitem;
                                    tail = curitem;
                                }
                            }

                            /* Now parse the /script tag and put it on the list */
                            tagp = ProcessTag(fb, &tagerr);
                            if (!tagp) {
                                if (tagerr) {
                                    PR_fprintf(errorFD, "Error in file %s: %s\n",
                                               filename, tagerr);
                                } else {
                                    PR_fprintf(errorFD,
                                               "Error in file %s, in tag starting at"
                                               " line %d\n",
                                               filename, linenum);
                                }
                                errorCount++;
                                goto loser;
                            }
                            curitem = CreateTagItem(tagp, linenum,
                                                    FB_GetLineNum(fb));
                            if (tail == NULL) {
                                head = tail = curitem;
                            } else {
                                tail->next = curitem;
                                tail = curitem;
                            }

                            /* go back to text state */
                            state = TEXT_HTML_STATE;

                            textStart = FB_GetPointer(fb);
                            startLine = FB_GetLineNum(fb);
                        }
                    }
                }
                break;
        }
    }

    /* End of the file.  Wrap up any remaining text */
    if (state == SCRIPT_HTML_STATE) {
        if (tail && tail->type == TAG_ITEM) {
            PR_fprintf(errorFD, "ERROR: tag.\n",
                       filename, tail->startLine);
        } else {
            PR_fprintf(errorFD, "ERROR: ,
                       filename);
        }
        errorCount++;
        goto loser;
    }
    curOffset = FB_GetPointer(fb) - 1;
    if (curOffset >= textStart) {
        text = NULL;
        if (FB_GetRange(fb, textStart, curOffset, &text) !=
            curOffset - textStart + 1) {
            PR_fprintf(errorFD, "Unable to read from %s.\n", filename);
            errorCount++;
            goto loser;
        }
        curitem = CreateTextItem(text, startLine, linenum);
        text = NULL;
        if (tail == NULL) {
            head = tail = curitem;
        } else {
            tail->next = curitem;
            tail = curitem;
        }
    }

    if (dumpParse) {
        PrintHTMLStream(outputFD, head);
    }

    /*
     * Now we have a stream of tags and text.  Go through and deal with each.
     */

    for (curitem = head; curitem; curitem = curitem->next) {
        AVPair *pairp = NULL;
        char *src = NULL, *id = NULL, *codebase = NULL;
        PRBool hasEventHandler = PR_FALSE;
        int i;

        /* Reset archive directory for each tag */
        if (archiveDir) {
            PR_Free(archiveDir);
            archiveDir = NULL;
        }

        /* We only analyze tags */
        if (curitem->type != TAG_ITEM) {
            continue;
        }

        tagp = curitem->item.tag;

        /* go through the attributes to get information */
        for (pairp = tagp->attList; pairp; pairp = pairp->next) {

            /* ARCHIVE= */
            if (!PL_strcasecmp(pairp->attribute, "archive")) {
                if (archiveDir) {
                    /* Duplicate attribute.  Print warning */
                    PR_fprintf(errorFD,
                               "warning: \"%s\" attribute overwrites previous attribute"
                               " in tag starting at %s:%d.\n",
                               pairp->attribute, filename, curitem->startLine);
                    warningCount++;
                    PR_Free(archiveDir);
                }
                archiveDir = PL_strdup(pairp->value);

                /* Substiture ".arc" for ".jar" */
                if ((PL_strlen(archiveDir) < 4) ||
                    PL_strcasecmp((archiveDir + strlen(archiveDir) - 4),
                                  ".jar")) {
                    char *newArchiveDir = NULL;
                    PR_fprintf(errorFD,
                               "warning: ARCHIVE attribute should end in \".jar\" in tag"
                               " starting on %s:%d.\n",
                               filename, curitem->startLine);
                    warningCount++;
                    newArchiveDir = PR_smprintf("%s.arc", archiveDir);
                    PR_Free(archiveDir);
                    archiveDir = newArchiveDir;
                } else {
                    PL_strcpy(archiveDir + strlen(archiveDir) - 4, ".arc");
                }

                /* Record the first archive.  This will be used later if
                 * the archive is not specified */

                if (firstArchiveDir == NULL) {
                    firstArchiveDir = PL_strdup(archiveDir);
                }
            }
            /* CODEBASE= */
            else if (!PL_strcasecmp(pairp->attribute, "codebase")) {
                if (codebase) {
                    /* Duplicate attribute.  Print warning */
                    PR_fprintf(errorFD,
                               "warning: \"%s\" attribute overwrites previous attribute"
                               " in tag staring at %s:%d.\n",
                               pairp->attribute, filename, curitem->startLine);
                    warningCount++;
                }
                codebase = pairp->value;
            }
            /* SRC= and HREF= */
            else if (!PORT_Strcasecmp(pairp->attribute, "src") ||
                     !PORT_Strcasecmp(pairp->attribute, "href")) {
                if (src) {
                    /* Duplicate attribute.  Print warning */
                    PR_fprintf(errorFD,
                               "warning: \"%s\" attribute overwrites previous attribute"
                               " in tag staring at %s:%d.\n",
                               pairp->attribute, filename, curitem->startLine);
                    warningCount++;
                }
                src = pairp->value;
            }
            /* CODE= */
            else if (!PORT_Strcasecmp(pairp->attribute, "code")) {
                /*!!!XXX Change PORT to PL all over this code !!! */
                if (src) {
                    /* Duplicate attribute.  Print warning */
                    PR_fprintf(errorFD,
                               "warning: \"%s\" attribute overwrites previous attribute"
                               " ,in tag staring at %s:%d.\n",
                               pairp->attribute, filename, curitem->startLine);
                    warningCount++;
                }
                src = pairp->value;

                /* Append a .class if one is not already present */
                if ((PL_strlen(src) < 6) ||
                    PL_strcasecmp((src + PL_strlen(src) - 6), ".class")) {
                    src = PR_smprintf("%s.class", src);
                    /* Put this string back into the data structure so it
                     * will be deallocated properly */

                    PR_Free(pairp->value);
                    pairp->value = src;
                }
            }
            /* ID= */
            else if (!PL_strcasecmp(pairp->attribute, "id")) {
                if (id) {
                    /* Duplicate attribute.  Print warning */
                    PR_fprintf(errorFD,
                               "warning: \"%s\" attribute overwrites previous attribute"
                               " in tag staring at %s:%d.\n",
                               pairp->attribute, filename, curitem->startLine);
                    warningCount++;
                }
                id = pairp->value;
            }

            /* STYLE= */
            /* style= attributes, along with JS entities, are stored into
             * files with dynamically generated names. The filenames are
             * based on the order in which the text is found in the file.
             * All JS entities on all lines up to and including the line
             * containing the end of the tag that has this style= attribute
             * will be processed before this style=attribute.  So we need
             * to record the line that this _tag_ (not the attribute) ends on.
             */

            else if (!PL_strcasecmp(pairp->attribute, "style") && pairp->value) {
                HTMLItem *styleItem;
                /* Put this item on the style list */
                styleItem = CreateTextItem(PL_strdup(pairp->value),
                                           curitem->startLine, curitem->endLine);
                if (styleListTail == NULL) {
                    styleList = styleListTail = styleItem;
                } else {
                    styleListTail->next = styleItem;
                    styleListTail = styleItem;
                }
            }
            /* Event handlers */
            else {
                for (i = 0; i < num_handlers; i++) {
                    if (!PL_strcasecmp(event_handlers[i], pairp->attribute)) {
                        hasEventHandler = PR_TRUE;
                        break;
                    }
                }
            }

            /* JS Entity */
            {
                char *entityStart, *entityEnd;
                HTMLItem *entityItem;

                /* go through each JavaScript entity ( &{...}; ) and store it
                 * in the entityList.  The important thing is to record what
                 * line number it's on, so we can get it in the right order
                 * in relation to style= attributes.
                 * Apparently, these can't flow across lines, so the start and
                 * end line will be the same.  That helps matters.
                 */

                entityEnd = pairp->value;
                while (entityEnd &&
                       (entityStart = PL_strstr(entityEnd, "&{")) /*}*/ != NULL) {
                    entityStart += 2; /* point at beginning of actual entity */
                    entityEnd = PL_strchr(entityStart, '}');
                    if (entityEnd) {
                        /* Put this item on the entity list */
                        *entityEnd = '\0';
                        entityItem = CreateTextItem(PL_strdup(entityStart),
                                                    pairp->valueLine, pairp->valueLine);
                        *entityEnd = /* { */ '}';
                        if (entityListTail) {
                            entityListTail->next = entityItem;
                            entityListTail = entityItem;
                        } else {
                            entityList = entityListTail = entityItem;
                        }
                    }
                }
            }
        }

        /* If no archive was supplied, we use the first one of the file */
        if (!archiveDir && firstArchiveDir) {
            archiveDir = PL_strdup(firstArchiveDir);
        }

        /* If we have an event handler, we need to archive this tag */
        if (hasEventHandler) {
            if (!id) {
                PR_fprintf(errorFD,
                           "warning: tag starting at %s:%d has event handler but"
                           " no ID attribute. The tag will not be signed.\n",
                           filename, curitem->startLine);
                warningCount++;
            } else if (!archiveDir) {
                PR_fprintf(errorFD,
                           "warning: tag starting at %s:%d has event handler but"
                           " no ARCHIVE attribute. The tag will not be signed.\n",
                           filename, curitem->startLine);
                warningCount++;
            } else {
                if (SaveInlineScript(tagp->text, id, basedir, archiveDir)) {
                    goto loser;
                }
            }
        }

        switch (tagp->type) {
            case APPLET_TAG:
                if (!src) {
                    PR_fprintf(errorFD,
                               "error: APPLET tag starting on %s:%d has no CODE "
                               "attribute.\n",
                               filename, curitem->startLine);
                    errorCount++;
                    goto loser;
                } else if (!archiveDir) {
                    PR_fprintf(errorFD,
                               "error: APPLET tag starting on %s:%d has no ARCHIVE "
                               "attribute.\n",
                               filename, curitem->startLine);
                    errorCount++;
                    goto loser;
                } else {
                    if (SaveSource(src, codebase, basedir, archiveDir)) {
                        goto loser;
                    }
                }
                break;
            case SCRIPT_TAG:
            case LINK_TAG:
            case STYLE_TAG:
                if (!archiveDir) {
                    PR_fprintf(errorFD,
                               "error: %s tag starting on %s:%d has no ARCHIVE "
                               "attribute.\n",
                               TagTypeToString(tagp->type),
                               filename, curitem->startLine);
                    errorCount++;
                    goto loser;
                } else if (src) {
                    if (SaveSource(src, codebase, basedir, archiveDir)) {
                        goto loser;
                    }
                } else if (id) {
                    /* Save the next text item */
                    if (!curitem->next || (curitem->next->type !=
                                           TEXT_ITEM)) {
                        PR_fprintf(errorFD,
                                   "warning: %s tag starting on %s:%d is not followed"
                                   " by script text.\n",
                                   TagTypeToString(tagp->type),
                                   filename, curitem->startLine);
                        warningCount++;
                        /* just create empty file */
                        if (SaveInlineScript("", id, basedir, archiveDir)) {
                            goto loser;
                        }
                    } else {
                        curitem = curitem->next;
                        if (SaveInlineScript(curitem->item.text,
                                             id, basedir,
                                             archiveDir)) {
                            goto loser;
                        }
                    }
                } else {
                    /* No src or id tag--warning */
                    PR_fprintf(errorFD,
                               "warning: %s tag starting on %s:%d has no SRC or"
                               " ID attributes. Will not sign.\n",
                               TagTypeToString(tagp->type), filename, curitem->startLine);
                    warningCount++;
                }
                break;
            default:
                /* do nothing for other tags */
                break;
        }
    }

    /* Now deal with all the unnamable scripts */
    if (firstArchiveDir) {
        HTMLItem *style, *entity;

        /* Go through the lists of JS entities and style attributes.  Do them
         * in chronological order within a list.  Pick the list with the lower
         * endLine. In case of a tie, entities come first.
         */

        style = styleList;
        entity = entityList;
        while (style || entity) {
            if (!entity || (style && (style->endLine < entity->endLine))) {
                /* Process style */
                SaveUnnamableScript(style->item.text, basedir, firstArchiveDir,
                                    filename);
                style = style->next;
            } else {
                /* Process entity */
                SaveUnnamableScript(entity->item.text, basedir, firstArchiveDir,
                                    filename);
                entity = entity->next;
            }
        }
    }

    retval = 0;
loser:
    /* Blow away the stream */
    while (head) {
        curitem = head;
        head = head->next;
        DestroyHTMLItem(curitem);
    }
    while (styleList) {
        curitem = styleList;
        styleList = styleList->next;
        DestroyHTMLItem(curitem);
    }
    while (entityList) {
        curitem = entityList;
        entityList = entityList->next;
        DestroyHTMLItem(curitem);
    }
    if (text) {
        PR_Free(text);
        text = NULL;
    }
    if (fb) {
        FB_Destroy(fb);
        fb = NULL;
    }
    if (fd) {
        PR_Close(fd);
    }
    if (tagerr) {
        PR_smprintf_free(tagerr);
        tagerr = NULL;
    }
    if (archiveDir) {
        PR_Free(archiveDir);
        archiveDir = NULL;
    }
    if (firstArchiveDir) {
        PR_Free(firstArchiveDir);
        firstArchiveDir = NULL;
    }
    if (entityListTail) {
        PR_Free(entityListTail);
    }
    if (basedir) {
        PR_Free(basedir);
    }
    return retval;
}

/**********************************************************************
 *
 * e n s u r e E x i s t s
 *
 * Check for existence of indicated directory.  If it doesn't exist,
 * it will be created.
 * Returns PR_SUCCESS if the directory is present, PR_FAILURE otherwise.
 */

static PRStatus
ensureExists(char *basepath, char *path)
{
    char fn[FNSIZE];
    PRDir *dir;
    int c = snprintf(fn, sizeof(fn), "%s/%s", basepath, path);
    if (c >= sizeof(fn)) {
        return PR_FAILURE;
    }

    /*PR_fprintf(outputFD, "Trying to open directory %s.\n", fn);*/

    if ((dir = PR_OpenDir(fn))) {
        PR_CloseDir(dir);
        return PR_SUCCESS;
    }
    return PR_MkDir(fn, 0777);
}

/***************************************************************************
 *
 * m a k e _ d i r s
 *
 * Ensure that the directory portion of the path exists.  This may require
 * making the directory, and its parent, and its parent's parent, etc.
 */

static int
make_dirs(char *path, int file_perms)
{
    char *Path;
    char *start;
    char *sep;
    int ret = 0;
    PRFileInfo info;

    if (!path) {
        return 0;
    }

    Path = PL_strdup(path);
    if (!Path) {
        return 0;
    }

    start = strpbrk(Path, "/\\");
    if (!start) {
        goto loser;
    }
    start++; /* start right after first slash */

    /* Each time through the loop add one more directory. */
    while ((sep = strpbrk(start, "/\\"))) {
        *sep = '\0';

        if (PR_GetFileInfo(Path, &info) != PR_SUCCESS) {
            /* No such dir, we have to create it */
            if (PR_MkDir(Path, file_perms) != PR_SUCCESS) {
                PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
                           Path);
                errorCount++;
                ret = -1;
                goto loser;
            }
        } else {
            /* something exists by this name, make sure it's a directory */
            if (info.type != PR_FILE_DIRECTORY) {
                PR_fprintf(errorFD, "ERROR: Unable to create directory %s.\n",
                           Path);
                errorCount++;
                ret = -1;
                goto loser;
            }
        }

        start = sep + 1; /* start after the next slash */
        *sep = '/';
    }

loser:
    PR_Free(Path);
    return ret;
}

/*
 *  c o p y i n t o
 *
 *  Function to copy file "from" to path "to".
 *
 */

static int
copyinto(char *from, char *to)
{
    PRInt32 num;
    char buf[BUFSIZ];
    PRFileDesc *infp = NULL, *outfp = NULL;
    int retval = -1;

    if ((infp = PR_Open(from, PR_RDONLY, 0777)) == NULL) {
        PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for reading.\n",
                   from);
        errorCount++;
        goto finish;
    }

    /* If to already exists, print a warning before deleting it */
    if (PR_Access(to, PR_ACCESS_EXISTS) == PR_SUCCESS) {
        PR_fprintf(errorFD, "warning: %s already exists--will overwrite\n", to);
        warningCount++;
        if (rm_dash_r(to)) {
            PR_fprintf(errorFD,
                       "ERROR: Unable to remove %s.\n", to);
            errorCount++;
            goto finish;
        }
    }

    if ((outfp = PR_Open(to, PR_WRONLY | PR_CREATE_FILE | PR_TRUNCATE, 0777)) ==
        NULL) {
        char *errBuf = NULL;

        errBuf = PR_Malloc(PR_GetErrorTextLength() + 1);
        PR_fprintf(errorFD, "ERROR: Unable to open \"%s\" for writing.\n", to);
        if (PR_GetErrorText(errBuf)) {
            PR_fprintf(errorFD, "Cause: %s\n", errBuf);
        }
        if (errBuf) {
            PR_Free(errBuf);
        }
        errorCount++;
        goto finish;
    }

    while ((num = PR_Read(infp, buf, BUFSIZ)) > 0) {
        if (PR_Write(outfp, buf, num) != num) {
            PR_fprintf(errorFD, "ERROR: Error writing to %s.\n", to);
            errorCount++;
            goto finish;
        }
    }

    retval = 0;
finish:
    if (infp)
        PR_Close(infp);
    if (outfp)
        PR_Close(outfp);

    return retval;
}

Messung V0.5
C=92 H=86 G=88

¤ Dauer der Verarbeitung: 0.46 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.