CSS-Minifier-XS
view release on metacpan or search on metacpan
/* 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 )