404

[ Avaa Bypassed ]




Upload:

Command:

botdev@18.191.233.167: ~ $
;;
;; Copyright (c) 2002 by The XFree86 Project, Inc.
;;
;; Permission is hereby granted, free of charge, to any person obtaining a
;; copy of this software and associated documentation files (the "Software"),
;; to deal in the Software without restriction, including without limitation
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
;; and/or sell copies of the Software, and to permit persons to whom the
;; Software is furnished to do so, subject to the following conditions:
;;
;; The above copyright notice and this permission notice shall be included in
;; all copies or substantial portions of the Software.
;;
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
;; THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
;; OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
;; SOFTWARE.
;;
;; Except as contained in this notice, the name of the XFree86 Project shall
;; not be used in advertising or otherwise to promote the sale, use or other
;; dealings in this Software without prior written authorization from the
;; XFree86 Project.
;;
;; Author: Paulo César Pereira de Andrade
;;
;;
;; $XFree86: xc/programs/xedit/lisp/modules/progmodes/c.lsp,v 1.27 2004/01/12 17:53:20 paulo Exp $
;;

(require "syntax")
(require "indent")
(in-package "XEDIT")

(defsynprop *prop-format*
    "format"
    :font	"*lucidatypewriter-medium-r*-12-*"
    :foreground	"RoyalBlue2"
    :underline	t
)

(defsynoptions *c-DEFAULT-style*
    ;; Positive number. Basic indentation.
    (:indentation		.	4)

    ;; Boolean. Support for GNU style indentation.
    (:brace-indent		.	nil)

    ;; Boolean. Add one indentation level to case and default?
    (:case-indent		.	t)

    ;; Boolean. Remove one indentation level for labels?
    (:label-dedent		.	t)

    ;; Boolean. Add one indentation level to continuations?
    (:cont-indent		.	t)

    ;; Boolean. Move cursor to the indent column after pressing <Enter>?
    (:newline-indent		.	t)

    ;; Boolean. Set to T if tabs shouldn't be used to fill indentation.
    (:emulate-tabs		.	nil)

    ;; Boolean. Force a newline before braces?
    (:newline-before-brace	.	nil)

    ;; Boolean. Force a newline after braces?
    (:newline-after-brace	.	nil)

    ;; Boolean. Force a newline after semicolons?
    (:newline-after-semi	.	nil)

    ;; Boolean. Only calculate indentation after pressing <Enter>?
    ;;		This may be useful if the parser does not always
    ;;		do what the user expects...
    (:only-newline-indent	.	nil)

    ;; Boolean. Remove extra spaces from previous line.
    ;;		This should default to T when newline-indent is not NIL.
    (:trim-blank-lines		.	t)

    ;; Boolean. If this hash-table entry is set, no indentation is done.
    ;;		Useful to temporarily disable indentation.
    (:disable-indent		.	nil)
)

;; BSD like style
(defsynoptions *c-BSD-style*
    (:indentation		.	8)
    (:brace-indent		.	nil)
    (:case-indent		.	nil)
    (:label-dedent		.	t)
    (:cont-indent		.	t)
    (:newline-indent		.	t)
    (:emulate-tabs		.	nil)
    (:newline-before-brace	.	nil)
    (:newline-after-brace	.	t)
    (:newline-after-semi	.	t)
    (:trim-blank-lines		.	t)
)

;; GNU like style
(defsynoptions *c-GNU-style*
    (:indentation		.	2)
    (:brace-indent		.	t)
    (:case-indent		.	nil)
    (:label-dedent		.	t)
    (:cont-indent		.	t)
    (:newline-indent		.	nil)
    (:emulate-tabs		.	nil)
    (:newline-before-brace	.	t)
    (:newline-after-brace	.	t)
    (:newline-after-semi	.	t)
    (:trim-blank-lines		.	nil)
)

;; K&R like style
(defsynoptions *c-K&R-style*
    (:indentation		.	5)
    (:brace-indent		.	nil)
    (:case-indent		.	nil)
    (:label-dedent		.	t)
    (:cont-indent		.	t)
    (:newline-indent		.	t)
    (:emulate-tabs		.	t)
    (:newline-before-brace	.	t)
    (:newline-after-brace	.	t)
    (:newline-after-semi	.	t)
    (:trim-blank-lines		.	t)
)

(defvar *c-styles* '(
    ("xedit"	.	*c-DEFAULT-style*)
    ("BSD"	.	*c-BSD-style*)
    ("GNU"	.	*c-GNU-style*)
    ("K&R"	.	*c-K&R-style*)
))

(defvar *c-mode-options* *c-DEFAULT-style*)
; (setq *c-mode-options* *c-gnu-style*)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; This is a very lazy "pattern matcher" for the C language.
;; If the syntax in the code is not correct, it may get confused, and
;; because it is "lazy" some wrong constructs will be recognized as
;; correct when reducing patterns.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defindent *c-mode-indent* :main
    ;; this must be the first token
    (indtoken "^\\s*"		:start-of-line)
    (indtoken "\\<case\\>"	:c-case)
    (indtoken "\\<default\\>"	:c-default)
    (indtoken "\\<do\\>"	:do)
    (indtoken "\\<if\\>"	:c-if)
    (indtoken "\\<else\\>"	:c-else)
    (indtoken "\\<for\\>"	:c-for)
    (indtoken "\\<switch\\>"	:c-switch)
    (indtoken "\\<while\\>"	:c-while)
    ;; Match identifiers and numbers as an expression
    (indtoken "\\w+"		:expression)
    (indtoken ";"		:semi		:nospec t)
    (indtoken ","		:comma		:nospec t)
    (indtoken ":"		:collon		:nospec t)
    ;;  Ignore spaces before collon, this avoids dedenting ternary
    ;; and bitfield definitions as the parser does not distinguish
    ;; labels from those, another option would be to use the pattern
    ;; "\\w+:", but this way should properly handle labels generated
    ;; by macros, example: `MACRO_LABEL(value):'
    (indtoken "\\s+:"		nil)

    (indinit			(c-braces 0))
    (indtoken "{"
	:obrace
	:nospec t
	:code	(decf c-braces)
    )
    (indtoken "}"
	:cbrace
	:nospec t
	:begin	:braces
	:code	(incf c-braces)
    )
    (indtable :braces
	(indtoken "{"
	    :obrace
	    :nospec t
	    :switch -1
	    :code   (decf c-braces)
	)
	(indtoken "}"
	    :cbrace
	    :nospec t
	    :begin  :braces
	    :code   (incf c-braces)
	)
    )

    (indinit			(c-bra 0))
    (indtoken ")"		:cparen		:nospec t :code (incf c-bra))
    (indtoken "("		:oparen		:nospec t :code (decf c-bra))
    (indtoken "]"		:cbrack		:nospec t :code (incf c-bra))
    (indtoken "["		:obrack		:nospec t :code (decf c-bra))
    (indtoken "\\\\$"		:continuation)

    ;; C++ style comment, disallow other tokens to match inside comment
    (indtoken "//.*$"		nil)

    (indtoken "#"		:hash		:nospec t)

    ;; if in the same line, reduce now, this must be done because the
    ;; delimiters are identical
    (indtoken "'([^\\']|\\\\.)*'"	:expression)
    (indtoken "\"([^\\\"]|\\\\.)*\""	:expression)

    (indtoken "\""		:cstring	:nospec t	:begin :string)

    (indtoken "'"		:cconstant	:nospec t	:begin :constant)

    (indtoken "*/"		:ccomment	:nospec t	:begin :comment)
    ;; this must be the last token
    (indtoken "$"		:end-of-line)

    (indtable :string
	;; Ignore escaped characters
	(indtoken "\\." 	nil)
	;; Return to the toplevel when the start of the string is found
	(indtoken "\""		:ostring	:nospec t	:switch -1)
    )
    (indtable :constant
	;; Ignore escaped characters
	(indtoken "\\." 	nil)
	;; Return to the toplevel when the start of the character is found
	(indtoken "'"		:oconstant	:nospec t	:switch -1)
    )
    (indtable :comment
	(indtoken "/*"		:ocomment	:nospec t	:switch -1)
    )

    ;; "Complex" statements
    (indinit		(c-complex 0) (c-cases 0))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Order of reduce rules here is important, process comment,
    ;; continuations, preprocessor and set states when an eol is found.
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

    (indinit	(c-offset (point-max))
		(c-prev-offset c-offset)
    )
    (indreduce :indent
	t
	((:start-of-line))
	(and (= *ind-start* *ind-offset*)
	    (setq
		*offset* (+ *ind-offset* *ind-length*)
	    )
	)
	(setq
	    c-prev-offset   c-offset
	    c-offset	    *ind-offset*
	)
    )

    ;; Delete comments
    (indreduce nil
	t
	((:ocomment nil :ccomment))
    )

    ;; Join in a single token to simplify removal of possible multiline
    ;; preprocessor directives
    (indinit			c-continuation)
    (indreduce :continuation
	t
	((:continuation :end-of-line))
	(setq c-continuation t)
    )

    (indreduce :eol
	t
	((:end-of-line))
	;; Anything after the eol offset is safe to parse now
	(setq c-continuation nil)
    )

    ;; Delete blank lines
    (indreduce nil
	t
	((:indent :eol))
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Preprocessor
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce nil
	(>= *ind-offset* *ind-start*)
	((:indent :hash))
	(setq *indent* 0)
	(indent-macro-reject-left)
    )
    (indreduce nil
	t
	((:indent :hash nil :eol))
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Expressions
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce :expression
	t
	;; Reduce to a single expression
	((:expression :parens)
	 (:expression :bracks)
	 (:expression :expression)
	;; These may be multiline
	 (:ostring (not :ostring) :cstring)
	 (:oconstant (not :oconstant) :cconstant)
	)
    )

    (indreduce :expression
	t
	((:expression :eol :indent :expression)
	 (:expression :eol :expression)
	)
    )

    (indreduce :exp-comma
	t
	((:expression :comma)
	)
    )

    ;; A semicollon, start a statement
    (indreduce :stat
	t
	((:semi))
    )

    ;; Expression following (possibly empty) statement
    (indreduce :stat
	t
	(((or :expression :exp-comma) :stat))
    )

    ;; Multiline statements
    (indreduce :stat
	t
	(((or :expression :exp-comma) :eol :indent :stat)
	 ;; rule below may have removed the :indent
	 ((or :expression :exp-comma) :eol :stat)
	)
    )

    (indinit	c-exp-indent)
    ;; XXX This rule avoids parsing large amounts of code
    (indreduce :stat
	t
	;; Eat eol if following expression
	((:indent :stat :eol)
	 (:indent :stat)
	)
	(if
	    (or
		(null c-exp-indent)
		(/= (cdar c-exp-indent) (+ *ind-offset* *ind-length*))
	    )
	    ;; A new statement, i.e. not just joining a multiline one
	    (push
		(cons
		    (offset-indentation *ind-offset* :resolve t)
		    (+ *ind-offset* *ind-length*)
		)
		c-exp-indent
	    )
	    ;; Update start of statement
	    (rplaca
		(car c-exp-indent)
		(offset-indentation *ind-offset* :resolve t)
	    )
	)
	(when (consp (cdr c-exp-indent))
	    (if (and
		    (zerop c-complex)
		    (zerop c-cases)
		    (zerop c-bra)
		    (= (caar c-exp-indent) (caadr c-exp-indent))
		)
		;; Two statements with the same indentation
		(progn
		    (setq *indent* (caar c-exp-indent))
		    (indent-macro-reject-left)
		)
		;; Different indentation or complex state
		(progn
		    (rplacd c-exp-indent nil)
		    (setq c-complex 0)
		)
	    )
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle braces
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce :stat
	;; If block finishes before current line, group as a statement
	(< (+ *ind-offset* *ind-length*) *ind-start*)
	((:obrace (not :obrace) :cbrace))
    )
    (indreduce :obrace
	;; If not in the first line
	(< *ind-offset* *ind-start*)
	;; If the opening { is the first non blank char in the line
	((:indent :obrace))
	(setq *indent* (offset-indentation (+ *ind-offset* *ind-length*)))

	;; XXX This may be the starting brace of a switch
	(setq c-case-flag nil)
	(indent-macro-reject-left)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Labels
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; XXX this frequently doesn't do what is expected, should redefine
    ;; some rules, as it frequently will dedent while typing something
    ;; like  test ? exp1 : exp2
    ;;                   ^ dedents here because it reduces everything
    ;;			   before ':' to a single :expression token.
    (indreduce :label
	t
	((:indent :expression :collon :eol))
	(when (and *label-dedent* (>= *ind-offset* *ind-start*))
	    (setq
		*indent*
		(- (offset-indentation *ind-offset* :resolve t) *base-indent*)
	    )
	    (indent-macro-reject-left)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle if
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce :if
	t
	((:c-if :parens)
	)
	(incf c-complex)
    )

    (indreduce :else
	t
	((:c-else))
	(incf c-complex)
    )

    ;; Join
    (indreduce :else-if
	t
	((:else :if)
	 (:else :eol :indent :if)
	)
	(incf c-complex)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle for
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Join with the parentheses
    (indreduce :for
	t
	((:c-for :parens)
	)
	(incf c-complex)
    )
    ;; Before current line, simplify
    (indreduce :stat
	(< (+ *ind-offset* *ind-length*) *ind-point*)
	((:for :stat)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle while and do
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce :while
	t
	((:c-while :parens)
	)
	(incf c-complex)
    )
    (indreduce :stat
	t
	((:do :stat :while)
	 (:while :stat)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle switch
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indinit			c-case-flag)

    (indreduce :switch
	t
	((:c-switch :parens)
	)
    )
    ;; Transform in a statement
    (indreduce :stat
	(< (+ *ind-offset* *ind-length*) *ind-start*)
	((:switch :stat)
	 ;; Do it now or some rule may stop parsing, and calculate
	 ;; a wrong indentation for nested switches
	 (:switch :eol :indent :stat)
	)
    )
    ;; An open switch
    (indreduce :obrace
	(and
	    (<= c-braces 0)
	    (> *ind-start* *ind-offset*)
	)
	((:indent :switch :obrace)
	)
	(setq
	    *indent* (offset-indentation *ind-offset* :resolve t)
	    c-case-flag nil
	)
	(indent-macro-reject-left)
    )
    (indreduce :obrace
	(and
	    (<= c-braces 0)
	    (> *ind-start* *ind-offset*)
	)
	((:indent :switch :eol :indent :obrace)
	)
	(setq
	    *indent* (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
	    c-case-flag nil
	)
	(and *brace-indent* (incf *indent* *base-indent*))
	(indent-macro-reject-left)
    )
    ;; Before current line
    (indreduce :case
	(and
	    (or
		(not *case-indent*)
		(prog1 c-case-flag (setq c-case-flag t))
	    )
	    (<= c-braces 0)
	    (< *ind-offset* *ind-start*)
	)
	((:indent :case)
	)
	(setq
	    *indent* (offset-indentation *ind-offset* :resolve t)
	    c-case-flag nil
	)
	(indent-macro-reject-left)
    )
    (indreduce :case
	t
	((:c-case :expression :collon)
	 (:c-default :collon)
	 ;; Assume that it is yet being edited, or adjusting indentation
	 (:c-case)
	 (:c-default)
	)
	(and (>= *ind-offset* *ind-start*)
	    (incf c-cases)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Handle parentheses and brackets
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Reduce matches
    (indreduce :parens
	t
	((:oparen (not :oparen) :cparen))
	(when
	    (and
		(< *ind-offset* *ind-start*)
		(> (+ *ind-offset* *ind-length*) *ind-start*)
	    )
	    (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
	    (indent-macro-reject-left)
	)
    )
    (indreduce :bracks
	t
	((:obrack (not :obrack) :cbrack))
	(when
	    (and
		(< *ind-offset* *ind-start*)
		(> (+ *ind-offset* *ind-length*) *ind-start*)
	    )
	    (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
	    (indent-macro-reject-left)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Assuming previous lines have correct indentation, this allows
    ;; resolving the indentation fastly
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Line ended with an open brace
    (indreduce :obrace
	(< *ind-offset* *ind-start*)
	((:indent (or :for :while :if :else-if :else :do) :obrace)
	)
	(setq *indent* (offset-indentation *ind-offset* :resolve t))
	(indent-macro-reject-left)
    )
    ;; Adjust indentation level if current line starts with an open brace
    (indreduce nil
	(< *ind-offset* *ind-start* (+ *ind-offset* *ind-length*))
	 ;; Just set initial indentation
	((:indent (or :for :while :if :else-if :else :do) :eol :indent :obrace)
	)
	(setq
	    *indent*
	    (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
	)
	(and *brace-indent* (incf *indent* *base-indent*))
	(indent-macro-reject-left)
    )
    ;; Previous rule failed, current line does not start with an open brace
    (indreduce :flow
	;; first statement is in current line
	(and
	    (<= c-braces 0)
	    (> (+ *ind-offset* *ind-length*) *ind-start* *ind-offset*)
	)
	((:indent (or :for :while :if :else-if :else :do) :eol :indent)
	)
	(setq *indent* (offset-indentation *ind-offset* :resolve t))
	(indent-macro-reject-left)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Simplify, remove old (:eol :indent)
    ;; This must be the last rule, to avoid not matching the
    ;; rules for fast calculation of indentation above
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indreduce nil
	(> *ind-offset* c-prev-offset)
	((:eol :indent))
    )


    (indinit			(c-flow 0))

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; If
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indinit			c-if-flow)
    (indresolve :if
	(and (< *ind-offset* *ind-start*)
	    (push c-flow c-if-flow)
	    (incf *indent* *base-indent*)
	    (incf c-flow)
	)
    )
    (indresolve (:else-if :else)
	(when c-if-flow
	    (while (< c-flow (car c-if-flow))
		(incf *indent* *base-indent*)
		(incf c-flow)
	    )
	    (or (eq *ind-token* :else-if) (pop c-if-flow))
	)
	(and (< *ind-offset* *ind-start*)
	    (incf *indent* *base-indent*)
	    (incf c-flow)
	)
    )


    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; For/while/do
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indinit			c-do-flow)
    (indresolve (:for :while :do)
	(if (eq *ind-token* :do)
	    (and (< *ind-offset* *ind-start*) (push c-flow c-do-flow))
	    (when (and c-do-flow (eq *ind-token* :while))
		(while (< c-flow (car c-do-flow))
		    (incf *indent* *base-indent*)
		    (incf c-flow)
		)
		(pop c-do-flow)
	    )
	)
	(and (< *ind-offset* *ind-start*)
	    (incf *indent* *base-indent*)
	    (incf c-flow)
	)
    )


    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Switch
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indresolve :switch
	(setq c-case-flag nil)
    )
    (indresolve (:case :c-case)
	(if (< *ind-offset* *ind-start*)
	    (or c-case-flag
		(setq
		    *indent*
		    (+ (offset-indentation *ind-offset* :resolve t)
			*base-indent*
		    )
		)
	    )
	    (if c-case-flag
		(and (= (decf c-cases) 0)
		    (decf *indent* *base-indent*)
		)
		(or *case-indent*
		    (decf *indent* *base-indent*)
		)
	    )
	)
	(setq c-case-flag t)
    )


    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Braces/flow control
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indresolve :flow
	(incf *indent* *base-indent*)
    )
    (indresolve :obrace
	(and (< *ind-offset* *ind-start*)
	    (incf *indent* *base-indent*)
	)
    )
    (indresolve :cbrace
	(decf *indent* *base-indent*)
	(and *case-indent* c-case-flag
	    (decf *indent* *base-indent*)
	    (setq c-case-flag nil)
	)
	(and (not *offset*) (>= *ind-offset* *ind-start*)
	    (setq *offset* *ind-offset*)
	)
    )


    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Statements
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indresolve :stat
	(when (< *ind-offset* *ind-start*)
	    (while (> c-flow 0)
		(setq
		    *indent*	(- *indent* *base-indent*)
		    c-flow	(1- c-flow)
		)
	    )
	)
	(and
	    *cont-indent*
	    (< *ind-offset* *ind-start*)
	    (> (+ *ind-offset* *ind-length*) *ind-start*)
	    (incf *indent* *base-indent*)
	)
    )

    (indresolve :expression
	(and
	    *cont-indent*
	    (zerop c-bra)
	    (> *indent* 0)
	    (< *ind-offset* *ind-start*)
	    (> (+ *ind-offset* *ind-length*) *ind-start*)
	    (incf *indent* *base-indent*)
	)
    )

    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    ;; Open
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    (indresolve (:oparen :obrack)
	(and (< *ind-offset* *ind-start*)
	    (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
	)
    )
)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Find a "good" offset to start parsing backwards, so that it should
;; always generate the same results.
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
(defun c-offset-indent (&aux char (point (point)))
    ;; Skip spaces forward
    (while (member (setq char (char-after point)) indent-spaces)
	(incf point)
    )
    (or (characterp char) (return-from c-offset-indent point))

    ;;	Skip word chars
    (when (alphanumericp char)
	(while (and (setq char (char-after point)) (alphanumericp char))
	    (incf point)
	)
	(or (characterp char) (return-from c-offset-indent point))

	;; Skip spaces forward
	(while (member (setq char (char-after point)) indent-spaces)
	    (incf point)
	)
	(or (characterp char) (return-from c-offset-indent point))
    )

    ;; don't include " or ' to avoid parsing strings "inverted"
    (if (member char '(#\Newline #\" #\')) point (1+ point))
)
(compile 'c-offset-indent)

(defun c-should-indent (options)
    (when (hash-table-p options)
	;; check if previous line has extra spaces
	(and (gethash :trim-blank-lines options)
	    (indent-clear-empty-line)
	)

	;; indentation disabled?
	(and (gethash :disable-indent options)
	    (return-from c-should-indent)
	)

	(let*
	    (
	    (point (point))
	    (start (scan point :eol :left))
	    (char (char-before point))
	    offset
	    match
	    text
	    )

	    ;; at the start of an empty file
	    (or (characterp char)
		(return-from c-should-indent)
	    )

	    ;; if at bol and should indent only when starting a line
	    (and (gethash :only-newline-indent options)
		(return-from c-should-indent (= point start))
	    )

	    (and
		(char= char #\;)
		(gethash :newline-after-semi options)
		(return-from c-should-indent t)
	    )

	    ;; if one of these was typed, must check indentation
	    (and (member char '(#\{ #\} #\: #\] #\) #\#))
		(return-from c-should-indent t)
	    )

	    ;; at the start of a line
	    (and (= point start)
		(return-from c-should-indent (gethash :newline-indent options))
	    )

	    ;; if first character
	    (and (= point (1+ start))
		(return-from c-should-indent t)
	    )

	    ;; check if is the first non-blank character in a new line
	    (when
		(and
		    (gethash :cont-indent options)
		    (= point (scan point :eol :right))
		    (alphanumericp char)
		)
		(setq offset (1- point))
		(while
		    (and
			(> offset start)
			(member (char-before offset) indent-spaces)
		    )
		    (decf offset)
		)
		;; line has only one character with possible spaces before it
		(and (<= offset start)
		    (return-from c-should-indent t)
		)
	    )

	    ;; check for keywords that change indentation
	    (when (alphanumericp char)
		(setq offset (1- point))
		(while
		    (and
			(alphanumericp (char-before offset))
			(> offset start)
		    )
		    (decf offset)
		)
		(setq
		    text	(read-text offset (- point offset))
		    match	(re-exec #.(re-comp "(case|else|while)\\w?\\>")
				    text)
		)
		(and
		    (consp match)
		    (return-from c-should-indent (<= (- (caar match) offset) 2))
		)
	    )
	)
    )
    ;; Should not indent
    nil
)
(compile 'c-should-indent)


(defun c-indent-check (syntax syntable options
		       &aux start point char left brace change)
    (setq
	point	(point)
	char	(char-before point)
	left	point
	brace	(member char '(#\{ #\}))
    )

    (when
	(and brace (gethash :newline-before-brace options))
	(setq start (scan point :eol :left))
	(while
	    (and
		(> (decf left) start)
		(member (char-before left) indent-spaces)
	    )
	    ;; skip blanks
	)
	(when (> left start)
	    (replace-text left left (string #\Newline))
	    (c-indent syntax syntable)
	    (setq change t)
	)
    )

    (when
	(or
	    (and brace (not change) (gethash :newline-after-brace options))
	    (and (char= char #\;) (gethash :newline-after-semi options))
	)
	(setq left (point))
	(replace-text left left (string #\Newline))
	(goto-char (1+ left))
	(c-indent syntax syntable)
    )
)

(defun c-indent (syntax syntable)
    (let*
	(
	(options (syntax-options syntax))
	*base-indent*
	*brace-indent*
	*case-indent*
	*label-dedent*
	*cont-indent*
	)

	(or (c-should-indent options) (return-from c-indent))

	(setq
	    *base-indent*	(gethash :indentation options 4)
	    *brace-indent*	(gethash :brace-indent options nil)
	    *case-indent*	(gethash :case-indent options t)
	    *label-dedent*	(gethash :label-dedent options t)
	    *cont-indent*	(gethash :cont-indent options t)
	)

	(indent-macro
	    *c-mode-indent*
	    (c-offset-indent)
	    (gethash :emulate-tabs options)
	)

	(c-indent-check syntax syntable options)
    )
)
(compile 'c-indent)

(defsyntax *c-mode* :main nil #'c-indent *c-mode-options*
    ;;  All recognized C keywords.
    (syntoken
	(string-concat
	    "\\<("
	    "asm|auto|break|case|catch|char|class|const|continue|default|"
	    "delete|do|double|else|enum|extern|float|for|friend|goto|if|"
	    "inline|int|long|new|operator|private|protected|public|register|"
	    "return|short|signed|sizeof|static|struct|switch|template|this|"
	    "throw|try|typedef|union|unsigned|virtual|void|volatile|while"
	    ")\\>")
	:property *prop-keyword*)

    ;; Numbers, this is optional, comment this rule if xedit is
    ;; too slow to load c files.
    (syntoken
	(string-concat
	    "\\<("
	    ;; Integers
	    "(\\d+|0x\\x+)(u|ul|ull|l|ll|lu|llu)?|"
	    ;; Floats
	    "\\d+\\.?\\d*(e[+-]?\\d+)?[lf]?"
	    ")\\>")
	:icase t
	:property *prop-number*
    )

    ;; String start rule.
    (syntoken "\"" :nospec t :begin :string :contained t)

    ;; Character start rule.
    (syntoken "'" :nospec t :begin :character :contained t)

    ;; Preprocessor start rule.
    (syntoken "^\\s*#\\s*\\w+" :begin :preprocessor :contained t)

    ;; Comment start rule.
    (syntoken "/*" :nospec t :begin :comment :contained t)

    ;; C++ style comments.
    (syntoken "//.*" :property *prop-comment*)

    ;; Punctuation, this is also optional, comment this rule if xedit is
    ;; too slow to load c files.
    (syntoken "[][(){}/*+:;=<>,&.!%|^~?-][][(){}*+:;=<>,&.!%|^~?-]?"
	:property *prop-punctuation*)


    ;; Rules for comments.
    (syntable :comment *prop-comment* #'default-indent
	;; Match nested comments as an error.
	(syntoken "/*" :nospec t :property *prop-error*)

	(syntoken "XXX|TODO|FIXME" :property *prop-annotation*)

	;;  Rule to finish a comment.
	(syntoken "*/" :nospec t :switch -1)
    )

    ;; Rules for strings.
    (syntable :string *prop-string* #'default-indent
	;; Ignore escaped characters, this includes \".
	(syntoken "\\\\.")

	;; Match, most, printf arguments.
	(syntoken "%%|%([+-]?\\d+)?(l?[deEfgiouxX]|[cdeEfgiopsuxX])"
	    :property *prop-format*)

	;; Ignore continuation in the next line.
	(syntoken "\\\\$")

	;; Rule to finish a string.
	(syntoken "\"" :nospec t :switch -1)

	;; Don't allow strings continuing in the next line.
	(syntoken ".?$" :begin :error)
    )

    ;; Rules for characters.
    (syntable :character *prop-constant* nil
	;; Ignore escaped characters, this includes \'.
	(syntoken "\\\\.")

	;; Ignore continuation in the next line.
	(syntoken "\\\\$")

	;; Rule to finish a character constant.
	(syntoken "'" :nospec t :switch -1)

	;; Don't allow constants continuing in the next line.
	(syntoken ".?$" :begin :error)
    )

    ;;  Rules for preprocessor.
    (syntable :preprocessor *prop-preprocessor* #'default-indent
	;;  Preprocessor includes comments.
	(syntoken "/*" :nospec t :begin :comment :contained t)

	;;  Ignore strings and constants in the same line and finishes table
	;; This is kind hackish, but must be done because the current parser
	;; will not flag eol. Maybe it could be extended to properly handle
	;; and have an internal flag to tell it to pass again if there
	;; is a regex that can match eol on an empty string.
	;;  A test is already done (but at compile time) to not allow patterns
	;; that match an empty string (but allow patterns matching
	;; bol, eol or both on an empty string).
	(syntoken "\"([^\\\"]|\\\\.)*\"$" :property *prop-string* :switch -1)
	(syntoken "'([^']|\\\\.)*'$" :property *prop-constant* :switch -1)

	;;  Ignore strings and constants in the same line
	(syntoken "\"([^\\\"]|\\\\.)*\"" :property *prop-string*)
	(syntoken "'([^']|\\\\.)*'" :property *prop-constant*)

	;;  Ignore lines finishing with a backslash.
	(syntoken "\\\\$")

	;; multiline strings
	(syntoken "\"" :nospec t :begin :string)

	;; multiline constants
	(syntoken "'" :nospec t :begin :character)

	;;  C++ style comments
	(syntoken "//.*$" :property *prop-comment* :switch -1)

	;; Return to previous state if end of line found.
	(syntoken ".?$" :switch -1)
    )

    (syntable :error *prop-error* nil
	(syntoken "^.*$" :switch -2)
    )

    ;;  You may also want to comment this rule if the parsing is
    ;; noticeably slow.
    (syntoken "\\c" :property *prop-control*)
)

Filemanager

Name Type Size Permission Actions
auto.lsp File 3.9 KB 0644
c.lsp File 29.39 KB 0644
html.lsp File 10.31 KB 0644
imake.lsp File 4.45 KB 0644
lisp.lsp File 11.32 KB 0644
make.lsp File 3.46 KB 0644
man.lsp File 4.04 KB 0644
patch.lsp File 2.16 KB 0644
perl.lsp File 16.8 KB 0644
python.lsp File 10.18 KB 0644
rpm.lsp File 5.53 KB 0644
sgml.lsp File 12.13 KB 0644
sh.lsp File 3.9 KB 0644
xconf.lsp File 2.39 KB 0644
xlog.lsp File 3.52 KB 0644
xrdb.lsp File 3.63 KB 0644