CSS-Minifier-XS

 view release on metacpan or  search on metacpan

XS.xs  view on Meta::CPAN

            /* leading whitespace gets pruned */
            if (!prev)
                return PRUNE_CURRENT;
            /* trailing whitespace gets pruned */
            if (!next)
                return PRUNE_CURRENT;
            /* keep all other whitespace */
            return PRUNE_NO;
        case NODE_BLOCKCOMMENT:
            /* keep comments that contain the word "copyright" */
            if (nodeContains(node,"copyright"))
                return PRUNE_NO;
            /* remove comment blocks */
            return PRUNE_CURRENT;
        case NODE_IDENTIFIER:
            /* keep all identifiers */
            return PRUNE_NO;
        case NODE_LITERAL:
            /* keep all literals */
            return PRUNE_NO;
        case NODE_SIGIL:
            /* remove whitespace after "prefix" sigils */
            if (nodeIsPREFIXSIGIL(node) && next && nodeIsWHITESPACE(next))
                return PRUNE_NEXT;
            /* remove whitespace before "postfix" sigils */
            if (nodeIsPOSTFIXSIGIL(node) && prev && nodeIsWHITESPACE(prev))
                return PRUNE_PREVIOUS;
            /* remove ";" characters at end of selector groups */
            if (nodeIsCHAR(node,';') && next && nodeIsSIGIL(next) && nodeIsCHAR(next,'}'))
                return PRUNE_CURRENT;
            /* keep all other sigils */
            return PRUNE_NO;
    }
    /* keep anything else */
    return PRUNE_NO;
}

/* prune nodes from the list */
Node* CssPruneNodes(Node *head) {
    Node* curr = head;
    while (curr) {
        /* see if/how we can prune this node */
        int prune = CssCanPrune(curr);
        /* prune.  each block is responsible for moving onto the next node */
        Node* prev = curr->prev;
        Node* next = curr->next;
        switch (prune) {
            case PRUNE_PREVIOUS:
                /* discard previous node */
                CssDiscardNode(prev);
                /* reset "head" if that's what got pruned */
                if (prev == head)
                    head = curr;
                break;
            case PRUNE_CURRENT:
                /* discard current node */
                CssDiscardNode(curr);
                /* reset "head" if that's what got pruned */
                if (curr == head)
                    head = prev ? prev : next;
                /* backup and try again if possible */
                curr = prev ? prev : next;
                break;
            case PRUNE_NEXT:
                /* discard next node */
                CssDiscardNode(next);
                /* stay on current node, and try again */
                break;
            default:
                /* move ahead to next node */
                curr = next;
                break;
        }
    }

    /* return the (possibly new) head node back to the caller */
    return head;
}

/* ****************************************************************************
 * Minifies the given CSS, returning a newly allocated string back to the
 * caller (YOU'RE responsible for freeing its memory).
 * ****************************************************************************
 */
char* CssMinify(const char* string) {
    char* results;
    CssDoc doc;

    /* initialize our CSS document object */
    doc.head = NULL;
    doc.tail = NULL;
    doc.buffer = string;
    doc.length = strlen(string);
    doc.offset = 0;
    Newz(0, doc.head_set, 1, NodeSet);
    doc.tail_set = doc.head_set;

    /* PASS 1: tokenize CSS into a list of nodes */
    Node* head = CssTokenizeString(&doc, string);
    if (!head) return NULL;
    /* PASS 2: collapse nodes */
    CssCollapseNodes(head);
    /* PASS 3: prune nodes */
    head = CssPruneNodes(head);
    if (!head) return NULL;
    /* PASS 4: re-assemble CSS into single string */
    {
        Node* curr;
        char* ptr;
        /* allocate the result buffer to the same size as the original CSS; in
         * a worst case scenario that's how much memory we'll need for it.
         */
        Newz(0, results, (strlen(string)+1), char);
        ptr = results;
        /* copy node contents into result buffer */
        curr = head;
        while (curr) {
            memcpy(ptr, curr->contents, curr->length);
            ptr += curr->length;
            curr = curr->next;
        }



( run in 0.973 second using v1.01-cache-2.11-cpan-df04353d9ac )