unit CSSParser;

// Version 1.01
//
// License: http://www.mozilla.org/MPL/
// Site: http://www.mythcode.org
// Author: Dzianis Koshkin
// E-mail: dzianis.k@gmail.com
//
// (C) 2005 MYTHcode.org

interface

type
  TCSSItemType = (itHead, itSimple, itLast, itEmptyLast, itComment, itSGMLComment);

TCSSParser = class
private
  Final: Boolean;
  FItemType: TCSSItemType;
  PInitial: PChar;
  PFinal: PChar;
  PRun: PChar;
  FItem: string;
  FComment: string;
public
  constructor Create(S: string);
  function Next: Boolean;
  property ItemType: TCSSItemType read FItemType;
  property Item: string read FItem;
  property Comment: string read FComment;
end;

implementation

function GetTrim(From,Before: PChar): string;
begin
  while (From<Before) and (From^<'!') do Inc(From);
  Dec(Before);
  while (From<Before) and (Before<'!') do Dec(Before);
  SetLength(Result, Succ(Before-From));
  Move(From^, Pointer(Result)^, Length(Result));
end;

constructor TCSSParser.Create(S: string);
begin
  PInitial:=Pointer(S);
  PRun:=PInitial;
  PFinal:=PInitial+Length(S);
  Final:=False;
end;

function TCSSParser.Next: boolean;
var
  PLabel: PChar;
  PComment: PChar;

label
  Loop;

begin

  PLabel:=PRun;

  Result:=False;

  if (PRun=nil) or (PRun>PFinal) then Exit;

  Loop:

  case PRun^ of

     '{':
     begin
       FItem:=GetTrim(PLabel,PRun);
       FItemType:=itHead;
       Result:=True;
       Inc(PRun);
     end;

     ';':
     begin
       FItem:=GetTrim(PLabel,PRun);
       FItemType:=itSimple;
       Result:=True;
       Inc(PRun);
     end;

     '}':
     begin
       FItem:=GetTrim(PLabel,PRun);
       if FItem<>''
       then FItemType:=itLast
       else FItemType:=itEmptyLast;
       Result:=True;
       Inc(PRun);
     end;

     '/': if PRun[1]='*' then
          begin
            PComment:=PRun;
            Inc(PComment);
            repeat
              Inc(PComment)
            until (PComment[1]=#0) or ((PComment[-1]='*') and (PComment[0]='/'));
            FItem:=GetTrim(PRun, @PComment[1]);
            FItemType:=itComment;
            Result:=True;
            Inc(PComment);
            Move(PComment^, PRun^, Succ(PFinal-PComment));
            Dec(PFinal, PComment-PRun);
            PRun:=PLabel;
          end else
          begin
            Inc(PRun);
            goto Loop;
          end;

     '<': if (PRun[1]='!') and (PRun[2]='-') and (PRun[3]='-') then
          begin
            FItem:=GetTrim(PLabel,PRun);
            FItemType:=itSGMLComment;
            Result:=True;
            Inc(PRun,4);
          end else
          begin
            Inc(PRun);
            goto Loop;
          end;

     '-': if (PRun[1]='-') and (PRun[2]='>') then
          begin
            FItem:=GetTrim(PLabel,PRun);
            FItemType:=itSGMLComment;
            Result:=True;
            Inc(PRun,3);
          end else
          begin
            Inc(PRun);
            goto Loop;
          end;

      #0: if Final then Result:=False else
          begin
            FItem:=GetTrim(PLabel,PRun);
            if FItem=''
            then FItemType:=itEmptylast
            else FItemType:=itLast;
            Result:=True;
            Final:=True;
          end;

      else

        begin
          Inc(PRun);
          goto Loop;
        end;

  end;
end;

end.