~ubuntu-branches/ubuntu/gutsy/vnc4/gutsy

« back to all changes in this revision

Viewing changes to unix/xc/programs/xedit/lisp/modules/progmodes/c.lsp

  • Committer: Bazaar Package Importer
  • Author(s): Ola Lundqvist
  • Date: 2006-05-15 20:35:17 UTC
  • mfrom: (1.1.2 upstream)
  • Revision ID: james.westby@ubuntu.com-20060515203517-l4lre1ku942mn26k
Tags: 4.1.1+X4.3.0-10
* Correction of critical security issue. Thanks to Martin Kogler
  <e9925248@student.tuwien.ac.at> that informed me about the issue,
  and provided the patch.
  This flaw was originally found by Steve Wiseman of intelliadmin.com.
* Applied patch from Javier Kohen <jkohen@users.sourceforge.net> that
  inform the user that only 8 first characters of the password will
  actually be used when typing more than 8 characters, closes:
  #355619.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
;;
 
2
;; Copyright (c) 2002 by The XFree86 Project, Inc.
 
3
;;
 
4
;; Permission is hereby granted, free of charge, to any person obtaining a
 
5
;; copy of this software and associated documentation files (the "Software"),
 
6
;; to deal in the Software without restriction, including without limitation
 
7
;; the rights to use, copy, modify, merge, publish, distribute, sublicense,
 
8
;; and/or sell copies of the Software, and to permit persons to whom the
 
9
;; Software is furnished to do so, subject to the following conditions:
 
10
;;
 
11
;; The above copyright notice and this permission notice shall be included in
 
12
;; all copies or substantial portions of the Software.
 
13
;;
 
14
;; THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 
15
;; IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 
16
;; FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
 
17
;; THE XFREE86 PROJECT BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
 
18
;; WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF
 
19
;; OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 
20
;; SOFTWARE.
 
21
;;
 
22
;; Except as contained in this notice, the name of the XFree86 Project shall
 
23
;; not be used in advertising or otherwise to promote the sale, use or other
 
24
;; dealings in this Software without prior written authorization from the
 
25
;; XFree86 Project.
 
26
;;
 
27
;; Author: Paulo C�sar Pereira de Andrade
 
28
;;
 
29
;;
 
30
;; $XFree86: xc/programs/xedit/lisp/modules/progmodes/c.lsp,v 1.26 2003/01/29 03:05:54 paulo Exp $
 
31
;;
 
32
 
 
33
(require "syntax")
 
34
(require "indent")
 
35
(in-package "XEDIT")
 
36
 
 
37
(defsynprop *prop-format*
 
38
    "format"
 
39
    :font       "*lucidatypewriter-medium-r*12*"
 
40
    :foreground "RoyalBlue2"
 
41
    :underline  t
 
42
)
 
43
 
 
44
(defsynoptions *c-DEFAULT-style*
 
45
    ;; Positive number. Basic indentation.
 
46
    (:indentation               .       4)
 
47
 
 
48
    ;; Boolean. Support for GNU style indentation.
 
49
    (:brace-indent              .       nil)
 
50
 
 
51
    ;; Boolean. Add one indentation level to case and default?
 
52
    (:case-indent               .       t)
 
53
 
 
54
    ;; Boolean. Remove one indentation level for labels?
 
55
    (:label-dedent              .       t)
 
56
 
 
57
    ;; Boolean. Add one indentation level to continuations?
 
58
    (:cont-indent               .       t)
 
59
 
 
60
    ;; Boolean. Move cursor to the indent column after pressing <Enter>?
 
61
    (:newline-indent            .       t)
 
62
 
 
63
    ;; Boolean. Set to T if tabs shouldn't be used to fill indentation.
 
64
    (:emulate-tabs              .       nil)
 
65
 
 
66
    ;; Boolean. Force a newline before braces?
 
67
    (:newline-before-brace      .       nil)
 
68
 
 
69
    ;; Boolean. Force a newline after braces?
 
70
    (:newline-after-brace       .       nil)
 
71
 
 
72
    ;; Boolean. Force a newline after semicolons?
 
73
    (:newline-after-semi        .       nil)
 
74
 
 
75
    ;; Boolean. Only calculate indentation after pressing <Enter>?
 
76
    ;;          This may be useful if the parser does not always
 
77
    ;;          do what the user expects...
 
78
    (:only-newline-indent       .       nil)
 
79
 
 
80
    ;; Boolean. Remove extra spaces from previous line.
 
81
    ;;          This should default to T when newline-indent is not NIL.
 
82
    (:trim-blank-lines          .       t)
 
83
 
 
84
    ;; Boolean. If this hash-table entry is set, no indentation is done.
 
85
    ;;          Useful to temporarily disable indentation.
 
86
    (:disable-indent            .       nil)
 
87
)
 
88
 
 
89
;; BSD like style
 
90
(defsynoptions *c-BSD-style*
 
91
    (:indentation               .       8)
 
92
    (:brace-indent              .       nil)
 
93
    (:case-indent               .       nil)
 
94
    (:label-dedent              .       t)
 
95
    (:cont-indent               .       t)
 
96
    (:newline-indent            .       t)
 
97
    (:emulate-tabs              .       nil)
 
98
    (:newline-before-brace      .       nil)
 
99
    (:newline-after-brace       .       t)
 
100
    (:newline-after-semi        .       t)
 
101
    (:trim-blank-lines          .       t)
 
102
)
 
103
 
 
104
;; GNU like style
 
105
(defsynoptions *c-GNU-style*
 
106
    (:indentation               .       2)
 
107
    (:brace-indent              .       t)
 
108
    (:case-indent               .       nil)
 
109
    (:label-dedent              .       t)
 
110
    (:cont-indent               .       t)
 
111
    (:newline-indent            .       nil)
 
112
    (:emulate-tabs              .       nil)
 
113
    (:newline-before-brace      .       t)
 
114
    (:newline-after-brace       .       t)
 
115
    (:newline-after-semi        .       t)
 
116
    (:trim-blank-lines          .       nil)
 
117
)
 
118
 
 
119
;; K&R like style
 
120
(defsynoptions *c-K&R-style*
 
121
    (:indentation               .       5)
 
122
    (:brace-indent              .       nil)
 
123
    (:case-indent               .       nil)
 
124
    (:label-dedent              .       t)
 
125
    (:cont-indent               .       t)
 
126
    (:newline-indent            .       t)
 
127
    (:emulate-tabs              .       t)
 
128
    (:newline-before-brace      .       t)
 
129
    (:newline-after-brace       .       t)
 
130
    (:newline-after-semi        .       t)
 
131
    (:trim-blank-lines          .       t)
 
132
)
 
133
 
 
134
(defvar *c-styles* '(
 
135
    ("xedit"    .       *c-DEFAULT-style*)
 
136
    ("BSD"      .       *c-BSD-style*)
 
137
    ("GNU"      .       *c-GNU-style*)
 
138
    ("K&R"      .       *c-K&R-style*)
 
139
))
 
140
 
 
141
(defvar *c-mode-options* *c-DEFAULT-style*)
 
142
; (setq *c-mode-options* *c-gnu-style*)
 
143
 
 
144
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
145
;; This is a very lazy "pattern matcher" for the C language.
 
146
;; If the syntax in the code is not correct, it may get confused, and
 
147
;; because it is "lazy" some wrong constructs will be recognized as
 
148
;; correct when reducing patterns.
 
149
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
150
(defindent *c-mode-indent* :main
 
151
    ;; this must be the first token
 
152
    (indtoken "^\\s*"           :start-of-line)
 
153
    (indtoken "\\<case\\>"      :c-case)
 
154
    (indtoken "\\<default\\>"   :c-default)
 
155
    (indtoken "\\<do\\>"        :do)
 
156
    (indtoken "\\<if\\>"        :c-if)
 
157
    (indtoken "\\<else\\>"      :c-else)
 
158
    (indtoken "\\<for\\>"       :c-for)
 
159
    (indtoken "\\<switch\\>"    :c-switch)
 
160
    (indtoken "\\<while\\>"     :c-while)
 
161
    ;; Match identifiers and numbers as an expression
 
162
    (indtoken "\\w+"            :expression)
 
163
    (indtoken ";"               :semi           :nospec t)
 
164
    (indtoken ","               :comma          :nospec t)
 
165
    (indtoken ":"               :collon         :nospec t)
 
166
    ;;  Ignore spaces before collon, this avoids dedenting ternary
 
167
    ;; and bitfield definitions as the parser does not distinguish
 
168
    ;; labels from those, another option would be to use the pattern
 
169
    ;; "\\w+:", but this way should properly handle labels generated
 
170
    ;; by macros, example: `MACRO_LABEL(value):'
 
171
    (indtoken "\\s+:"           nil)
 
172
 
 
173
    (indinit                    (c-braces 0))
 
174
    (indtoken "{"
 
175
        :obrace
 
176
        :nospec t
 
177
        :code   (decf c-braces)
 
178
    )
 
179
    (indtoken "}"
 
180
        :cbrace
 
181
        :nospec t
 
182
        :begin  :braces
 
183
        :code   (incf c-braces)
 
184
    )
 
185
    (indtable :braces
 
186
        (indtoken "{"
 
187
            :obrace
 
188
            :nospec t
 
189
            :switch -1
 
190
            :code   (decf c-braces)
 
191
        )
 
192
        (indtoken "}"
 
193
            :cbrace
 
194
            :nospec t
 
195
            :begin  :braces
 
196
            :code   (incf c-braces)
 
197
        )
 
198
    )
 
199
 
 
200
    (indinit                    (c-bra 0))
 
201
    (indtoken ")"               :cparen         :nospec t :code (incf c-bra))
 
202
    (indtoken "("               :oparen         :nospec t :code (decf c-bra))
 
203
    (indtoken "]"               :cbrack         :nospec t :code (incf c-bra))
 
204
    (indtoken "["               :obrack         :nospec t :code (decf c-bra))
 
205
    (indtoken "\\\\$"           :continuation)
 
206
 
 
207
    ;; C++ style comment, disallow other tokens to match inside comment
 
208
    (indtoken "//.*$"           nil)
 
209
 
 
210
    (indtoken "#"               :hash           :nospec t)
 
211
 
 
212
    ;; if in the same line, reduce now, this must be done because the
 
213
    ;; delimiters are identical
 
214
    (indtoken "'([^\\']|\\\\.)*'"       :expression)
 
215
    (indtoken "\"([^\\\"]|\\\\.)*\""    :expression)
 
216
 
 
217
    (indtoken "\""              :cstring        :nospec t       :begin :string)
 
218
 
 
219
    (indtoken "'"               :cconstant      :nospec t       :begin :constant)
 
220
 
 
221
    (indtoken "*/"              :ccomment       :nospec t       :begin :comment)
 
222
    ;; this must be the last token
 
223
    (indtoken "$"               :end-of-line)
 
224
 
 
225
    (indtable :string
 
226
        ;; Ignore escaped characters
 
227
        (indtoken "\\."         nil)
 
228
        ;; Return to the toplevel when the start of the string is found
 
229
        (indtoken "\""          :ostring        :nospec t       :switch -1)
 
230
    )
 
231
    (indtable :constant
 
232
        ;; Ignore escaped characters
 
233
        (indtoken "\\."         nil)
 
234
        ;; Return to the toplevel when the start of the character is found
 
235
        (indtoken "'"           :oconstant      :nospec t       :switch -1)
 
236
    )
 
237
    (indtable :comment
 
238
        (indtoken "/*"          :ocomment       :nospec t       :switch -1)
 
239
    )
 
240
 
 
241
    ;; "Complex" statements
 
242
    (indinit            (c-complex 0) (c-cases 0))
 
243
 
 
244
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
245
    ;; Order of reduce rules here is important, process comment,
 
246
    ;; continuations, preprocessor and set states when an eol is found.
 
247
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
248
 
 
249
    (indinit    (c-offset (point-max))
 
250
                (c-prev-offset c-offset)
 
251
    )
 
252
    (indreduce :indent
 
253
        t
 
254
        ((:start-of-line))
 
255
        (and (= *ind-start* *ind-offset*)
 
256
            (setq
 
257
                *offset* (+ *ind-offset* *ind-length*)
 
258
            )
 
259
        )
 
260
        (setq
 
261
            c-prev-offset   c-offset
 
262
            c-offset        *ind-offset*
 
263
        )
 
264
    )
 
265
 
 
266
    ;; Delete comments
 
267
    (indreduce nil
 
268
        t
 
269
        ((:ocomment nil :ccomment))
 
270
    )
 
271
 
 
272
    ;; Join in a single token to simplify removal of possible multiline
 
273
    ;; preprocessor directives
 
274
    (indinit                    c-continuation)
 
275
    (indreduce :continuation
 
276
        t
 
277
        ((:continuation :end-of-line))
 
278
        (setq c-continuation t)
 
279
    )
 
280
 
 
281
    (indreduce :eol
 
282
        t
 
283
        ((:end-of-line))
 
284
        ;; Anything after the eol offset is safe to parse now
 
285
        (setq c-continuation nil)
 
286
    )
 
287
 
 
288
    ;; Delete blank lines
 
289
    (indreduce nil
 
290
        t
 
291
        ((:indent :eol))
 
292
    )
 
293
 
 
294
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
295
    ;; Preprocessor
 
296
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
297
    (indreduce nil
 
298
        (>= *ind-offset* *ind-start*)
 
299
        ((:indent :hash))
 
300
        (setq *indent* 0)
 
301
        (indent-macro-reject-left)
 
302
    )
 
303
    (indreduce nil
 
304
        t
 
305
        ((:indent :hash nil :eol))
 
306
    )
 
307
 
 
308
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
309
    ;; Expressions
 
310
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
311
    (indreduce :expression
 
312
        t
 
313
        ;; Reduce to a single expression
 
314
        ((:expression :parens)
 
315
         (:expression :bracks)
 
316
         (:expression :expression)
 
317
        ;; These may be multiline
 
318
         (:ostring (not :ostring) :cstring)
 
319
         (:oconstant (not :oconstant) :cconstant)
 
320
        )
 
321
    )
 
322
 
 
323
    (indreduce :expression
 
324
        t
 
325
        ((:expression :eol :indent :expression)
 
326
         (:expression :eol :expression)
 
327
        )
 
328
    )
 
329
 
 
330
    (indreduce :exp-comma
 
331
        t
 
332
        ((:expression :comma)
 
333
        )
 
334
    )
 
335
 
 
336
    ;; A semicollon, start a statement
 
337
    (indreduce :stat
 
338
        t
 
339
        ((:semi))
 
340
    )
 
341
 
 
342
    ;; Expression following (possibly empty) statement
 
343
    (indreduce :stat
 
344
        t
 
345
        (((or :expression :exp-comma) :stat))
 
346
    )
 
347
 
 
348
    ;; Multiline statements
 
349
    (indreduce :stat
 
350
        t
 
351
        (((or :expression :exp-comma) :eol :indent :stat)
 
352
         ;; rule below may have removed the :indent
 
353
         ((or :expression :exp-comma) :eol :stat)
 
354
        )
 
355
    )
 
356
 
 
357
    (indinit    c-exp-indent)
 
358
    ;; XXX This rule avoids parsing large amounts of code
 
359
    (indreduce :stat
 
360
        t
 
361
        ;; Eat eol if following expression
 
362
        ((:indent :stat :eol)
 
363
         (:indent :stat)
 
364
        )
 
365
        (if
 
366
            (or
 
367
                (null c-exp-indent)
 
368
                (/= (cdar c-exp-indent) (+ *ind-offset* *ind-length*))
 
369
            )
 
370
            ;; A new statement, i.e. not just joining a multiline one
 
371
            (push
 
372
                (cons
 
373
                    (offset-indentation *ind-offset* :resolve t)
 
374
                    (+ *ind-offset* *ind-length*)
 
375
                )
 
376
                c-exp-indent
 
377
            )
 
378
            ;; Update start of statement
 
379
            (rplaca
 
380
                (car c-exp-indent)
 
381
                (offset-indentation *ind-offset* :resolve t)
 
382
            )
 
383
        )
 
384
        (when (consp (cdr c-exp-indent))
 
385
            (if (and
 
386
                    (zerop c-complex)
 
387
                    (zerop c-cases)
 
388
                    (zerop c-bra)
 
389
                    (= (caar c-exp-indent) (caadr c-exp-indent))
 
390
                )
 
391
                ;; Two statements with the same indentation
 
392
                (progn
 
393
                    (setq *indent* (caar c-exp-indent))
 
394
                    (indent-macro-reject-left)
 
395
                )
 
396
                ;; Different indentation or complex state
 
397
                (progn
 
398
                    (rplacd c-exp-indent nil)
 
399
                    (setq c-complex 0)
 
400
                )
 
401
            )
 
402
        )
 
403
    )
 
404
 
 
405
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
406
    ;; Handle braces
 
407
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
408
    (indreduce :stat
 
409
        ;; If block finishes before current line, group as a statement
 
410
        (< (+ *ind-offset* *ind-length*) *ind-start*)
 
411
        ((:obrace (not :obrace) :cbrace))
 
412
    )
 
413
    (indreduce :obrace
 
414
        ;; If not in the first line
 
415
        (< *ind-offset* *ind-start*)
 
416
        ;; If the opening { is the first non blank char in the line
 
417
        ((:indent :obrace))
 
418
        (setq *indent* (offset-indentation (+ *ind-offset* *ind-length*)))
 
419
 
 
420
        ;; XXX This may be the starting brace of a switch
 
421
        (setq c-case-flag nil)
 
422
        (indent-macro-reject-left)
 
423
    )
 
424
 
 
425
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
426
    ;; Labels
 
427
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
428
    ;; XXX this frequently doesn't do what is expected, should redefine
 
429
    ;; some rules, as it frequently will dedent while typing something
 
430
    ;; like  test ? exp1 : exp2
 
431
    ;;                   ^ dedents here because it reduces everything
 
432
    ;;                     before ':' to a single :expression token.
 
433
    (indreduce :label
 
434
        t
 
435
        ((:indent :expression :collon :eol))
 
436
        (when (and *label-dedent* (>= *ind-offset* *ind-start*))
 
437
            (setq
 
438
                *indent*
 
439
                (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
 
440
            )
 
441
            (indent-macro-reject-left)
 
442
        )
 
443
    )
 
444
 
 
445
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
446
    ;; Handle if
 
447
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
448
    (indreduce :if
 
449
        t
 
450
        ((:c-if :parens)
 
451
        )
 
452
        (incf c-complex)
 
453
    )
 
454
 
 
455
    (indreduce :else
 
456
        t
 
457
        ((:c-else))
 
458
        (incf c-complex)
 
459
    )
 
460
 
 
461
    ;; Join
 
462
    (indreduce :else-if
 
463
        t
 
464
        ((:else :if)
 
465
         (:else :eol :indent :if)
 
466
        )
 
467
        (incf c-complex)
 
468
    )
 
469
 
 
470
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
471
    ;; Handle for
 
472
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
473
    ;; Join with the parentheses
 
474
    (indreduce :for
 
475
        t
 
476
        ((:c-for :parens)
 
477
        )
 
478
        (incf c-complex)
 
479
    )
 
480
    ;; Before current line, simplify
 
481
    (indreduce :stat
 
482
        (< (+ *ind-offset* *ind-length*) *ind-point*)
 
483
        ((:for :stat)
 
484
        )
 
485
    )
 
486
 
 
487
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
488
    ;; Handle while and do
 
489
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
490
    (indreduce :while
 
491
        t
 
492
        ((:c-while :parens)
 
493
         ;; Assume that it is yet being edited, or adjusting indentation
 
494
        (:c-while)
 
495
        )
 
496
        (incf c-complex)
 
497
    )
 
498
    (indreduce :stat
 
499
        t
 
500
        ((:do :stat :while)
 
501
         (:while :stat)
 
502
        )
 
503
    )
 
504
 
 
505
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
506
    ;; Handle switch
 
507
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
508
    (indinit                    c-case-flag)
 
509
 
 
510
    (indreduce :switch
 
511
        t
 
512
        ((:c-switch :parens)
 
513
        )
 
514
    )
 
515
    ;; Transform in a statement
 
516
    (indreduce :stat
 
517
        (< (+ *ind-offset* *ind-length*) *ind-start*)
 
518
        ((:switch :stat)
 
519
         ;; Do it now or some rule may stop parsing, and calculate
 
520
         ;; a wrong indentation for nested switches
 
521
         (:switch :eol :indent :stat)
 
522
        )
 
523
    )
 
524
    ;; An open switch
 
525
    (indreduce :obrace
 
526
        (and
 
527
            (<= c-braces 0)
 
528
            (> *ind-start* *ind-offset*)
 
529
        )
 
530
        ((:indent :switch :obrace)
 
531
        )
 
532
        (setq
 
533
            *indent* (offset-indentation *ind-offset* :resolve t)
 
534
            c-case-flag nil
 
535
        )
 
536
        (indent-macro-reject-left)
 
537
    )
 
538
    (indreduce :obrace
 
539
        (and
 
540
            (<= c-braces 0)
 
541
            (> *ind-start* *ind-offset*)
 
542
        )
 
543
        ((:indent :switch :eol :indent :obrace)
 
544
        )
 
545
        (setq
 
546
            *indent* (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
 
547
            c-case-flag nil
 
548
        )
 
549
        (and *brace-indent* (incf *indent* *base-indent*))
 
550
        (indent-macro-reject-left)
 
551
    )
 
552
    ;; Before current line
 
553
    (indreduce :case
 
554
        (and
 
555
            (or
 
556
                (not *case-indent*)
 
557
                (prog1 c-case-flag (setq c-case-flag t))
 
558
            )
 
559
            (<= c-braces 0)
 
560
            (< *ind-offset* *ind-start*)
 
561
        )
 
562
        ((:indent :case)
 
563
        )
 
564
        (setq
 
565
            *indent* (offset-indentation *ind-offset* :resolve t)
 
566
            c-case-flag nil
 
567
        )
 
568
        (indent-macro-reject-left)
 
569
    )
 
570
    (indreduce :case
 
571
        t
 
572
        ((:c-case :expression :collon)
 
573
         (:c-default :collon)
 
574
         ;; Assume that it is yet being edited, or adjusting indentation
 
575
         (:c-case)
 
576
         (:c-default)
 
577
        )
 
578
        (and (>= *ind-offset* *ind-start*)
 
579
            (incf c-cases)
 
580
        )
 
581
    )
 
582
 
 
583
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
584
    ;; Handle parentheses and brackets
 
585
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
586
    ;; Reduce matches
 
587
    (indreduce :parens
 
588
        t
 
589
        ((:oparen (not :oparen) :cparen))
 
590
        (when
 
591
            (and
 
592
                (< *ind-offset* *ind-start*)
 
593
                (> (+ *ind-offset* *ind-length*) *ind-start*)
 
594
            )
 
595
            (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
 
596
            (indent-macro-reject-left)
 
597
        )
 
598
    )
 
599
    (indreduce :bracks
 
600
        t
 
601
        ((:obrack (not :obrack) :cbrack))
 
602
        (when
 
603
            (and
 
604
                (< *ind-offset* *ind-start*)
 
605
                (> (+ *ind-offset* *ind-length*) *ind-start*)
 
606
            )
 
607
            (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
 
608
            (indent-macro-reject-left)
 
609
        )
 
610
    )
 
611
 
 
612
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
613
    ;; Assuming previous lines have correct indentation, this allows
 
614
    ;; resolving the indentation fastly
 
615
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
616
    ;; Line ended with an open brace
 
617
    (indreduce :obrace
 
618
        (< *ind-offset* *ind-start*)
 
619
        ((:indent (or :for :while :if :else-if :else :do) :obrace)
 
620
        )
 
621
        (setq *indent* (offset-indentation *ind-offset* :resolve t))
 
622
        (indent-macro-reject-left)
 
623
    )
 
624
    ;; Adjust indentation level if current line starts with an open brace
 
625
    (indreduce nil
 
626
        (< *ind-offset* *ind-start* (+ *ind-offset* *ind-length*))
 
627
         ;; Just set initial indentation
 
628
        ((:indent (or :for :while :if :else-if :else :do) :eol :indent :obrace)
 
629
        )
 
630
        (setq
 
631
            *indent*
 
632
            (- (offset-indentation *ind-offset* :resolve t) *base-indent*)
 
633
        )
 
634
        (and *brace-indent* (incf *indent* *base-indent*))
 
635
        (indent-macro-reject-left)
 
636
    )
 
637
    ;; Previous rule failed, current line does not start with an open brace
 
638
    (indreduce :flow
 
639
        ;; first statement is in current line
 
640
        (and
 
641
            (<= c-braces 0)
 
642
            (> (+ *ind-offset* *ind-length*) *ind-start* *ind-offset*)
 
643
        )
 
644
        ((:indent (or :for :while :if :else-if :else :do) :eol :indent)
 
645
        )
 
646
        (setq *indent* (offset-indentation *ind-offset* :resolve t))
 
647
        (indent-macro-reject-left)
 
648
    )
 
649
 
 
650
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
651
    ;; Simplify, remove old (:eol :indent)
 
652
    ;; This must be the last rule, to avoid not matching the
 
653
    ;; rules for fast calculation of indentation above
 
654
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
655
    (indreduce nil
 
656
        (> *ind-offset* c-prev-offset)
 
657
        ((:eol :indent))
 
658
    )
 
659
 
 
660
 
 
661
    (indinit                    (c-flow 0))
 
662
 
 
663
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
664
    ;; If
 
665
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
666
    (indinit                    c-if-flow)
 
667
    (indresolve :if
 
668
        (and (< *ind-offset* *ind-start*)
 
669
            (push c-flow c-if-flow)
 
670
            (incf *indent* *base-indent*)
 
671
            (incf c-flow)
 
672
        )
 
673
    )
 
674
    (indresolve (:else-if :else)
 
675
        (when c-if-flow
 
676
            (while (< c-flow (car c-if-flow))
 
677
                (incf *indent* *base-indent*)
 
678
                (incf c-flow)
 
679
            )
 
680
            (or (eq *ind-token* :else-if) (pop c-if-flow))
 
681
        )
 
682
        (and (< *ind-offset* *ind-start*)
 
683
            (incf *indent* *base-indent*)
 
684
            (incf c-flow)
 
685
        )
 
686
    )
 
687
 
 
688
 
 
689
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
690
    ;; For/while/do
 
691
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
692
    (indinit                    c-do-flow)
 
693
    (indresolve (:for :while :do)
 
694
        (if (eq *ind-token* :do)
 
695
            (and (< *ind-offset* *ind-start*) (push c-flow c-do-flow))
 
696
            (when (and c-do-flow (eq *ind-token* :while))
 
697
                (while (< c-flow (car c-do-flow))
 
698
                    (incf *indent* *base-indent*)
 
699
                    (incf c-flow)
 
700
                )
 
701
                (pop c-do-flow)
 
702
            )
 
703
        )
 
704
        (and (< *ind-offset* *ind-start*)
 
705
            (incf *indent* *base-indent*)
 
706
            (incf c-flow)
 
707
        )
 
708
    )
 
709
 
 
710
 
 
711
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
712
    ;; Switch
 
713
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
714
    (indresolve :switch
 
715
        (setq c-case-flag nil)
 
716
    )
 
717
    (indresolve (:case :c-case)
 
718
        (if (< *ind-offset* *ind-start*)
 
719
            (or c-case-flag
 
720
                (setq
 
721
                    *indent*
 
722
                    (+ (offset-indentation *ind-offset* :resolve t)
 
723
                        *base-indent*
 
724
                    )
 
725
                )
 
726
            )
 
727
            (if c-case-flag
 
728
                (and (= (decf c-cases) 0)
 
729
                    (decf *indent* *base-indent*)
 
730
                )
 
731
                (or *case-indent*
 
732
                    (decf *indent* *base-indent*)
 
733
                )
 
734
            )
 
735
        )
 
736
        (setq c-case-flag t)
 
737
    )
 
738
 
 
739
 
 
740
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
741
    ;; Braces/flow control
 
742
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
743
    (indresolve :flow
 
744
        (incf *indent* *base-indent*)
 
745
    )
 
746
    (indresolve :obrace
 
747
        (and (< *ind-offset* *ind-start*)
 
748
            (incf *indent* *base-indent*)
 
749
        )
 
750
    )
 
751
    (indresolve :cbrace
 
752
        (decf *indent* *base-indent*)
 
753
        (and *case-indent* c-case-flag
 
754
            (decf *indent* *base-indent*)
 
755
            (setq c-case-flag nil)
 
756
        )
 
757
        (and (not *offset*) (>= *ind-offset* *ind-start*)
 
758
            (setq *offset* *ind-offset*)
 
759
        )
 
760
    )
 
761
 
 
762
 
 
763
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
764
    ;; Statements
 
765
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
766
    (indresolve :stat
 
767
        (when (< *ind-offset* *ind-start*)
 
768
            (while (> c-flow 0)
 
769
                (setq
 
770
                    *indent*    (- *indent* *base-indent*)
 
771
                    c-flow      (1- c-flow)
 
772
                )
 
773
            )
 
774
        )
 
775
        (and
 
776
            *cont-indent*
 
777
            (< *ind-offset* *ind-start*)
 
778
            (> (+ *ind-offset* *ind-length*) *ind-start*)
 
779
            (incf *indent* *base-indent*)
 
780
        )
 
781
    )
 
782
 
 
783
    (indresolve :expression
 
784
        (and
 
785
            *cont-indent*
 
786
            (zerop c-bra)
 
787
            (> *indent* 0)
 
788
            (< *ind-offset* *ind-start*)
 
789
            (> (+ *ind-offset* *ind-length*) *ind-start*)
 
790
            (incf *indent* *base-indent*)
 
791
        )
 
792
    )
 
793
 
 
794
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
795
    ;; Open
 
796
    ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
797
    (indresolve (:oparen :obrack)
 
798
        (and (< *ind-offset* *ind-start*)
 
799
            (setq *indent* (1+ (offset-indentation *ind-offset* :align t)))
 
800
        )
 
801
    )
 
802
)
 
803
 
 
804
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
805
;; Find a "good" offset to start parsing backwards, so that it should
 
806
;; always generate the same results.
 
807
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
 
808
(defun c-offset-indent (&aux char (point (point)))
 
809
    ;; Skip spaces forward
 
810
    (while (member (setq char (char-after point)) indent-spaces)
 
811
        (incf point)
 
812
    )
 
813
    (or (characterp char) (return-from c-offset-indent point))
 
814
 
 
815
    ;;  Skip word chars
 
816
    (when (alphanumericp char)
 
817
        (while (and (setq char (char-after point)) (alphanumericp char))
 
818
            (incf point)
 
819
        )
 
820
        (or (characterp char) (return-from c-offset-indent point))
 
821
 
 
822
        ;; Skip spaces forward
 
823
        (while (member (setq char (char-after point)) indent-spaces)
 
824
            (incf point)
 
825
        )
 
826
        (or (characterp char) (return-from c-offset-indent point))
 
827
    )
 
828
 
 
829
    ;; don't include " or ' to avoid parsing strings "inverted"
 
830
    (if (member char '(#\Newline #\" #\')) point (1+ point))
 
831
)
 
832
(compile 'c-offset-indent)
 
833
 
 
834
(defun c-should-indent (options)
 
835
    (when (hash-table-p options)
 
836
        ;; check if previous line has extra spaces
 
837
        (and (gethash :trim-blank-lines options)
 
838
            (indent-clear-empty-line)
 
839
        )
 
840
 
 
841
        ;; indentation disabled?
 
842
        (and (gethash :disable-indent options)
 
843
            (return-from c-should-indent)
 
844
        )
 
845
 
 
846
        (let*
 
847
            (
 
848
            (point (point))
 
849
            (start (scan point :eol :left))
 
850
            (char (char-before point))
 
851
            offset
 
852
            match
 
853
            text
 
854
            )
 
855
 
 
856
            ;; at the start of an empty file
 
857
            (or (characterp char)
 
858
                (return-from c-should-indent)
 
859
            )
 
860
 
 
861
            ;; if at bol and should indent only when starting a line
 
862
            (and (gethash :only-newline-indent options)
 
863
                (return-from c-should-indent (= point start))
 
864
            )
 
865
 
 
866
            (and
 
867
                (char= char #\;)
 
868
                (gethash :newline-after-semi options)
 
869
                (return-from c-should-indent t)
 
870
            )
 
871
 
 
872
            ;; if one of these was typed, must check indentation
 
873
            (and (member char '(#\{ #\} #\: #\] #\) #\#))
 
874
                (return-from c-should-indent t)
 
875
            )
 
876
 
 
877
            ;; at the start of a line
 
878
            (and (= point start)
 
879
                (return-from c-should-indent (gethash :newline-indent options))
 
880
            )
 
881
 
 
882
            ;; if first character
 
883
            (and (= point (1+ start))
 
884
                (return-from c-should-indent t)
 
885
            )
 
886
 
 
887
            ;; check if is the first non-blank character in a new line
 
888
            (when
 
889
                (and
 
890
                    (gethash :cont-indent options)
 
891
                    (= point (scan point :eol :right))
 
892
                    (alphanumericp char)
 
893
                )
 
894
                (setq offset (1- point))
 
895
                (while
 
896
                    (and
 
897
                        (> offset start)
 
898
                        (member (char-before offset) indent-spaces)
 
899
                    )
 
900
                    (decf offset)
 
901
                )
 
902
                ;; line has only one character with possible spaces before it
 
903
                (and (<= offset start)
 
904
                    (return-from c-should-indent t)
 
905
                )
 
906
            )
 
907
 
 
908
            ;; check for keywords that change indentation
 
909
            (when (alphanumericp char)
 
910
                (setq offset (1- point))
 
911
                (while
 
912
                    (and
 
913
                        (alphanumericp (char-before offset))
 
914
                        (> offset start)
 
915
                    )
 
916
                    (decf offset)
 
917
                )
 
918
                (setq
 
919
                    text        (read-text offset (- point offset))
 
920
                    match       (re-exec #.(re-comp "(case|else|while)\\w?\\>")
 
921
                                    text)
 
922
                )
 
923
                (and
 
924
                    (consp match)
 
925
                    (return-from c-should-indent (<= (- (caar match) offset) 2))
 
926
                )
 
927
            )
 
928
        )
 
929
    )
 
930
    ;; Should not indent
 
931
    nil
 
932
)
 
933
(compile 'c-should-indent)
 
934
 
 
935
 
 
936
(defun c-indent-check (syntax syntable options
 
937
                       &aux start point char left brace change)
 
938
    (setq
 
939
        point   (point)
 
940
        char    (char-before point)
 
941
        left    point
 
942
        brace   (member char '(#\{ #\}))
 
943
    )
 
944
 
 
945
    (when
 
946
        (and brace (gethash :newline-before-brace options))
 
947
        (setq start (scan point :eol :left))
 
948
        (while
 
949
            (and
 
950
                (> (decf left) start)
 
951
                (member (char-before left) indent-spaces)
 
952
            )
 
953
            ;; skip blanks
 
954
        )
 
955
        (when (> left start)
 
956
            (replace-text left left (string #\Newline))
 
957
            (c-indent syntax syntable)
 
958
            (setq change t)
 
959
        )
 
960
    )
 
961
 
 
962
    (when
 
963
        (or
 
964
            (and brace (not change) (gethash :newline-after-brace options))
 
965
            (and (char= char #\;) (gethash :newline-after-semi options))
 
966
        )
 
967
        (setq left (point))
 
968
        (replace-text left left (string #\Newline))
 
969
        (goto-char (1+ left))
 
970
        (c-indent syntax syntable)
 
971
    )
 
972
)
 
973
 
 
974
(defun c-indent (syntax syntable)
 
975
    (let*
 
976
        (
 
977
        (options (syntax-options syntax))
 
978
        *base-indent*
 
979
        *brace-indent*
 
980
        *case-indent*
 
981
        *label-dedent*
 
982
        *cont-indent*
 
983
        )
 
984
 
 
985
        (or (c-should-indent options) (return-from c-indent))
 
986
 
 
987
        (setq
 
988
            *base-indent*       (gethash :indentation options 4)
 
989
            *brace-indent*      (gethash :brace-indent options nil)
 
990
            *case-indent*       (gethash :case-indent options t)
 
991
            *label-dedent*      (gethash :label-dedent options t)
 
992
            *cont-indent*       (gethash :cont-indent options t)
 
993
        )
 
994
 
 
995
        (indent-macro
 
996
            *c-mode-indent*
 
997
            (c-offset-indent)
 
998
            (gethash :emulate-tabs options)
 
999
        )
 
1000
 
 
1001
        (c-indent-check syntax syntable options)
 
1002
    )
 
1003
)
 
1004
(compile 'c-indent)
 
1005
 
 
1006
(defsyntax *c-mode* :main nil #'c-indent *c-mode-options*
 
1007
    ;;  All recognized C keywords.
 
1008
    (syntoken
 
1009
        (string-concat
 
1010
            "\\<("
 
1011
            "asm|auto|break|case|catch|char|class|const|continue|default|"
 
1012
            "delete|do|double|else|enum|extern|float|for|friend|goto|if|"
 
1013
            "inline|int|long|new|operator|private|protected|public|register|"
 
1014
            "return|short|signed|sizeof|static|struct|switch|template|this|"
 
1015
            "throw|try|typedef|union|unsigned|virtual|void|volatile|while"
 
1016
            ")\\>")
 
1017
        :property *prop-keyword*)
 
1018
 
 
1019
    ;; Numbers, this is optional, comment this rule if xedit is
 
1020
    ;; too slow to load c files.
 
1021
    (syntoken
 
1022
        (string-concat
 
1023
            "\\<("
 
1024
            ;; Integers
 
1025
            "(\\d+|0x\\x+)(u|ul|ull|l|ll|lu|llu)?|"
 
1026
            ;; Floats
 
1027
            "\\d+\\.?\\d*(e[+-]?\\d+)?[lf]?"
 
1028
            ")\\>")
 
1029
        :icase t
 
1030
        :property *prop-number*
 
1031
    )
 
1032
 
 
1033
    ;; String start rule.
 
1034
    (syntoken "\"" :nospec t :begin :string :contained t)
 
1035
 
 
1036
    ;; Character start rule.
 
1037
    (syntoken "'" :nospec t :begin :character :contained t)
 
1038
 
 
1039
    ;; Preprocessor start rule.
 
1040
    (syntoken "^\\s*#\\s*\\w+" :begin :preprocessor :contained t)
 
1041
 
 
1042
    ;; Comment start rule.
 
1043
    (syntoken "/*" :nospec t :begin :comment :contained t)
 
1044
 
 
1045
    ;; C++ style comments.
 
1046
    (syntoken "//.*" :property *prop-comment*)
 
1047
 
 
1048
    ;; Punctuation, this is also optional, comment this rule if xedit is
 
1049
    ;; too slow to load c files.
 
1050
    (syntoken "[][(){}/*+:;=<>,&.!%|^~?-][][(){}*+:;=<>,&.!%|^~?-]?"
 
1051
        :property *prop-punctuation*)
 
1052
 
 
1053
 
 
1054
    ;; Rules for comments.
 
1055
    (syntable :comment *prop-comment* #'default-indent
 
1056
        ;; Match nested comments as an error.
 
1057
        (syntoken "/*" :nospec t :property *prop-error*)
 
1058
 
 
1059
        (syntoken "XXX|TODO|FIXME" :property *prop-annotation*)
 
1060
 
 
1061
        ;;  Rule to finish a comment.
 
1062
        (syntoken "*/" :nospec t :switch -1)
 
1063
    )
 
1064
 
 
1065
    ;; Rules for strings.
 
1066
    (syntable :string *prop-string* #'default-indent
 
1067
        ;; Ignore escaped characters, this includes \".
 
1068
        (syntoken "\\\\.")
 
1069
 
 
1070
        ;; Match, most, printf arguments.
 
1071
        (syntoken "%%|%([+-]?\\d+)?(l?[deEfgiouxX]|[cdeEfgiopsuxX])"
 
1072
            :property *prop-format*)
 
1073
 
 
1074
        ;; Ignore continuation in the next line.
 
1075
        (syntoken "\\\\$")
 
1076
 
 
1077
        ;; Rule to finish a string.
 
1078
        (syntoken "\"" :nospec t :switch -1)
 
1079
 
 
1080
        ;; Don't allow strings continuing in the next line.
 
1081
        (syntoken ".?$" :begin :error)
 
1082
    )
 
1083
 
 
1084
    ;; Rules for characters.
 
1085
    (syntable :character *prop-constant* nil
 
1086
        ;; Ignore escaped characters, this includes \'.
 
1087
        (syntoken "\\\\.")
 
1088
 
 
1089
        ;; Ignore continuation in the next line.
 
1090
        (syntoken "\\\\$")
 
1091
 
 
1092
        ;; Rule to finish a character constant.
 
1093
        (syntoken "'" :nospec t :switch -1)
 
1094
 
 
1095
        ;; Don't allow constants continuing in the next line.
 
1096
        (syntoken ".?$" :begin :error)
 
1097
    )
 
1098
 
 
1099
    ;;  Rules for preprocessor.
 
1100
    (syntable :preprocessor *prop-preprocessor* #'default-indent
 
1101
        ;;  Preprocessor includes comments.
 
1102
        (syntoken "/*" :nospec t :begin :comment :contained t)
 
1103
 
 
1104
        ;;  Ignore lines finishing with a backslash.
 
1105
        (syntoken "\\\\$")
 
1106
 
 
1107
        ;; Return to previous state if end of line found.
 
1108
        (syntoken ".?$" :switch -1)
 
1109
    )
 
1110
 
 
1111
    (syntable :error *prop-error* nil
 
1112
        (syntoken "^.*$" :switch -2)
 
1113
    )
 
1114
 
 
1115
    ;;  You may also want to comment this rule if the parsing is
 
1116
    ;; noticeably slow.
 
1117
    (syntoken "\\c" :property *prop-control*)
 
1118
)