unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#11749: 24.1; C-mode indentation gives wrong-type-argument error.
@ 2012-06-19 20:45 Kim F. Storm
  2012-06-21  7:17 ` Glenn Morris
                   ` (5 more replies)
  0 siblings, 6 replies; 55+ messages in thread
From: Kim F. Storm @ 2012-06-19 20:45 UTC (permalink / raw)
  To: 11749


Every now and then, while editing some C files, indentation fails
with a wrong-type-argument number-or-marker-p error.

I have seen it happen when yanking text - but also just typing code
and all of a sudden it fails to indent after a {.

Here is the last incident:






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: 24.1; C-mode indentation gives wrong-type-argument error.
  2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
@ 2012-06-21  7:17 ` Glenn Morris
  2012-06-21  9:34   ` Kim Storm
  2012-08-28 16:17 ` bug#11749: 24.2; wrong-type-argument Kim F. Storm
                   ` (4 subsequent siblings)
  5 siblings, 1 reply; 55+ messages in thread
From: Glenn Morris @ 2012-06-21  7:17 UTC (permalink / raw)
  To: Kim F. Storm; +Cc: 11749

Kim F. Storm wrote:

> Here is the last incident:

At this point, the report ended... :)
Could you (re)send the details?
Does they resemble http://debbugs.gnu.org/9957 ?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: 24.1; C-mode indentation gives wrong-type-argument error.
  2012-06-21  7:17 ` Glenn Morris
@ 2012-06-21  9:34   ` Kim Storm
  0 siblings, 0 replies; 55+ messages in thread
From: Kim Storm @ 2012-06-21  9:34 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 11749

On 06/21/2012 09:17 AM, Glenn Morris wrote:
> Kim F. Storm wrote:
>
>> Here is the last incident:
> At this point, the report ended... :)
> Could you (re)send the details?
> Does they resemble http://debbugs.gnu.org/9957 ?
>
I no longer have the original message - but yes, from what I remeber, it 
resembles that other bug.
It was also related to indentation.  I'll send another backtrace next 
time it happens.

About the truncated mail:

I remember that while sending the mail, emacs barfed that there were NUL 
characters (or similar) in the message
and what I would like to do about it.  I hit the "d" option (delete 
non-printable characters and send the messsage).
Seems it removed a lot more than just non-printable characters (or is 
has a rather stupid interpretation of "non-printing").

Also the message log contains only the truncated message.

Still that's a different issue.

Kim








^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: 24.2; wrong-type-argument
  2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
  2012-06-21  7:17 ` Glenn Morris
@ 2012-08-28 16:17 ` Kim F. Storm
       [not found] ` <handler.11749.B.13401389485673.ack@debbugs.gnu.org>
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 55+ messages in thread
From: Kim F. Storm @ 2012-08-28 16:17 UTC (permalink / raw)
  To: 11749

[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #1: Type: text/plain, Size: 5756 bytes --]


Tried 24.2 RC2 - and once again I hit this annoying indentation bug i c mode:


In GNU Emacs 24.2.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.24.10)
 of 2012-08-24 on kfs-lx2
Windowing system distributor `The X.Org Foundation', version 11.0.11104000
Important settings:
  value of $LC_ALL: nil
  value of $LC_COLLATE: nil
  value of $LC_CTYPE: nil
  value of $LC_MESSAGES: nil
  value of $LC_MONETARY: en_DK.utf8
  value of $LC_NUMERIC: en_DK.utf8
  value of $LC_TIME: en_DK.utf8
  value of $LANG: en_US.utf8
  value of $XMODIFIERS: nil
  locale-coding-system: utf-8-unix
  default enable-multibyte-characters: t

Major mode: Debugger

Minor modes in effect:
  diff-auto-refine-mode: t
  shell-dirtrack-mode: t
  display-time-mode: t
  cua-mode: t
  ido-everywhere: t
  tooltip-mode: t
  mouse-wheel-mode: t
  tool-bar-mode: t
  menu-bar-mode: t
  file-name-shadow-mode: t
  global-font-lock-mode: t
  font-lock-mode: t
  blink-cursor-mode: t
  auto-composition-mode: t
  auto-encryption-mode: t
  auto-compression-mode: t
  line-number-mode: t
  transient-mark-mode: t

Recent input:
<right> <right> <right> <right> <right> <right> <right> 
<right> <right> <right> <right> <S-right> <S-right> 
o b j C-z <left> <left> <S-right> <S-right> <S-right> 
o b j M-v <right> <right> <right> <right> <right> <right> 
<right> <right> <right> <right> <right> <right> <right> 
<right> <right> <right> <right> <right> <left> <left> 
<delete> <delete> <delete> x t r M-v <backspace> <backspace> 
<backspace> <backspace> x x ½ <end> <down> <up> <up> 
<up> <up> <up> <up> <left> <C-left> <C-left> <left> 
1 <down> <left> 1 <down> <left> 1 <down> <left> <M-backspace> 
<C-right> 1 <C-right> <C-right> <up> <up> <C-left> 
M-d a c t <down> <left> <left> <left> M-d o b j <down> 
<backspace> <backspace> <backspace> x t r <right> <S-end> 
<S-left> <delete> <up> <up> <up> <C-left> <C-left> 
<C-left> <C-left> <C-left> <C-left> <C-return> <down> 
<down> <down> <right> <right> <right> <right> <right> 
<right> <left> <delete> <right> <right> <right> <right> 
<right> <delete> <down> <delete> <down> <delete> <down> 
<delete> <down> <down> <left> <S-end> <S-left> <delete> 
( x d o m SPC | SPC x a c t SPC ' <backspace> | SPC 
a x <backspace> o b j <backspace> <backspace> <backspace> 
<backspace> x o b j SPC | SPC x x t r ) SPC & S-SPC 
0 x 8 0 <home> <right> <right> <right> <right> <right> 
<right> <right> <right> <right> ( ! <end> ) <down> 
<down> <down> <left> SPC & & S-SPC <up> <up> <up> <C-left> 
<C-left> <C-left> <C-left> <C-right> <right> <right> 
<S-end> C-c <timeout> <down> <down> <down> <left> C-v 
<C-left> <right> <right> <delete> 1 <backspace> <right> 
1 <C-left> <C-left> <C-left> <C-left> <left> <left> 
<left> M-d <end> <backspace> <backspace> ) <up> <S-down> 
<S-down> <S-down> <S-down> <S-down> <S-down> C-c <timeout> 


Recent messages:
Mark set
Undo!
Mark set [4 times]
Auto-saving...done
Mark set [3 times]
Undo!
Mark set
Auto-saving...done
Mark set
Entering debugger...

Load-path shadows:
/home/kfs/emacs/common/emacs/user/kfs/nero hides /home/kfs/emacs/common/emacs/lisp/nero
/home/kfs/emacs/common/emacs/lisp/mwheel hides /home/kfs/Downloads/emacs-24.2/lisp/mwheel
/home/kfs/emacs/common/emacs/lisp/misc hides /home/kfs/Downloads/emacs-24.2/lisp/misc
/home/kfs/emacs/common/emacs/user/kfs/vcursor hides /home/kfs/Downloads/emacs-24.2/lisp/vcursor
/home/kfs/emacs/common/emacs/lisp/avoid hides /home/kfs/Downloads/emacs-24.2/lisp/avoid
/home/kfs/emacs/common/emacs/lisp/printing hides /home/kfs/Downloads/emacs-24.2/lisp/printing
/home/kfs/emacs/common/emacs/lisp/pong hides /home/kfs/Downloads/emacs-24.2/lisp/play/pong
/home/kfs/emacs/common/emacs/lisp/smtpmail hides /home/kfs/Downloads/emacs-24.2/lisp/mail/smtpmail

Features:
(shadow emacsbug message mml mml-sec mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047
rfc2045 ietf-drums mail-utils debug perl-mode make-mode conf-mode
jka-compr woman man skeleton tramp-cache tramp-sh tramp tramp-compat
auth-source eieio assoc gnus-util mm-util mail-prsvr password-cache
format-spec advice help-fns advice-preload tramp-loaddefs sh-script
executable help-mode view vc-annotate log-view vc-rcs js byte-opt
bytecomp byte-compile cconv macroexp json thingatpt newcomment
log-edit add-log diff-mode vc ediff-merg ediff-diff ediff-wind
ediff-help ediff-util ediff-mult ediff-init ediff vc-dispatcher
sgml-mode cua-gmrk cc-mode cc-fonts cc-guess cc-menus cc-cmds
find-dired grep-x grep compile pcmpl-unix shell pcomplete dabbrev
tabify cua-rect rect misearch multi-isearch parse-time vc-cvs pcvs
pcvs-parse pcvs-info pcvs-defs easy-mmode pcvs-util ewoc dired imenu
cgi-mode derived windmove kmacro paren keypad time cua-base cus-start
cus-load telnet mailcrypt rfc822 comint ansi-color ring easymenu make
begendol ido server cc-styles cc-align cc-engine cc-vars cc-defs
regexp-opt disp-table match aux-fct common printing ps-print ps-def
lpr time-date tooltip ediff-hook vc-hooks lisp-float-type mwheel x-win
x-dnd tool-bar dnd fontset image fringe lisp-mode register page
menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core frame cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer
loaddefs button faces cus-face files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget
hashtable-print-readable backquote make-network-process dbusbind
dynamic-setting system-font-setting font-render-setting move-toolbar
gtk x-toolkit x multi-tty emacs)


-- 
Kim F. Storm  <storm@cua.dk>      http://www.cua.dk






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
       [not found] ` <handler.11749.B.13401389485673.ack@debbugs.gnu.org>
@ 2012-08-28 22:49   ` Kim Storm
  2012-08-31 11:01     ` Eli Zaretskii
  2012-09-02 21:16     ` Alan Mackenzie
  0 siblings, 2 replies; 55+ messages in thread
From: Kim Storm @ 2012-08-28 22:49 UTC (permalink / raw)
  To: 11749

M-x report-emacs-bug obviously refuses to include any useful information 
-- so I send it through my Thunderbird client... this time.

Tried 24.2 RC2 - and once again I hit this annoying indentation bug i c 
mode:

Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p 
(5457 . 5720))
   c-guess-basic-syntax()
   c-indent-line()
   indent-according-to-mode()
   c-electric-paren(nil)
   call-interactively(c-electric-paren nil nil)

The offsets corresponds to a preceding { ... } block.

The code I was working on is the following (sorry, I cannot show more 
than that):

       if (!((xdom | xact | xobj | xxtr) & 0x80))
     continue;

       if (domains && !alldom && !((xdom | xobj | xxtr) & 0x01))
     {


I get a lot of errors -- making 24.2 impossible to work with for my C code.

Here are some more backtraces:

Debugger entered--Lisp error: (error "Invalid search bound (wrong side 
of point)")
   re-search-backward("^[     ]*:[     ]*\\(.\\)?" 5920 t)
   c-lineup-gcc-asm-reg((arglist-cont-nonempty . 5920))
   c-evaluate-offset(c-lineup-gcc-asm-reg (arglist-cont-nonempty 5920 
5950) arglist-cont-nonempty)
   c-evaluate-offset((c-lineup-gcc-asm-reg c-lineup-arglist) 
(arglist-cont-nonempty 5920 5950) arglist-cont-nonempty)
   c-calc-offset((arglist-cont-nonempty 5920 5950))
   c-get-syntactic-indentation(((arglist-cont-nonempty 5920 5950)))
   c-indent-line()
   indent-according-to-mode()
   c-electric-paren(nil)
   call-interactively(c-electric-paren nil nil)


Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p 
(5874 . 5881))
   c-guess-basic-syntax()
   c-indent-line()
   indent-according-to-mode()
   c-electric-paren(nil)
   call-interactively(c-electric-paren nil nil)

The last one came when I inserted the final ; in the last line of the 
following snippet:

static void add_hash_ext(idhash_t **hp, id_t *idtab, int n)
{

  }


   static idhash_t *lookup_ext(idhash_t **hp, );


Yes, there are syntax errors in that code -- but indentation should be 
able to
handle that without signalling errors all the time.



I have seen similar problems in 24.1 - but not in 23.4 that I usually
use (for this very reason).


If Emacs crashed, and you have the Emacs process in the gdb debugger,
please include the output from the following gdb commands:
     `bt full' and `xbacktrace'.
For information about debugging Emacs, please read the file
/home/kfs/Downloads/emacs-24.2/etc/DEBUG.


In GNU Emacs 24.2.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.24.10)
  of 2012-08-24 on kfs-lx2
Windowing system distributor `The X.Org Foundation', version 11.0.11104000
Important settings:
   value of $LC_ALL: nil
   value of $LC_COLLATE: nil
   value of $LC_CTYPE: nil
   value of $LC_MESSAGES: nil
   value of $LC_MONETARY: en_DK.utf8
   value of $LC_NUMERIC: en_DK.utf8
   value of $LC_TIME: en_DK.utf8
   value of $LANG: en_US.utf8
   value of $XMODIFIERS: nil
   locale-coding-system: utf-8-unix
   default enable-multibyte-characters: t

Major mode: Debugger

Minor modes in effect:
   diff-auto-refine-mode: t
   shell-dirtrack-mode: t
   display-time-mode: t
   cua-mode: t
   ido-everywhere: t
   tooltip-mode: t
   mouse-wheel-mode: t
   tool-bar-mode: t
   menu-bar-mode: t
   file-name-shadow-mode: t
   global-font-lock-mode: t
   font-lock-mode: t
   blink-cursor-mode: t
   auto-composition-mode: t
   auto-encryption-mode: t
   auto-compression-mode: t
   line-number-mode: t
   transient-mark-mode: t

Recent input:
<right> <right> <right> <right> <right> <right> <right>
<right> <right> <right> <right> <S-right> <S-right>
o b j C-z <left> <left> <S-right> <S-right> <S-right>
o b j M-v <right> <right> <right> <right> <right> <right>
<right> <right> <right> <right> <right> <right> <right>
<right> <right> <right> <right> <right> <left> <left>
<delete> <delete> <delete> x t r M-v <backspace> <backspace>
<backspace> <backspace> x x ½ <end> <down> <up> <up>
<up> <up> <up> <up> <left> <C-left> <C-left> <left>
1 <down> <left> 1 <down> <left> 1 <down> <left> <M-backspace>
<C-right> 1 <C-right> <C-right> <up> <up> <C-left>
M-d a c t <down> <left> <left> <left> M-d o b j <down>
<backspace> <backspace> <backspace> x t r <right> <S-end>
<S-left> <delete> <up> <up> <up> <C-left> <C-left>
<C-left> <C-left> <C-left> <C-left> <C-return> <down>
<down> <down> <right> <right> <right> <right> <right>
<right> <left> <delete> <right> <right> <right> <right>
<right> <delete> <down> <delete> <down> <delete> <down>
<delete> <down> <down> <left> <S-end> <S-left> <delete>
( x d o m SPC | SPC x a c t SPC ' <backspace> | SPC
a x <backspace> o b j <backspace> <backspace> <backspace>
<backspace> x o b j SPC | SPC x x t r ) SPC & S-SPC
0 x 8 0 <home> <right> <right> <right> <right> <right>
<right> <right> <right> <right> ( ! <end> ) <down>
<down> <down> <left> SPC & & S-SPC <up> <up> <up> <C-left>
<C-left> <C-left> <C-left> <C-right> <right> <right>
<S-end> C-c <timeout> <down> <down> <down> <left> C-v
<C-left> <right> <right> <delete> 1 <backspace> <right>
1 <C-left> <C-left> <C-left> <C-left> <left> <left>
<left> M-d <end> <backspace> <backspace> ) <up> <S-down>
<S-down> <S-down> <S-down> <S-down> <S-down> C-c <timeout>


Recent messages:
Mark set
Undo!
Mark set [4 times]
Auto-saving...done
Mark set [3 times]
Undo!
Mark set
Auto-saving...done
Mark set
Entering debugger...

Load-path shadows:
/home/kfs/emacs/common/emacs/user/kfs/nero hides 
/home/kfs/emacs/common/emacs/lisp/nero
/home/kfs/emacs/common/emacs/lisp/mwheel hides 
/home/kfs/Downloads/emacs-24.2/lisp/mwheel
/home/kfs/emacs/common/emacs/lisp/misc hides 
/home/kfs/Downloads/emacs-24.2/lisp/misc
/home/kfs/emacs/common/emacs/user/kfs/vcursor hides 
/home/kfs/Downloads/emacs-24.2/lisp/vcursor
/home/kfs/emacs/common/emacs/lisp/avoid hides 
/home/kfs/Downloads/emacs-24.2/lisp/avoid
/home/kfs/emacs/common/emacs/lisp/printing hides 
/home/kfs/Downloads/emacs-24.2/lisp/printing
/home/kfs/emacs/common/emacs/lisp/pong hides 
/home/kfs/Downloads/emacs-24.2/lisp/play/pong
/home/kfs/emacs/common/emacs/lisp/smtpmail hides 
/home/kfs/Downloads/emacs-24.2/lisp/mail/smtpmail

Features:
(shadow emacsbug message mml mml-sec mm-decode mm-bodies mm-encode
mail-parse rfc2231 mailabbrev gmm-utils mailheader sendmail rfc2047
rfc2045 ietf-drums mail-utils debug perl-mode make-mode conf-mode
jka-compr woman man skeleton tramp-cache tramp-sh tramp tramp-compat
auth-source eieio assoc gnus-util mm-util mail-prsvr password-cache
format-spec advice help-fns advice-preload tramp-loaddefs sh-script
executable help-mode view vc-annotate log-view vc-rcs js byte-opt
bytecomp byte-compile cconv macroexp json thingatpt newcomment
log-edit add-log diff-mode vc ediff-merg ediff-diff ediff-wind
ediff-help ediff-util ediff-mult ediff-init ediff vc-dispatcher
sgml-mode cua-gmrk cc-mode cc-fonts cc-guess cc-menus cc-cmds
find-dired grep-x grep compile pcmpl-unix shell pcomplete dabbrev
tabify cua-rect rect misearch multi-isearch parse-time vc-cvs pcvs
pcvs-parse pcvs-info pcvs-defs easy-mmode pcvs-util ewoc dired imenu
cgi-mode derived windmove kmacro paren keypad time cua-base cus-start
cus-load telnet mailcrypt rfc822 comint ansi-color ring easymenu make
begendol ido server cc-styles cc-align cc-engine cc-vars cc-defs
regexp-opt disp-table match aux-fct common printing ps-print ps-def
lpr time-date tooltip ediff-hook vc-hooks lisp-float-type mwheel x-win
x-dnd tool-bar dnd fontset image fringe lisp-mode register page
menu-bar rfn-eshadow timer select scroll-bar mouse jit-lock font-lock
syntax facemenu font-core frame cham georgian utf-8-lang misc-lang
vietnamese tibetan thai tai-viet lao korean japanese hebrew greek
romanian slovak czech european ethiopic indian cyrillic chinese
case-table epa-hook jka-cmpr-hook help simple abbrev minibuffer
loaddefs button faces cus-face files text-properties overlay sha1 md5
base64 format env code-pages mule custom widget
hashtable-print-readable backquote make-network-process dbusbind
dynamic-setting system-font-setting font-render-setting move-toolbar
gtk x-toolkit x multi-tty emacs)







^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-08-28 22:49   ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Kim Storm
@ 2012-08-31 11:01     ` Eli Zaretskii
  2012-08-31 12:37       ` Kim Storm
  2012-09-02 21:16     ` Alan Mackenzie
  1 sibling, 1 reply; 55+ messages in thread
From: Eli Zaretskii @ 2012-08-31 11:01 UTC (permalink / raw)
  To: Kim Storm; +Cc: 11749

> Date: Wed, 29 Aug 2012 00:49:53 +0200
> From: Kim Storm <storm@cua.dk>
> 
> M-x report-emacs-bug obviously refuses to include any useful information 

How does it refuse to do that?  Any error messages, or some other
hints?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-08-31 11:01     ` Eli Zaretskii
@ 2012-08-31 12:37       ` Kim Storm
  0 siblings, 0 replies; 55+ messages in thread
From: Kim Storm @ 2012-08-31 12:37 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 11749

On 2012-08-31 13:01, Eli Zaretskii wrote:
>> Date: Wed, 29 Aug 2012 00:49:53 +0200
>> From: Kim Storm<storm@cua.dk>
>>
>> M-x report-emacs-bug obviously refuses to include any useful information
> How does it refuse to do that?  Any error messages, or some other
> hints?
>
No, it sent the message, but the text I had pasted into the mail buffer 
had vanished
when I checked in debbugs. So fortunately I had saved a copy of the message
(based on previous experience *) so I could send it again.

*) The first time I sent that bug report emacs had removed the entire 
body (at that
time I was asked something about problems with the character set or 
something,
and I guess I said "go ahead").

Still the original problem makes 24.1 and 24.2 absolutely useless for me.
It works fine for some time -- and then suddenly it barfs about 
indentation all the time.
I know I should start from -Q etc. - but I need to get some work done ...

I really wonder why I'm the only one seeing this -- can my C style 
really be that different :-)

BTW - 23.4 has quite some display problems with Debian / Gnome - it 
leaves highlight artifacts
and missing screen updates when scrolling and when killing and inserting 
text
  ... those problems are still present in 24.2 ... and maybe they've 
gotten worse.

I remember having seen some bug reports about it, so I haven't bothered
reporting them -- but it happens "all the time".

Kim








^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-08-28 22:49   ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Kim Storm
  2012-08-31 11:01     ` Eli Zaretskii
@ 2012-09-02 21:16     ` Alan Mackenzie
  2012-09-03  9:47       ` Kim Storm
  1 sibling, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-09-02 21:16 UTC (permalink / raw)
  To: Kim Storm; +Cc: 11749

Hello, Kim.

On Wed, Aug 29, 2012 at 12:49:53AM +0200, Kim Storm wrote:
> M-x report-emacs-bug obviously refuses to include any useful information 
> -- so I send it through my Thunderbird client... this time.

> Tried 24.2 RC2 - and once again I hit this annoying indentation bug i c 
> mode:

> Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p 
> (5457 . 5720))
>    c-guess-basic-syntax()
>    c-indent-line()
>    indent-according-to-mode()
>    c-electric-paren(nil)
>    call-interactively(c-electric-paren nil nil)

> The offsets corresponds to a preceding { ... } block.

Yes.  It looks like the "state cache" (a cache of certain brace, paren
and bracket positions) has got corrupted.  This is difficult to make
repeatable, and is very dependent upon the exact navigation taken around
the C buffer.

> The code I was working on is the following (sorry, I cannot show more 
> than that):

>        if (!((xdom | xact | xobj | xxtr) & 0x80))
>      continue;

>        if (domains && !alldom && !((xdom | xobj | xxtr) & 0x01))
>      {


> I get a lot of errors -- making 24.2 impossible to work with for my C code.

> Here are some more backtraces:

> Debugger entered--Lisp error: (error "Invalid search bound (wrong side 
> of point)")
>    re-search-backward("^[     ]*:[     ]*\\(.\\)?" 5920 t)
>    c-lineup-gcc-asm-reg((arglist-cont-nonempty . 5920))
>    c-evaluate-offset(c-lineup-gcc-asm-reg (arglist-cont-nonempty 5920 
> 5950) arglist-cont-nonempty)
>    c-evaluate-offset((c-lineup-gcc-asm-reg c-lineup-arglist) 
> (arglist-cont-nonempty 5920 5950) arglist-cont-nonempty)
>    c-calc-offset((arglist-cont-nonempty 5920 5950))
>    c-get-syntactic-indentation(((arglist-cont-nonempty 5920 5950)))
>    c-indent-line()
>    indent-according-to-mode()
>    c-electric-paren(nil)
>    call-interactively(c-electric-paren nil nil)

That looks a bit like bug #10941, but isn't it.  It could be something
quite easy inside `c-lineup-gcc-asm-reg' (which I've not seen being used
before).  Is this an easily repeatable bug?  Any chance of a recipe?
Would you also dump your CC Mode configuration (C-c C-b) please.

> Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p 
> (5874 . 5881))
>    c-guess-basic-syntax()
>    c-indent-line()
>    indent-according-to-mode()
>    c-electric-paren(nil)
>    call-interactively(c-electric-paren nil nil)

> The last one came when I inserted the final ; in the last line of the 
> following snippet:

> static void add_hash_ext(idhash_t **hp, id_t *idtab, int n)
> {

>   }


>    static idhash_t *lookup_ext(idhash_t **hp, );

I've not been able to reproduce it in that limited context.  It looks
like another bug in the state cache, and they're bastards.

> Yes, there are syntax errors in that code -- but indentation should be 
> able to
> handle that without signalling errors all the time.

Yes.

> I have seen similar problems in 24.1 - but not in 23.4 that I usually
> use (for this very reason).

Might you have something unusual in your CC Mode config?

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-02 21:16     ` Alan Mackenzie
@ 2012-09-03  9:47       ` Kim Storm
  2012-09-03 13:56         ` Stefan Monnier
  2012-09-05 20:48         ` Alan Mackenzie
  0 siblings, 2 replies; 55+ messages in thread
From: Kim Storm @ 2012-09-03  9:47 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749

On 2012-09-02 23:16, Alan Mackenzie wrote:
> Yes. It looks like the "state cache" (a cache of certain brace, paren 
> and bracket positions) has got corrupted.
> This is difficult to make repeatable, and is very dependent upon the 
> exact navigation taken around the C buffer.
Well - my navigation triggers that bug a lot.


>> Debugger entered--Lisp error: (error "Invalid search bound (wrong side
>> of point)")
>>     re-search-backward("^[     ]*:[     ]*\\(.\\)?" 5920 t)
>>     c-lineup-gcc-asm-reg((arglist-cont-nonempty . 5920))
>>     c-evaluate-offset(c-lineup-gcc-asm-reg (arglist-cont-nonempty 5920
>> 5950) arglist-cont-nonempty)
>>     c-evaluate-offset((c-lineup-gcc-asm-reg c-lineup-arglist)
>> (arglist-cont-nonempty 5920 5950) arglist-cont-nonempty)
>>     c-calc-offset((arglist-cont-nonempty 5920 5950))
>>     c-get-syntactic-indentation(((arglist-cont-nonempty 5920 5950)))
>>     c-indent-line()
>>     indent-according-to-mode()
>>     c-electric-paren(nil)
>>     call-interactively(c-electric-paren nil nil)
> That looks a bit like bug #10941, but isn't it.  It could be something
> quite easy inside `c-lineup-gcc-asm-reg' (which I've not seen being used
> before).  Is this an easily repeatable bug?  Any chance of a recipe?
> Would you also dump your CC Mode configuration (C-c C-b) please.
I think I only saw this once - the other bug already happened, and I 
just started typing some random code snippets, and this bug happened.
>
>> Debugger entered--Lisp error: (wrong-type-argument integer-or-marker-p
>> (5874 . 5881))
>>     c-guess-basic-syntax()
>>     c-indent-line()
>>     indent-according-to-mode()
>>     c-electric-paren(nil)
>>     call-interactively(c-electric-paren nil nil)
>
> I've not been able to reproduce it in that limited context.  It looks
> like another bug in the state cache, and they're bastards.
Any way of clearing the cache?
>
> Might you have something unusual in your CC Mode config?
I have this:

(modify-syntax-entry ?_ "w" c-mode-syntax-table)

But otherwise, I don't seem to have any customizations ... only an 
awkward programming style :-)


_Subject: CC Mode 5.32.3 (C/l); emacs bug 11749

_ X-Reporter-Void-Vars-Found: auto-fill-mode (setq
c-basic-offset 2
c-comment-only-line-offset '(0 . 0)
c-indent-comment-alist '((anchored-comment column . 0) (end-block space 
. 1) (cpp-end-block space . 2))
c-indent-comments-syntactically-p nil
c-block-comment-prefix ""
c-comment-prefix-regexp '((pike-mode . "//+!?\\|\\**") (awk-mode . "#+") 
(other . "//+\\|\\**"))
c-doc-comment-style '((java-mode . javadoc) (pike-mode . autodoc) 
(c-mode . gtkdoc))
c-cleanup-list '(scope-operator)
c-hanging-braces-alist '((substatement-open before after) 
(arglist-cont-nonempty))
c-hanging-colons-alist nil
c-hanging-semi&comma-criteria '(c-semi&comma-inside-parenlist)
c-backslash-column 48
c-backslash-max-column 72
c-special-indent-hook '(c-gnu-impose-minimum)
c-label-minimum-indentation 1
c-offsets-alist '((inexpr-class . +)
(inexpr-statement . +)
(lambda-intro-cont . +)
(inlambda . c-lineup-inexpr-block)
(template-args-cont c-lineup-template-args +)
(incomposition . +)
(inmodule . +)
(innamespace . +)
(inextern-lang . +)
(composition-close . 0)
(module-close . 0)
(namespace-close . 0)
(extern-lang-close . 0)
(composition-open . 0)
(module-open . 0)
(namespace-open . 0)
(extern-lang-open . 0)
(objc-method-call-cont c-lineup-ObjC-method-call-colons 
c-lineup-ObjC-method-call +)
(objc-method-args-cont . c-lineup-ObjC-method-args)
(objc-method-intro . [0])
(friend . 0)
(cpp-define-intro c-lineup-cpp-define +)
(cpp-macro-cont . +)
(cpp-macro . [0])
(inclass . +)
(stream-op . c-lineup-streamop)
(arglist-cont-nonempty c-lineup-gcc-asm-reg c-lineup-arglist)
(arglist-cont c-lineup-gcc-asm-reg 0)
(comment-intro c-lineup-knr-region-comment c-lineup-comment)
(catch-clause . 0)
(else-clause . 0)
(do-while-closure . 0)
(access-label . -)
(case-label . 0)
(substatement . +)
(statement-case-intro . +)
(statement . 0)
(brace-entry-open . 0)
(brace-list-entry . 0)
(brace-list-intro . +)
(brace-list-close . 0)
(block-close . 0)
(block-open . 0)
(inher-cont . c-lineup-multi-inher)
(inher-intro . +)
(member-init-cont . c-lineup-multi-inher)
(member-init-intro . +)
(annotation-var-cont . +)
(annotation-top-cont . 0)
(topmost-intro . 0)
(knr-argdecl . 0)
(func-decl-cont . +)
(inline-close . 0)
(class-close . 0)
(class-open . 0)
(defun-block-intro . +)
(defun-close . 0)
(defun-open . 0)
(c . c-lineup-C-comments)
(string . c-lineup-dont-change)
(topmost-intro-cont first c-lineup-topmost-intro-cont 
c-lineup-gnu-DEFUN-intro-cont)
(brace-list-open . +)
(inline-open . 0)
(arglist-close . c-lineup-arglist)
(arglist-intro . c-lineup-arglist-intro-after-paren)
(statement-cont . +)
(statement-case-open . +)
(label . 0)
(substatement-label . 0)
(substatement-open . +)
(knr-argdecl-intro . 5)
(statement-block-intro . +)
)
c-buffer-is-cc-mode 'c-mode
c-tab-always-indent t
c-syntactic-indentation t
c-syntactic-indentation-in-macros t
c-ignore-auto-fill '(string cpp code)
c-auto-align-backslashes t
c-backspace-function 'backward-delete-char-untabify
c-delete-function 'delete-char
c-electric-pound-behavior nil
c-default-style '((java-mode . "java") (awk-mode . "awk") (other . "gnu"))
c-enable-xemacs-performance-kludge-p nil
c-old-style-variable-behavior nil
defun-prompt-regexp nil
tab-width 8
comment-column 32
parse-sexp-ignore-comments t
parse-sexp-lookup-properties t
auto-fill-function nil
comment-multi-line t
comment-start-skip "\\(//+\\|/\\*+\\)\\s *"
fill-prefix nil
fill-column 70
paragraph-start "[ ]*\\(//+\\|\\**\\)[ ]*$\\|^\f"
adaptive-fill-mode t
adaptive-fill-regexp "[ ]*\\(//+\\|\\**\\)[ ]*\\([ 
]*\\([-–!|#%;>*·•‣⁃◦]+[ ]*\\)*\\)"
)

Emacs : GNU Emacs 24.2.1 (x86_64-unknown-linux-gnu, GTK+ Version 2.24.10)
of 2012-08-24 on kfs-lx2
Package: CC Mode 5.32.3 (C/l)
Buffer Style: gnu
c-emacs-features: (pps-extended-state col-0-paren posix-char-classes 
gen-string-delim gen-comment-delim syntax-properties 1-bit)

current state:
==============






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-03  9:47       ` Kim Storm
@ 2012-09-03 13:56         ` Stefan Monnier
  2012-09-03 14:20           ` Kim Storm
  2012-09-05 20:48         ` Alan Mackenzie
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2012-09-03 13:56 UTC (permalink / raw)
  To: Kim Storm; +Cc: Alan Mackenzie, 11749

> I have this:
> (modify-syntax-entry ?_ "w" c-mode-syntax-table)

I don't know if it's the culprit, or if Alan considers this is a broken
config, but at least for the major modes I maintain, I consider this as
a broken config.


        Stefan





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-03 13:56         ` Stefan Monnier
@ 2012-09-03 14:20           ` Kim Storm
  2012-09-03 18:52             ` Stefan Monnier
  0 siblings, 1 reply; 55+ messages in thread
From: Kim Storm @ 2012-09-03 14:20 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Alan Mackenzie, 11749

On 2012-09-03 15:56, Stefan Monnier wrote:
>> I have this:
>> (modify-syntax-entry ?_ "w" c-mode-syntax-table)
> I don't know if it's the culprit, or if Alan considers this is a broken
> config, but at least for the major modes I maintain, I consider this as
> a broken config.
>
Still, it never caused any problems in emacs 23.

Kim





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-03 14:20           ` Kim Storm
@ 2012-09-03 18:52             ` Stefan Monnier
  0 siblings, 0 replies; 55+ messages in thread
From: Stefan Monnier @ 2012-09-03 18:52 UTC (permalink / raw)
  To: Kim Storm; +Cc: Alan Mackenzie, 11749

>>> I have this:
>>> (modify-syntax-entry ?_ "w" c-mode-syntax-table)
>> I don't know if it's the culprit, or if Alan considers this is a broken
>> config, but at least for the major modes I maintain, I consider this as
>> a broken config.
> Still, it never caused any problems in Emacs 23.

A broken config is not guaranteed to trigger problems ;-)
In any case, I do not know if it's the culprit (or even if Alan
considers it to be broken).  Still, I comment you try to remove it, to
see if it helps, and if it does, try to find some other way to get the
same result (e.g. using forward-symbol instead of forward-word).


        Stefan





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: I also have this issue
  2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
                   ` (2 preceding siblings ...)
       [not found] ` <handler.11749.B.13401389485673.ack@debbugs.gnu.org>
@ 2012-09-05 13:11 ` Denis Zalevskiy
  2013-01-08 19:10 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Glenn Morris
  2013-02-02 18:37 ` bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Alan Mackenzie
  5 siblings, 0 replies; 55+ messages in thread
From: Denis Zalevskiy @ 2012-09-05 13:11 UTC (permalink / raw)
  To: 11749

In GNU Emacs 24.1.1 (x86_64-redhat-linux-gnu, GTK+ Version 2.24.11)
 of 2012-08-13 on buildvm-11.phx2.fedoraproject.org

*Messages*
...
c-inside-bracelist-p: Wrong type argument: number-or-marker-p, (4212 . 4415)
...

it occurs sometimes. 

I think it has some relation to bug 4590. At least, symptoms are the same and 
4590 is reproducible on my debian installation with the same version of emacs.

In c++ I can use C-c C-s to see all the code now is topmost-intro (like in bug 
4590), here it just end up in error message pointed above.






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-03  9:47       ` Kim Storm
  2012-09-03 13:56         ` Stefan Monnier
@ 2012-09-05 20:48         ` Alan Mackenzie
  2012-09-07  3:45           ` Michael Welsh Duggan
  1 sibling, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-09-05 20:48 UTC (permalink / raw)
  To: Kim Storm; +Cc: 11749

Hello, Kim.

On Mon, Sep 03, 2012 at 11:47:00AM +0200, Kim Storm wrote:
> On 2012-09-02 23:16, Alan Mackenzie wrote:
> > Yes. It looks like the "state cache" (a cache of certain brace, paren 
> > and bracket positions) has got corrupted.
> > This is difficult to make repeatable, and is very dependent upon the 
> > exact navigation taken around the C buffer.
> Well - my navigation triggers that bug a lot.

It's strange that it doesn't seem to be happening much to other people.

[ .... ]

> > I've not been able to reproduce it in that limited context.  It looks
> > like another bug in the state cache, and they're bastards.
> Any way of clearing the cache?

M-: c-state-cache-init.  As a workaround, you could turn that into a
command and bind it to a spare C-c C-<letter>.

> > Might you have something unusual in your CC Mode config?
> I have this:

> (modify-syntax-entry ?_ "w" c-mode-syntax-table)

That shouldn't be causing the current problem.

> But otherwise, I don't seem to have any customizations ... only an 
> awkward programming style :-)

Thanks for the config!

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-05 20:48         ` Alan Mackenzie
@ 2012-09-07  3:45           ` Michael Welsh Duggan
  2012-09-07 14:53             ` Stefan Monnier
  2012-09-08 21:14             ` Alan Mackenzie
  0 siblings, 2 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-07  3:45 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Hello, Kim.
>
> On Mon, Sep 03, 2012 at 11:47:00AM +0200, Kim Storm wrote:
>> On 2012-09-02 23:16, Alan Mackenzie wrote:
>> > Yes. It looks like the "state cache" (a cache of certain brace, paren 
>> > and bracket positions) has got corrupted.
>> > This is difficult to make repeatable, and is very dependent upon the 
>> > exact navigation taken around the C buffer.
>> Well - my navigation triggers that bug a lot.
>
> It's strange that it doesn't seem to be happening much to other people.

It happens to me irregularly.  There is generally no way to re-create
it, so I've stopped reporting these.  I wish there were some way to
record all actions in c-mode buffers such that they could be saved and
re-played when this type of problem happens.  If there were some sort of
debug flag I could turn on, I would turn it on by default and hopefully
be able to catch some useful information.

-- 
Michael Welsh Duggan
(md5i@md5i.com)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-07  3:45           ` Michael Welsh Duggan
@ 2012-09-07 14:53             ` Stefan Monnier
  2012-09-07 16:16               ` Kim Storm
  2012-09-08 21:14             ` Alan Mackenzie
  1 sibling, 1 reply; 55+ messages in thread
From: Stefan Monnier @ 2012-09-07 14:53 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: Alan Mackenzie, 11749, Kim Storm

>>> > Yes. It looks like the "state cache" (a cache of certain brace, paren 
>>> > and bracket positions) has got corrupted.
>>> > This is difficult to make repeatable, and is very dependent upon the 
>>> > exact navigation taken around the C buffer.
>>> Well - my navigation triggers that bug a lot.
>> It's strange that it doesn't seem to be happening much to other people.
> It happens to me irregularly.  There is generally no way to re-create
> it, so I've stopped reporting these.  I wish there were some way to
> record all actions in c-mode buffers such that they could be saved and
> re-played when this type of problem happens.  If there were some sort of
> debug flag I could turn on, I would turn it on by default and hopefully
> be able to catch some useful information.

If the problem happens while browsing a file (i.e. without any
intervening buffer modifications), then a trace of calls to
font-lock-default-fontify-region (but only those in the affected buffer)
might do the trick.

This said, I'm wondering why cc-mode's cache of parsing state is
so fragile.


        Stefan





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-07 14:53             ` Stefan Monnier
@ 2012-09-07 16:16               ` Kim Storm
  0 siblings, 0 replies; 55+ messages in thread
From: Kim Storm @ 2012-09-07 16:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: Alan Mackenzie, 11749

On 2012-09-07 16:53, Stefan Monnier wrote:
> If the problem happens while browsing a file (i.e. without any
> intervening buffer modifications), then a trace of calls to
> font-lock-default-fontify-region (but only those in the affected buffer)
> might do the trick.
I have never seen it just by browsing a C file.

When I see it, I have made "a number of changes".

Maybe changes have to include kill&yanks.

As I said, it's hard to work with 24.x due to this bug, but I'll give it 
another try
now that I know how to clear the cache.

Kim





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-07  3:45           ` Michael Welsh Duggan
  2012-09-07 14:53             ` Stefan Monnier
@ 2012-09-08 21:14             ` Alan Mackenzie
  2012-09-10 12:18               ` Michael Welsh Duggan
  1 sibling, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-09-08 21:14 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749, Kim Storm

Hello again, Michael!

On Thu, Sep 06, 2012 at 11:45:48PM -0400, Michael Welsh Duggan wrote:
> Alan Mackenzie <acm@muc.de> writes:

> > Hello, Kim.

> > On Mon, Sep 03, 2012 at 11:47:00AM +0200, Kim Storm wrote:
> >> On 2012-09-02 23:16, Alan Mackenzie wrote:
> >> > Yes. It looks like the "state cache" (a cache of certain brace, paren 
> >> > and bracket positions) has got corrupted.
> >> > This is difficult to make repeatable, and is very dependent upon the 
> >> > exact navigation taken around the C buffer.
> >> Well - my navigation triggers that bug a lot.

> > It's strange that it doesn't seem to be happening much to other people.

> It happens to me irregularly.

Once a week?  Once a day?  Is it associated with buffer changes, or does
it just happen?

> There is generally no way to re-create it, so I've stopped reporting
> these.  I wish there were some way to record all actions in c-mode
> buffers such that they could be saved and re-played when this type of
> problem happens.  If there were some sort of debug flag I could turn
> on, I would turn it on by default and hopefully be able to catch some
> useful information.

M-x c-toggle-parse-state-debug

(or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
`c-debug-parse-state' is not buffer local.  I wrote this on 19th October
last year to help sort out the bug you reported a little earlier.  :-)

It works by calculating c-parse-state twice for each call - The first
time normally, then again with the internal state bound to "newly
initialised".  If the the two results differ, they are printed to
*Messages*, together with the saved previous state.  If this does
trigger, please note any recent buffer changes.  It may make editing
intolerably slow.

Kim, would you please try this out on a buffer you could actually send to
me.  Thanks!

> -- 
> Michael Welsh Duggan
> (md5i@md5i.com)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-08 21:14             ` Alan Mackenzie
@ 2012-09-10 12:18               ` Michael Welsh Duggan
  2012-09-10 12:48                 ` Michael Welsh Duggan
  2012-09-10 13:10                 ` Michael Welsh Duggan
  0 siblings, 2 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-10 12:18 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Hello again, Michael!
>
> On Thu, Sep 06, 2012 at 11:45:48PM -0400, Michael Welsh Duggan wrote:
>> Alan Mackenzie <acm@muc.de> writes:
>
>> > Hello, Kim.
>
>> > On Mon, Sep 03, 2012 at 11:47:00AM +0200, Kim Storm wrote:
>> >> On 2012-09-02 23:16, Alan Mackenzie wrote:
>> >> > Yes. It looks like the "state cache" (a cache of certain brace, paren 
>> >> > and bracket positions) has got corrupted.
>> >> > This is difficult to make repeatable, and is very dependent upon the 
>> >> > exact navigation taken around the C buffer.
>> >> Well - my navigation triggers that bug a lot.
>
>> > It's strange that it doesn't seem to be happening much to other people.
>
>> It happens to me irregularly.
>
> Once a week?  Once a day?  Is it associated with buffer changes, or does
> it just happen?

It happens when I'm editing C code.  I can't say once a week/day, etc.,
because I don't edit C code every day.  Most days I don't see it at all.
When it does happen, it is either extremely ephemeral (and goes away
immediately), or happens frequently in the same file, and I have to
reload the file completely just to get back to status quo.  It's very
hard to characterize.  (It used to happen a lot more often before you
fixed this in a few places.)

>> There is generally no way to re-create it, so I've stopped reporting
>> these.  I wish there were some way to record all actions in c-mode
>> buffers such that they could be saved and re-played when this type of
>> problem happens.  If there were some sort of debug flag I could turn
>> on, I would turn it on by default and hopefully be able to catch some
>> useful information.
>
> M-x c-toggle-parse-state-debug
>
> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
> last year to help sort out the bug you reported a little earlier.  :-)
>
> It works by calculating c-parse-state twice for each call - The first
> time normally, then again with the internal state bound to "newly
> initialised".  If the the two results differ, they are printed to
> *Messages*, together with the saved previous state.  If this does
> trigger, please note any recent buffer changes.  It may make editing
> intolerably slow.

I will turn this on.

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-10 12:18               ` Michael Welsh Duggan
@ 2012-09-10 12:48                 ` Michael Welsh Duggan
  2012-09-21 17:47                   ` Michael Welsh Duggan
  2012-09-10 13:10                 ` Michael Welsh Duggan
  1 sibling, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-10 12:48 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Kim Storm

Michael Welsh Duggan <mwd@cert.org> writes:

>>> There is generally no way to re-create it, so I've stopped reporting
>>> these.  I wish there were some way to record all actions in c-mode
>>> buffers such that they could be saved and re-played when this type of
>>> problem happens.  If there were some sort of debug flag I could turn
>>> on, I would turn it on by default and hopefully be able to catch some
>>> useful information.
>>
>> M-x c-toggle-parse-state-debug
>>
>> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
>> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
>> last year to help sort out the bug you reported a little earlier.  :-)
>>
>> It works by calculating c-parse-state twice for each call - The first
>> time normally, then again with the internal state bound to "newly
>> initialised".  If the the two results differ, they are printed to
>> *Messages*, together with the saved previous state.  If this does
>> trigger, please note any recent buffer changes.  It may make editing
>> intolerably slow.
>
> I will turn this on.

And I have already hit several warnings.  I noticed nothing when
editing.  The latest one seemed to happen when I was cut/pasting code
from one place to another.  Now that I noticed the problems, I can't
recreate them.  I will modify my sources to beep at me when the messages
come up again so I notice them more immediately.

c-parse-state inconsistency at 6033: using cache: (6031 (5900 . 6025) 5819 (5689 . 5767) 5456 2847 2824), from scratch: (6031 (5900 . 6025) 5819 (5689 . 5767) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6644 . 6646) 2847 2824)  c-state-cache-good-pos 6646  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5602)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6033: using cache: (6031 (5900 . 6025) 5819 (5689 . 5767) 5456 2847 2824), from scratch: (6031 (5900 . 6025) 5819 (5689 . 5767) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6031 (5900 . 6025) 5819 (5689 . 5767) 5456 2847 2824)  c-state-cache-good-pos 6032  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5602)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6044: using cache: (6042 (5911 . 6036) 5830 (5700 . 5778) 5456 2847 2824), from scratch: (6042 (5911 . 6036) 5830 (5700 . 5778) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6655 . 6657) 2847 2824)  c-state-cache-good-pos 6657  c-state-nonlit-pos-cache '(9001 6001 3001)  c-state-nonlit-pos-cache-limit 6001  c-state-brace-pair-desert '(2847 . 5582)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6044: using cache: (6042 (5911 . 6036) 5830 (5700 . 5778) 5456 2847 2824), from scratch: (6042 (5911 . 6036) 5830 (5700 . 5778) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6042 (5911 . 6036) 5830 (5700 . 5778) 5456 2847 2824)  c-state-cache-good-pos 6043  c-state-nonlit-pos-cache '(9001 6001 3001)  c-state-nonlit-pos-cache-limit 6001  c-state-brace-pair-desert '(2847 . 5582)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
Opening nnimap server on home...done
nnimap read 0k from localhost
No more unseen articles
No more unread articles
Mark set [5 times]
Undo! [12 times]
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6607 . 6609) 2847 2824)  c-state-cache-good-pos 6609  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6271: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6446: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6446: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6477  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6506: using cache: ((6257 . 6497) 5456 2847 2824), from scratch: ((6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6477  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6506: using cache: ((6257 . 6497) 5456 2847 2824), from scratch: ((6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6214: using cache: ((5759 . 6205) 5456 2847 2824), from scratch: ((5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6525: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6205  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6525: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6516 (6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6517: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6516 (6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6517  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6607 . 6609) 2847 2824)  c-state-cache-good-pos 6609  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6271: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6294: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6271: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6271: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6446: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6446: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6306: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6477: using cache: (6476 6257 (5759 . 6205) 5456 2847 2824), from scratch: (6476 6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6477  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6506: using cache: ((6257 . 6497) 5456 2847 2824), from scratch: ((6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6476 6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6477  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6506: using cache: ((6257 . 6497) 5456 2847 2824), from scratch: ((6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6214: using cache: ((5759 . 6205) 5456 2847 2824), from scratch: ((5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6525: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6205  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6525: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6516 (6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6497  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6517: using cache: (6516 (6257 . 6497) 5456 2847 2824), from scratch: (6516 (6257 . 6497) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6516 (6257 . 6497) 5456 2847 2824)  c-state-cache-good-pos 6517  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '((6607 . 6609) 2847 2824)  c-state-cache-good-pos 6676  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 6259: using cache: (6257 (5759 . 6205) 5456 2847 2824), from scratch: (6257 (5759 . 6205) 5456 (5210 . 5330) 2847 2824)
Old state:
(setq c-state-cache '(6257 (5759 . 6205) 5456 2847 2824)  c-state-cache-good-pos 6258  c-state-nonlit-pos-cache '(9010 6010 3001)  c-state-nonlit-pos-cache-limit 6010  c-state-brace-pair-desert '(2847 . 5546)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)


-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-10 12:18               ` Michael Welsh Duggan
  2012-09-10 12:48                 ` Michael Welsh Duggan
@ 2012-09-10 13:10                 ` Michael Welsh Duggan
  2012-09-10 13:22                   ` Michael Welsh Duggan
  1 sibling, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-10 13:10 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 2141 bytes --]

Michael Welsh Duggan <mwd@cert.org> writes:

>>> There is generally no way to re-create it, so I've stopped reporting
>>> these.  I wish there were some way to record all actions in c-mode
>>> buffers such that they could be saved and re-played when this type of
>>> problem happens.  If there were some sort of debug flag I could turn
>>> on, I would turn it on by default and hopefully be able to catch some
>>> useful information.
>>
>> M-x c-toggle-parse-state-debug
>>
>> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
>> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
>> last year to help sort out the bug you reported a little earlier.  :-)
>
> I will turn this on.

Okay, I have something repeatable.  This is with an older checkout
("109494 dmantipov@yandex.ru-20120807112841-k0pyiinoxi2llcmu"), so I'm
updating my sources to see if this holds in the current bzr.  In the
meantime, here's a recipe that works in the above version.

1) emacs -Q
2) C-x C-f <attached-file>
3) M-x c-toggle-parse-state-debug RET
4) C-v until you get a state inconsistency message (10 times for me)

c-parse-state inconsistency at 9942: using cache: (9866 9516 5134 5090), from scratch: (9866 9516 (7654 . 9439) 5134 5090)
Old state:
(setq c-state-cache '(9516 5134 5090)  c-state-cache-good-pos 10231  c-state-nonlit-pos-cache '(15063 12049 9049 6049 3049)  c-state-nonlit-pos-cache-limit 15063  c-state-brace-pair-desert '(9516 . 9818)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)
c-parse-state inconsistency at 9942: using cache: (9866 9516 5134 5090), from scratch: (9866 9516 (7654 . 9439) 5134 5090)
Old state:
(setq c-state-cache '(9866 9516 5134 5090)  c-state-cache-good-pos 9867  c-state-nonlit-pos-cache '(15063 12049 9049 6049 3049)  c-state-nonlit-pos-cache-limit 15063  c-state-brace-pair-desert '(9516 . 9818)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil)


[-- Attachment #2: conn_memory.lzz --]
[-- Type: text/plain, Size: 17995 bytes --]

/*
** Copyright (C) 2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

#hdr
#include <silk/silk.h>

RCSIDENTVAR(rcsID_CONN_MEMORY_H, "$Id$");

#include "connector.hh"
#end

#src
RCSIDENT("$Id$");

#include <silk/utils.h>

#ifdef SKCONNECTOR_TRACE_LEVEL
#define TRACEMSG_LEVEL SKCONNECTOR_TRACE_LEVEL
#endif
#define TRACEMSG(lvl, msg) TRACEMSG_TO_TRACEMSGLVL(lvl, msg)
#include <silk/sktracemsg.h>

/*
 *
 *    Tracing macros
 *
 */

/* Levels at which certain types of tracing are emitted */
#define FUNCTION_LEVEL 3        /* Main function tracing */
#define CHUNK_LEVEL    4        /* Chunk tracing */

/*
 *    TRACE_FUNC;
 *
 *    Emits a trace message for the containing function.  The pointer
 *    emitted is the connection object.
 */
#define TRACE_FUNC                                                      \
    TRACEMSG(FUNCTION_LEVEL, ("Function: (%p) %s", conn, __func__))


/*
 *    TRACE_MEM_CHUNK(chunk);
 *
 *    Emits trace info for a conn_mem_chunk_t data structure.
 */
#define TRACE_MEM_CHUNK(chunk)                                  \
    TRACEMSG(CHUNK_LEVEL,                                       \
             (("%s:%d Chunk: %p, writer_pos: %zd"               \
               "  reader_pos: %zd  max_reader_pos: %zd"),       \
              __FILE__, __LINE__,                               \
              chunk, chunk->writer_pos, chunk->reader_pos,      \
              chunk->max_reader_pos));


/* TYPEDEFS AND DEFINES */

/* minimum size we allow for a chunk is 4k */
#define CONN_MEM_MIN_CHUNK_SIZE     0x1000

/* standard chunk size is half a meg */
#define CONN_MEM_STD_CHUNK_SIZE     0x80000

/* standard number of chunks the connector norally has---used to
 * compute the maximum allocation */
#define CONN_MEM_STD_NUMBER_CHUNKS  3

/*
 *
 *    Macros common to all connectors
 *
 */

/* when the writer wraps, ensure this much space between the end of
 * the writer's block and the start of the reader's block */
#define WRAP_GAP  sizeof(uint64_t)

/* total space required for a block that holds 'bts_size' bytes of
 * memory in its 'data' member; includes the 'block_size' member and
 * ensures 'data' is 64-bit aligned */
#define BLOCK_TOTAL_SIZE(bts_size)                              \
    (((bts_size) + 2 * sizeof(uint64_t) - 1) & ~(UINT64_C(7)))

/* max size a caller may request; we require at least 3 blocks per
 * chunk; allow for overhead within the chunk */
#define BLOCK_MAX_SIZE_FROM_CHUNK_SIZE(bms_chunk_size)  \
    (((bms_chunk_size) - 4 * WRAP_GAP) / 3)

#end

namespace silk {

class MemoryConnector : public Connector
{
  private:
    struct conn_mem_chunk_t {
        /* pointer to the next chunk */
        conn_mem_chunk_t   *next;

        /* the data used for conn_block_t, which 'writer_pos' and
         * 'reader_pos' are offsets into */
        uint8_t            *blocks;

        /* offset to the location for the upstream writer */
        size_t              writer_pos;
        /* offset to the location for the downstream reader */
        size_t              reader_pos;

        /* total number of bytes in 'blocks'; this space includes blocks
         * the callers access and any overhead */
        size_t              capacity;

        /* last valid byte that can be read in 'blocks'; used to determine
         * when the reader_pos needs to be reset to 0 */
        size_t              max_reader_pos;
    };


  public:

    const char *get_type() const
    {
        return CONN_MEM_NAME;
    }

  private:

    static void setup_class();

    static void teardown_class(
        void *dummy);

    MemoryConnector();

    virtual ~MemoryConnector();

    conn_mem_chunk_t *chunk_alloc()
    {
        conn_mem_chunk_t *chunk;

        chunk = new conn_mem_chunk_t;
        chunk->blocks = new uint8_t[chunk_size];
        chunk->capacity = chunk_size;
        return chunk;
    }

    void chunk_free(
        conn_mem_chunk_t   *chunk)
    {
        if (chunk) {
            if (chunk->blocks) {
                delete[] chunk->blocks;
            }
            delete chunk;
        }
    }

    void chunk_pop()
    {
        conn_mem_chunk_t *chunk;

        assert(reader_chunk);
        assert(reader_chunk->next);

        if (!spare_chunk) {
            spare_chunk = reader_chunk;
            reader_chunk = reader_chunk->next;
        } else {
            chunk = reader_chunk;
            reader_chunk = reader_chunk->next;
            chunk_free(chunk);
        }
    }

    void chunk_push()
    {
        if (spare_chunk) {
            spare_chunk->next = NULL;
            spare_chunk->writer_pos = 0;
            spare_chunk->reader_pos = 0;
            spare_chunk->max_reader_pos = 0;
            writer_chunk->next = spare_chunk;
            writer_chunk = writer_chunk->next;
            spare_chunk = NULL;
        } else {
            writer_chunk->next = chunk_alloc();
            writer_chunk = writer_chunk->next;
        }
    }

    int _get_read_block(
        const conn_block_t    **reader_block,
        size_t                  size,
        bool                    no_wait)
    {
        conn_mem_chunk_t *chunk;

        assert(reader_block);
        assert(size);

        for (;;) {
            chunk = reader_chunk;
            if (chunk) {
                if (stopped) {
                    return -1;
                }

                if (chunk->reader_pos != chunk->writer_pos) {
                    if (chunk->max_reader_pos
                        && (chunk->reader_pos == chunk->max_reader_pos))
                    {
                        /* wrap the reader if the writer has wrapped */
                        chunk->reader_pos = 0;
                        chunk->max_reader_pos = 0;
                        continue;
                    }

                    /* there is data to return */
                    break;
                }
                /* else, there is no data in this block */
                if (chunk->next) {
                    /* I don't think this ever gets called, since we
                     * should have moved to the next block when the reader
                     * returned its previous block */

                    /* free this block and move to the next */
                    chunk_pop();
                    continue;
                }
            }
            /* else no data is available */

            /* check the stopping condition */
            if (stopped || no_more_data) {
                return -1;
            }

            /* wait for data unless no_wait was specified */
            empty = true;
            if (no_wait) {
                return 1;
            }
            pthread_cond_wait(&cond, &mutex);
        }

        TRACE_FUNC;

        /* we get here when there is data to return */
        *reader_block = (conn_block_t*)&chunk->blocks[chunk->reader_pos];
        return 0;
    }

    void _return_read_block(
        const conn_block_t *reader_block)
    {
        conn_mem_chunk_t *chunk;

        assert(reader_block);

        chunk = reader_chunk;
        assert(reader_block==(conn_block_t*)&chunk->blocks[chunk->reader_pos]);

        /* move to next reader position */
        chunk->reader_pos += BLOCK_TOTAL_SIZE(reader_block->block_size);
        if (chunk->reader_pos == chunk->max_reader_pos) {
            chunk->reader_pos = 0;
            chunk->max_reader_pos = 0;
        }
        TRACE_MEM_CHUNK(chunk);

        /* check whether we need to move to the next chunk */
        if (chunk->reader_pos == chunk->writer_pos
            && chunk->next)
        {
            /* free this block and move to the next */
            chunk_pop();
        }
    }

    int _get_write_block(
        const conn_block_t    **writer_block,
        size_t                  size,
        bool                    no_wait)
    {
        conn_mem_chunk_t *chunk;
        size_t required_size;

        assert(writer_block);
        assert(size);

        *writer_block = NULL;

        if (block_max_size < size) {
            throw sk_error_conn_block_size_too_large_t();
        }

        /* account for overhead */
        required_size = BLOCK_TOTAL_SIZE(size);

        /* loop until there is space available */
        for (;;) {
            /* handle stopped condition */
            if (stopped) {
                return -1;
            }

            if (total_used + size > max_allocation) {
                /* we are full; wait for space unless no_wait was
                 * specified */
                full = true;
                if (no_wait) {
                    return 1;
                }
                pthread_cond_wait(&cond, &mutex);
                continue;
            }

            chunk = writer_chunk;
            if (NULL == chunk) {
                /* create the initial chunk */
                chunk = writer_chunk = reader_chunk = chunk_alloc();
            }

            if (chunk->writer_pos < chunk->reader_pos) {
                /* the writer has wrapped; look for space between the
                 * writer_pos and the reader_pos */
                if ((chunk->reader_pos - chunk->writer_pos)
                    >= (required_size + WRAP_GAP))
                {
                    /* space is available */
                    break;
                }
            } else {
                if ((chunk->capacity - chunk->writer_pos) >= required_size) {
                    /* space is available at end of the buffer */
                    break;
                }
                /* else, see if space is available at the front */
                if (chunk->reader_pos >= required_size + WRAP_GAP) {
                    /* space is available; wrap around */
                    chunk->max_reader_pos = chunk->writer_pos;
                    chunk->writer_pos = 0;
                    TRACE_MEM_CHUNK(chunk);
                    break;
                }
            }

            /* space is not available; allocate new block */
            chunk_push();
        }

        TRACE_FUNC;

        /* when we get here, space is available */
        *writer_block = (conn_block_t*)&chunk->blocks[chunk->writer_pos];
        ((conn_block_t*)&chunk->blocks[chunk->writer_pos])->block_size
            = required_size - sizeof(uint64_t);

        return  0;
    }

    void _return_write_block(
        const conn_block_t *writer_block,
        size_t              size)
    {
        conn_mem_chunk_t *chunk;

        assert(writer_block);
        assert(size > 0);

        chunk = writer_chunk;
        assert(writer_block==(conn_block_t*)&chunk->blocks[chunk->writer_pos]);

        ((conn_block_t*)&chunk->blocks[chunk->writer_pos])->block_size = size;
        chunk->writer_pos += BLOCK_TOTAL_SIZE(size);
        TRACE_MEM_CHUNK(chunk);
    }

    void _set_param(
        const Definition& defn,
        const std::vector<std::string>& values) throw (Error)
    {
        uint64_t u64;
        int rv;

        switch (*(param_id_t *)(defn.get_context())) {
          case CONN_MEM_CHUNK_SIZE:
            rv = skStringParseUint64(&u64, values[0].c_str(), 0, 0);
            if (rv) {
                goto PARSE_ERROR;
            }
            chunk_size = u64;
            break;

          case CONN_MEM_MAX_ALLOCATION:
            rv = skStringParseUint64(&u64, values[0].c_str(), 0, 0);
            if (rv) {
                goto PARSE_ERROR;
            }
            max_allocation = u64;
            break;
        }
        return;

      PARSE_ERROR:
        std::ostringstream os;
        os << "Invalid " << defn.get_name() << " '" << values[0] << "': "
           << skStringParseStrerror(rv);
        throw sk_error_conn_param_value_t(os.str());
    }


    void _init()
    {
        if (chunk_size) {
            if (chunk_size < CONN_MEM_MIN_CHUNK_SIZE) {
                std::ostringstream os;
                os << "Specified chunk size is below minimum of "
                   << CONN_MEM_MIN_CHUNK_SIZE;
                throw sk_error_conn_param_value_t(os.str());
            }
            if (0 == max_allocation) {
                /* use caller's chunk size, and the default multiple of it
                 * for the maximum allocation */
                max_allocation = CONN_MEM_STD_NUMBER_CHUNKS * chunk_size;
            } else if (chunk_size > max_allocation) {
                /* chunk size is larger than max allocation */
                throw sk_error_conn_param_value_t(
                    ("Specified chunk size greater than"
                     " specified max allocation"));
            }
            /* else both values specified and are valid */
        } else if (max_allocation) {
            if (max_allocation < CONN_MEM_MIN_CHUNK_SIZE) {
                std::ostringstream os;
                os << "Specified max allocation is below minimum of "
                   << CONN_MEM_MIN_CHUNK_SIZE;
                throw sk_error_conn_param_value_t(os.str());
            }

            /* determine the chunk size */
            if (max_allocation >= CONN_MEM_STD_CHUNK_SIZE) {
                /* use standard chunk size */
                chunk_size = CONN_MEM_STD_CHUNK_SIZE;
            } else {
                chunk_size = (max_allocation / CONN_MEM_STD_NUMBER_CHUNKS);
                if (chunk_size < CONN_MEM_MIN_CHUNK_SIZE) {
                    chunk_size = CONN_MEM_MIN_CHUNK_SIZE;
                }
            }
        } else {
            /* use the default sizes */
            chunk_size = CONN_MEM_STD_CHUNK_SIZE;
            max_allocation = CONN_MEM_STD_NUMBER_CHUNKS * chunk_size;
        }

        block_max_size = BLOCK_MAX_SIZE_FROM_CHUNK_SIZE(chunk_size);

        initialized = true;
    }

    /* linked list of chunks of memory */
    conn_mem_chunk_t   *writer_chunk;
    conn_mem_chunk_t   *reader_chunk;
    conn_mem_chunk_t   *spare_chunk;

    /* size of an individual chunk of memory; may be specified by the
     * caller */
    size_t              chunk_size;

    /* maximum block size a module may request; calculated as
     * roughly 1/3 of the chunk_size */
    size_t              block_max_size;

    enum param_id_t {
        CONN_MEM_CHUNK_SIZE,
        CONN_MEM_MAX_ALLOCATION
    };

    struct class_params_t {
        const char    *key;
        int            val;
        const char    *desciption;
    };

    static MemoryConnector::class_params_t class_params[] = {
        {"chunk_size",     CONN_MEM_CHUNK_SIZE,
         "Size of an individual chunk of memory"},
        {"max_allocation", CONN_MEM_MAX_ALLOCATION,
         ("Maximum amount of memory that may be allocated across all blocks"
          " on all chunks; does not include internal overhead")},
        {0, 0, 0}          /* sentinel */
    };

#if 0
    static const std::set<Parameterized::Definition>& create_param_defs()
    {
        size_t i;
        std::set<Parameterized::Definition> defs;

        for (i = 0; class_params[i].key != NULL; ++i) {
            assert(i == (size_t)class_params[i].val);
            Parameterized::Definition d(class_params[i].key,
                                        class_params[i].desciption,
                                        (void*)&class_params[i].val, 1, 1);
            assert(defs.find(d) = defs.end());
            defs.insert(d);
        }
        return defs;
    }
#endif

};

}

/*
** Local Variables:
** mode:c++
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-10 13:10                 ` Michael Welsh Duggan
@ 2012-09-10 13:22                   ` Michael Welsh Duggan
  2012-09-10 18:25                     ` Michael Welsh Duggan
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-10 13:22 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Michael Welsh Duggan <mwd@cert.org> writes:

> Michael Welsh Duggan <mwd@cert.org> writes:
>
> Okay, I have something repeatable.  This is with an older checkout
> ("109494 dmantipov@yandex.ru-20120807112841-k0pyiinoxi2llcmu"), so I'm
> updating my sources to see if this holds in the current bzr.  

It indeed works in bzr version "109966
rgm@gnu.org-20120910101811-dxrpeq7h0vulwpr4", to which I have just
updated.

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-10 13:22                   ` Michael Welsh Duggan
@ 2012-09-10 18:25                     ` Michael Welsh Duggan
  0 siblings, 0 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-10 18:25 UTC (permalink / raw)
  To: Alan Mackenzie, Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Michael Welsh Duggan <mwd@cert.org> writes:

> Michael Welsh Duggan <mwd@cert.org> writes:
>
>> Michael Welsh Duggan <mwd@cert.org> writes:
>>
>> Okay, I have something repeatable.  This is with an older checkout
>> ("109494 dmantipov@yandex.ru-20120807112841-k0pyiinoxi2llcmu"), so I'm
>> updating my sources to see if this holds in the current bzr.  
>
> It indeed works in bzr version "109966
> rgm@gnu.org-20120910101811-dxrpeq7h0vulwpr4", to which I have just
> updated.

And by works, I mean the recipe works, and the warning is triggered.

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-10 12:48                 ` Michael Welsh Duggan
@ 2012-09-21 17:47                   ` Michael Welsh Duggan
  2012-10-07 10:59                     ` Alan Mackenzie
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-09-21 17:47 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Michael Welsh Duggan <mwd@cert.org> writes:

> Michael Welsh Duggan <mwd@cert.org> writes:
>
>>>> There is generally no way to re-create it, so I've stopped reporting
>>>> these.  I wish there were some way to record all actions in c-mode
>>>> buffers such that they could be saved and re-played when this type of
>>>> problem happens.  If there were some sort of debug flag I could turn
>>>> on, I would turn it on by default and hopefully be able to catch some
>>>> useful information.
>>>
>>> M-x c-toggle-parse-state-debug
>>>
>>> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
>>> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
>>> last year to help sort out the bug you reported a little earlier.  :-)
>>>
>>> It works by calculating c-parse-state twice for each call - The first
>>> time normally, then again with the internal state bound to "newly
>>> initialised".  If the the two results differ, they are printed to
>>> *Messages*, together with the saved previous state.  If this does
>>> trigger, please note any recent buffer changes.  It may make editing
>>> intolerably slow.
>>
>> I will turn this on.

I turned this on, and inserted a (ding) where cc-mode outputs an
inconsistency message.  I can barely stand to edit code now, due to
what seem to be almost every key press causing a beep.  Have you made
any progress here, or do you need more data?

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-09-21 17:47                   ` Michael Welsh Duggan
@ 2012-10-07 10:59                     ` Alan Mackenzie
  2012-10-09 14:05                       ` Michael Welsh Duggan
  0 siblings, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-10-07 10:59 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael.

On Fri, Sep 21, 2012 at 01:47:15PM -0400, Michael Welsh Duggan wrote:
> Michael Welsh Duggan <mwd@cert.org> writes:

> > Michael Welsh Duggan <mwd@cert.org> writes:

> >>>> There is generally no way to re-create it, so I've stopped reporting
> >>>> these.  I wish there were some way to record all actions in c-mode
> >>>> buffers such that they could be saved and re-played when this type of
> >>>> problem happens.  If there were some sort of debug flag I could turn
> >>>> on, I would turn it on by default and hopefully be able to catch some
> >>>> useful information.

> >>> M-x c-toggle-parse-state-debug

> >>> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
> >>> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
> >>> last year to help sort out the bug you reported a little earlier.  :-)

> >>> It works by calculating c-parse-state twice for each call - The first
> >>> time normally, then again with the internal state bound to "newly
> >>> initialised".  If the the two results differ, they are printed to
> >>> *Messages*, together with the saved previous state.  If this does
> >>> trigger, please note any recent buffer changes.  It may make editing
> >>> intolerably slow.

> >> I will turn this on.

> I turned this on, and inserted a (ding) where cc-mode outputs an
> inconsistency message.  I can barely stand to edit code now, due to
> what seem to be almost every key press causing a beep.  Have you made
> any progress here, or do you need more data?

I have found the bug which is causing (most of) these dings, though I
don't think it is the one which caused Kim's original bug.  Could you try
out the patch below, please.  (I have also enhanced/corrected the
debugging routines a bit, too.)



diff -r ac6584d14c06 cc-engine.el
--- a/cc-engine.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-engine.el	Sun Oct 07 10:54:51 2012 +0000
@@ -2648,17 +2648,19 @@
 	;; If we're essentially repeating a fruitless search, just give up.
 	(unless (and c-state-brace-pair-desert
 		     (eq cache-pos (car c-state-brace-pair-desert))
+		     (> from (car c-state-brace-pair-desert))
 		     (<= from (cdr c-state-brace-pair-desert)))
-	  ;; DESERT-LIM.  Only search what we absolutely need to,
+	  ;; DESERT-LIM.  Avoid repeated searching through the cached desert.
 	  (let ((desert-lim
 		 (and c-state-brace-pair-desert
 		      (eq cache-pos (car c-state-brace-pair-desert))
+		      (>= from (cdr c-state-brace-pair-desert))
 		      (cdr c-state-brace-pair-desert)))
 		;; CACHE-LIM.  This limit will be necessary when an opening
 		;; paren at `cache-pos' has just had its matching close paren
-		;; inserted.  `cache-pos' continues to be a search bound, even
-		;; though the algorithm below would skip over the new paren
-		;; pair.
+		;; inserted into the buffer.  `cache-pos' continues to be a
+		;; search bound, even though the algorithm below would skip
+		;; over the new paren pair.
 		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
 	    (narrow-to-region
 		(cond
@@ -3354,13 +3356,19 @@
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 
+(defvar c-parse-state-point nil)
 (defvar c-parse-state-state nil)
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
+  (setq c-parse-state-point (point))
   (setq c-parse-state-state
 	(mapcar
 	 (lambda (arg)
-	   (cons arg (symbol-value arg)))
+	   (let ((val (symbol-value arg)))
+	     (cons arg
+		   (if (consp val)
+		       (copy-tree val)
+		     val))))
 	 '(c-state-cache
 	   c-state-cache-good-pos
 	   c-state-nonlit-pos-cache
@@ -3373,7 +3381,8 @@
 	   c-state-point-min-lit-start
 	   c-state-min-scan-pos
 	   c-state-old-cpp-beg
-	   c-state-old-cpp-end))))
+	   c-state-old-cpp-end
+	   c-parse-state-point))))
 (defun c-replay-parse-state-state ()
   (message
    (concat "(setq "
@@ -3416,7 +3425,8 @@
       (message "Old state:")
       (c-replay-parse-state-state))
     (c-record-parse-state-state)
-    res1))
+    res2 ; res1 correct a cascading series of errors ASAP
+    ))
 
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")


> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-07 10:59                     ` Alan Mackenzie
@ 2012-10-09 14:05                       ` Michael Welsh Duggan
  2012-10-10 20:00                         ` Alan Mackenzie
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-10-09 14:05 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 2358 bytes --]

Alan Mackenzie <acm@muc.de> writes:

> Hi, Michael.
>
> On Fri, Sep 21, 2012 at 01:47:15PM -0400, Michael Welsh Duggan wrote:
>> Michael Welsh Duggan <mwd@cert.org> writes:
>
>> > Michael Welsh Duggan <mwd@cert.org> writes:
>
>> >>>> There is generally no way to re-create it, so I've stopped reporting
>> >>>> these.  I wish there were some way to record all actions in c-mode
>> >>>> buffers such that they could be saved and re-played when this type of
>> >>>> problem happens.  If there were some sort of debug flag I could turn
>> >>>> on, I would turn it on by default and hopefully be able to catch some
>> >>>> useful information.
>
>> >>> M-x c-toggle-parse-state-debug
>
>> >>> (or (c-toggle-parse-state-debug 1) in your .emacs).  Warning: variable
>> >>> `c-debug-parse-state' is not buffer local.  I wrote this on 19th October
>> >>> last year to help sort out the bug you reported a little earlier.  :-)
>
>> >>> It works by calculating c-parse-state twice for each call - The first
>> >>> time normally, then again with the internal state bound to "newly
>> >>> initialised".  If the the two results differ, they are printed to
>> >>> *Messages*, together with the saved previous state.  If this does
>> >>> trigger, please note any recent buffer changes.  It may make editing
>> >>> intolerably slow.
>
>> >> I will turn this on.
>
>> I turned this on, and inserted a (ding) where cc-mode outputs an
>> inconsistency message.  I can barely stand to edit code now, due to
>> what seem to be almost every key press causing a beep.  Have you made
>> any progress here, or do you need more data?
>
> I have found the bug which is causing (most of) these dings, though I
> don't think it is the one which caused Kim's original bug.  Could you try
> out the patch below, please.  (I have also enhanced/corrected the
> debugging routines a bit, too.)

Still doesn't seem to help much here.  I have attached a file which
reliably causes a cache failure.  I have attached the smallest file of
the set of files I am working on that causes this particular problem.
Load the attached file and toggle on parse state debugging.  Then scroll
to the bottom of the file.  (Use C-v multiple times, or just M->.)  One
reason I have attached this file is that it only triggers the warning
message once.  Most of my larger files cause this to happen quite a lot.


[-- Attachment #2: mod_fan_in.lzz --]
[-- Type: text/plain, Size: 11027 bytes --]

/*
** Copyright (C) 2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  mod_fan_in.lzz
**
**    Implementation of the "Fan-In" module.
**
**    The Fan-In module copies blocks of data from a user-specified
**    number of inputs to one output.
**
*/

#hdr
#include <silk/silk.h>

RCSIDENTVAR(rcsID_MOD_FAN_OUT_H, "$Id$");

#include "module.hh"
#end

#src
RCSIDENT("$Id$");

#include "modsys.hh"

#define MOD_FAN_IN_CLASS_NAME "Fan-In"
#define DEFAULT_READ_BLOCK_SIZE 10000

#end

namespace silk {

class ModFanIn : public Module
{
    friend int mod_fan_in_so_loader(
        uint16_t        major_version,
        uint16_t        minor_version,
        void           *so_loader_data);

  private:

    static const Module::port_t ports_out[] = {
        {"out",  "Record output"},
        SK_MODULE_PORT_SENTINEL
    };

    std::vector<Module::port_t> ports_in;
    std::vector<std::string> port_names;

    enum params_id_t {
        OPT_INPUT_COUNT
    };

    /** The definition of parameters for the ModFanOut module. */
    struct class_params_t {
        /** name of the parameter */
        const char         *key;
        /** an integer identifier for it  */
        int                 val;
        /** min number of values it supports */
        long                lower;
        /** max number of values it supports */
        long                upper;
        /** description of parameter */
        const char         *description;
    };

    static ModFanIn::class_params_t class_params[] = {
        {"input_count",        OPT_INPUT_COUNT,       1, -1,
         "Number of input connectors to create"},
        {0, 0, 0, 0, 0}         /* sentinel entry */
    };

    ModFanIn()
    {
        conns_out.push_back(NULL);
    }

    ~ModFanIn() {}

  public:

    const char *get_type(void) const
    {
        return MOD_FAN_IN_CLASS_NAME;
    }

  private:

    static Module *_create() {
        return new ModFanIn();
    }

    void _init()
    {
        unsigned int i;

        if (conns_out[0] == NULL) {
            std::ostringstream os;
            os << "The " << get_type() << " module's "
               << ports_out[0].name
               << " connector is not connected";
            throw sk_error_module_bad_param_t(os);
        }
        for (i = 0; i < conns_in.size(); i++) {
            if (conns_in[i]) {
                continue;
            }
            std::ostringstream os;
            os << "The " << get_type() << " module's "
               << ports_in[i].name
               << " connector is not connected";
            throw sk_error_module_bad_param_t(os);
        }
    }

    void _run()
    {
        std::vector<Connector *> ready;
        std::vector<Connector *>::iterator conn;
        Connector *out = conns_out[0];
        void *in_block;
        void *out_block = NULL;
        size_t in_size;
        size_t out_size;
        size_t active_inputs;
        int rv;

        /* create and initialize the connector poll object */
        PollConn poller(PollConn::READ);

        for (conn = conns_in.begin(); conn != conns_in.end(); ++conn) {
            (*conn)->add_to_poll(&poller);
        }

        active_inputs = conns_in.size();

        /* run until no one is giving us data */
        while (active_inputs > 0) {
            /* Which of the upstream connectors have data?  If none have
             * data, wait forever for data to become available. */
            poller.poll(1, ready);

            if (stopped || ready.empty()) {
                goto END;
            }

            in_size = DEFAULT_READ_BLOCK_SIZE;

            /* Process all the connectors that have data */
            for (conn = ready.begin(); conn != ready.end(); ++conn) {
                rv = (*conn)->get_read_block(&in_block, &in_size);
                if (rv) {
                    --active_inputs;
                    (*conn)->remove_from_poll(&poller);
                    continue;
                }

                /* Copy the block to the downstream connector */
                out_size = in_size;
                rv = out->get_write_block(&out_block, &out_size);
                if (rv || stopped) {
                    (*conn)->return_read_block(in_block);
                    goto END;
                }
                if (stopped) {
                    (*conn)->return_read_block(in_block);
                    goto END;
                }
                assert(out_size >= in_size);
                memcpy(out_block, in_block, in_size);

                out->return_write_block(out_block, in_size);
                out_block = NULL;
                (*conn)->return_read_block(in_block);

                if (stopped) {
                    goto END;
                }
            }
        }

      END:
        if (out_block) {
            out->return_read_block(out_block);
        }
        out->stop_no_more_data();

        for (conn = conns_in.begin(); conn != conns_in.end(); ++conn) {
            (*conn)->stop();
            try {
                (*conn)->remove_from_poll(&poller);
            } catch (sk_error_conn_poll_add_remove_t &e) {
                // ignore this exception
            }
        }
    }

    void _get_ports(
        std::vector<port_t> &inputs,
        std::vector<port_t> &outputs)
    {
        const Module::port_t *port;

        inputs = ports_in;
        outputs.clear();
        for (port = ports_out; port->name; ++port) {
            outputs.push_back(*port);
        }
    }

    static Parameterized::param_registry_t *create_param_registry() {
        param_registry_t *registry = new param_registry_t();
        class_params_t *param = class_params;

        while (param->key) {
            registry->insert(
                Definition(param->key, param->description,
                           &param->val, param->lower, param->upper));
            ++param;
        }
        return registry;
    }

    static std::auto_ptr<Parameterized::param_registry_t> param_registry =
        std::auto_ptr<Parameterized::param_registry_t>(
            ModFanIn::create_param_registry());

    const Parameterized::param_registry_t& get_param_registry() const
    {
        return *param_registry;
    }

    void _set_param(
        const Definition& defn,
        const std::vector<std::string>& values) throw (Error)
    {
        int rv;
        uint32_t u32;
        unsigned int i;

        switch (*(params_id_t *)(defn.get_context())) {
          case OPT_INPUT_COUNT:
            if (!conns_in.empty()) {
                std::ostringstream os;
                os << "Invalid " << defn.get_name()
                   << " '" << values[0]
                   << "': Cannot change value once connectors are created";
                throw sk_error_module_bad_param_t(os);
            }
            rv = skStringParseUint32(&u32, values[0].c_str(), 1, 0);
            if (rv) {
                goto PARSE_ERROR;
            }
            for (i = 0; i < u32; i++) {
                Module::port_t port = {NULL, NULL};
                char name[32];
                snprintf(name, sizeof(name), "in.%u", i);
                port_names.push_back(name);
                port.name = port_names.back().c_str();
                ports_in.push_back(port);
                conns_in.push_back(NULL);
            }
            break;
        }

        return;

      PARSE_ERROR:
        std::ostringstream os;
        os << "Invalid " << defn.get_name() << " '" << values[0] << "': "
           << skStringParseStrerror(rv);
        throw sk_error_conn_param_value_t(os.str());
    }
};

int mod_fan_in_so_loader(
    uint16_t        major_version,
    uint16_t        minor_version,
    void           *so_loader_data)
{
    ModuleSystem::loader_data_t *so_loader =
        static_cast<ModuleSystem::loader_data_t *>(so_loader_data);
    ModuleSystem *module_system = so_loader->modsys;

    // ADD VERSION CHECK

    try {
        module_system->register_module(
            MOD_FAN_IN_CLASS_NAME, &ModFanIn::_create);
    }
    catch (Error &e) {
        skAppPrintErr("Failed to load " MOD_FAN_IN_CLASS_NAME ": %s",
                      e.get_string().c_str());
        return -1;
    }
    catch (...) {
        skAppPrintErr("Failed to load " MOD_FAN_IN_CLASS_NAME ": %s",
                      "Unknown error");
        return -1;
    }

    return 0;
}


}

/*
** Local Variables:
** mode:c++
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/


[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-09 14:05                       ` Michael Welsh Duggan
@ 2012-10-10 20:00                         ` Alan Mackenzie
  2012-10-14 17:06                           ` Alan Mackenzie
  0 siblings, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-10-10 20:00 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael,

On Tue, Oct 09, 2012 at 10:05:07AM -0400, Michael Welsh Duggan wrote:
> Alan Mackenzie <acm@muc.de> writes:

[ .... ]

> >> >>> M-x c-toggle-parse-state-debug

> >> >>> It works by calculating c-parse-state twice for each call - The first
> >> >>> time normally, then again with the internal state bound to "newly
> >> >>> initialised".  If the the two results differ, they are printed to
> >> >>> *Messages*, together with the saved previous state.  If this does
> >> >>> trigger, please note any recent buffer changes.  It may make editing
> >> >>> intolerably slow.

> >> >> I will turn this on.

> >> I turned this on, and inserted a (ding) where cc-mode outputs an
> >> inconsistency message.  I can barely stand to edit code now, due to
> >> what seem to be almost every key press causing a beep.  Have you made
> >> any progress here, or do you need more data?

> > I have found the bug which is causing (most of) these dings, though I
> > don't think it is the one which caused Kim's original bug.  Could you try
> > out the patch below, please.  (I have also enhanced/corrected the
> > debugging routines a bit, too.)

> Still doesn't seem to help much here.  I have attached a file which
> reliably causes a cache failure.  I have attached the smallest file of
> the set of files I am working on that causes this particular problem.
> Load the attached file and toggle on parse state debugging.  Then scroll
> to the bottom of the file.  (Use C-v multiple times, or just M->.)  One
> reason I have attached this file is that it only triggers the warning
> message once.  Most of my larger files cause this to happen quite a lot.

What is happening in this file is another bug, arising from historical
assumptions which are no longer valid.

The "from scratch" calculation notes that the starting scanning position
would be a long way (>5000) back, hence it tries going back to the second
"beginning-of-defun" to get a top-level starting point.  This
"beginning-of-defun" is a pure "brace in column zero" test.

This doesn't work in C++ when constructs inside a namespace have braces
at column zero, something I believe has become very common in recent
years.  Namespaces didn't exist in C++ when c-parse-state was originally
written.

Obviously this optimisation is no longer valid.  I wouldn't be surprised
if it has caused quite a bit of buggy behaviour.  I'll need to think it
over for a few days to decide what to do.

Again, thanks for taking so much trouble in submitting these bug
reports.


> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-10 20:00                         ` Alan Mackenzie
@ 2012-10-14 17:06                           ` Alan Mackenzie
  2012-10-23 16:13                             ` Michael Welsh Duggan
  2012-10-25 13:41                             ` Michael Welsh Duggan
  0 siblings, 2 replies; 55+ messages in thread
From: Alan Mackenzie @ 2012-10-14 17:06 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael,

On Wed, Oct 10, 2012 at 08:00:25PM +0000, Alan Mackenzie wrote:
> On Tue, Oct 09, 2012 at 10:05:07AM -0400, Michael Welsh Duggan wrote:
> > Alan Mackenzie <acm@muc.de> writes:

[ .... ]

> > > I have found the bug which is causing (most of) these dings, though I
> > > don't think it is the one which caused Kim's original bug.  Could you try
> > > out the patch below, please.  (I have also enhanced/corrected the
> > > debugging routines a bit, too.)

> > Still doesn't seem to help much here.  I have attached a file which
> > reliably causes a cache failure.  I have attached the smallest file of
> > the set of files I am working on that causes this particular problem.
> > Load the attached file and toggle on parse state debugging.  Then scroll
> > to the bottom of the file.  (Use C-v multiple times, or just M->.)  One
> > reason I have attached this file is that it only triggers the warning
> > message once.  Most of my larger files cause this to happen quite a lot.

> What is happening in this file is another bug, arising from historical
> assumptions which are no longer valid.

> The "from scratch" calculation notes that the starting scanning position
> would be a long way (>5000) back, hence it tries going back to the second
> "beginning-of-defun" to get a top-level starting point.  This
> "beginning-of-defun" is a pure "brace in column zero" test.

> This doesn't work in C++ when constructs inside a namespace have braces
> at column zero, something I believe has become very common in recent
> years.  Namespaces didn't exist in C++ when c-parse-state was originally
> written.

> Obviously this optimisation is no longer valid.  I wouldn't be surprised
> if it has caused quite a bit of buggy behaviour.  I'll need to think it
> over for a few days to decide what to do.

The only reasonable thing to do is to disable the heuristic for C++ Mode.
This is what the patch below now does.  Could you try it out as usual,
please.  Thanks!




diff -r ac6584d14c06 cc-engine.el
--- a/cc-engine.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-engine.el	Sun Oct 14 17:02:08 2012 +0000
@@ -2560,8 +2560,11 @@
 	      start-point cache-pos)))
 
     ;; Might we be better off starting from the top level, two defuns back,
-    ;; instead?
-    (when (> how-far c-state-cache-too-far)
+    ;; instead?  This heuristic no longer works well in C++, where
+    ;; declarations inside namespace brace blocks are frequently placed at
+    ;; column zero.
+    (when (and (not (c-major-mode-is 'c++-mode))
+	       (> how-far c-state-cache-too-far))
       (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
       (if (< (- here BOD-pos) how-far)
 	  (setq strategy 'BOD
@@ -2648,17 +2651,19 @@
 	;; If we're essentially repeating a fruitless search, just give up.
 	(unless (and c-state-brace-pair-desert
 		     (eq cache-pos (car c-state-brace-pair-desert))
+		     (> from (car c-state-brace-pair-desert))
 		     (<= from (cdr c-state-brace-pair-desert)))
-	  ;; DESERT-LIM.  Only search what we absolutely need to,
+	  ;; DESERT-LIM.  Avoid repeated searching through the cached desert.
 	  (let ((desert-lim
 		 (and c-state-brace-pair-desert
 		      (eq cache-pos (car c-state-brace-pair-desert))
+		      (>= from (cdr c-state-brace-pair-desert))
 		      (cdr c-state-brace-pair-desert)))
 		;; CACHE-LIM.  This limit will be necessary when an opening
 		;; paren at `cache-pos' has just had its matching close paren
-		;; inserted.  `cache-pos' continues to be a search bound, even
-		;; though the algorithm below would skip over the new paren
-		;; pair.
+		;; inserted into the buffer.  `cache-pos' continues to be a
+		;; search bound, even though the algorithm below would skip
+		;; over the new paren pair.
 		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
 	    (narrow-to-region
 		(cond
@@ -3354,13 +3359,19 @@
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 
+(defvar c-parse-state-point nil)
 (defvar c-parse-state-state nil)
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
+  (setq c-parse-state-point (point))
   (setq c-parse-state-state
 	(mapcar
 	 (lambda (arg)
-	   (cons arg (symbol-value arg)))
+	   (let ((val (symbol-value arg)))
+	     (cons arg
+		   (if (consp val)
+		       (copy-tree val)
+		     val))))
 	 '(c-state-cache
 	   c-state-cache-good-pos
 	   c-state-nonlit-pos-cache
@@ -3373,7 +3384,8 @@
 	   c-state-point-min-lit-start
 	   c-state-min-scan-pos
 	   c-state-old-cpp-beg
-	   c-state-old-cpp-end))))
+	   c-state-old-cpp-end
+	   c-parse-state-point))))
 (defun c-replay-parse-state-state ()
   (message
    (concat "(setq "
@@ -3416,7 +3428,8 @@
       (message "Old state:")
       (c-replay-parse-state-state))
     (c-record-parse-state-state)
-    res1))
+    res2 ; res1 correct a cascading series of errors ASAP
+    ))
 
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")


> > -- 
> > Michael Welsh Duggan
> > (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-14 17:06                           ` Alan Mackenzie
@ 2012-10-23 16:13                             ` Michael Welsh Duggan
  2012-10-25 13:41                             ` Michael Welsh Duggan
  1 sibling, 0 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-10-23 16:13 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Hi, Michael,
>
> On Wed, Oct 10, 2012 at 08:00:25PM +0000, Alan Mackenzie wrote:
>> On Tue, Oct 09, 2012 at 10:05:07AM -0400, Michael Welsh Duggan wrote:
>> > Alan Mackenzie <acm@muc.de> writes:
>
> [ .... ]
>
>> > > I have found the bug which is causing (most of) these dings, though I
>> > > don't think it is the one which caused Kim's original bug.  Could you try
>> > > out the patch below, please.  (I have also enhanced/corrected the
>> > > debugging routines a bit, too.)
>
>> > Still doesn't seem to help much here.  I have attached a file which
>> > reliably causes a cache failure.  I have attached the smallest file of
>> > the set of files I am working on that causes this particular problem.
>> > Load the attached file and toggle on parse state debugging.  Then scroll
>> > to the bottom of the file.  (Use C-v multiple times, or just M->.)  One
>> > reason I have attached this file is that it only triggers the warning
>> > message once.  Most of my larger files cause this to happen quite a lot.
>
>> What is happening in this file is another bug, arising from historical
>> assumptions which are no longer valid.
>
>> The "from scratch" calculation notes that the starting scanning position
>> would be a long way (>5000) back, hence it tries going back to the second
>> "beginning-of-defun" to get a top-level starting point.  This
>> "beginning-of-defun" is a pure "brace in column zero" test.
>
>> This doesn't work in C++ when constructs inside a namespace have braces
>> at column zero, something I believe has become very common in recent
>> years.  Namespaces didn't exist in C++ when c-parse-state was originally
>> written.
>
>> Obviously this optimisation is no longer valid.  I wouldn't be surprised
>> if it has caused quite a bit of buggy behaviour.  I'll need to think it
>> over for a few days to decide what to do.
>
> The only reasonable thing to do is to disable the heuristic for C++ Mode.
> This is what the patch below now does.  Could you try it out as usual,
> please.  Thanks!

Better, but doesn't solve all problems.  I'll see if I can't find
something reproducible for you.

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-14 17:06                           ` Alan Mackenzie
  2012-10-23 16:13                             ` Michael Welsh Duggan
@ 2012-10-25 13:41                             ` Michael Welsh Duggan
  2012-10-28 11:36                               ` Alan Mackenzie
  1 sibling, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-10-25 13:41 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 464 bytes --]

A new recipe.  This is a strange one.  I hope it works for you as well.

emacs -Q
M-x tool-bar-mode
resize the frame to be height 56 (according to the window manager)
Load the included file
M-x c-toggle-parse-state-debug
C-s FIXME C-s
Move cursor to the "o" on the next line (1175).
Type: 
PyTYPE( 
C-f 
)

I get errors at the first open paren, and the close paren.  Resizing the
fame is important!  I think it's due to caching that happens during font
locking. 


[-- Attachment #2: pysilk.c --]
[-- Type: text/plain, Size: 236217 bytes --]

/*
** Copyright (C) 2007-2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  Python wrappers
**
*/


#include <Python.h>             /* Must be included before any system
                                   headers */
#include <silk/silk.h>

RCSIDENT("$Id$");

#include <silk/rwrec.h>
#include <silk/skbag.h>
#include <silk/skcountry.h>
#include <silk/skipaddr.h>
#include <silk/skipset.h>
#include <silk/skprefixmap.h>
#include <silk/sksite.h>
#include <silk/skstream.h>
#include <silk/skvector.h>
#include <silk/utils.h>
#include <datetime.h>
#include <structmember.h>
#include "pysilk_common.h"


/* LOCAL DEFINES AND TYPEDEFS */

#if PY_MAJOR_VERSION >= 3
#  ifndef PyMODINIT_FUNC        /* declarations for DLL import/export */
#    define PyMODINIT_FUNC PyObject *
#  endif
#  define INIT_RETURN(x) return x
#  define XMOD_INIT(x) PyInit_ ## x
#else
#  ifndef PyMODINIT_FUNC        /* declarations for DLL import/export */
#    define PyMODINIT_FUNC void
#  endif
#  define INIT_RETURN(x) x
#  define XMOD_INIT(x) init ## x
#endif
#define MOD_INIT(x) XMOD_INIT(x) /* Avoid argument prescan problem by
                                    indirection */

/* get an object's type; added in Python 2.6 */
#ifndef Py_TYPE
#define Py_TYPE(ob) (((PyObject*)(ob))->ob_type)
#endif


#define XSTR(s) #s
#define STR(s) XSTR(s)

#define PYSILK_NAME     pysilk
#define PYSILK_NL_NAME  pysilk_nl
#define PYSILK_INIT     MOD_INIT(PYSILK_NAME)
#define PYSILK_NL_INIT  MOD_INIT(PYSILK_NL_NAME)

/* In Python 2.4, length()-type functions are 'inquiry's that return
 * int.  In Python 2.5, they are 'lenfunc's that return Py_ssize_t. */
#if PY_VERSION_HEX < 0x02050000
#define Py_ssize_t     int
#define PY_SSIZE_T_MAX INT_MAX
#endif

#define NOT_SET -9999

#if SK_ENABLE_IPV6
#define UNUSED_NOv6(x) x
#else
#define UNUSED_NOv6(x) UNUSED(x)
#endif


#define CHECK_SITE(err)                         \
    do {                                        \
        if (init_site(NULL)) {                  \
            return err;                         \
        }                                       \
    } while(0)


/*
 *  ASSERT_RESULT(ar_func_args, ar_type, ar_expected);
 *
 *    ar_func_args  -- is a function and any arguments it requires
 *    ar_type       -- is the type that ar_func_args returns
 *    ar_expected   -- is the expected return value from ar_func_args
 *
 *    If assert() is disabled, simply call 'ar_func_args'.
 *
 *    If assert() is enabled, call 'ar_func_args', capture its result,
 *    and assert() that its result is 'ar_expected'.
 */
#ifdef  NDEBUG
/* asserts are disabled; just call the function */
#define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)  ar_func_args
#else
#define ASSERT_RESULT(ar_func_args, ar_type, ar_expected)       \
    do {                                                        \
        ar_type ar_rv = (ar_func_args);                         \
        assert(ar_rv == (ar_expected));                         \
    } while(0)
#endif


typedef skBagErr_t (*silkBagModFn)(
    skBag_t *,
    const skBagTypedKey_t *,
    const skBagTypedCounter_t *,
    skBagTypedCounter_t *);

typedef struct silkpy_globals_st {
    PyObject *silkmod;
    PyObject *timedelta;
    PyObject *datetime;
    PyObject *maxelapsed;
    PyObject *minelapsed;
    PyObject *zerotime;
    PyObject *thousand;
    PyObject *havesite;
    PyObject *sensors;
    PyObject *classes;
    PyObject *flowtypes;
    PyObject *newrawrec;
    PyObject *maxintipv4;
#if SK_ENABLE_IPV6
    PyObject *maxintipv6;
#endif
    int site_configured;
} silkpy_globals_t;


/* LOCAL VARIABLE DEFINITIONS */

static  char error_buffer[1024];

#if PY_MAJOR_VERSION >= 3
/* Global state for 3.0 Python is found by searching for this
 * module */
static struct PyModuleDef *pysilk_module = NULL;

#define GLOBALS                                                         \
    ((silkpy_globals_t*)PyModule_GetState(PyState_FindModule(pysilk_module)))

#else

/* Global state for Pre-3.0 Python */
static silkpy_globals_t silkpy_globals_static;

#define GLOBALS   (&silkpy_globals_static)

#endif  /* #else of #if PY_MAJOR_VERSION >= 3 */


/* EXPORTED FUNCTION PROTOTYPES */

PyMODINIT_FUNC PYSILK_INIT(void);
PyMODINIT_FUNC PYSILK_NL_INIT(void);


/* LOCAL FUNCTION PROTOTYPES */

/* basic support functions */
static PyObject *any_obj_error(
    PyObject   *exc,
    const char *format,
    PyObject   *obj);
#ifdef TEST_PRINTF_FORMATS
#define error_printf  printf
#else  /* TEST_PRINTF_FORMATS */
static int error_printf(
    const char *fmt,
    ...)
    SK_CHECK_PRINTF(1, 2);
#endif
static int init_classes(void);
static int init_flowtypes(void);
static int init_sensors(void);
static int init_silkfile_module(
    PyObject   *mod);
static int init_site(
    const char *site_file);
static PyObject *initpysilkbase(
    char*   name);
static PyObject *iter_iter(
    PyObject   *self);
static void obj_dealloc(
    PyObject   *obj);
static PyObject *obj_error(
    const char *format,
    PyObject   *obj);
static PyObject *reduce_error(
    PyObject   *self);
static int silkPyDatetimeToSktime(
    sktime_t   *silktime,
    PyObject   *datetime);
#if !SK_ENABLE_IPV6
static PyObject *silkPyNotImplemented(
    PyObject    UNUSED(*self),
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds));
#endif


/* FUNCTION DEFINITIONS */


/*
 *************************************************************************
 *   IPAddr
 *************************************************************************
 */

typedef struct silkPyIPAddr_st {
    PyObject_HEAD
    skipaddr_t addr;
} silkPyIPAddr;

/* function prototypes */
static PyObject *silkPyIPAddr_country_code(
    silkPyIPAddr   *self);
static long silkPyIPAddr_hash(
    silkPyIPAddr   *obj);
static PyObject *silkPyIPAddr_int(
    silkPyIPAddr   *obj);
static PyObject *silkPyIPAddr_is_ipv6(
    silkPyIPAddr   UNUSED_NOv6(*self));
static PyObject *silkPyIPAddr_isipv6_deprecated(
    silkPyIPAddr   *self);
static PyObject *silkPyIPAddr_mask(
    silkPyIPAddr   *self,
    PyObject       *mask);
static PyObject *silkPyIPAddr_mask_prefix(
    silkPyIPAddr   *self,
    PyObject       *prefix);
static PyObject *silkPyIPAddr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyIPAddr_octets(
    silkPyIPAddr   *self);
static PyObject *silkPyIPAddr_padded(
    silkPyIPAddr   *obj);
static PyObject *silkPyIPAddr_repr(
    silkPyIPAddr   *obj);
static PyObject *silkPyIPAddr_richcompare(
    silkPyIPAddr   *self,
    PyObject       *obj,
    int             cmp);
static int silkPyIPAddr_setup(
    PyObject   *mod);
static PyObject *silkPyIPAddr_str(
    silkPyIPAddr   *obj);
static PyObject *silkPyIPAddr_to_ipv4(
    PyObject   *self);
#if SK_ENABLE_IPV6
static PyObject *silkPyIPAddr_to_ipv6(
    PyObject   *self);
#endif
static int silkPyIPv4Addr_init(
    silkPyIPAddr   *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyIPv4Addr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds);
static int silkPyIPv6Addr_init(
    silkPyIPAddr   *self,
    PyObject       *args,
    PyObject       *kwds);
#if SK_ENABLE_IPV6
static PyObject *silkPyIPv6Addr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds);
#endif
static PyObject *silkPyIPvXAddr_new(
    PyTypeObject   *basetype,
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds);

/* define docs and methods */
static char silkPyIPAddr_doc[] =
    ("IPAddr(string) -> ip address\n"
     "IPAddr(ipaddr) -> copy of ip address");

static char silkPyIPv4Addr_doc[] =
    ("IPv4Addr(string) -> IPv4 address\n"
     "IPv4Addr(int) -> IPv4 address\n"
     "IPv4Addr(IPV6Addr) -> IPv4 from IPv4 in IPv6 address\n"
     "IPv4Addr(IPv4Addr) -> copy of ip address");

static char silkPyIPv6Addr_doc[] =
    ("IPv6Addr(string) -> IPv6 address\n"
     "IPv6Addr(int) -> IPv6 address\n"
     "IPv6Addr(IPV4Addr) -> IPv4 in IPv6 address\n"
     "IPv6Addr(IPv6Addr) -> copy of ip address");

static PyNumberMethods silkPyIPAddr_number_methods;

static PyMethodDef silkPyIPAddr_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"isipv6", (PyCFunction)silkPyIPAddr_isipv6_deprecated, METH_NOARGS,
     "addr.isipv6() -> bool -- return whether addr is an IPv6 address"},
    {"is_ipv6", (PyCFunction)silkPyIPAddr_is_ipv6, METH_NOARGS,
     "addr.isipv6() -> bool -- return whether addr is an IPv6 address"},
    {"to_ipv6", (PyCFunction)
#if SK_ENABLE_IPV6
     silkPyIPAddr_to_ipv6, METH_NOARGS,
#else
     silkPyNotImplemented, METH_VARARGS | METH_KEYWORDS,
#endif
     "addr.to_ipv6() -- return addr converted to an IPv6 address"},
    {"to_ipv4", (PyCFunction)silkPyIPAddr_to_ipv4, METH_NOARGS,
     "addr.to_ipv4() -- return addr converted to an IPv4 address"},
    {"padded", (PyCFunction)silkPyIPAddr_padded, METH_NOARGS,
     "addr.padded() -> str -- return zero-padded IP string"},
    {"mask", (PyCFunction)silkPyIPAddr_mask, METH_O,
     "addr.mask(addr2) -> addr3 -- return addr masked by addr2"},
    {"mask_prefix", (PyCFunction)silkPyIPAddr_mask_prefix, METH_O,
     ("addr.mask(prefix) -> addr2 -- "
      "return addr masked by the top prefix bits")},
    {"country_code", (PyCFunction)silkPyIPAddr_country_code, METH_NOARGS,
     "addr.country_code() -> string -- 2-character country code"},
    {"octets", (PyCFunction)silkPyIPAddr_octets, METH_NOARGS,
     ("addr.octets() = (o1, o2 ...) -- "
      "return the octets of addr as a tuple")},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

/* define the object types */
static PyTypeObject silkPyIPAddrType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.IPAddr",              /* tp_name */
    sizeof(silkPyIPAddr),       /* tp_basicsize */
    0,                          /* tp_itemsize */
    obj_dealloc,                /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    (reprfunc)silkPyIPAddr_repr, /* tp_repr */
    &silkPyIPAddr_number_methods, /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    (hashfunc)silkPyIPAddr_hash, /* tp_hash  */
    0,                          /* tp_call */
    (reprfunc)silkPyIPAddr_str, /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
#if PY_MAJOR_VERSION < 3
    Py_TPFLAGS_HAVE_RICHCOMPARE |
#endif
    Py_TPFLAGS_DEFAULT,         /* tp_flags */
    silkPyIPAddr_doc,           /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    (richcmpfunc)silkPyIPAddr_richcompare, /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    silkPyIPAddr_methods,       /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    silkPyIPAddr_new,           /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyIPv4AddrType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.IPv4Addr",            /* tp_name */
    0,                          /* tp_basicsize */
    0,                          /* tp_itemsize */
    0,                          /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyIPv4Addr_doc,         /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    &silkPyIPAddrType,          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyIPv4Addr_init, /* tp_init */
    0,                          /* tp_alloc */
    silkPyIPv4Addr_new,         /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyIPv6AddrType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.IPv6Addr",            /* tp_name */
    0,                          /* tp_basicsize */
    0,                          /* tp_itemsize */
    0,                          /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyIPv6Addr_doc,         /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    &silkPyIPAddrType,          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyIPv6Addr_init, /* tp_init */
    0,                          /* tp_alloc */
#if SK_ENABLE_IPV6
    silkPyIPv6Addr_new,         /* tp_new */
#else
    (newfunc)silkPyNotImplemented, /* tp_new */
#endif
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyIPAddr_Check(op)                  \
    PyObject_TypeCheck(op, &silkPyIPAddrType)
#define silkPyIPv4Addr_Check(op)                \
    PyObject_TypeCheck(op, &silkPyIPv4AddrType)
#define silkPyIPv6Addr_Check(op)                \
    PyObject_TypeCheck(op, &silkPyIPv6AddrType)

static PyObject *silkPyIPAddr_country_code(
    silkPyIPAddr   *self)
{
    char name[3];
    sk_countrycode_t code;
    int rv;

    rv = skCountrySetup(NULL, error_printf);
    if (rv != 0) {
        PyErr_SetString(PyExc_RuntimeError, error_buffer);
        return NULL;
    }

    code = skCountryLookupCode(&self->addr);
    if (code == SK_COUNTRYCODE_INVALID) {
        Py_RETURN_NONE;
    }

    return PyUnicode_FromString(skCountryCodeToName(code, name, sizeof(name)));
}

static long silkPyIPAddr_hash(
    silkPyIPAddr   *obj)
{
    long retval;
#if SK_ENABLE_IPV6
    if (skipaddrIsV6(&obj->addr)) {
        uint8_t v6[16];
        skipaddrGetAsV6(&obj->addr, v6);
#if SK_SIZEOF_LONG == 8
        retval = *(long*)(&v6[8]);
#else  /* SK_SIZEOF_LONG */
        /* Assume long is 4 bytes */
        retval = *(long*)(&v6[12]);
#endif  /* SK_SIZEOF_LONG */
        return retval;
    }
#endif  /* SK_ENABLE_IPV6 */
    retval = skipaddrGetV4(&obj->addr);
    if (retval == -1) {
        retval = 0;
    }
    return retval;
}

static PyObject *silkPyIPAddr_int(
    silkPyIPAddr   *obj)
{
    PyObject *result;

#if SK_ENABLE_IPV6
    if (skipaddrIsV6(&obj->addr)) {
        char      buf[33];
        char     *p;
        int       i;
        uint32_t *v6;

        p = buf;
        v6 = (uint32_t*)obj->addr.ip_ip.ipu_ipv6;
        for (i = 0; i < 4; i++) {
            sprintf(p, "%08" PRIx32, ntohl(*v6));
            p += 8;
            ++v6;
        }
        result = PyLong_FromString(buf, NULL, 16);
    } else
#endif  /* SK_ENABLE_IPV6 */
    {
        result = PyLong_FromUnsignedLong(skipaddrGetV4(&obj->addr));
    }

    return result;
}

static PyObject *silkPyIPAddr_is_ipv6(
    silkPyIPAddr   UNUSED_NOv6(*self))
{
#if SK_ENABLE_IPV6
    return PyBool_FromLong(skipaddrIsV6(&self->addr));
#else
    Py_RETURN_FALSE;
#endif
}

static PyObject *silkPyIPAddr_isipv6_deprecated(
    silkPyIPAddr   *self)
{
    PyErr_Warn(PyExc_DeprecationWarning,
               ("IPAddr.isipv6() is deprecated.  "
                "Use IPAddr.is_ipv6() instead."));
    return silkPyIPAddr_is_ipv6(self);
}

static PyObject *silkPyIPAddr_mask(
    silkPyIPAddr   *self,
    PyObject       *mask)
{
    silkPyIPAddr *retval;
    skipaddr_t addr;
    PyTypeObject *type;

    if (!silkPyIPAddr_Check(mask)) {
        PyErr_SetString(PyExc_TypeError, "Argument must be an IPAddr");
        return NULL;
    }

    skipaddrCopy(&addr, &self->addr);
    skipaddrMask(&addr, &((silkPyIPAddr*)mask)->addr);
    if (skipaddrIsV6(&addr)) {
        type = &silkPyIPv6AddrType;
    } else {
        type = &silkPyIPv4AddrType;
    }
    retval = PyObject_New(silkPyIPAddr, type);
    if (retval == NULL) {
        return NULL;
    }
    skipaddrCopy(&retval->addr, &addr);

    return (PyObject*)retval;
}

static PyObject *silkPyIPAddr_mask_prefix(
    silkPyIPAddr   *self,
    PyObject       *prefix)
{
    silkPyIPAddr *retval;
    PyTypeObject *type;
    long p;
    int max;

    if (!IS_INT(prefix)) {
        PyErr_SetString(PyExc_TypeError, "Prefix must be an integer");
        return NULL;
    }

    if (skipaddrIsV6(&self->addr)) {
        type = &silkPyIPv6AddrType;
        max = 128;
    } else {
        type = &silkPyIPv4AddrType;
        max = 32;
    }

    p = PyInt_AsLong(prefix);
    if (PyErr_Occurred()) {
        return NULL;
    }

    if (p < 0 || p > max) {
        return PyErr_Format(PyExc_ValueError,
                            "Prefix must be between 0 and %d", max);
    }

    if (skipaddrIsV6(&self->addr)) {
        type = &silkPyIPv6AddrType;
    } else {
        type = &silkPyIPv4AddrType;
    }
    retval = PyObject_New(silkPyIPAddr, type);
    if (retval == NULL) {
        return NULL;
    }

    skipaddrCopy(&retval->addr, &self->addr);
    skipaddrApplyCIDR(&retval->addr, p);

    return (PyObject*)retval;
}

static PyObject *silkPyIPAddr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds)
{
    static char  *kwlist[] = {"address", NULL};
    silkPyIPAddr *self;
    PyObject     *o;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &o)) {
        return NULL;
    }

    /* FIXME: Is this valid in python 3?  Change to Py_TYPE() instead? */
    if (o->ob_type == &silkPyIPv4AddrType ||
        o->ob_type == &silkPyIPv6AddrType)
    {
        /* IPv{4,6}Addr objects are immutable, so just incref*/
        Py_INCREF(o);
        return o;
    }
    if (silkPyIPAddr_Check(o)) {
        /* Unknown subclass of IPAddr, do a real copy */
        if (type == &silkPyIPAddrType) {
            if (skipaddrIsV6(&((silkPyIPAddr*)o)->addr)) {
                type = &silkPyIPv6AddrType;
            } else {
                type = &silkPyIPv4AddrType;
            }
        }
    } else if (IS_STRING(o)) {
        PyObject *bytes = bytes_from_string(o);
        const char *straddr;
        const char *c;

        if (bytes == NULL) {
            return NULL;
        }

        straddr = PyBytes_AS_STRING(bytes);
        c = strchr(straddr, ':');
        if (c) {
            type = &silkPyIPv6AddrType;
        } else {
            type = &silkPyIPv4AddrType;
        }
        Py_DECREF(bytes);
    } else if (IS_INT(o)) {
        /* The IPAddr(int) constructor is deprecated */
        int rv = PyErr_Warn(PyExc_DeprecationWarning,
                            ("IPAddr(int) is deprecated.  Use IPv4Addr(int) "
                             "or IPv6Addr(int) instead."));
        if (rv) {
            return NULL;
        }
        type = &silkPyIPv4AddrType;

    } else {
        return PyErr_Format(PyExc_TypeError, "Must be a string or IPAddr");
    }

    /* Allocate the object */
    self = (silkPyIPAddr*)type->tp_alloc(type, 0);
    if (self == NULL) {
        return NULL;
    }

    return (PyObject*)self;
}

static PyObject *silkPyIPAddr_octets(
    silkPyIPAddr   *self)
{
    PyObject *retval;
    PyObject *octet;
    int i;

#if SK_ENABLE_IPV6
    if (skipaddrIsV6(&self->addr)) {
        uint8_t v6[16];
        retval = PyTuple_New(16);
        if (retval == NULL) {
            return NULL;
        }
        skipaddrGetV6(&self->addr, v6);

        for (i = 0; i < 16; i++) {
            octet = PyInt_FromLong(v6[i]);
            if (octet == NULL) {
                Py_DECREF(retval);
                return NULL;
            }
            PyTuple_SET_ITEM(retval, i, octet);
        }
    } else
#endif
    {
        uint32_t v4 = skipaddrGetV4(&self->addr);
        retval = PyTuple_New(4);
        if (retval == NULL) {
            return NULL;
        }

        for (i = 3; i >= 0; i--) {
            octet = PyInt_FromLong(v4 & 0xff);
            if (octet == NULL) {
                Py_DECREF(retval);
                return NULL;
            }
            PyTuple_SET_ITEM(retval, i, octet);
            v4 >>= 8;
        }
    }

    return retval;
}

static PyObject *silkPyIPAddr_padded(
    silkPyIPAddr   *obj)
{
    char buf[SK_NUM2DOT_STRLEN];

    skipaddrString(buf, &obj->addr, SKIPADDR_ZEROPAD);
    return PyUnicode_FromString(buf);
}

static PyObject *silkPyIPAddr_repr(
    silkPyIPAddr   *obj)
{
    char buf[SK_NUM2DOT_STRLEN];
    PyTypeObject *type;
    PyObject *retval;

    type = (PyTypeObject*)PyObject_Type((PyObject*)obj);
    if (type == NULL) {
        return NULL;
    }

    skipaddrString(buf, &obj->addr, SKIPADDR_CANONICAL);

    retval = PyUnicode_FromFormat("%s('%s')", type->tp_name, buf);
    Py_DECREF(type);

    return retval;
}

static PyObject *silkPyIPAddr_richcompare(
    silkPyIPAddr   *self,
    PyObject       *obj,
    int             cmp)
{
    int rv;
    silkPyIPAddr *other;

    if (!silkPyIPAddr_Check(obj)) {
        PyErr_SetString(PyExc_TypeError, "Expected silk.IPAddr");
        return NULL;
    }
    other = (silkPyIPAddr*)obj;
    rv = skipaddrCompare(&self->addr, &other->addr);
    if (rv < 0) {
        return PyBool_FromLong(cmp == Py_LT || cmp == Py_LE || cmp == Py_NE);
    }
    if (rv > 0) {
        return PyBool_FromLong(cmp == Py_GT || cmp == Py_GE || cmp == Py_NE);
    }
    return PyBool_FromLong(cmp == Py_EQ || cmp == Py_LE || cmp == Py_GE);
}

static int silkPyIPAddr_setup(
    PyObject   *mod)
{
    /* Setup number methods */
    memset(&silkPyIPAddr_number_methods, 0,
           sizeof(silkPyIPAddr_number_methods));
    silkPyIPAddr_number_methods.nb_int = (unaryfunc)silkPyIPAddr_int;
#if PY_MAJOR_VERSION < 3
    silkPyIPAddr_number_methods.nb_long = (unaryfunc)silkPyIPAddr_int;
#endif

    /* Initialize type and add to module */
    if (PyType_Ready(&silkPyIPAddrType) < 0) {
        return -1;
    }
    return PyModule_AddObject(mod, "IPAddr", (PyObject*)&silkPyIPAddrType);
}

static PyObject *silkPyIPAddr_str(
    silkPyIPAddr   *obj)
{
    char buf[SK_NUM2DOT_STRLEN];

    skipaddrString(buf, &obj->addr, SKIPADDR_CANONICAL);
    return PyUnicode_FromString(buf);
}

static PyObject *silkPyIPAddr_to_ipv4(
    PyObject   *self)
{
#if SK_ENABLE_IPV6
    PyObject *obj;

    obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPv4AddrType,
                                       self, NULL);
    if (obj == NULL) {
        if (PyErr_ExceptionMatches(PyExc_ValueError)) {
            PyErr_Clear();
            Py_RETURN_NONE;
        }
    }

    return obj;
#else  /* SK_ENABLE_IPV6 */
    Py_INCREF(self);
    return self;
#endif  /* SK_ENABLE_IPV6 */
}

#if SK_ENABLE_IPV6
static PyObject *silkPyIPAddr_to_ipv6(
    PyObject   *self)
{
    return PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPv6AddrType,
                                        self, NULL);
}
#endif  /* SK_ENABLE_IPV6 */

static int silkPyIPv4Addr_init(
    silkPyIPAddr   *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char  *kwlist[] = {"address", NULL};
    PyObject     *addr;
    int           rv;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &addr)) {
        return -1;
    }

    if (addr == (PyObject*)self) {
        /* We were initialized by new */
        return 0;
    }

    if (IS_STRING(addr)) {
        PyObject *bytes;
        bytes = bytes_from_string(addr);
        if (bytes == NULL) {
            return -1;
        }
        rv = skStringParseIP(&self->addr, PyBytes_AS_STRING(bytes));
        Py_DECREF(bytes);
        if (rv != 0) {
            PyErr_SetString(PyExc_ValueError,
                            "String is not a valid IP address");
            return -1;
        }
        if (skipaddrIsV6(&self->addr)) {
            PyErr_SetString(PyExc_ValueError,
                            "String is not a valid IPv4 address");
            return -1;
        }
    } else if (IS_INT(addr)) {
        uint32_t value;
        PyObject *num;

        num = PyLong_FromLong(0);
        rv = PyObject_RichCompareBool(addr, num, Py_LT);
        Py_DECREF(num);
        if (rv) {
            /* Negative */
            PyErr_SetString(PyExc_ValueError,
                            "Illegal IPv4 address (negative)");
            return -1;
        }
        rv = PyObject_RichCompareBool(addr, GLOBALS->maxintipv4, Py_GT);
        if (rv) {
            PyErr_SetString(PyExc_ValueError,
                            "Illegal IPv4 address (integer too large)");
            return -1;
        }

        value = PyLong_AsUnsignedLong(addr);
        skipaddrSetV4(&self->addr, &value);

#if SK_ENABLE_IPV6
    } else if (silkPyIPv6Addr_Check(addr)) {
        /* Convert to v4 */
        silkPyIPAddr *v6addr = (silkPyIPAddr*)addr;

        if (skipaddrV6toV4(&v6addr->addr, &self->addr)) {
            PyErr_SetString(PyExc_ValueError,
                            "IP address not convertable to IPv4.");
            return -1;
        }
#endif  /* SK_ENABLE_IPV6 */

    } else if (silkPyIPv4Addr_Check(addr)) {
        /* Copy */
        skipaddrCopy(&self->addr, &((silkPyIPAddr*)addr)->addr);
    } else {
        PyErr_SetString(PyExc_TypeError, "Must be a string or integer");
        return -1;
    }

    return 0;
}

static PyObject *silkPyIPv4Addr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds)
{
    return silkPyIPvXAddr_new(&silkPyIPv4AddrType, type, args, kwds);
}

static int silkPyIPv6Addr_init(
    silkPyIPAddr   *self,
    PyObject       *args,
    PyObject       *kwds)
{
#if !SK_ENABLE_IPV6
    silkPyNotImplemented((PyObject*)self, args, kwds);
    return -1;
#else  /* if SK_ENABLE_IPV6 */
    static char  *kwlist[] = {"address", NULL};
    PyObject     *addr;
    int           rv;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &addr)) {
        return -1;
    }

    if (addr == (PyObject*)self) {
        /* We were initialized by new */
        return 0;
    }

    if (IS_STRING(addr)) {
        PyObject *bytes = bytes_from_string(addr);
        if (bytes == NULL) {
            return -1;
        }
        rv = skStringParseIP(&self->addr, PyBytes_AS_STRING(bytes));
        Py_DECREF(bytes);
        if (rv != 0) {
            PyErr_SetString(PyExc_ValueError,
                            "String is not a valid IP address");
            return -1;
        }
        if (!skipaddrIsV6(&self->addr)) {
            PyErr_SetString(PyExc_ValueError,
                            "String is not a valid IPv6 address");
            return -1;
        }
    } else if (IS_INT(addr)) {
        uint8_t   v6[16];
        uint32_t *v6_32;
        PyObject *next;
        PyObject *shift;
        PyObject *num;
        int i;

        num = PyLong_FromLong(0);
        rv = PyObject_RichCompareBool(addr, num, Py_LT);
        Py_DECREF(num);
        if (rv) {
            /* Negative */
            PyErr_SetString(PyExc_ValueError,
                            "Illegal IPv6 address (negative)");
            return -1;
        }
        rv = PyObject_RichCompareBool(addr, GLOBALS->maxintipv6, Py_GT);
        if (rv) {
            PyErr_SetString(PyExc_ValueError,
                            "Illegal IPv6 address (integer too large)");
            return -1;
        }

        /* Set IP */
        shift = PyLong_FromLong(32);
        v6_32 = (uint32_t*)v6 + 3;

        next = addr;
        Py_INCREF(next);
        for (i = 0; i < 4; i++, v6_32--) {
            PyObject *tmp;

            tmp = PyNumber_And(next, GLOBALS->maxintipv4);
            *v6_32 = htonl(PyLong_AsUnsignedLong(tmp));
            Py_DECREF(tmp);
            tmp = next;
            next = PyNumber_Rshift(tmp, shift);
            Py_DECREF(tmp);
        }
        Py_DECREF(shift);
        skipaddrSetV6(&self->addr, v6);

    } else if (silkPyIPv4Addr_Check(addr)) {
        /* Convert to v6 */
        silkPyIPAddr *v4addr = (silkPyIPAddr*)addr;

        if (skipaddrIsV6(&v4addr->addr)) {
            skipaddrCopy(&self->addr, &v4addr->addr);
        } else {
            skipaddrV4toV6(&v4addr->addr, &self->addr);
        }

    } else if (silkPyIPv6Addr_Check(addr)) {
        /* Copy */
        skipaddrCopy(&self->addr, &((silkPyIPAddr*)addr)->addr);
    } else {
        PyErr_SetString(PyExc_TypeError, "Must be a string or integer");
        return -1;
    }

    return 0;
#endif  /* else of !SK_ENABLE_IPV6 */
}

#if SK_ENABLE_IPV6
static PyObject *silkPyIPv6Addr_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds)
{
    return silkPyIPvXAddr_new(&silkPyIPv6AddrType, type, args, kwds);
}
#endif  /* SK_ENABLE_IPV6 */

static PyObject *silkPyIPvXAddr_new(
    PyTypeObject   *basetype,
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds)
{
    static char  *kwlist[] = {"address", NULL};
    PyObject   *self;
    PyObject   *o;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &o)) {
        return NULL;
    }

    /* FIXME: Is this valid in python 3?  Change to Py_TYPE() instead? */
    if (type == basetype && o->ob_type == basetype) {
        Py_INCREF(o);
        return o;
    }

    self = type->tp_alloc(type, 0);
    return self;
}


/*
 *************************************************************************
 *   IPWildcard
 *************************************************************************
 */

typedef struct silkPyIPWildcard_st {
    PyObject_HEAD
    skIPWildcard_t  wildcard;
    PyObject       *name;
} silkPyIPWildcard;

typedef struct silkPyIPWildcardIter_st {
    PyObject_HEAD
    silkPyIPWildcard       *wildcard;
    skIPWildcardIterator_t  iter;
} silkPyIPWildcardIter;

/* function prototypes */
static void silkPyIPWildcardIter_dealloc(
    silkPyIPWildcardIter   *self);
static PyObject *silkPyIPWildcardIter_iternext(
    silkPyIPWildcardIter   *self);
static int silkPyIPWildcard_contains(
    silkPyIPWildcard   *self,
    PyObject           *obj);
static void silkPyIPWildcard_dealloc(
    silkPyIPWildcard   *obj);
static PyObject *silkPyIPWildcard_is_ipv6(
    silkPyIPWildcard   UNUSED_NOv6(*self));
static PyObject *silkPyIPWildcard_isipv6_deprecated(
    silkPyIPWildcard   *self);
static PyObject *silkPyIPWildcard_iter(
    silkPyIPWildcard   *self);
static PyObject *silkPyIPWildcard_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyIPWildcard_repr(
    silkPyIPWildcard   *obj);
static PyObject *silkPyIPWildcard_str(
    silkPyIPWildcard   *obj);

/* define docs and methods */
static char silkPyIPWildcard_doc[] =
    ("IPWildcard(string) -> IP Wildcard address");

static PyMethodDef silkPyIPWildcard_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"isipv6", (PyCFunction)silkPyIPWildcard_isipv6_deprecated, METH_NOARGS,
     "wild.isipv6() -> bool -- return whether wild is an IPv6 wildcard"},
    {"is_ipv6", (PyCFunction)silkPyIPWildcard_is_ipv6, METH_NOARGS,
     "wild.is_ipv6() -> bool -- return whether wild is an IPv6 wildcard"},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PySequenceMethods silkPyIPWildcard_sequence_methods = {
    0,                          /* sq_length */
    0,                          /* sq_concat */
    0,                          /* sq_repeat */
    0,                          /* sq_item */
    0,                          /* sq_slice */
    0,                          /* sq_ass_item */
    0,                          /* sq_ass_slice */
    (objobjproc)silkPyIPWildcard_contains, /* sq_contains */
    0,                          /* sq_inplace_concat */
    0                           /* sq_inplace_repeat */
};

/* define the object types */
static PyTypeObject silkPyIPWildcardType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.IPWildcard",          /* tp_name */
    sizeof(silkPyIPWildcard),   /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyIPWildcard_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    (reprfunc)silkPyIPWildcard_repr, /* tp_repr */
    0,                          /* tp_as_number */
    &silkPyIPWildcard_sequence_methods, /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    (reprfunc)silkPyIPWildcard_str, /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE,
                                /* tp_flags */
    silkPyIPWildcard_doc,       /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    (getiterfunc)silkPyIPWildcard_iter, /* tp_iter */
    0,                          /* tp_iternext */
    silkPyIPWildcard_methods,   /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    silkPyIPWildcard_new,       /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyIPWildcardIterType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.IPWildcardIter", /* tp_name */
    sizeof(silkPyIPWildcardIter), /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyIPWildcardIter_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "IP Wildcard iterator object", /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    iter_iter,                  /* tp_iter */
    (iternextfunc)silkPyIPWildcardIter_iternext, /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyIPWildcard_Check(op)                      \
    PyObject_TypeCheck(op, &silkPyIPWildcardType)
#define silkPyIPWildcardIter_Check(op)                  \
    PyObject_TypeCheck(op, &silkPyIPWildcardIterType)

static void silkPyIPWildcardIter_dealloc(
    silkPyIPWildcardIter   *self)
{
    Py_XDECREF(self->wildcard);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *silkPyIPWildcardIter_iternext(
    silkPyIPWildcardIter   *self)
{
    silkPyIPAddr       *addr;
    skIteratorStatus_t  rv;
    skipaddr_t          raw_addr;

    rv = skIPWildcardIteratorNext(&self->iter, &raw_addr);
    if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }
    addr = (silkPyIPAddr*)silkPyIPv4AddrType.tp_alloc(&silkPyIPv4AddrType, 0);
    if (addr == NULL) {
        return NULL;
    }
    addr->addr = raw_addr;

    return (PyObject*)addr;
}

static int silkPyIPWildcard_contains(
    silkPyIPWildcard   *self,
    PyObject           *obj)
{
    int           retval;
    silkPyIPAddr *silkaddr;

    if (IS_STRING(obj)) {
        obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPAddrType,
                                           obj, NULL);
        if (obj == NULL) {
            return -1;
        }
    } else if (silkPyIPAddr_Check(obj)) {
        Py_INCREF(obj);
    } else {
        PyErr_SetString(PyExc_TypeError, "Must be a string or silk.IPAddr");
        return -1;
    }

    silkaddr = (silkPyIPAddr*)obj;
    retval = skIPWildcardCheckIp(&self->wildcard, &silkaddr->addr);
    Py_DECREF(obj);

    return retval ? 1 : 0;
}

static void silkPyIPWildcard_dealloc(
    silkPyIPWildcard   *obj)
{
    Py_XDECREF(obj->name);
    Py_TYPE(obj)->tp_free((PyObject*)obj);
}

static PyObject *silkPyIPWildcard_is_ipv6(
    silkPyIPWildcard   UNUSED_NOv6(*self))
{
#if SK_ENABLE_IPV6
    return PyBool_FromLong(skIPWildcardIsV6(&self->wildcard));
#else
    Py_RETURN_FALSE;
#endif
}

static PyObject *silkPyIPWildcard_isipv6_deprecated(
    silkPyIPWildcard   *self)
{
    PyErr_Warn(PyExc_DeprecationWarning,
               ("IPWildcard.isipv6() is deprecated.  "
                "Use IPWildcard.is_ipv6() instead."));
    return silkPyIPWildcard_is_ipv6(self);
}

static PyObject *silkPyIPWildcard_iter(
    silkPyIPWildcard   *self)
{
    silkPyIPWildcardIter *iter;

    iter = (silkPyIPWildcardIter*)silkPyIPWildcardIterType.tp_alloc(
        &silkPyIPWildcardIterType, 0);
    if (iter) {
        ASSERT_RESULT(skIPWildcardIteratorBind(&iter->iter, &self->wildcard),
                      int, 0);
        Py_INCREF(self);
        iter->wildcard = self;
    }
    return (PyObject*)iter;
}

static PyObject *silkPyIPWildcard_new(
    PyTypeObject   *type,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"wildcard", NULL};
    silkPyIPWildcard *self;

    if (PyArg_ParseTupleAndKeywords(args, kwds, "O!", kwlist,
                                    &silkPyIPWildcardType, &self))
    {
        Py_INCREF(self);
        return (PyObject*)self;
    } else {
        PyErr_Clear();
    }

    self = (silkPyIPWildcard*)type->tp_alloc(type, 0);
    if (self != NULL) {
        int   len;
        const char  *wildcard;
        int          rv;

        if (!PyArg_ParseTupleAndKeywords(args, kwds, "s#", kwlist,
                                         &wildcard, &len))
        {
            Py_DECREF(self);
            return NULL;
        }
        rv = skStringParseIPWildcard(&self->wildcard, wildcard);
        if (rv != 0) {
            Py_DECREF(self);
            return PyErr_Format(PyExc_ValueError,
                                "Illegal IP wildcard: %s", wildcard);
        }
        self->name = PyUnicode_DecodeASCII(wildcard, len, "strict");
        if (self->name == NULL) {
            Py_DECREF(self);
            return NULL;
        }
    }

    return (PyObject*)self;
}

static PyObject *silkPyIPWildcard_repr(
    silkPyIPWildcard   *obj)
{
    PyObject *format;
    PyObject *arg;
    PyObject *retval;

    format = PyUnicode_FromString("silk.IPWildcard(\"%s\")");
    if (format == NULL) {
        return NULL;
    }
    arg = Py_BuildValue("(O)", obj->name);
    if (arg == NULL) {
        Py_DECREF(format);
        return NULL;
    }
    retval = PyUnicode_Format(format, arg);
    Py_DECREF(format);
    Py_DECREF(arg);

    return retval;
}

static PyObject *silkPyIPWildcard_str(
    silkPyIPWildcard   *obj)
{
    Py_INCREF(obj->name);
    return obj->name;
}


/*
 *************************************************************************
 *   IPSet
 *************************************************************************
 */

typedef struct silkPyIPSet_st {
    PyObject_HEAD
    skipset_t  *ipset;
} silkPyIPSet;

typedef struct silkPyIPSetIter_st {
    PyObject_HEAD
    silkPyIPSet *set;
    skipset_iterator_t iter;
    unsigned is_cidr : 1;
} silkPyIPSetIter;

/* function prototypes */
static void silkPyIPSetIter_dealloc(
    silkPyIPSetIter    *self);
static PyObject *silkPyIPSetIter_iternext(
    silkPyIPSetIter    *self);
static PyObject *silkPyIPSet_add(
    silkPyIPSet    *self,
    PyObject       *obj);
static PyObject *silkPyIPSet_cardinality(
    silkPyIPSet    *self);
static PyObject *silkPyIPSet_cidr_iter(
    silkPyIPSet    *self);
static PyObject *silkPyIPSet_clear(
    silkPyIPSet    *self);
static int silkPyIPSet_contains(
    silkPyIPSet    *self,
    PyObject       *obj);
static void silkPyIPSet_dealloc(
    silkPyIPSet    *obj);
static PyObject *silkPyIPSet_difference_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj);
static PyObject *silkPyIPSet_discard(
    silkPyIPSet    *self,
    PyObject       *obj);
static int silkPyIPSet_init(
    silkPyIPSet    *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyIPSet_intersection_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj);
static PyObject *silkPyIPSet_isdisjoint(
    silkPyIPSet    *self,
    PyObject       *obj);
static PyObject *silkPyIPSet_iter(
    silkPyIPSet    *self);
static Py_ssize_t silkPyIPSet_len(
    silkPyIPSet    *self);
static PyObject *silkPyIPSet_save(
    silkPyIPSet    *self,
    PyObject       *name);
static PyObject *silkPyIPSet_union_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj);

/* define docs and methods */
static char silkPyIPSet_doc[] =
    ("IPSetBase() -> empty IPset\n"
     "IPSetBase(filename) -> IPset from file");

static PyMethodDef silkPyIPSet_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"cardinality", (PyCFunction)silkPyIPSet_cardinality, METH_NOARGS,
     "ipset.cardinality() -> long -- number of IP Addresses in the IPSet"},
    {"intersection_update", (PyCFunction)silkPyIPSet_intersection_update,
     METH_O,
     ("Return the intersection of two IPSets as a new IPSet.\n"
      "\n"
      "(i.e. all elements that are in both IPSets.)")},
    {"update", (PyCFunction)silkPyIPSet_union_update,
     METH_O,
     ("Update the IPSet with the union of itself and another.")},
    {"difference_update", (PyCFunction)silkPyIPSet_difference_update,
     METH_O,
     ("Remove all elements of another IPSet from this IPSet.")},
    {"clear", (PyCFunction)silkPyIPSet_clear, METH_NOARGS,
     ("Remove all elements from this IPSet.")},
    {"save", (PyCFunction)silkPyIPSet_save, METH_O,
     "ipset.save(filename) -- Saves the set to a file."},
    {"cidr_iter", (PyCFunction)silkPyIPSet_cidr_iter, METH_NOARGS,
     "Return an iterator over IPAddr/prefix tuples."},
    {"add", (PyCFunction)silkPyIPSet_add, METH_O,
     ("Add an element to an IPSet.  The element can be an IP address, an\n"
      "IP wildcard, or the string representation of either.\n"
      "\n"
      "This has no effect for any element already present.")},
    {"discard", (PyCFunction)silkPyIPSet_discard, METH_O,
     ("Discard an element to an IPSet.  The element can be an IP address, an\n"
      "IP wildcard, or the string representation of either.\n"
      "\n"
      "This has no effect for any element not present in the IPset.")},
    {"isdisjoint", (PyCFunction)silkPyIPSet_isdisjoint, METH_O,
     "Return whether the IPSet has any elements in common with the argument"},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PySequenceMethods silkPyIPSet_sequence_methods = {
#if PY_VERSION_HEX < 0x02050000
    (inquiry)silkPyIPSet_len,   /* sq_length */
#else
    (lenfunc)silkPyIPSet_len,   /* sq_length */
#endif
    0,                          /* sq_concat */
    0,                          /* sq_repeat */
    0,                          /* sq_item */
    0,                          /* sq_slice */
    0,                          /* sq_ass_item */
    0,                          /* sq_ass_slice */
    (objobjproc)silkPyIPSet_contains, /* sq_contains */
    0,                          /* sq_inplace_concat */
    0                           /* sq_inplace_repeat */
};

/* define the object types */
static PyTypeObject silkPyIPSetType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.IPSetBase",    /* tp_name */
    sizeof(silkPyIPSet),        /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyIPSet_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    &silkPyIPSet_sequence_methods, /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyIPSet_doc,            /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    (getiterfunc)silkPyIPSet_iter, /* tp_iter */
    0,                          /* tp_iternext */
    silkPyIPSet_methods,        /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyIPSet_init, /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyIPSetIterType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.IPSetIter",    /* tp_name */
    sizeof(silkPyIPSetIter),    /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyIPSetIter_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "IP Set iterator object",   /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    iter_iter,                  /* tp_iter */
    (iternextfunc)silkPyIPSetIter_iternext, /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};


/* macro and function defintions */
#define silkPyIPSet_Check(op)                   \
    PyObject_TypeCheck(op, &silkPyIPSetType)
#define silkPyIPSetIter_Check(op)                       \
    PyObject_TypeCheck(op, &silkPyIPSetIterType)

static void silkPyIPSetIter_dealloc(
    silkPyIPSetIter    *self)
{
    Py_XDECREF(self->set);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *silkPyIPSetIter_iternext(
    silkPyIPSetIter    *self)
{
    silkPyIPAddr       *addr;
    int                 rv;
    PyObject           *retval;
    skipaddr_t          raw_addr;
    uint32_t            raw_prefix;

    rv = skIPSetIteratorNext(&self->iter, &raw_addr, &raw_prefix);
    if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }

    addr = (silkPyIPAddr*)silkPyIPAddrType.tp_alloc(&silkPyIPAddrType, 0);
    if (addr == NULL) {
        return NULL;
    }
    addr->addr = raw_addr;

    if (!self->is_cidr) {
        retval = (PyObject*)addr;
    } else {
        PyObject       *pair;
        PyObject       *len;

        len = PyInt_FromLong(raw_prefix);
        if (len == NULL) {
            Py_DECREF(addr);
            return NULL;
        }
        pair = PyTuple_New(2);
        if (pair == NULL) {
            Py_DECREF(addr);
            Py_DECREF(len);
        }
        PyTuple_SET_ITEM(pair, 0, (PyObject*)addr);
        PyTuple_SET_ITEM(pair, 1, len);

        retval = pair;
    }

    return retval;
}

static PyObject *silkPyIPSet_add(
    silkPyIPSet    *self,
    PyObject       *obj)
{
    int           rv;

    if (silkPyIPAddr_Check(obj)) {
        silkPyIPAddr *addr = (silkPyIPAddr*)obj;

        rv = skIPSetInsertAddress(self->ipset, &addr->addr,
                                  (skipaddrIsV6(&addr->addr) ? 128 : 32));
    } else if silkPyIPWildcard_Check(obj) {
        silkPyIPWildcard *wild;

        assert(silkPyIPWildcard_Check(obj));

        wild = (silkPyIPWildcard*)obj;

        rv = skIPSetInsertIPWildcard(self->ipset, &wild->wildcard);
    } else {
        PyErr_SetString(PyExc_TypeError,
                        "Must be a silk.IPAddr or a silk.IPWildcard");
        return NULL;
    }

    if (rv == SKIPSET_ERR_ALLOC) {
        return PyErr_NoMemory();
    }
    if (rv == SKIPSET_ERR_IPV6) {
        PyErr_SetString(PyExc_ValueError,
                        "Must only include IPv4 addresses");
        return NULL;
    }
    assert(rv == SKIPSET_OK);

    Py_INCREF(self);
    return (PyObject*)self;
}

static PyObject *silkPyIPSet_cardinality(
    silkPyIPSet    *self)
{
    uint64_t count;
    double count_d;

    skIPSetClean(self->ipset);
    count = skIPSetCountIPs(self->ipset, &count_d);
    return PyLong_FromUnsignedLongLong(count);
}

static PyObject *silkPyIPSet_cidr_iter(
    silkPyIPSet    *self)
{
    silkPyIPSetIter *iter;

    iter = (silkPyIPSetIter*)silkPyIPSetIterType.tp_alloc(
        &silkPyIPSetIterType, 0);
    if (iter) {
        skIPSetClean(self->ipset);
        if (skIPSetIteratorBind(&iter->iter, self->ipset, 1,SK_IPV6POLICY_MIX))
        {
            Py_DECREF(iter);
            return PyErr_NoMemory();
        }
        Py_INCREF(self);
        iter->set = self;
        iter->is_cidr = 1;
    }
    return (PyObject*)iter;
}

static PyObject *silkPyIPSet_clear(
    silkPyIPSet    *self)
{
    skIPSetRemoveAll(self->ipset);

    Py_INCREF(self);
    return (PyObject*)self;
}

static int silkPyIPSet_contains(
    silkPyIPSet    *self,
    PyObject       *obj)
{
    int           retval;
    silkPyIPAddr *silkaddr;

    if (IS_STRING(obj)) {
        obj = PyObject_CallFunctionObjArgs((PyObject*)&silkPyIPAddrType,
                                           obj, NULL);
        if (obj == NULL) {
            return -1;
        }
    } else if (silkPyIPAddr_Check(obj)) {
        Py_INCREF(obj);
    } else {
        PyErr_SetString(PyExc_TypeError, "Must be a string or silk.IPAddr");
        return -1;
    }

    silkaddr = (silkPyIPAddr*)obj;
    retval = skIPSetCheckAddress(self->ipset, &silkaddr->addr);
    Py_DECREF(obj);

    return retval ? 1 : 0;
}

static void silkPyIPSet_dealloc(
    silkPyIPSet    *obj)
{
    if (obj->ipset) {
        skIPSetDestroy(&obj->ipset);
    }
    Py_TYPE(obj)->tp_free((PyObject*)obj);
}

static PyObject *silkPyIPSet_difference_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj)
{
    if (!silkPyIPSet_Check(obj)) {
        PyErr_SetString(PyExc_NotImplementedError,
                        "Argument must be a silk.IPSet");
        return NULL;
    }

    skIPSetClean(self->ipset);
    skIPSetClean(obj->ipset);
    skIPSetSubtract(self->ipset, obj->ipset);

    Py_INCREF(self);
    return (PyObject*)self;
}

static PyObject *silkPyIPSet_discard(
    silkPyIPSet    *self,
    PyObject       *obj)
{
    int rv;

    if (silkPyIPAddr_Check(obj)) {
        silkPyIPAddr *addr = (silkPyIPAddr*)obj;

        rv = skIPSetRemoveAddress(self->ipset, &addr->addr,
                                  (skipaddrIsV6(&addr->addr) ? 128 : 32));
    } else if silkPyIPWildcard_Check(obj) {
        silkPyIPWildcard *wild;

        assert(silkPyIPWildcard_Check(obj));

        wild = (silkPyIPWildcard*)obj;

        rv = skIPSetRemoveIPWildcard(self->ipset, &wild->wildcard);
    } else {
        PyErr_SetString(PyExc_TypeError,
                        "Must be a silk.IPAddr or a silk.IPWildcard");
        return NULL;
    }

    if (rv == SKIPSET_ERR_ALLOC) {
        return PyErr_NoMemory();
    }
    assert(rv == SKIPSET_OK);

    Py_INCREF(self);
    return (PyObject*)self;
}

static int silkPyIPSet_init(
    silkPyIPSet    *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"filename", NULL};
    char        *fname = NULL;
    int          rv;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|et", kwlist,
                                     Py_FileSystemDefaultEncoding, &fname))
    {
        return -1;
    }

    if (fname) {
        rv = skIPSetLoad(&self->ipset, fname);
        if (rv != 0) {
            PyErr_Format(PyExc_IOError, "Unable to read IPSet from %s: %s",
                         fname, skIPSetStrerror(rv));
            PyMem_Free(fname);
            return -1;
        }
        PyMem_Free(fname);
    } else {
        rv = skIPSetCreate(&self->ipset, 0);
        if (rv == SKIPSET_ERR_ALLOC) {
            PyErr_NoMemory();
            return -1;
        }
        assert(rv == SKIPSET_OK);
    }

    return 0;
}

static PyObject *silkPyIPSet_intersection_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj)
{
    if (!silkPyIPSet_Check(obj)) {
        PyErr_SetString(PyExc_NotImplementedError,
                        "Argument must be a silk.IPSet");
        return NULL;
    }

    skIPSetClean(self->ipset);
    skIPSetClean(obj->ipset);
    skIPSetIntersect(self->ipset, obj->ipset);

    Py_INCREF(self);
    return (PyObject*)self;
}

static PyObject *silkPyIPSet_isdisjoint(
    silkPyIPSet    *self,
    PyObject       *obj)
{
    int disjoint;

    if (silkPyIPSet_Check(obj)) {
        disjoint = !skIPSetCheckIPSet(
            self->ipset, ((silkPyIPSet*)obj)->ipset);
    } else if (silkPyIPWildcard_Check(obj)) {
        disjoint = !skIPSetCheckIPWildcard(
            self->ipset, &((silkPyIPWildcard*)obj)->wildcard);
    } else {
        PyErr_SetString(PyExc_TypeError, "Expected an IPSet or an IPWildcard");
        return NULL;
    }
    if (disjoint) {
        Py_RETURN_TRUE;
    }
    Py_RETURN_FALSE;
}

static PyObject *silkPyIPSet_iter(
    silkPyIPSet    *self)
{
    silkPyIPSetIter *iter;

    iter = (silkPyIPSetIter*)silkPyIPSetIterType.tp_alloc(
        &silkPyIPSetIterType, 0);
    if (iter) {
        skIPSetClean(self->ipset);
        if (skIPSetIteratorBind(&iter->iter, self->ipset, 0,SK_IPV6POLICY_MIX))
        {
            Py_DECREF(iter);
            return PyErr_NoMemory();
        }
        Py_INCREF(self);
        iter->set = self;
    }
    return (PyObject*)iter;
}

static Py_ssize_t silkPyIPSet_len(
    silkPyIPSet    *self)
{
    uint64_t count;
    double count_d;

    skIPSetClean(self->ipset);
    count = skIPSetCountIPs(self->ipset, &count_d);
    if (count > PY_SSIZE_T_MAX) {
        PyErr_SetString(PyExc_OverflowError, "IPSet too long for integer");
        return -1;
    }
    return (Py_ssize_t)count;
}

static PyObject *silkPyIPSet_save(
    silkPyIPSet    *self,
    PyObject       *name)
{
    int rv;
    PyObject *bytes;

    if (!IS_STRING(name)) {
        PyErr_SetString(PyExc_TypeError, "Filename required");
        return NULL;
    }
#if PY_MAJOR_VERSION < 3
    if (PyBytes_Check(name)) {
        bytes = name;
        Py_INCREF(bytes);
    } else
#endif
    {
        bytes = PyUnicode_AsEncodedString(name, Py_FileSystemDefaultEncoding,
                                          "strict");
        if (bytes == NULL) {
            return NULL;
        }
    }

    skIPSetClean(self->ipset);
    rv = skIPSetSave(self->ipset, PyBytes_AS_STRING(bytes));
    Py_DECREF(bytes);
    if (rv != SKIPSET_OK) {
        PyErr_SetString(PyExc_IOError, skIPSetStrerror(rv));
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject *silkPyIPSet_union_update(
    silkPyIPSet    *self,
    silkPyIPSet    *obj)
{
    int rv;

    if (!silkPyIPSet_Check(obj)) {
        PyErr_SetString(PyExc_NotImplementedError,
                        "Argument must be a silk.IPSet");
        return NULL;
    }

    skIPSetClean(self->ipset);
    skIPSetClean(obj->ipset);
    rv = skIPSetUnion(self->ipset, obj->ipset);
    if (rv != 0) {
        return PyErr_NoMemory();
    }

    Py_INCREF(self);
    return (PyObject*)self;
}


/* *************************************************************************
 *   Prefix Map
 *************************************************************************
 */

typedef struct silkPyPmap_st {
    PyObject_HEAD
    skPrefixMap_t *map;
} silkPyPmap;

typedef struct silkPyPmapIter_st {
    PyObject_HEAD
    silkPyPmap *map;
    skPrefixMapIterator_t iter;
} silkPyPmapIter;

/* function prototypes */
static void silkPyPmapIter_dealloc(
    silkPyPmapIter *self);
static PyObject *silkPyPmapIter_iternext(
    silkPyPmapIter *self);
static void silkPyPmap_dealloc(
    silkPyPmap *obj);
static PyObject *silkPyPmap_get_content(
    silkPyPmap     *self,
    void    UNUSED(*cbdata));
static PyObject *silkPyPmap_get_name(
    silkPyPmap     *self,
    void    UNUSED(*cbdata));
static PyObject *silkPyPmap_get_num_values(
    silkPyPmap     *self,
    void    UNUSED(*cbdata));
static PyObject *silkPyPmap_get_value_string(
    silkPyPmap *self,
    PyObject   *value);
static int silkPyPmap_init(
    silkPyPmap *self,
    PyObject   *args,
    PyObject   *kwds);
static PyObject *silkPyPmap_iter(
    silkPyPmap *self);
static PyObject *silkPyPmap_subscript(
    silkPyPmap *self,
    PyObject   *sub);

/* define docs and methods */
static char silkPyPmap_doc[] =
    ("PMapBase(filename) -> Prefix map from file");

static PyMethodDef silkPyPmap_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"get_value_string", (PyCFunction)silkPyPmap_get_value_string, METH_O,
     ("Get the string associated with an integer value")},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PyGetSetDef silkPyPmap_getsetters[] = {
    {"content", (getter)silkPyPmap_get_content, NULL, "Content type", NULL},
    {"name", (getter)silkPyPmap_get_name, NULL, "Prefix map name", NULL},
    {"num_values", (getter)silkPyPmap_get_num_values, NULL,
     "Prefix map number of values", NULL},
    {NULL, NULL, NULL, NULL, NULL}
};

static PyMappingMethods silkPyPmap_mapping_methods = {
    0,
    (binaryfunc)silkPyPmap_subscript,
    0
};

/* define the object types */
static PyTypeObject silkPyPmapType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.PMapBase",     /* tp_name */
    sizeof(silkPyPmap),         /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyPmap_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    &silkPyPmap_mapping_methods, /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyPmap_doc,             /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    (getiterfunc)silkPyPmap_iter, /* tp_iter */
    0,                          /* tp_iternext */
    silkPyPmap_methods,         /* tp_methods */
    0,                          /* tp_members */
    silkPyPmap_getsetters,      /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyPmap_init,  /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyPmapIterType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.PMapBaseIter", /* tp_name */
    sizeof(silkPyPmapIterType), /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyPmapIter_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "Prefix map iterator object", /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    iter_iter,                  /* tp_iter */
    (iternextfunc)silkPyPmapIter_iternext, /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyPmap_Check(op)                    \
    PyObject_TypeCheck(op, &silkPyPmapType)
#define silkPyPmapIter_Check(op)                \
    PyObject_TypeCheck(op, &silkPyPmapIterType)

static void silkPyPmapIter_dealloc(
    silkPyPmapIter *self)
{
    Py_XDECREF(self->map);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *silkPyPmapIter_iternext(
    silkPyPmapIter *self)
{
    skIteratorStatus_t    rv;
    PyObject             *retval;
    PyObject             *startval = NULL;
    PyObject             *endval = NULL;
    union {
        skipaddr_t             addr;
        skPrefixMapProtoPort_t pp;
    } start, end;
    uint32_t              value;
    skPrefixMapContent_t  content;

    rv = skPrefixMapIteratorNext(&self->iter, &start, &end, &value);
    if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }

    content = skPrefixMapGetContentType(self->map->map);
    switch (content) {
      case SKPREFIXMAP_CONT_ADDR_V4:
      case SKPREFIXMAP_CONT_ADDR_V6:
        {
            PyTypeObject *type =
                (content == SKPREFIXMAP_CONT_ADDR_V4) ?
                &silkPyIPv4AddrType : &silkPyIPv6AddrType;

            startval = type->tp_alloc(type, 0);
            if (startval == NULL) {
                return NULL;
            }
            endval = type->tp_alloc(type, 0);
            if (endval == NULL) {
                Py_DECREF(startval);
                return NULL;
            }
            skipaddrCopy(&((silkPyIPAddr*)startval)->addr, &start.addr);
            skipaddrCopy(&((silkPyIPAddr*)endval)->addr, &end.addr);
        }
        break;
      case SKPREFIXMAP_CONT_PROTO_PORT:
        {
            startval = Py_BuildValue("BH", start.pp.proto, start.pp.port);
            if (startval == NULL) {
                return NULL;
            }
            endval = Py_BuildValue("BH", end.pp.proto, end.pp.port);
            if (endval == NULL) {
                Py_DECREF(startval);
                return NULL;
            }
        }
        break;
    }

    retval = Py_BuildValue("NNk", startval, endval, value);
    if (retval == NULL) {
        Py_DECREF(startval);
        Py_DECREF(endval);
    }

    return retval;
}

static void silkPyPmap_dealloc(
    silkPyPmap *obj)
{
    if (obj->map) {
        skPrefixMapDelete(obj->map);
    }
    Py_TYPE(obj)->tp_free((PyObject*)obj);
}

static PyObject *silkPyPmap_get_content(
    silkPyPmap     *self,
    void    UNUSED(*cbdata))
{
    return PyUnicode_FromString(skPrefixMapGetContentName(
                                    skPrefixMapGetContentType(self->map)));
}

static PyObject *silkPyPmap_get_name(
    silkPyPmap     *self,
    void    UNUSED(*cbdata))
{
    const char *name = skPrefixMapGetMapName(self->map);
    if (name == NULL) {
        Py_RETURN_NONE;
    }

    return PyUnicode_FromString(name);
}

static PyObject *silkPyPmap_get_num_values(
    silkPyPmap     *self,
    void    UNUSED(*cbdata))
{
    return PyInt_FromLong(skPrefixMapDictionaryGetWordCount(self->map));
}

static PyObject *silkPyPmap_get_value_string(
    silkPyPmap *self,
    PyObject   *value)
{
    uint32_t  val;
    uint32_t  size;
    char     *buf;
    int       rv;
    PyObject *retval;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return NULL;
    }

    val = PyLong_AsUnsignedLong(value);
    if (PyErr_Occurred()) {
        return NULL;
    }

    size = skPrefixMapDictionaryGetMaxWordSize(self->map) + 1;
    buf = (char*)malloc(size);
    if (buf == NULL) {
        return PyErr_NoMemory();
    }

    rv = skPrefixMapDictionaryGetEntry(self->map, val, buf, size);
    assert(rv < (int32_t)size);

    retval = PyUnicode_DecodeASCII(buf, rv, "strict");
    free(buf);

    return retval;
}

static int silkPyPmap_init(
    silkPyPmap *self,
    PyObject   *args,
    PyObject   *kwds)
{
    static char      *kwlist[] = {"filename", NULL};
    char             *fname;
    skPrefixMapErr_t  rv;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "et", kwlist,
                                     Py_FileSystemDefaultEncoding, &fname))
    {
        return -1;
    }

    rv = skPrefixMapLoad(&self->map, fname);
    if (rv != SKPREFIXMAP_OK) {
        PyMem_Free(fname);
        PyErr_Format(PyExc_IOError, "Unable to read prefix map from %s: %s",
                     fname, skPrefixMapStrerror(rv));
        return -1;
    }
    PyMem_Free(fname);

    return 0;
}

static PyObject *silkPyPmap_iter(
    silkPyPmap *self)
{
    int             rv;
    silkPyPmapIter *iter;

    iter = (silkPyPmapIter*)silkPyPmapIterType.tp_alloc(
        &silkPyPmapIterType, 0);
    if (iter) {
        rv = skPrefixMapIteratorBind(&iter->iter, self->map);
        if (rv != 0) {
            Py_DECREF(iter);
            PyErr_SetString(PyExc_RuntimeError,
                            "Failed to create prefix map iterator");
            return NULL;
        }
        Py_INCREF(self);
        iter->map = self;
    }
    return (PyObject*)iter;
}

static PyObject *silkPyPmap_subscript(
    silkPyPmap *self,
    PyObject   *sub)
{
    void *key = NULL;
    uint32_t value;
    skPrefixMapProtoPort_t protoport;
    skPrefixMapContent_t content;
    PyObject *tuple;
    int32_t i32;
    int rv;

    content = skPrefixMapGetContentType(self->map);

    switch (content) {
      case SKPREFIXMAP_CONT_ADDR_V4:
      case SKPREFIXMAP_CONT_ADDR_V6:
        if (!silkPyIPAddr_Check(sub)) {
            PyErr_SetString(PyExc_TypeError, "Expected an IPAddr");
            return NULL;
        }
        key = &((silkPyIPAddr*)sub)->addr;
        break;
      case SKPREFIXMAP_CONT_PROTO_PORT:
        if (!PySequence_Check(sub) || PySequence_Size(sub) != 2) {
            PyErr_SetString(PyExc_TypeError, "Expected a (proto, port) pair");
            return NULL;
        }
        tuple = PySequence_Tuple(sub);
        if (tuple == NULL) {
            return NULL;
        }
        rv = PyArg_ParseTuple(tuple, "bi;Expected a (proto, port) pair",
                              &protoport.proto, &i32);
        Py_DECREF(tuple);
        if (!rv) {
            return NULL;
        }
        if (i32 < 0 || i32 > 0xFFFF) {
            PyErr_SetString(PyExc_OverflowError, "Port is out of bounds");
            return NULL;
        }
        protoport.port = i32;
        key = &protoport;
        break;
    }

    value = skPrefixMapGet(self->map, key);

    return PyLong_FromUnsignedLong(value);
}


/*
 *************************************************************************
 *   Bag
 *************************************************************************
 */

typedef struct silkPyBag_st {
    PyObject_HEAD
    skBag_t *bag;
    unsigned is_ipaddr : 1;
} silkPyBag;

typedef struct silkPyBagIter_st {
    PyObject_HEAD
    silkPyBag       *bag;
    skBagIterator_t *iter;
    unsigned         ipaddr : 1;
} silkPyBagIter;

/* function prototypes */
static void silkPyBagIter_dealloc(
    silkPyBagIter  *self);
static PyObject *silkPyBagIter_iternext(
    silkPyBagIter  *self);
static PyObject *silkPyBag__get_custom_type(
    PyObject    UNUSED(*self));
static PyObject *silkPyBag__get_ipv4_type(
    PyObject    UNUSED(*self));
static PyObject *silkPyBag__get_ipv6_type(
    PyObject    UNUSED(*self));
static int silkPyBag_ass_subscript(
    silkPyBag  *self,
    PyObject   *sub,
    PyObject   *value);
static PyObject *silkPyBag_clear(
    silkPyBag  *self);
static Py_ssize_t silkPyBag_count(
    silkPyBag  *self);
static void silkPyBag_dealloc(
    silkPyBag  *obj);
static PyObject *silkPyBag_decr(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds);
static PyObject *silkPyBag_field_types(
    PyObject    UNUSED(*self));
static PyObject *silkPyBag_get_info(
    silkPyBag  *self);
static PyObject *silkPyBag_iadd(
    silkPyBag  *self,
    silkPyBag  *other);
#if 0
static skBagErr_t silkPyBag_iadd_bounds(
    const skBagTypedKey_t       UNUSED(*key),
    skBagTypedCounter_t                *in_out_counter,
    const skBagTypedCounter_t   UNUSED(*in_counter),
    void                        UNUSED(*cb_data));
#endif
static PyObject *silkPyBag_incr(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds);
static int silkPyBag_init(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds);
static PyObject *silkPyBag_iter(
    silkPyBag  *self);
static PyObject *silkPyBag_iter_helper(
    silkPyBag  *self,
    int         sorted);
static int silkPyBag_modify(
    silkPyBag      *self,
    PyObject       *sub,
    PyObject       *value,
    silkBagModFn    fn);
static PyObject *silkPyBag_save(
    silkPyBag  *self,
    PyObject   *name);
static PyObject *silkPyBag_set_info(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds);
static int silkPyBag_setup(
    PyObject   *mod);
static PyObject *silkPyBag_sorted_iter(
    silkPyBag  *self);
static PyObject *silkPyBag_subscript(
    silkPyBag  *self,
    PyObject   *sub);
static PyObject *silkPyBag_type_merge(
    PyObject    UNUSED(*self),
    PyObject           *args);

/* define docs and methods */
static char silkPyBag_doc[] =
    ("BagBase(filename) -> Bag from file");

static PyNumberMethods silkPyBag_number_methods;

static PyMappingMethods silkPyBag_mapping_methods = {
#if PY_VERSION_HEX < 0x02050000
    (inquiry)silkPyBag_count,   /* mp_length */
#else
    (lenfunc)silkPyBag_count,   /* mp_length */
#endif
    (binaryfunc)silkPyBag_subscript,       /* mp_subscript */
    (objobjargproc)silkPyBag_ass_subscript /* mp_ass_subscript */
};

static PyMethodDef silkPyBag_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"incr", (PyCFunction)silkPyBag_incr, METH_KEYWORDS | METH_VARARGS,
     ("bag.incr(key, value) -- increments bag[key] by value")},
    {"decr", (PyCFunction)silkPyBag_decr, METH_KEYWORDS | METH_VARARGS,
     ("bag.decr(key, value) -- decrements bag[key] by value")},
    {"save", (PyCFunction)silkPyBag_save, METH_O,
     "bag.save(filename) -- saves the bag to a file"},
    {"clear", (PyCFunction)silkPyBag_clear, METH_NOARGS,
     "bag.clear() -- empties the bag"},
    {"sorted_iter", (PyCFunction)silkPyBag_sorted_iter, METH_NOARGS,
     ("bag.sorted_iter() -- returns an iterator whose values are "
      "sorted by key")},
    {"get_info", (PyCFunction)silkPyBag_get_info, METH_NOARGS,
     "get_info() -- returns (key_type, key_len, counter_type, counter_len)"},
    {"set_info", (PyCFunction)silkPyBag_set_info,
     METH_KEYWORDS | METH_VARARGS,
     ("set_info([key_type][, key_len][, counter_type][, counter_len]) --\n\t"
      "returns the result of bag.get_info()")},
    {"field_types", (PyCFunction)silkPyBag_field_types,
     METH_NOARGS | METH_STATIC,
     "field_types() -> Tuple of valid field types for Bag keys and counters"},
    {"type_merge", (PyCFunction)silkPyBag_type_merge,
     METH_VARARGS | METH_STATIC,
     "type_merge(keytype_a, keytype_b) -> key_type of merged output"},
    {"_get_custom_type", (PyCFunction)silkPyBag__get_custom_type,
     METH_NOARGS | METH_STATIC, NULL},
    {"_get_ipv4_type", (PyCFunction)silkPyBag__get_ipv4_type,
     METH_NOARGS | METH_STATIC, NULL},
    {"_get_ipv6_type", (PyCFunction)silkPyBag__get_ipv6_type,
     METH_NOARGS | METH_STATIC, NULL},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};


/* define the object types */
static PyTypeObject silkPyBagType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.BagBase",      /* tp_name */
    sizeof(silkPyBag),          /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyBag_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    &silkPyBag_number_methods,  /* tp_as_number */
    0,                          /* tp_as_sequence */
    &silkPyBag_mapping_methods, /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
#if PY_MAJOR_VERSION < 3
    Py_TPFLAGS_CHECKTYPES |
#endif
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyBag_doc,              /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    (getiterfunc)silkPyBag_iter, /* tp_iter */
    0,                          /* tp_iternext */
    silkPyBag_methods,          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyBag_init,   /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyBagIterType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.BagBaseIter",  /* tp_name */
    sizeof(silkPyBagIterType),  /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyBagIter_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "Bag iterator object",      /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    iter_iter,                  /* tp_iter */
    (iternextfunc)silkPyBagIter_iternext, /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    0,                          /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyBag_Check(op)                     \
    PyObject_TypeCheck(op, &silkPyBagType)
#define silkPyBagIter_Check(op)                 \
    PyObject_TypeCheck(op, &silkPyBagIterType)

#define IS_IPV4_KEY(k)                          \
    ((k) == SKBAG_FIELD_SIPv4                   \
     || (k) == SKBAG_FIELD_DIPv4                \
     || (k) == SKBAG_FIELD_NHIPv4               \
     || (k) == SKBAG_FIELD_ANY_IPv4)

#define IS_IPV6_KEY(k)                          \
    ((k) == SKBAG_FIELD_SIPv6                   \
     || (k) == SKBAG_FIELD_DIPv6                \
     || (k) == SKBAG_FIELD_NHIPv6               \
     || (k) == SKBAG_FIELD_ANY_IPv6)

#define IS_IP_KEY(k) (IS_IPV4_KEY(k) || IS_IPV6_KEY(k))

static void silkPyBagIter_dealloc(
    silkPyBagIter  *self)
{
    Py_XDECREF(self->bag);
    skBagIteratorDestroy(self->iter);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static PyObject *silkPyBagIter_iternext(
    silkPyBagIter  *self)
{
    skBagErr_t           rv;
    PyObject            *retkey;
    skBagTypedKey_t      key;
    skBagTypedCounter_t  counter;

    counter.type = SKBAG_COUNTER_U64;
    key.type = self->ipaddr ? SKBAG_KEY_IPADDR : SKBAG_KEY_U32;

    rv = skBagIteratorNextTyped(self->iter, &key, &counter);
    if (rv == SKBAG_ERR_KEY_NOT_FOUND) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }
    if (rv == SKBAG_ERR_MODIFIED) {
        PyErr_SetString(PyExc_RuntimeError,
                        "Underlying Bag changed during iteration");
        return NULL;
    }
    if (self->ipaddr) {
        PyTypeObject *type = (skipaddrIsV6(&key.val.addr)
                              ? &silkPyIPv6AddrType : &silkPyIPv4AddrType);
        retkey = type->tp_alloc(type, 0);
        if (retkey == NULL) {
            return NULL;
        }
        skipaddrCopy(&((silkPyIPAddr*)retkey)->addr, &key.val.addr);
    } else {
        retkey = PyLong_FromUnsignedLong(key.val.u32);
        if (retkey == NULL) {
            return NULL;
        }
    }

    return Py_BuildValue("OK", retkey, counter.val.u64);
}

static PyObject *silkPyBag__get_custom_type(
    PyObject    UNUSED(*self))
{
    char buf[SKBAG_MAX_FIELD_BUFLEN];

    skBagFieldTypeAsString(SKBAG_FIELD_CUSTOM, buf, sizeof(buf));
    return PyUnicode_FromString(buf);
}

static PyObject *silkPyBag__get_ipv4_type(
    PyObject    UNUSED(*self))
{
    char buf[SKBAG_MAX_FIELD_BUFLEN];

    skBagFieldTypeAsString(SKBAG_FIELD_ANY_IPv4, buf, sizeof(buf));
    return PyUnicode_FromString(buf);
}

static PyObject *silkPyBag__get_ipv6_type(
    PyObject    UNUSED(*self))
{
    char buf[SKBAG_MAX_FIELD_BUFLEN];

    skBagFieldTypeAsString(SKBAG_FIELD_ANY_IPv6, buf, sizeof(buf));
    return PyUnicode_FromString(buf);
}

static int silkPyBag_ass_subscript(
    silkPyBag  *self,
    PyObject   *sub,
    PyObject   *value)
{
    /* skBagCounterSet will ignore the extra NULL passed to it */
    return silkPyBag_modify(self, sub, value, (silkBagModFn)skBagCounterSet);
}

static PyObject *silkPyBag_clear(
    silkPyBag  *self)
{
    skBagErr_t rv;
    skBagFieldType_t key, value;
    size_t keylen, valuelen;
    skBag_t *bag;

    key = skBagKeyFieldType(self->bag);
    keylen = skBagKeyFieldLength(self->bag);
    value = skBagCounterFieldType(self->bag);
    valuelen = skBagCounterFieldLength(self->bag);

    rv = skBagCreateTyped(&bag, key, value, keylen, valuelen);
    if (rv == SKBAG_ERR_MEMORY) {
        return PyErr_NoMemory();
    }
    assert(rv == SKBAG_OK);
    skBagAutoConvertDisable(bag);

    skBagDestroy(&self->bag);
    self->bag = bag;

    Py_RETURN_NONE;
}

static Py_ssize_t silkPyBag_count(
    silkPyBag  *self)
{
    uint64_t count = skBagCountKeys(self->bag);
    return (Py_ssize_t)count;
}

static void silkPyBag_dealloc(
    silkPyBag  *obj)
{
    if (obj->bag) {
        skBagDestroy(&obj->bag);
    }
    Py_TYPE(obj)->tp_free((PyObject*)obj);
}

static PyObject *silkPyBag_decr(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds)
{
    static char *kwlist[] = {"key", "value", NULL};
    PyObject *sub;
    PyObject *value;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &sub, &value)) {
        return NULL;
    }

    if (silkPyBag_modify(self, sub, value, skBagCounterSubtract)) {
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject *silkPyBag_field_types(
    PyObject    UNUSED(*self))
{
    char buf[SKBAG_MAX_FIELD_BUFLEN];
    skBagFieldTypeIterator_t iter;
    Py_ssize_t count;
    PyObject *retval;

    /* First, count thee types */
    skBagFieldTypeIteratorBind(&iter);
    count = 0;
    while (skBagFieldTypeIteratorNext(&iter, NULL, NULL, NULL, 0) == SKBAG_OK)
    {
        count++;
    }

    /* Create the tuple */
    retval = PyTuple_New(count);
    if (retval == NULL) {
        return NULL;
    }

    /* Then fill in the tuple */
    skBagFieldTypeIteratorReset(&iter);
    count = 0;
    while (skBagFieldTypeIteratorNext(&iter, NULL, NULL, buf, sizeof(buf))
           == SKBAG_OK)
    {
        PyObject *name = PyUnicode_InternFromString(buf);
        if (name == NULL) {
            Py_DECREF(retval);
            return NULL;
        }
        PyTuple_SET_ITEM(retval, count, name);
        count++;
    }

    return retval;
}

static PyObject *silkPyBag_get_info(
    silkPyBag  *self)
{
    char buf[80];
    unsigned int key_len;
    unsigned int counter_len;
    PyObject *key_name;
    PyObject *counter_name;

    skBagKeyFieldName(self->bag, buf, sizeof(buf));
    key_len = skBagKeyFieldLength(self->bag);
    key_name = PyUnicode_FromString(buf);
    if (key_name == NULL) {
        return NULL;
    }
    skBagCounterFieldName(self->bag, buf, sizeof(buf));
    counter_len = skBagCounterFieldLength(self->bag);
    counter_name = PyUnicode_FromString(buf);
    if (counter_name == NULL) {
        Py_DECREF(key_name);
        return NULL;
    }
    return Py_BuildValue("{sN sI sN sI}",
                         "key_type", key_name, "key_len", key_len,
                         "counter_type", counter_name,
                         "counter_len", counter_len);
}

static PyObject *silkPyBag_iadd(
    silkPyBag  *self,
    silkPyBag  *other)
{
    skBagErr_t rv;

    if (!silkPyBag_Check(other)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    rv = skBagAddBag(self->bag, other->bag, NULL, NULL);
    switch (rv) {
      case SKBAG_OK:
        break;
      case SKBAG_ERR_MEMORY:
        PyErr_NoMemory();
        return NULL;
      case SKBAG_ERR_OP_BOUNDS:
        PyErr_SetString(PyExc_OverflowError, skBagStrerror(rv));
        return NULL;
      case SKBAG_ERR_KEY_RANGE:
        PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
        return NULL;
      case SKBAG_ERR_INPUT:
      case SKBAG_ERR_KEY_NOT_FOUND:
        /* Fall through */
      default:
        skAbortBadCase(rv);
    }
    self->is_ipaddr = (skBagKeyFieldLength(self->bag) == 16
                       || IS_IP_KEY(skBagKeyFieldType(self->bag)));

    Py_INCREF(self);
    return (PyObject*)self;
}

#if 0
/* Clamp bag values for iadd to SKBAG_COUNTER_MAX without errors. */
static skBagErr_t silkPyBag_iadd_bounds(
    const skBagTypedKey_t       UNUSED(*key),
    skBagTypedCounter_t                *in_out_counter,
    const skBagTypedCounter_t   UNUSED(*in_counter),
    void                        UNUSED(*cb_data))
{
    in_out_counter->type = SKBAG_COUNTER_U64;
    in_out_counter->val.u64 = SKBAG_COUNTER_MAX;
    return SKBAG_OK;
}
#endif

static PyObject *silkPyBag_incr(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds)
{
    static char *kwlist[] = {"key", "value", NULL};
    PyObject *sub;
    PyObject *value;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO", kwlist, &sub, &value)) {
        return NULL;
    }

    if (silkPyBag_modify(self, sub, value, skBagCounterAdd)) {
        return NULL;
    }

    Py_RETURN_NONE;
}

static int silkPyBag_init(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds)
{
    static char *kwlist[] = {"copy", "filename", "key_type", "counter_type",
                             "key_len", "counter_len", NULL};
    char         *fname        = NULL;
    silkPyBag    *copy         = NULL;
    char         *key          = NULL;
    char         *counter      = NULL;
    unsigned int  key_size     = 0;
    unsigned int  counter_size = 0;
    skBagErr_t    rv;

    if (!PyArg_ParseTupleAndKeywords(
            args, kwds, "|O!etssII", kwlist, &silkPyBagType,
            (PyObject*)&copy, Py_FileSystemDefaultEncoding, &fname,
            &key, &counter, &key_size, &counter_size))
    {
        return -1;
    }

    if ((copy && fname)
        || (copy && (key || counter))
        || (fname && (key || counter)))
    {
        PyErr_SetString(PyExc_ValueError, "Illegal argument combination");
        return -1;
    }

    if (fname) {
        rv = skBagLoad(&self->bag, fname);
        if (rv != SKBAG_OK) {
            PyErr_Format(PyExc_IOError, "Unable to read Bag from %s: %s",
                         fname, skBagStrerror(rv));
            PyMem_Free(fname);
            return -1;
        }
        PyMem_Free(fname);
        self->is_ipaddr = skBagKeyFieldLength(self->bag) == 16
                          || IS_IP_KEY(skBagKeyFieldType(self->bag));
    } else if (copy) {
        rv = skBagCopy(&self->bag, copy->bag);
        self->is_ipaddr = copy->is_ipaddr;
    } else {
        skBagFieldType_t key_type, counter_type;
        if (!key) {
            key_type = SKBAG_FIELD_CUSTOM;
        } else {
            rv = skBagFieldTypeLookup(key, &key_type, NULL);
            if (rv != SKBAG_OK) {
                PyErr_Format(PyExc_ValueError,
                             "'%s' is not a valid key type", key);
                return -1;
            }
        }
        if (key_type == SKBAG_FIELD_CUSTOM && key_size == 0) {
            key_size = 4;
        }
        if (!counter) {
            counter_type = SKBAG_FIELD_CUSTOM;
        } else {
            rv = skBagFieldTypeLookup(counter, &counter_type, NULL);
            if (rv != SKBAG_OK) {
                PyErr_Format(PyExc_ValueError,
                             "'%s' is not a valid counter type", counter);
                return -1;
            }
        }
        if (counter_type == SKBAG_FIELD_CUSTOM && counter_size == 0) {
            counter_size = 8;
        }

        rv = skBagCreateTyped(&self->bag, key_type, counter_type,
                              key_size, counter_size);
        if (rv == SKBAG_ERR_INPUT) {
            PyErr_Format(PyExc_ValueError,
                         "Illegal arguments to Bag constructor");
            return -1;
        }
        skBagAutoConvertDisable(self->bag);
        self->is_ipaddr = (counter_size == 16 || IS_IP_KEY(key_type));
    }

    if (rv == SKBAG_ERR_MEMORY) {
        PyErr_NoMemory();
        return -1;
    }
    assert(rv == SKBAG_OK);

    return 0;
}

static PyObject *silkPyBag_iter(
    silkPyBag  *self)
{
    return silkPyBag_iter_helper(self, 0);
}

static PyObject *silkPyBag_iter_helper(
    silkPyBag  *self,
    int         sorted)
{
    skBagErr_t     rv;
    silkPyBagIter *iter;

    iter = (silkPyBagIter*)silkPyBagIterType.tp_alloc(
        &silkPyBagIterType, 0);
    if (iter) {
        if (sorted) {
            rv = skBagIteratorCreate(self->bag, &iter->iter);
        } else {
            rv = skBagIteratorCreateUnsorted(self->bag, &iter->iter);
        }
        if (rv == SKBAG_ERR_MEMORY) {
            Py_DECREF(iter);
            return PyErr_NoMemory();
        }
        if (rv != SKBAG_OK) {
            Py_DECREF(iter);
            PyErr_SetString(PyExc_RuntimeError,
                            "Failed to create bag iterator");
            return NULL;
        }
        Py_INCREF(self);
        iter->bag = self;
        iter->ipaddr = self->is_ipaddr;
    }
    return (PyObject*)iter;
}

static int silkPyBag_modify(
    silkPyBag      *self,
    PyObject       *sub,
    PyObject       *value,
    silkBagModFn    fn)
{
    skBagTypedCounter_t bagvalue;
    skBagTypedKey_t     key;
    skBagErr_t          rv;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer value");
        return -1;
    }
    bagvalue.val.u64 = LONG_AS_UNSIGNED_LONGLONG(value);
    if (PyErr_Occurred()) {
        return -1;
    }
    bagvalue.type = SKBAG_COUNTER_U64;

    if (IS_INT(sub)) {
        if (self->is_ipaddr) {
            PyErr_SetString(PyExc_TypeError, "Expected an IPAddr index");
            return -1;
        }
        /* long long is 64-bits on 32 and 64-bit arches, so use it for
         * consistency. */
        key.val.u64 = LONG_AS_UNSIGNED_LONGLONG(sub);
        if (PyErr_Occurred()) {
            if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
                PyErr_Clear();
                PyErr_SetString(PyExc_IndexError, "Index out of range");
            }
            return -1;
        }
        if (key.val.u64 > 0xffffffff) {
            PyErr_SetString(PyExc_IndexError, "Index out of range");
            return -1;
        }
        key.val.u32 = key.val.u64;
        key.type = SKBAG_KEY_U32;
    } else if (silkPyIPAddr_Check(sub)) {
        silkPyIPAddr *addr;
        if (!self->is_ipaddr) {
            PyErr_SetString(PyExc_TypeError, "Expected an integer index");
            return -1;
        }
        addr = (silkPyIPAddr*)sub;
        skipaddrCopy(&key.val.addr, &addr->addr);
        key.type = SKBAG_KEY_IPADDR;
    } else {
        PyErr_SetString(PyExc_TypeError, "Expected an integer or IP address");
        return -1;
    }

    rv = fn(self->bag, &key, &bagvalue, NULL);
    switch (rv) {
      case SKBAG_OK:
        break;
      case SKBAG_ERR_INPUT:
      case SKBAG_ERR_KEY_RANGE:
        PyErr_SetString(PyExc_IndexError, "Address out of range");
        return -1;
      case SKBAG_ERR_MEMORY:
        PyErr_NoMemory();
        return -1;
      case SKBAG_ERR_OP_BOUNDS:
        PyErr_SetString(PyExc_OverflowError, skBagStrerror(rv));
        return -1;
      case SKBAG_ERR_KEY_NOT_FOUND:
        /* Fall through */
      default:
        skAbortBadCase(rv);
    }

    return 0;
}

static PyObject *silkPyBag_save(
    silkPyBag  *self,
    PyObject   *name)
{
    skBagErr_t rv;
    PyObject *bytes;

    if (!IS_STRING(name)) {
        PyErr_SetString(PyExc_TypeError, "Filename required");
        return NULL;
    }
#if PY_MAJOR_VERSION < 3
    if (PyBytes_Check(name)) {
        bytes = name;
        Py_INCREF(bytes);
    } else
#endif
    {
        bytes = PyUnicode_AsEncodedString(name, Py_FileSystemDefaultEncoding,
                                          "strict");
        if (bytes == NULL) {
            return NULL;
        }
    }

    rv = skBagSave(self->bag, PyBytes_AS_STRING(bytes));
    Py_DECREF(bytes);
    if (rv != SKBAG_OK) {
        PyErr_SetString(PyExc_IOError, skBagStrerror(rv));
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject *silkPyBag_set_info(
    silkPyBag  *self,
    PyObject   *args,
    PyObject   *kwds)
{
    static char *kwlist[] = {"key_type", "key_len",
                             "counter_type", "counter_len", NULL};
    size_t key_len = SKBAG_OCTETS_NO_CHANGE;
    size_t counter_len = SKBAG_OCTETS_NO_CHANGE;
    unsigned int key_len_tmp = UINT_MAX;
    unsigned int counter_len_tmp = UINT_MAX;
    char *key_name = NULL;
    char *counter_name = NULL;
    skBagFieldType_t key_type;
    skBagFieldType_t counter_type;
    skBagErr_t err;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|sIsI", kwlist,
                                     &key_name, &key_len_tmp,
                                     &counter_name, &counter_len_tmp))
    {
        return NULL;
    }

    /* key_len_tmp and counter_len_tmp are unsigned ints, since there
     * were no conversion functions to size_t until Python 2.6 */
    if (key_len_tmp != UINT_MAX) {
        key_len = key_len_tmp;
    }
    if (counter_len_tmp != UINT_MAX) {
        counter_len = counter_len_tmp;
    }
    if (key_name) {
        err = skBagFieldTypeLookup(key_name, &key_type, NULL);
        if (err != SKBAG_OK) {
            assert(err == SKBAG_ERR_INPUT);
            return PyErr_Format(PyExc_ValueError,
                                "'%s' is not a valid key type", key_name);
        }
    } else {
        key_type = skBagKeyFieldType(self->bag);
    }

    if (counter_name) {
        err = skBagFieldTypeLookup(counter_name, &counter_type, NULL);
        if (err != SKBAG_OK) {
            assert(err == SKBAG_ERR_INPUT);
            return PyErr_Format(PyExc_ValueError,
                                "'%s' is not a valid counter type",
                                counter_name);
        }
    } else {
        counter_type = skBagCounterFieldType(self->bag);
    }

    err = skBagModify(self->bag, key_type, counter_type,
                      key_len, counter_len);
    if (err != SKBAG_OK) {
        PyErr_SetString(PyExc_ValueError,
                        "Illegal value was passed to Bag.set_info");
        return NULL;
    }

    self->is_ipaddr = (counter_len == 16 || IS_IP_KEY(key_type));

    return silkPyBag_get_info(self);
}

static int silkPyBag_setup(
    PyObject   *mod)
{
    /* Setup number methods */
    memset(&silkPyBag_number_methods, 0, sizeof(silkPyBag_number_methods));
    silkPyBag_number_methods.nb_inplace_add = (binaryfunc)silkPyBag_iadd;

    /* Initialize type and add to module */
    silkPyBagType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyBagType) < 0) {
        return -1;
    }
    return PyModule_AddObject(mod, "BagBase", (PyObject*)&silkPyBagType);
}

static PyObject *silkPyBag_sorted_iter(
    silkPyBag  *self)
{
    return silkPyBag_iter_helper(self, 1);
}

static PyObject *silkPyBag_subscript(
    silkPyBag  *self,
    PyObject   *sub)
{
    skBagTypedKey_t     key;
    skBagTypedCounter_t value;
    skBagErr_t          rv;

    if (IS_INT(sub)) {
        if (self->is_ipaddr) {
            PyErr_SetString(PyExc_TypeError, "Expected an IPAddr index");
            return NULL;
        }
        /* long long is 64-bits on 32 and 64-bit arches, so use it for
         * consistency. */
        key.val.u64 = LONG_AS_UNSIGNED_LONGLONG(sub);
        if (PyErr_Occurred()) {
            if (PyErr_ExceptionMatches(PyExc_OverflowError)) {
                PyErr_Clear();
                PyErr_SetString(PyExc_IndexError, "Index out of range");
            }
            return NULL;
        }
        if (key.val.u64 > 0xffffffff) {
            PyErr_SetString(PyExc_IndexError, "Index out of range");
            return NULL;
        }
        key.val.u32 = key.val.u64;
        key.type = SKBAG_KEY_U32;
    } else if (silkPyIPAddr_Check(sub)) {
        silkPyIPAddr *addr;
        if (!self->is_ipaddr) {
            PyErr_SetString(PyExc_TypeError, "Expected an integer index");
            return NULL;
        }
        addr = (silkPyIPAddr*)sub;
        skipaddrCopy(&key.val.addr, &addr->addr);
        key.type = SKBAG_KEY_IPADDR;
    } else {
        PyErr_SetString(PyExc_TypeError, "Expected an integer or IP address");
        return NULL;
    }

    value.type = SKBAG_COUNTER_U64;
    rv = skBagCounterGet(self->bag, &key, &value);

    assert(rv != SKBAG_ERR_KEY_NOT_FOUND);
    if (rv == SKBAG_ERR_KEY_RANGE) {
        PyErr_SetString(PyExc_IndexError, "Index out of range");
        return NULL;
    }
    if (rv != SKBAG_OK) {
        PyErr_SetString(PyExc_ValueError, skBagStrerror(rv));
        return NULL;
    }
    assert(value.type == SKBAG_COUNTER_U64);

    return PyLong_FromUnsignedLongLong(value.val.u64);
}

static PyObject *silkPyBag_type_merge(
    PyObject    UNUSED(*self),
    PyObject           *args)
{
    char *a, *b;
    skBagFieldType_t a_type, b_type, c_type;
    skBagErr_t rv;
    char buf[SKBAG_MAX_FIELD_BUFLEN];

    if (!PyArg_ParseTuple(args, "ss", &a, &b)) {
        return NULL;
    }
    rv = skBagFieldTypeLookup(a, &a_type, NULL);
    if (rv != SKBAG_OK) {
        PyErr_Format(PyExc_ValueError, "'%s' is not a valid key type", a);
    }
    rv = skBagFieldTypeLookup(b, &b_type, NULL);
    if (rv != SKBAG_OK) {
        PyErr_Format(PyExc_ValueError, "'%s' is not a valid key type", b);
    }
    c_type = skBagFieldTypeMerge(a_type, b_type);
    skBagFieldTypeAsString(c_type, buf, sizeof(buf));
    return PyUnicode_FromString(buf);
}


/*
 *************************************************************************
 *   TCP Flags
 *************************************************************************
 */

typedef struct silkPyTCPFlags_st {
    PyObject_HEAD
    uint8_t val;
} silkPyTCPFlags;

/* function prototypes */
static PyObject *silkPyTCPFlags_and(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b);
static PyObject *silkPyTCPFlags_getflag(
    silkPyTCPFlags *obj,
    void           *bit);
static PyObject *silkPyTCPFlags_getflag_deprecated(
    silkPyTCPFlags *obj,
    void           *bit);
static long silkPyTCPFlags_hash(
    silkPyTCPFlags *obj);
static int silkPyTCPFlags_init(
    silkPyTCPFlags *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyTCPFlags_int(
    silkPyTCPFlags *obj);
static silkPyTCPFlags *silkPyTCPFlags_invert(
    silkPyTCPFlags *obj);
static PyObject *silkPyTCPFlags_matches(
    silkPyTCPFlags *self,
    PyObject       *arg);
static PyObject *silkPyTCPFlags_new(
    PyTypeObject       *type,
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds));
static int silkPyTCPFlags_nonzero(
    silkPyTCPFlags *a);
static PyObject *silkPyTCPFlags_or(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b);
static PyObject *silkPyTCPFlags_padded(
    silkPyTCPFlags *obj);
static PyObject *silkPyTCPFlags_repr(
    silkPyTCPFlags *obj);
static PyObject *silkPyTCPFlags_richcompare(
    silkPyTCPFlags *self,
    PyObject       *obj,
    int             cmp);
static int silkPyTCPFlags_setup(
    PyObject   *mod);
static PyObject *silkPyTCPFlags_str(
    silkPyTCPFlags *obj);
static PyObject *silkPyTCPFlags_xor(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b);

/* define docs and methods */
static char silkPyTCPFlags_doc[] =
    ("TCPFlags(string)   -> TCPFlags based on flag string\n"
     "TCPFlags(int)      -> TCPFlags based on integer representation\n"
     "TCPFlags(TCPFlags) -> Copy of TCPFlags");

static PyNumberMethods silkPyTCPFlags_number_methods;

static PyMethodDef silkPyTCPFlags_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"matches", (PyCFunction)silkPyTCPFlags_matches, METH_O,
     "Return whether the flags match the high/mask flagstring"},
    {"padded", (PyCFunction)silkPyTCPFlags_padded, METH_NOARGS,
     "Returns the flags string padded with spaces, so flags line up"},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static uint8_t flags_array[] = {
    FIN_FLAG, SYN_FLAG, RST_FLAG, PSH_FLAG,
    ACK_FLAG, URG_FLAG, ECE_FLAG, CWR_FLAG};

static PyGetSetDef silkPyTCPFlags_getsetters[] = {
    {"fin", (getter)silkPyTCPFlags_getflag, NULL,
     "FIN flag", (void*)&flags_array[0]},
    {"syn", (getter)silkPyTCPFlags_getflag, NULL,
     "SYN flag", (void*)&flags_array[1]},
    {"rst", (getter)silkPyTCPFlags_getflag, NULL,
     "RST flag", (void*)&flags_array[2]},
    {"psh", (getter)silkPyTCPFlags_getflag, NULL,
     "PSH flag", (void*)&flags_array[3]},
    {"ack", (getter)silkPyTCPFlags_getflag, NULL,
     "ACK flag", (void*)&flags_array[4]},
    {"urg", (getter)silkPyTCPFlags_getflag, NULL,
     "URG flag", (void*)&flags_array[5]},
    {"ece", (getter)silkPyTCPFlags_getflag, NULL,
     "ECE flag", (void*)&flags_array[6]},
    {"cwr", (getter)silkPyTCPFlags_getflag, NULL,
     "CWR flag", (void*)&flags_array[7]},

    {"FIN", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "FIN flag", (void*)&flags_array[0]},
    {"SYN", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "SYN flag", (void*)&flags_array[1]},
    {"RST", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "RST flag", (void*)&flags_array[2]},
    {"PSH", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "PSH flag", (void*)&flags_array[3]},
    {"ACK", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "ACK flag", (void*)&flags_array[4]},
    {"URG", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "URG flag", (void*)&flags_array[5]},
    {"ECE", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "ECE flag", (void*)&flags_array[6]},
    {"CWR", (getter)silkPyTCPFlags_getflag_deprecated, NULL,
     "CWR flag", (void*)&flags_array[7]},
    {NULL, NULL, NULL, NULL, NULL}
};

/* define the object types */
static PyTypeObject silkPyTCPFlagsType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.TCPFlags",            /* tp_name */
    sizeof(silkPyTCPFlags),     /* tp_basicsize */
    0,                          /* tp_itemsize */
    obj_dealloc,                /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    (reprfunc)silkPyTCPFlags_repr, /* tp_repr */
    &silkPyTCPFlags_number_methods, /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    (hashfunc)silkPyTCPFlags_hash, /* tp_hash  */
    0,                          /* tp_call */
    (reprfunc)silkPyTCPFlags_str, /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
#if PY_MAJOR_VERSION < 3
    Py_TPFLAGS_CHECKTYPES | Py_TPFLAGS_HAVE_RICHCOMPARE |
#endif
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    silkPyTCPFlags_doc,         /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    (richcmpfunc)silkPyTCPFlags_richcompare, /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    silkPyTCPFlags_methods,     /* tp_methods */
    0,                          /* tp_members */
    silkPyTCPFlags_getsetters,  /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyTCPFlags_init, /* tp_init */
    0,                          /* tp_alloc */
    silkPyTCPFlags_new,         /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyTCPFlags_Check(op)                \
    PyObject_TypeCheck(op, &silkPyTCPFlagsType)

static PyObject *silkPyTCPFlags_and(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b)
{
    PyObject *new_obj;

    if (!silkPyTCPFlags_Check(b)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
    if (new_obj != NULL) {
        ((silkPyTCPFlags*)new_obj)->val = a->val & b->val;
    }
    return new_obj;
}

static PyObject *silkPyTCPFlags_getflag(
    silkPyTCPFlags *obj,
    void           *bit)
{
    return PyBool_FromLong(obj->val & *(uint8_t*)bit);
}

static PyObject *silkPyTCPFlags_getflag_deprecated(
    silkPyTCPFlags *obj,
    void           *bit)
{
    PyErr_Warn(PyExc_DeprecationWarning,
               ("Use of upper-case flag check attributes for "
                "TCPFlags is deprecated"));
    return PyBool_FromLong(obj->val & *(uint8_t*)bit);
}

static long silkPyTCPFlags_hash(
    silkPyTCPFlags *obj)
{
    return obj->val;
}

static int silkPyTCPFlags_init(
    silkPyTCPFlags *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"value", NULL};
    PyObject *val;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "O", kwlist, &val)) {
        return -1;
    }

    if (silkPyTCPFlags_Check(val)) {
        silkPyTCPFlags *oflags = (silkPyTCPFlags*)val;
        self->val = oflags->val;
    } else if (IS_INT(val)) {
        long intval = PyLong_AsLong(val);
        if (intval < 0 || intval > (long)UINT8_MAX) {
            PyErr_Format(PyExc_OverflowError,
                         "Illegal TCP flag value: %ld", intval);
            return -1;
        }
        self->val = intval;
    } else if (IS_STRING(val)) {
        PyObject *bytes = bytes_from_string(val);
        char *strval;

        if (bytes == NULL) {
            return -1;
        }
        strval = PyBytes_AS_STRING(bytes);
        if (skStringParseTCPFlags(&self->val, strval)) {
            PyErr_Format(PyExc_ValueError,
                         "Illegal TCP flag value: %s", strval);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
    } else {
        obj_error("Illegal value: %s", val);
        return -1;
    }

    return 0;
}

static PyObject *silkPyTCPFlags_int(
    silkPyTCPFlags *obj)
{
    return PyInt_FromLong(obj->val);
}

static silkPyTCPFlags *silkPyTCPFlags_invert(
    silkPyTCPFlags *obj)
{
    silkPyTCPFlags *new_obj =
        (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);

    if (new_obj != NULL) {
        new_obj->val = ~obj->val;
    }
    return new_obj;
}

static PyObject *silkPyTCPFlags_matches(
    silkPyTCPFlags *self,
    PyObject       *arg)
{
    char *repr;
    PyObject *bytes;
    uint8_t high, mask;
    int rv;

    if (!IS_STRING(arg)) {
        PyErr_SetString(PyExc_TypeError, "Expected string");
        return NULL;
    }

    bytes = bytes_from_string(arg);
    repr = PyBytes_AS_STRING(bytes);
    rv = skStringParseTCPFlagsHighMask(&high, &mask, repr);
    Py_DECREF(bytes);
    if (rv == SKUTILS_ERR_SHORT) {
        mask = high;
    } else if (rv != 0) {
        PyErr_SetString(PyExc_ValueError, "Illegal flag/mask");
        return NULL;
    }

    return PyBool_FromLong((self->val & mask) == high);
}

static PyObject *silkPyTCPFlags_new(
    PyTypeObject       *type,
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds))
{
    silkPyTCPFlags *self;

    self = (silkPyTCPFlags*)type->tp_alloc(type, 0);

    if (self != NULL) {
        self->val = 0;
    }

    return (PyObject*)self;
}

static int silkPyTCPFlags_nonzero(
    silkPyTCPFlags *a)
{
    return a->val ? 1 : 0;
}

static PyObject *silkPyTCPFlags_or(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b)
{
    PyObject *new_obj;

    if (!silkPyTCPFlags_Check(b)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
    if (new_obj != NULL) {
        ((silkPyTCPFlags*)new_obj)->val = a->val | b->val;
    }
    return new_obj;
}

static PyObject *silkPyTCPFlags_padded(
    silkPyTCPFlags *obj)
{
    char flags[SK_TCPFLAGS_STRLEN];

    tcpflags_string_r(obj->val, flags);

    return PyUnicode_FromString(flags);
}

static PyObject *silkPyTCPFlags_repr(
    silkPyTCPFlags *obj)
{
    char flags[SK_TCPFLAGS_STRLEN];

    tcpflags_string_r(obj->val, flags);

    return PyUnicode_FromFormat("silk.TCPFlags('%s')", flags);
}

static PyObject *silkPyTCPFlags_richcompare(
    silkPyTCPFlags *self,
    PyObject       *obj,
    int             cmp)
{
    if (cmp != Py_EQ && cmp != Py_NE) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    if (!silkPyTCPFlags_Check(obj)) {
        PyErr_SetString(PyExc_TypeError, "Expected silk.TCPFlags");
        return NULL;
    }

    if (self->val == ((silkPyTCPFlags*)obj)->val) {
        if (cmp == Py_EQ) {
            Py_RETURN_TRUE;
        } else {
            Py_RETURN_FALSE;
        }
    }
    if (cmp == Py_NE) {
        Py_RETURN_TRUE;
    }

    Py_RETURN_FALSE;
}

static int silkPyTCPFlags_setup(
    PyObject   *mod)
{
    /* Setup number methods */
    memset(&silkPyTCPFlags_number_methods, 0,
           sizeof(silkPyTCPFlags_number_methods));
#if PY_MAJOR_VERSION >= 3
    silkPyTCPFlags_number_methods.nb_bool =
        (inquiry)silkPyTCPFlags_nonzero;
#else
    silkPyTCPFlags_number_methods.nb_nonzero =
        (inquiry)silkPyTCPFlags_nonzero;
#endif
    silkPyTCPFlags_number_methods.nb_invert =
        (unaryfunc)silkPyTCPFlags_invert;
    silkPyTCPFlags_number_methods.nb_and = (binaryfunc)silkPyTCPFlags_and;
    silkPyTCPFlags_number_methods.nb_xor = (binaryfunc)silkPyTCPFlags_xor;
    silkPyTCPFlags_number_methods.nb_or = (binaryfunc)silkPyTCPFlags_or;
    silkPyTCPFlags_number_methods.nb_int = (unaryfunc)silkPyTCPFlags_int;

    /* Initialize type and add to module */
    if (PyType_Ready(&silkPyTCPFlagsType) < 0) {
        return -1;
    }
    return PyModule_AddObject(mod, "TCPFlags",
                              (PyObject*)&silkPyTCPFlagsType);
}

static PyObject *silkPyTCPFlags_str(
    silkPyTCPFlags *obj)
{
    char flags[SK_TCPFLAGS_STRLEN];
    char unpadded[SK_TCPFLAGS_STRLEN];
    char *f, *u;

    tcpflags_string_r(obj->val, flags);
    for (f = flags, u = unpadded; *f; f++) {
        if (*f != ' ') {
            *u++ = *f;
        }
    }
    *u = '\0';

    return PyUnicode_FromString(unpadded);
}

static PyObject *silkPyTCPFlags_xor(
    silkPyTCPFlags *a,
    silkPyTCPFlags *b)
{
    PyObject *new_obj;

    if (!silkPyTCPFlags_Check(b)) {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    new_obj = silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType, 0);
    if (new_obj != NULL) {
        ((silkPyTCPFlags*)new_obj)->val = a->val ^ b->val;
    }
    return new_obj;
}


/*
 *************************************************************************
 *   RWRec
 *************************************************************************
 */

typedef struct silkPyRawRWRec_st {
    PyObject_HEAD
    rwRec rec;
} silkPyRawRWRec;

typedef struct silkPyRWRec_st {
    PyObject_HEAD
    silkPyRawRWRec *raw;
} silkPyRWRec;

/* function prototypes */
static PyObject *silkPyRWRec_application_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_application_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_bytes_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_bytes_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_classname_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_classtype_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_classtype_id_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_classtype_id_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static int silkPyRWRec_classtype_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static void silkPyRWRec_dealloc(
    silkPyRWRec    *obj);
static PyObject *silkPyRWRec_dip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_dip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_dport_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_dport_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_duration_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_duration_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_duration_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static int silkPyRWRec_duration_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_etime_epoch_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_etime_epoch_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_etime_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_etime_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_finnoack_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_finnoack_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_icmpcode_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_icmpcode_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_icmptype_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_icmptype_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_new(
    PyTypeObject *type,
    PyObject     *args,
    PyObject     *kwds);
static int silkPyRWRec_init(
    silkPyRWRec    *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyRWRec_initial_tcpflags_get(
    silkPyRWRec    *obj,
    PyObject       *deprecated);
static int silkPyRWRec_initial_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    PyObject       *deprecated);
static PyObject *silkPyRWRec_input_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_input_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_is_web(
    silkPyRWRec    *obj);
static PyObject *silkPyRWRec_nhip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_nhip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_output_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_output_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_packets_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_packets_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_protocol_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_protocol_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_richcompare(
    silkPyRWRec    *self,
    PyObject       *obj,
    int             cmp);
static PyObject *silkPyRWRec_sensor_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_sensor_id_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_sensor_id_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static int silkPyRWRec_sensor_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_session_tcpflags_get(
    silkPyRWRec    *obj,
    PyObject       *deprecated);
static int silkPyRWRec_session_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    PyObject       *deprecated);
static PyObject *silkPyRWRec_sip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_sip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_sport_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_sport_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_stime_epoch_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_stime_epoch_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_stime_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_stime_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_tcpflags_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_timeout_killed_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_timeout_killed_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_timeout_started_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_timeout_started_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_typename_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static PyObject *silkPyRWRec_uniform_packets_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure));
static int silkPyRWRec_uniform_packets_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure));
static int silkPyRawRWRec_init(
    silkPyRawRWRec *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyRawRWRec_new(
    PyTypeObject       *type,
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds));

/* define docs and methods */
static PyMethodDef silkPyRWRec_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"is_web", (PyCFunction)silkPyRWRec_is_web, METH_NOARGS,
     "Returns whether IPv6 can be stored in a WWW file format"},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PyGetSetDef silkPyRWRec_getseters[] = {
    {"application",
     (getter)silkPyRWRec_application_get, (setter)silkPyRWRec_application_set,
     "\"service\" port set by the collector", NULL},
    {"bytes",
     (getter)silkPyRWRec_bytes_get,       (setter)silkPyRWRec_bytes_set,
     "Count of bytes", NULL},
    {"classname",
     (getter)silkPyRWRec_classname_get,   NULL,
     "class name (read-only)", NULL},
    {"classtype",
     (getter)silkPyRWRec_classtype_get,   (setter)silkPyRWRec_classtype_set,
     "class name, type name pair", NULL},
    {"classtype_id",
     (getter)silkPyRWRec_classtype_id_get,(setter)silkPyRWRec_classtype_id_set,
     "class, type pair ID", NULL},
    {"dip",
     (getter)silkPyRWRec_dip_get,         (setter)silkPyRWRec_dip_set,
     "destination IP", NULL},
    {"dport",
     (getter)silkPyRWRec_dport_get,       (setter)silkPyRWRec_dport_set,
     "Destination port", NULL},
    {"duration",
     (getter)silkPyRWRec_duration_get,    (setter)silkPyRWRec_duration_set,
     "duration of flow as datetime.timedelta", NULL},
    {"duration_secs",
     (getter)silkPyRWRec_duration_secs_get,
     (setter)silkPyRWRec_duration_secs_set,
     "duration of flow in seconds", NULL},
    {"etime",
     (getter)silkPyRWRec_etime_get,       (setter)silkPyRWRec_etime_set,
     "end time of flow as datetime.timedelta", NULL},
    {"etime_epoch_secs",
     (getter)silkPyRWRec_etime_epoch_secs_get,
     (setter)silkPyRWRec_etime_epoch_secs_set,
     "end time of flow as a number of seconds since the epoch time", NULL},
    {"finnoack",
     (getter)silkPyRWRec_finnoack_get,    (setter)silkPyRWRec_finnoack_set,
     "FIN followed by not ACK", NULL},
    {"icmpcode",
     (getter)silkPyRWRec_icmpcode_get,    (setter)silkPyRWRec_icmpcode_set,
     "ICMP code", NULL},
    {"icmptype",
     (getter)silkPyRWRec_icmptype_get,    (setter)silkPyRWRec_icmptype_set,
     "ICMP type", NULL},
    {"initflags",
     (getter)silkPyRWRec_initial_tcpflags_get,
     (setter)silkPyRWRec_initial_tcpflags_set,
     "TCP flags of first packet", Py_True}, /* Deprecated */
    {"initial_tcpflags",
     (getter)silkPyRWRec_initial_tcpflags_get,
     (setter)silkPyRWRec_initial_tcpflags_set,
     "TCP flags of first packet", NULL},
    {"input",
     (getter)silkPyRWRec_input_get,       (setter)silkPyRWRec_input_set,
     "router incoming SNMP interface", NULL},
    {"nhip",
     (getter)silkPyRWRec_nhip_get,        (setter)silkPyRWRec_nhip_set,
     "router next hop IP", NULL},
    {"output",
     (getter)silkPyRWRec_output_get,      (setter)silkPyRWRec_output_set,
     "router outgoing SNMP interface", NULL},
    {"packets",
     (getter)silkPyRWRec_packets_get,     (setter)silkPyRWRec_packets_set,
     "count of packets", NULL},
    {"protocol",
     (getter)silkPyRWRec_protocol_get,    (setter)silkPyRWRec_protocol_set,
     "IP protocol", NULL},
    {"restflags",
     (getter)silkPyRWRec_session_tcpflags_get,
     (setter)silkPyRWRec_session_tcpflags_set,
     "TCP flags on non-initial packets", Py_True}, /* Deprecated */
    {"sensor",
     (getter)silkPyRWRec_sensor_get,      (setter)silkPyRWRec_sensor_set,
     "sensor name", NULL},
    {"sensor_id",
     (getter)silkPyRWRec_sensor_id_get,   (setter)silkPyRWRec_sensor_id_set,
     "sensor ID", NULL},
    {"session_tcpflags",
     (getter)silkPyRWRec_session_tcpflags_get,
     (setter)silkPyRWRec_session_tcpflags_set,
     "TCP flags on non-initial packets", NULL},
    {"sip",
     (getter)silkPyRWRec_sip_get,         (setter)silkPyRWRec_sip_set,
     "source IP", NULL},
    {"sport",
     (getter)silkPyRWRec_sport_get,       (setter)silkPyRWRec_sport_set,
     "source port", NULL},
    {"stime",
     (getter)silkPyRWRec_stime_get,       (setter)silkPyRWRec_stime_set,
     "start time of flow as datetime.datetime", NULL},
    {"stime_epoch_secs",
     (getter)silkPyRWRec_stime_epoch_secs_get,
     (setter)silkPyRWRec_stime_epoch_secs_set,
     "start time of flow as a number of seconds since the epoch time", NULL},
    {"tcpflags",
     (getter)silkPyRWRec_tcpflags_get,    (setter)silkPyRWRec_tcpflags_set,
     "OR of all tcpflags", NULL},
    {"timeout_killed",
     (getter)silkPyRWRec_timeout_killed_get,
     (setter)silkPyRWRec_timeout_killed_set,
     "flow ended prematurely due to timeout by the collector", NULL},
    {"timeout_started",
     (getter)silkPyRWRec_timeout_started_get,
     (setter)silkPyRWRec_timeout_started_set,
     "flow is a continuation of a flow timed-out by the collector", NULL},
    {"typename",
     (getter)silkPyRWRec_typename_get,    NULL,
     "type name (read-only)", NULL},
    {"uniform_packets",
     (getter)silkPyRWRec_uniform_packets_get,
     (setter)silkPyRWRec_uniform_packets_set,
     "flow contained only packets of uniform size", NULL},
    {NULL, NULL, NULL, NULL, NULL}
};

/* define the object types */
static PyTypeObject silkPyRawRWRecType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.RWRawRec",     /* tp_name */
    sizeof(silkPyRawRWRec),     /* tp_basicsize */
    0,                          /* tp_itemsize */
    obj_dealloc,                /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "Raw RW Record",            /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyRawRWRec_init, /* tp_init */
    0,                          /* tp_alloc */
    silkPyRawRWRec_new,         /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

static PyTypeObject silkPyRWRecType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.RWRecBase",    /* tp_name */
    sizeof(silkPyRWRec),        /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyRWRec_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
#if PY_MAJOR_VERSION < 3
    Py_TPFLAGS_HAVE_RICHCOMPARE |
#endif
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "Base RW Record",           /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    (richcmpfunc)silkPyRWRec_richcompare, /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    silkPyRWRec_methods,        /* tp_methods */
    0,                          /* tp_members */
    silkPyRWRec_getseters,      /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyRWRec_init, /* tp_init */
    0,                          /* tp_alloc */
    silkPyRWRec_new,            /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyRawRWRec_Check(op)                \
    PyObject_TypeCheck(op, &silkPyRawRWRecType)
#define silkPyRWRec_Check(op)                   \
    PyObject_TypeCheck(op, &silkPyRWRecType)

static PyObject *silkPyRWRec_application_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetApplication(&obj->raw->rec));
}

static int silkPyRWRec_application_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The application value must be a 16-bit integer");
        return -1;
    }

    rwRecSetApplication(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_bytes_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyLong_FromUnsignedLong(rwRecGetBytes(&obj->raw->rec));
}

static int silkPyRWRec_bytes_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    unsigned long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsUnsignedLong(value);
    if (PyErr_Occurred() || val > UINT32_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The bytes value must be a 32-bit integer");
        return -1;
    }

    rwRecSetBytes(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_classname_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    char          class_name[SK_MAX_STRLEN_FLOWTYPE+1];
    flowtypeID_t  flowtype = rwRecGetFlowType(&obj->raw->rec);

    CHECK_SITE(NULL);

    sksiteFlowtypeGetClass(class_name, sizeof(class_name), flowtype);

    return PyUnicode_InternFromString(class_name);
}

static PyObject *silkPyRWRec_classtype_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    char          class_name[SK_MAX_STRLEN_FLOWTYPE+1];
    char          type_name[SK_MAX_STRLEN_FLOWTYPE+1];
    flowtypeID_t  flowtype = rwRecGetFlowType(&obj->raw->rec);
    PyObject     *pair     = PyTuple_New(2);

    if (pair == NULL) {
        return NULL;
    }

    CHECK_SITE(NULL);

    sksiteFlowtypeGetClass(class_name, sizeof(class_name), flowtype);
    sksiteFlowtypeGetType(type_name, sizeof(type_name), flowtype);

    PyTuple_SET_ITEM(pair, 0, PyUnicode_InternFromString(class_name));
    PyTuple_SET_ITEM(pair, 1, PyUnicode_InternFromString(type_name));

    return pair;
}

static PyObject *silkPyRWRec_classtype_id_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetFlowType(&obj->raw->rec));
}

static int silkPyRWRec_classtype_id_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The classtype_id value must be an 8-bit integer");
        return -1;
    }

    rwRecSetFlowType(&obj->raw->rec, val);
    return 0;
}

static int silkPyRWRec_classtype_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    char *class_name, *type_name;
    flowtypeID_t flowtype;


    if (!PyArg_ParseTuple(value, "ss", &class_name, &type_name)) {
        return -1;
    }

    CHECK_SITE(-1);

    flowtype = sksiteFlowtypeLookupByClassType(class_name, type_name);

    if (flowtype == SK_INVALID_FLOWTYPE) {
        PyErr_SetString(PyExc_ValueError, "Invalid (class_name, type) pair");
        return -1;
    }

    rwRecSetFlowType(&obj->raw->rec, flowtype);
    return 0;
}

static void silkPyRWRec_dealloc(
    silkPyRWRec    *obj)
{
    Py_XDECREF((PyObject*)obj->raw);
    Py_TYPE(obj)->tp_free(obj);
}

static PyObject *silkPyRWRec_dip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    silkPyIPAddr *addr;
    PyTypeObject *type;

    if (rwRecIsIPv6(&obj->raw->rec)) {
        type = &silkPyIPv6AddrType;
    } else {
        type = &silkPyIPv4AddrType;
    }

    addr = PyObject_New(silkPyIPAddr, type);
    if (addr != NULL) {
        rwRecMemGetDIP(&obj->raw->rec, &addr->addr);
    }

    return (PyObject*)addr;
}

static int silkPyRWRec_dip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    if (IS_STRING(value)) {
        skipaddr_t  addr;
        PyObject   *bytes;
        char       *repr;
        int         rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv = skStringParseIP(&addr, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecMemSetDIP(&obj->raw->rec, &addr);
        return 0;
    }

    if (silkPyIPAddr_Check(value)) {
        silkPyIPAddr *addr = (silkPyIPAddr*)value;
        rwRecMemSetDIP(&obj->raw->rec, &addr->addr);
        return 0;
    }

    PyErr_SetString(PyExc_TypeError, "The dip must be a valid IP address");
    return -1;
}

static PyObject *silkPyRWRec_dport_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetDPort(&obj->raw->rec));
}

static int silkPyRWRec_dport_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The dport value must be a 16-bit integer");
        return -1;
    }

    rwRecSetDPort(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_duration_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyObject_CallFunction(GLOBALS->timedelta, "IIII", 0, 0, 0,
                                 rwRecGetElapsed(&obj->raw->rec));
}

static PyObject *silkPyRWRec_duration_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    double elapsed = ((double)rwRecGetElapsed(&obj->raw->rec)) / 1.0e3;

    return PyFloat_FromDouble(elapsed);
}

static int silkPyRWRec_duration_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    const char *errstr = "The duration_secs value must be a positive number";
    PyObject *pyfloat_val;
    PyObject *pyint_val;
    int64_t long_val;

    if (!PyNumber_Check(value)) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }

    pyfloat_val = PyNumber_Multiply(value, GLOBALS->thousand);
    if (pyfloat_val == NULL) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }
    pyint_val = PyNumber_Long(pyfloat_val);
    Py_DECREF(pyfloat_val);
    if (pyint_val == NULL) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }
    long_val = PyLong_AsLongLong(pyint_val);
    Py_DECREF(pyint_val);
    if (long_val < 0) {
        PyErr_SetString(PyExc_OverflowError, errstr);
        return -1;
    }

    if (long_val > UINT32_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The duration_secs value must be less than "
                        "4294967.295");
        return -1;
    }

    rwRecSetElapsed(&obj->raw->rec, long_val);
    return 0;
}

static int silkPyRWRec_duration_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    PyObject *days;
    PyObject *secs;
    PyObject *usecs;
    uint32_t millisecs;

    if (!PyDelta_Check(value)) {
        PyErr_SetString(PyExc_TypeError,
                        "The duration value must be a datetime.timedelta");
        return -1;
    }
    if (PyObject_RichCompareBool(value, GLOBALS->minelapsed, Py_LT) ||
        PyObject_RichCompareBool(value, GLOBALS->maxelapsed, Py_GT))
    {
        PyErr_SetString(PyExc_OverflowError,
                        ("The duration must be in the range [0,4294967295] "
                         "milliseconds"));
        return -1;
    }
    days = PyObject_GetAttrString(value, "days");
    secs = PyObject_GetAttrString(value, "seconds");
    usecs = PyObject_GetAttrString(value, "microseconds");
    millisecs = PyLong_AsLong(days) * 1000 * 3600 * 24 +
                PyLong_AsLong(secs) * 1000 +
                PyLong_AsLong(usecs) / 1000;
    Py_DECREF(secs);
    Py_DECREF(usecs);

    rwRecSetElapsed(&obj->raw->rec, millisecs);
    return 0;
}

static PyObject *silkPyRWRec_etime_epoch_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    double duration = (double)(rwRecGetStartTime(&obj->raw->rec) +
                               rwRecGetElapsed(&obj->raw->rec)) / 1.0e3;

    return PyFloat_FromDouble(duration);
}

static int silkPyRWRec_etime_epoch_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    PyObject *s_time, *dur;
    int       retval;

    s_time = silkPyRWRec_stime_epoch_secs_get(obj, NULL);
    if (s_time == NULL) {
        return -1;
    }

    dur = PyNumber_Subtract(value, s_time);
    Py_DECREF(s_time);
    if (dur == NULL) {
        return -1;
    }

    retval = silkPyRWRec_duration_secs_set(obj, dur, NULL);
    Py_DECREF(dur);

    return retval;
}

static PyObject *silkPyRWRec_etime_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    PyObject *s_time, *dur;
    PyObject *retval;

    s_time = silkPyRWRec_stime_get(obj, NULL);
    if (s_time == NULL) {
        return NULL;
    }
    dur = silkPyRWRec_duration_get(obj, NULL);
    if (dur == NULL) {
        Py_DECREF(s_time);
        return NULL;
    }

    retval = PyNumber_Add(s_time, dur);

    Py_DECREF(s_time);

    return retval;
}

static int silkPyRWRec_etime_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    PyObject *s_time, *dur;
    int       retval;

    s_time = silkPyRWRec_stime_get(obj, NULL);
    if (s_time == NULL) {
        return -1;
    }

    dur = PyNumber_Subtract(value, s_time);
    Py_DECREF(s_time);
    if (dur == NULL) {
        return -1;
    }

    retval = silkPyRWRec_duration_set(obj, dur, NULL);
    Py_DECREF(dur);

    return retval;
}

static PyObject *silkPyRWRec_finnoack_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    uint8_t state;

    state = rwRecGetTcpState(&obj->raw->rec);
    if (!(state & SK_TCPSTATE_EXPANDED)) {
        Py_RETURN_NONE;
    }
    return PyBool_FromLong(state & SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK);
}

static int silkPyRWRec_finnoack_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    int     rv;
    uint8_t state;

    rv = PyObject_IsTrue(value);
    if (rv == -1) {
        return -1;
    }
    state = rwRecGetTcpState(&obj->raw->rec) | SK_TCPSTATE_EXPANDED;
    if (rv) {
        state |= SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
    } else {
        state &= ~SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK;
    }
    rwRecSetTcpState(&obj->raw->rec, state);

    return 0;
}

static PyObject *silkPyRWRec_icmpcode_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetIcmpCode(&obj->raw->rec));
}

static int silkPyRWRec_icmpcode_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The icmpcode value must be a 8-bit integer");
        return -1;
    }

    rwRecSetIcmpCode(&obj->raw->rec, (uint8_t)val);
    return 0;
}

static PyObject *silkPyRWRec_icmptype_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetIcmpType(&obj->raw->rec));
}

static int silkPyRWRec_icmptype_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The icmptype value must be a 8-bit integer");
        return -1;
    }

    rwRecSetIcmpType(&obj->raw->rec, (uint8_t)val);
    return 0;
}

static PyObject *silkPyRWRec_new(
    PyTypeObject    *type,
    PyObject UNUSED(*args),
    PyObject UNUSED(*kwds))
{
    silkPyRWRec *self;
    PyObject *newrawrec = GLOBALS->newrawrec;

    self = (silkPyRWRec *)type->tp_alloc(type, 0);
    if (self != NULL) {
        self->raw = (silkPyRawRWRec *)newrawrec;
        Py_INCREF(newrawrec);
    }
    return (PyObject *)self;
}

static int silkPyRWRec_init(
    silkPyRWRec    *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"clone", "copy", NULL};
    silkPyRawRWRec *clne = NULL;
    silkPyRWRec    *copy  = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!O!", kwlist,
                                     &silkPyRawRWRecType, (PyObject **)&clne,
                                     &silkPyRWRecType, (PyObject **)&copy))
    {
        return -1;
    }

    if (clne && copy) {
        PyErr_SetString(PyExc_RuntimeError, "Cannot clone and copy");
        return -1;
    }

    Py_XDECREF((PyObject*)self->raw);
    if (clne) {
        Py_INCREF(clne);
        self->raw = clne;
    } else if (copy) {
        self->raw = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
            (PyObject*)&silkPyRawRWRecType, copy->raw, NULL);
    } else {
        self->raw = (silkPyRawRWRec*)PyObject_CallFunctionObjArgs(
            (PyObject*)&silkPyRawRWRecType, NULL);
    }

    if (self->raw == NULL) {
        return -1;
    }

    return 0;
}

static PyObject *silkPyRWRec_initial_tcpflags_get(
    silkPyRWRec    *obj,
    PyObject       *deprecated)
{
    silkPyTCPFlags *flags;

    if (deprecated == Py_True) {
        int rv = PyErr_Warn(PyExc_DeprecationWarning,
                            ("'initflags' is deprecated in favor of"
                             " 'initial_tcpflags'."));
        if (rv) {
            return NULL;
        }
    }

    if (!(rwRecGetTcpState(&obj->raw->rec) & SK_TCPSTATE_EXPANDED)) {
        Py_RETURN_NONE;
    }
    flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
                                                          0);
    if (flags != NULL) {
        flags->val = rwRecGetInitFlags(&obj->raw->rec);
    }

    return (PyObject*)flags;
}

static int silkPyRWRec_initial_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    PyObject       *deprecated)
{
    long    val;
    uint8_t state;

    if (deprecated == Py_True) {
        int rv = PyErr_Warn(PyExc_DeprecationWarning,
                            ("'initflags' is deprecated in favor of"
                             " 'initial_tcpflags'."));
        if (rv) {
            return -1;
        }
    }

    state = rwRecGetTcpState(&obj->raw->rec) | SK_TCPSTATE_EXPANDED;

    if (IS_STRING(value)) {
        uint8_t  flagval;
        PyObject *bytes;
        char    *repr;
        int      rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv = skStringParseTCPFlags(&flagval, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal TCP flags: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecSetTcpState(&obj->raw->rec, state);
        rwRecSetInitFlags(&obj->raw->rec, flagval);
        return 0;
    }

    if (silkPyTCPFlags_Check(value)) {
        silkPyTCPFlags *flags = (silkPyTCPFlags*)value;
        rwRecSetTcpState(&obj->raw->rec, state);
        rwRecSetInitFlags(&obj->raw->rec, flags->val);
        return 0;
    }

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        obj_error("Illegal TCP flags value: %s", value);
        return -1;
    }

    rwRecSetTcpState(&obj->raw->rec, state);
    rwRecSetInitFlags(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_input_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return  PyInt_FromLong(rwRecGetInput(&obj->raw->rec));
}

static int silkPyRWRec_input_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The input value must be a 16-bit integer");
        return -1;
    }

    rwRecSetInput(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_is_web(
    silkPyRWRec    *obj)
{
    uint16_t sport = rwRecGetSPort(&obj->raw->rec);
    uint16_t dport = rwRecGetDPort(&obj->raw->rec);
    return PyBool_FromLong(
        rwRecGetProto(&obj->raw->rec) == 6 &&
        (sport == 80 || dport == 80 ||
         sport == 443 || dport == 443 ||
         sport == 8080 || dport == 8080));
}

static PyObject *silkPyRWRec_nhip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    silkPyIPAddr *addr;
    PyTypeObject *type;

    if (rwRecIsIPv6(&obj->raw->rec)) {
        type = &silkPyIPv6AddrType;
    } else {
        type = &silkPyIPv4AddrType;
    }

    addr = PyObject_New(silkPyIPAddr, type);
    if (addr != NULL) {
        rwRecMemGetNhIP(&obj->raw->rec, &addr->addr);
    }
    return (PyObject*)addr;
}

static int silkPyRWRec_nhip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    if (IS_STRING(value)) {
        skipaddr_t  addr;
        PyObject   *bytes;
        char       *repr;
        int         rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv   = skStringParseIP(&addr, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecMemSetNhIP(&obj->raw->rec, &addr);
        return 0;
    }

    if (silkPyIPAddr_Check(value)) {
        silkPyIPAddr *addr = (silkPyIPAddr*)value;
        rwRecMemSetNhIP(&obj->raw->rec, &addr->addr);
        return 0;
    }

    PyErr_SetString(PyExc_TypeError, "The nhip must be a valid IP address");
    return -1;
}

static PyObject *silkPyRWRec_output_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetOutput(&obj->raw->rec));
}

static int silkPyRWRec_output_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The output value must be a 16-bit integer");
        return -1;
    }

    rwRecSetOutput(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_packets_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyLong_FromUnsignedLong(rwRecGetPkts(&obj->raw->rec));
}

static int silkPyRWRec_packets_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    unsigned long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsUnsignedLong(value);
    if (PyErr_Occurred() || val > UINT32_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The packets value must be a 32-bit integer");
        return -1;
    }

    rwRecSetPkts(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_protocol_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetProto(&obj->raw->rec));
}

static int silkPyRWRec_protocol_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The protocol value must be an 8-bit integer");
        return -1;
    }

    rwRecSetProto(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_richcompare(
    silkPyRWRec    *self,
    PyObject       *obj,
    int             cmp)
{
    int rv;

    if ((cmp != Py_EQ && cmp != Py_NE) ||
        !silkPyRWRec_Check(obj))
    {
        Py_INCREF(Py_NotImplemented);
        return Py_NotImplemented;
    }

    rv = memcmp(&self->raw->rec, &((silkPyRWRec*)obj)->raw->rec,
                sizeof(self->raw->rec));
    rv = (rv == 0) ? 1 : 0;
    if (cmp == Py_NE) {
        rv = !rv;
    }

    return PyBool_FromLong(rv);
}

static PyObject *silkPyRWRec_sensor_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    char name[SK_MAX_STRLEN_SENSOR+1];

    CHECK_SITE(NULL);

    sksiteSensorGetName(name, sizeof(name), rwRecGetSensor(&obj->raw->rec));
    return PyUnicode_InternFromString(name);
}

static PyObject *silkPyRWRec_sensor_id_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetSensor(&obj->raw->rec));
}

static int silkPyRWRec_sensor_id_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The sensor_id value must be a 16-bit integer");
        return -1;
    }

    rwRecSetSensor(&obj->raw->rec, val);
    return 0;
}

static int silkPyRWRec_sensor_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    char *repr;
    sensorID_t sensor;
    PyObject *bytes;

    bytes = bytes_from_string(value);
    if (bytes == NULL) {
        PyErr_SetString(PyExc_TypeError, "The sensor value must be a string");
        return -1;
    }
    repr = PyBytes_AS_STRING(bytes);

    if (init_site(NULL)) {
        Py_DECREF(bytes);
        return -1;
    }

    sensor = sksiteSensorLookup(repr);
    Py_DECREF(bytes);
    if (sensor == SK_INVALID_SENSOR) {
        PyErr_SetString(PyExc_ValueError, "Invalid sensor name");
        return -1;
    }

    rwRecSetSensor(&obj->raw->rec, sensor);
    return 0;
}

static PyObject *silkPyRWRec_session_tcpflags_get(
    silkPyRWRec    *obj,
    PyObject       *deprecated)
{
    silkPyTCPFlags *flags;

    if (deprecated == Py_True) {
        int rv = PyErr_Warn(PyExc_DeprecationWarning,
                            ("'restflags' is deprecated in favor of"
                             " 'session_tcpflags'."));
        if (rv) {
            return NULL;
        }
    }

    if (!(rwRecGetTcpState(&obj->raw->rec) & SK_TCPSTATE_EXPANDED)) {
        Py_RETURN_NONE;
    }
    flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
                                                          0);
    if (flags != NULL) {
        flags->val = rwRecGetRestFlags(&obj->raw->rec);
    }

    return (PyObject*)flags;
}

static int silkPyRWRec_session_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    PyObject       *deprecated)
{
    long    val;
    uint8_t state;

    if (deprecated == Py_True) {
        int rv = PyErr_Warn(PyExc_DeprecationWarning,
                            ("'restflags' is deprecated in favor of"
                             " 'session_tcpflags'."));
        if (rv) {
            return -1;
        }
    }

    state = rwRecGetTcpState(&obj->raw->rec) | SK_TCPSTATE_EXPANDED;

    if (IS_STRING(value)) {
        uint8_t     flagval;
        PyObject   *bytes;
        char       *repr;
        int         rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv   = skStringParseTCPFlags(&flagval, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal TCP flags: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecSetTcpState(&obj->raw->rec, state);
        rwRecSetRestFlags(&obj->raw->rec, flagval);
        return 0;
    }

    if (silkPyTCPFlags_Check(value)) {
        silkPyTCPFlags *flags = (silkPyTCPFlags*)value;
        rwRecSetTcpState(&obj->raw->rec, state);
        rwRecSetRestFlags(&obj->raw->rec, flags->val);
        return 0;
    }

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        obj_error("Illegal TCP flags value: %s", value);
        return -1;
    }

    rwRecSetTcpState(&obj->raw->rec, state);
    rwRecSetRestFlags(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_sip_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    silkPyIPAddr *addr;
    PyTypeObject *type;

    if (rwRecIsIPv6(&obj->raw->rec)) {
        type = &silkPyIPv6AddrType;
    } else {
        type = &silkPyIPv4AddrType;
    }

    addr = PyObject_New(silkPyIPAddr, type);
    if (addr != NULL) {
        rwRecMemGetSIP(&obj->raw->rec, &addr->addr);
    }
    return (PyObject*)addr;
}

static int silkPyRWRec_sip_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    if (IS_STRING(value)) {
        skipaddr_t  addr;
        PyObject   *bytes;
        char       *repr;
        int         rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv   = skStringParseIP(&addr, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal IP address: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecMemSetSIP(&obj->raw->rec, &addr);
        return 0;
    }

    if (silkPyIPAddr_Check(value)) {
        silkPyIPAddr *addr = (silkPyIPAddr*)value;
        rwRecMemSetSIP(&obj->raw->rec, &addr->addr);
        return 0;
    }

    PyErr_SetString(PyExc_TypeError, "The sip must be a valid IP address");
    return -1;
}

static PyObject *silkPyRWRec_sport_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(rwRecGetSPort(&obj->raw->rec));
}

static int silkPyRWRec_sport_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT16_MAX) {
        PyErr_SetString(PyExc_OverflowError,
                        "The sport value must be a 16-bit integer");
        return -1;
    }

    rwRecSetSPort(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_stime_epoch_secs_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    double s_time = ((double)rwRecGetStartTime(&obj->raw->rec)) / 1.0e3;

    return PyFloat_FromDouble(s_time);
}

static int silkPyRWRec_stime_epoch_secs_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    const char *errstr = ("The stime_epoch_secs value must be a "
                          "positive number");
    PyObject *pyfloat_val;
    PyObject *pyint_val;
    int64_t long_val;

    if (!PyNumber_Check(value)) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }

    pyfloat_val = PyNumber_Multiply(value, GLOBALS->thousand);
    if (pyfloat_val == NULL) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }
    pyint_val = PyNumber_Long(pyfloat_val);
    Py_DECREF(pyfloat_val);
    if (pyint_val == NULL) {
        PyErr_SetString(PyExc_TypeError, errstr);
        return -1;
    }
    long_val = PyLong_AsLongLong(pyint_val);
    Py_DECREF(pyint_val);
    if (long_val < 0) {
        PyErr_SetString(PyExc_OverflowError, errstr);
        return -1;
    }

    rwRecSetStartTime(&obj->raw->rec, long_val);
    return 0;
}

static PyObject *silkPyRWRec_stime_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    PyObject *seconds, *millisecs, *final;
    imaxdiv_t d = imaxdiv(rwRecGetStartTime(&obj->raw->rec), 1000);

    seconds = PyObject_CallMethod(GLOBALS->datetime,
                                  "utcfromtimestamp", "L", d.quot);
    millisecs = PyObject_CallFunction(GLOBALS->timedelta,
                                      "IIIL", 0, 0, 0, d.rem);
    final = PyNumber_Add(seconds, millisecs);
    Py_DECREF(seconds);
    Py_DECREF(millisecs);
    return final;
}

static int silkPyRWRec_stime_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    sktime_t t;
    int rv;

    rv = silkPyDatetimeToSktime(&t, value);

    if (rv == 0) {
        rwRecSetStartTime(&obj->raw->rec, t);
    }
    return rv;
}

static PyObject *silkPyRWRec_tcpflags_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    silkPyTCPFlags *flags;

    flags = (silkPyTCPFlags*)silkPyTCPFlagsType.tp_alloc(&silkPyTCPFlagsType,
                                                          0);
    if (flags != NULL) {
        flags->val = rwRecGetFlags(&obj->raw->rec);
    }

    return (PyObject*)flags;
}

static int silkPyRWRec_tcpflags_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    long val;

    if (IS_STRING(value)) {
        uint8_t   flagval;
        PyObject *bytes;
        char     *repr;
        int       rv;

        bytes = bytes_from_string(value);
        if (bytes == NULL) {
            return -1;
        }
        repr = PyBytes_AS_STRING(bytes);
        rv = skStringParseTCPFlags(&flagval, repr);
        if (rv != 0) {
            PyErr_Format(PyExc_ValueError, "Illegal TCP flags: %s", repr);
            Py_DECREF(bytes);
            return -1;
        }
        Py_DECREF(bytes);
        rwRecSetFlags(&obj->raw->rec, flagval);
        return 0;
    }

    if (silkPyTCPFlags_Check(value)) {
        silkPyTCPFlags *flags = (silkPyTCPFlags*)value;
        rwRecSetFlags(&obj->raw->rec, flags->val);
        return 0;
    }

    if (!IS_INT(value)) {
        PyErr_SetString(PyExc_TypeError, "Expected an integer");
        return -1;
    }

    val = PyLong_AsLong(value);
    if (PyErr_Occurred() || val < 0 || val > (long)UINT8_MAX) {
        obj_error("Illegal TCP flags value: %s", value);
        return -1;
    }

    rwRecSetFlags(&obj->raw->rec, val);
    return 0;
}

static PyObject *silkPyRWRec_timeout_killed_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    uint8_t state;

    state = rwRecGetTcpState(&obj->raw->rec);
    if (!(state & SK_TCPSTATE_EXPANDED)) {
        Py_RETURN_NONE;
    }
    return PyBool_FromLong(state & SK_TCPSTATE_TIMEOUT_KILLED);
}

static int silkPyRWRec_timeout_killed_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    int     rv;
    uint8_t state;

    rv = PyObject_IsTrue(value);
    if (rv == -1) {
        return -1;
    }
    state = rwRecGetTcpState(&obj->raw->rec) | SK_TCPSTATE_EXPANDED;
    if (rv) {
        state |= SK_TCPSTATE_TIMEOUT_KILLED;
    } else {
        state &= ~SK_TCPSTATE_TIMEOUT_KILLED;
    }
    rwRecSetTcpState(&obj->raw->rec, state);

    return 0;
}

static PyObject *silkPyRWRec_timeout_started_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    uint8_t state;

    state = rwRecGetTcpState(&obj->raw->rec);
    if (!(state & SK_TCPSTATE_EXPANDED)) {
        Py_RETURN_NONE;
    }
    return PyBool_FromLong(state & SK_TCPSTATE_TIMEOUT_STARTED);
}

static int silkPyRWRec_timeout_started_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    int     rv;
    uint8_t state;

    rv = PyObject_IsTrue(value);
    if (rv == -1) {
        return -1;
    }
    state = rwRecGetTcpState(&obj->raw->rec) | SK_TCPSTATE_EXPANDED;
    if (rv) {
        state |= SK_TCPSTATE_TIMEOUT_STARTED;
    } else {
        state &= ~SK_TCPSTATE_TIMEOUT_STARTED;
    }
    rwRecSetTcpState(&obj->raw->rec, state);

    return 0;
}

static PyObject *silkPyRWRec_typename_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    char          type_name[SK_MAX_STRLEN_FLOWTYPE+1];
    flowtypeID_t  flowtype = rwRecGetFlowType(&obj->raw->rec);

    CHECK_SITE(NULL);

    sksiteFlowtypeGetType(type_name, sizeof(type_name), flowtype);
    return PyUnicode_InternFromString(type_name);
}

static PyObject *silkPyRWRec_uniform_packets_get(
    silkPyRWRec    *obj,
    void    UNUSED(*closure))
{
    uint8_t state;

    state = rwRecGetTcpState(&obj->raw->rec);
    return PyBool_FromLong(state & SK_TCPSTATE_UNIFORM_PACKET_SIZE);
}

static int silkPyRWRec_uniform_packets_set(
    silkPyRWRec    *obj,
    PyObject       *value,
    void    UNUSED(*closure))
{
    int     rv;
    uint8_t state;

    rv = PyObject_IsTrue(value);
    if (rv == -1) {
        return -1;
    }
    state = rwRecGetTcpState(&obj->raw->rec);
    if (rv) {
        state |= SK_TCPSTATE_UNIFORM_PACKET_SIZE;
    } else {
        state &= ~SK_TCPSTATE_UNIFORM_PACKET_SIZE;
    }
    rwRecSetTcpState(&obj->raw->rec, state);

    return 0;
}

static int silkPyRawRWRec_init(
    silkPyRawRWRec *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"rec", NULL};
    PyObject *copy = NULL;

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!", kwlist,
                                     &silkPyRawRWRecType, &copy))
    {
        return -1;
    }

    if (copy) {
        RWREC_COPY(&self->rec, &((silkPyRawRWRec*)copy)->rec);
    }
    return 0;
}

static PyObject *silkPyRawRWRec_new(
    PyTypeObject       *type,
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds))
{
    silkPyRawRWRec *self;

    self = (silkPyRawRWRec*)type->tp_alloc(type, 0);

    if (self != NULL) {
        RWREC_CLEAR(&self->rec);
    }

    return (PyObject*)self;
}


/*
 *************************************************************************
 *   SiLK File
 *************************************************************************
 */

typedef struct silkPySilkFile_st {
    PyObject_HEAD
    skstream_t *io;
} silkPySilkFile;

/* function prototypes */
static PyObject *silkPySilkFile_close(
    silkPySilkFile *obj);
static void silkPySilkFile_dealloc(
    silkPySilkFile *obj);
static PyObject *silkPySilkFile_get_mode(
    silkPySilkFile *obj,
    void    UNUSED(*closure));
static PyObject *silkPySilkFile_get_name(
    silkPySilkFile *obj,
    void    UNUSED(*closure));
static int silkPySilkFile_init(
    silkPySilkFile *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPySilkFile_invocations(
    silkPySilkFile *obj);
static PyObject *silkPySilkFile_notes(
    silkPySilkFile *obj);
static PyObject *silkPySilkFile_read(
    silkPySilkFile *obj);
static PyObject *silkPySilkFile_write(
    silkPySilkFile *obj,
    PyObject       *rec);

/* define docs and methods */
static PyMethodDef silkPySilkFile_methods[] = {
    {"__reduce__", (PyCFunction)reduce_error, METH_NOARGS, ""},
    {"read", (PyCFunction)silkPySilkFile_read, METH_NOARGS,
     "Read a RWRec from a RW File"},
    {"write", (PyCFunction)silkPySilkFile_write, METH_O,
     "Write a RWRec to a RW File"},
    {"close", (PyCFunction)silkPySilkFile_close, METH_NOARGS,
     "Read a RWRec from a RW File"},
    {"notes", (PyCFunction)silkPySilkFile_notes, METH_NOARGS,
     "Get the file's annotations"},
    {"invocations", (PyCFunction)silkPySilkFile_invocations, METH_NOARGS,
     "Get the file's invocations"},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PyGetSetDef silkPySilkFile_getseters[] = {
    {"name", (getter)silkPySilkFile_get_name, NULL,
     "name of file associated with SilkFile", NULL},
    {"mode", (getter)silkPySilkFile_get_mode, NULL,
     "mode associated with SilkFile", NULL},
    {NULL, NULL, NULL, NULL, NULL}    /* Sentinel */
};

/* define the object types */
static PyTypeObject silkPySilkFileType = {
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.SilkFileBase", /* tp_name */
    sizeof(silkPySilkFile),         /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPySilkFile_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "Base Silk File",           /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    0,                          /* tp_iter */
    0,                          /* tp_iternext */
    silkPySilkFile_methods,     /* tp_methods */
    0,                          /* tp_members */
    silkPySilkFile_getseters,   /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPySilkFile_init, /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPySilkFile_Check(op) \
    PyObject_TypeCheck(op, &silkPySilkFileType)

static PyObject *throw_ioerror(
    silkPySilkFile *obj,
    int             errcode)
{
    skStreamPrintLastErr(obj->io, errcode, error_printf);
    PyErr_SetString(PyExc_IOError, error_buffer);
    return NULL;
}

static PyObject *silkPySilkFile_close(
    silkPySilkFile *obj)
{
    int rv;

    rv = skStreamClose(obj->io);
    if (rv == 0) {
        Py_RETURN_NONE;
    }

    return throw_ioerror(obj, rv);
}

static void silkPySilkFile_dealloc(
    silkPySilkFile *obj)
{
    if (obj->io) {
        skStreamDestroy(&obj->io);
    }
    Py_TYPE(obj)->tp_free(obj);
}

static PyObject *silkPySilkFile_get_mode(
    silkPySilkFile *obj,
    void    UNUSED(*closure))
{
    return PyInt_FromLong(skStreamGetMode(obj->io));
}

static PyObject *silkPySilkFile_get_name(
    silkPySilkFile *obj,
    void    UNUSED(*closure))
{
    const char *name = skStreamGetPathname(obj->io);
    if (name) {
        return PyUnicode_FromString(name);
    }
    Py_RETURN_NONE;
}

static int silkPySilkFile_init(
    silkPySilkFile *self,
    PyObject       *args,
    PyObject       *kwds)
{
    char             *filename;
    int               mode;
    int               format      = NOT_SET;
    int               policy      = NOT_SET;
    int               compr       = NOT_SET;
    int               file_des    = NOT_SET;
    PyObject         *annotations = NULL;
    PyObject         *invocations = NULL;
    sk_file_header_t *hdr;
    int               rv;

    static char *kwlist[] = {"filename", "mode", "compression",
                             "format", "policy", "invocations",
                             "notes", "_fileno", NULL};

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "si|iiiO!O!i", kwlist,
                                     &filename, &mode, &compr,
                                     &format, &policy,
                                     &PyList_Type, &invocations,
                                     &PyList_Type, &annotations,
                                     &file_des))
    {
        return -1;
    }

    if (mode != SK_IO_READ && mode != SK_IO_WRITE && mode != SK_IO_APPEND) {
        PyErr_SetString(PyExc_ValueError, "Illegal mode");
        Py_DECREF(self);
        return -1;
    }
    if (self->io) {
        skStreamDestroy(&self->io);
    }
    rv = skStreamCreate(&self->io, (skstream_mode_t)mode,SK_CONTENT_SILK_FLOW);
    if (rv != 0) {
        throw_ioerror(self, rv);
        return -1;
    }

    rv = skStreamBind(self->io, filename);
    if (rv != 0) {
        throw_ioerror(self, rv);
        return -1;
    }

    hdr = skStreamGetSilkHeader(self->io);

    if (policy != NOT_SET) {
        rv = skStreamSetIPv6Policy(self->io, (sk_ipv6policy_t)policy);
        if (rv != 0) {
            throw_ioerror(self, rv);
            return -1;
        }
    }

    if (compr != NOT_SET) {
        if (mode != SK_IO_WRITE) {
            PyErr_SetString(PyExc_ValueError,
                            "Cannot set compression unless in WRITE mode");
            return -1;
        }
        rv = skHeaderSetCompressionMethod(hdr, compr);
        if (rv != 0) {
            throw_ioerror(self, rv);
            return -1;
        }
    }

    if (format != NOT_SET) {
        if (mode != SK_IO_WRITE) {
            PyErr_SetString(PyExc_ValueError,
                            "Cannot set file format unless in WRITE mode");
            return -1;
        }
        rv = skHeaderSetFileFormat(hdr, format);
        if (rv != 0) {
            throw_ioerror(self, rv);
            return -1;
        }
    }

    if (annotations != NULL) {
        if (mode != SK_IO_WRITE) {
            PyErr_SetString(PyExc_ValueError,
                            "Cannot set file format unless in WRITE mode");
            return -1;
        }
        if (hdr != NULL) {
            ssize_t len = PyList_GET_SIZE(annotations);
            ssize_t i;

            for (i = 0; i < len; i++) {
                PyObject *bytes;
                PyObject *item = PyList_GET_ITEM(annotations, i);

                if (!IS_STRING(item)) {
                    PyErr_SetString(PyExc_TypeError,
                                    "Annotation was not a string");
                    return -1;
                }
                bytes = bytes_from_string(item);
                if (bytes == NULL) {
                    return -1;
                }

                rv = skHeaderAddAnnotation(hdr, PyBytes_AS_STRING(bytes));
                Py_DECREF(bytes);
                if (rv != 0) {
                    throw_ioerror(self, rv);
                }
            }
        }
    }

    if (invocations != NULL) {
        if (mode != SK_IO_WRITE) {
            PyErr_SetString(PyExc_ValueError,
                            "Cannot set file format unless in WRITE mode");
            return -1;
        }
        if (hdr != NULL) {
            ssize_t len = PyList_GET_SIZE(invocations);
            ssize_t i;

            for (i = 0; i < len; i++) {
                PyObject *item = PyList_GET_ITEM(invocations, i);
                char     *value;
                PyObject *bytes;

                if (!IS_STRING(item)) {
                    PyErr_SetString(PyExc_TypeError,
                                    "Invocation was not a string");
                    return -1;
                }

                bytes = bytes_from_string(item);
                if (bytes == NULL) {
                    return -1;
                }
                value = PyBytes_AS_STRING(bytes);
                rv = skHeaderAddInvocation(hdr, 0, 1, &value);
                Py_DECREF(bytes);
                if (rv != 0) {
                    throw_ioerror(self, rv);
                }
            }
        }
    }

    if (file_des == NOT_SET) {
        rv = skStreamOpen(self->io);
    } else {
        rv = skStreamFDOpen(self->io, file_des);
    }
    if (rv != 0) {
        throw_ioerror(self, rv);
        return -1;
    }

    if (mode == SK_IO_WRITE) {
        rv = skStreamWriteSilkHeader(self->io);
        if (rv != 0) {
            throw_ioerror(self, rv);
            return -1;
        }
    } else {
        rv = skStreamReadSilkHeader(self->io, NULL);
        if (rv != 0) {
            throw_ioerror(self, rv);
            return -1;
        }
    }

    return 0;
}

static PyObject *silkPySilkFile_invocations(
    silkPySilkFile *obj)
{
    sk_file_header_t     *hdr;
    sk_header_entry_t    *entry;
    sk_hentry_iterator_t  iter;
    PyObject             *list;
    PyObject             *invoc;
    int                   rv;

    list = PyList_New(0);
    if (list == NULL) {
        return NULL;
    }
    hdr = skStreamGetSilkHeader(obj->io);
    if (hdr != NULL) {
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_INVOCATION_ID);
        while ((entry = skHeaderIteratorNext(&iter)) != NULL) {
            invoc = PyUnicode_FromString(
                ((sk_hentry_invocation_t*)entry)->command_line);
            if (invoc == NULL) {
                Py_DECREF(list);
                return NULL;
            }
            rv = PyList_Append(list, invoc);
            Py_DECREF(invoc);
            if (rv != 0) {
                Py_DECREF(list);
                return NULL;
            }
        }
    }

    return list;
}

static PyObject *silkPySilkFile_notes(
    silkPySilkFile *obj)
{
    sk_file_header_t     *hdr;
    sk_header_entry_t    *entry;
    sk_hentry_iterator_t  iter;
    PyObject             *list;
    PyObject             *annot;
    int                   rv;

    list = PyList_New(0);
    if (list == NULL) {
        return NULL;
    }
    hdr = skStreamGetSilkHeader(obj->io);
    if (hdr != NULL) {
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_ANNOTATION_ID);
        while ((entry = skHeaderIteratorNext(&iter)) != NULL) {
            annot = PyUnicode_FromString(
                ((sk_hentry_annotation_t*)entry)->annotation);
            if (annot == NULL) {
                Py_DECREF(list);
                return NULL;
            }
            rv = PyList_Append(list, annot);
            Py_DECREF(annot);
            if (rv != 0) {
                Py_DECREF(list);
                return NULL;
            }
        }
    }

    return list;
}

static PyObject *silkPySilkFile_read(
    silkPySilkFile *obj)
{
    PyObject *pyrec;
    int rv;

    pyrec = silkPyRawRWRecType.tp_alloc(&silkPyRawRWRecType, 0);
    if (pyrec == NULL) {
        return NULL;
    }

    rv = skStreamReadRecord(obj->io, &((silkPyRawRWRec*)pyrec)->rec);
    if (rv != 0) {
        Py_DECREF(pyrec);
        if (rv == SKSTREAM_ERR_EOF) {
            Py_RETURN_NONE;
        }
        return throw_ioerror(obj, rv);
    }

    return pyrec;
}

static PyObject *silkPySilkFile_write(
    silkPySilkFile *obj,
    PyObject       *rec)
{
    int rv;

    if (!silkPyRWRec_Check(rec)) {
        PyErr_SetString(PyExc_TypeError, "Argument not a RWRec");
        return NULL;
    }

    rv = skStreamWriteRecord(obj->io, &((silkPyRWRec*)rec)->raw->rec);
    if (rv == 0) {
        Py_RETURN_NONE;
    }

    return throw_ioerror(obj, rv);
}


/*
 *************************************************************************
 *   RepoIter
 *************************************************************************
 */

typedef struct silkPyRepoIter_st {
    PyObject_HEAD
    sksite_repo_iter_t *iter;
} silkPyRepoIter;

/* function prototypes */
static void silkPyRepoIter_dealloc(
    silkPyRepoIter *self);
static int silkPyRepoIter_init(
    silkPyRepoIter *self,
    PyObject       *args,
    PyObject       *kwds);
static PyObject *silkPyRepoIter_iternext(
    silkPyRepoIter *self);

/* define the object types */
static PyTypeObject silkPyRepoIterType ={
    PyVarObject_HEAD_INIT(NULL, 0)
    "silk.pysilk.RepoIter",    /* tp_name */
    sizeof(silkPyRepoIterType), /* tp_basicsize */
    0,                          /* tp_itemsize */
    (destructor)silkPyRepoIter_dealloc, /* tp_dealloc */
    0,                          /* tp_print */
    0,                          /* tp_getattr */
    0,                          /* tp_setattr */
    0,                          /* tp_compare */
    0,                          /* tp_repr */
    0,                          /* tp_as_number */
    0,                          /* tp_as_sequence */
    0,                          /* tp_as_mapping */
    0,                          /* tp_hash  */
    0,                          /* tp_call */
    0,                          /* tp_str */
    0,                          /* tp_getattro */
    0,                          /* tp_setattro */
    0,                          /* tp_as_buffer */
    Py_TPFLAGS_DEFAULT | Py_TPFLAGS_BASETYPE, /* tp_flags */
    "SiLK repo file iterator object", /* tp_doc */
    0,                          /* tp_traverse */
    0,                          /* tp_clear */
    0,                          /* tp_richcompare */
    0,                          /* tp_weaklistoffset */
    iter_iter,                  /* tp_iter */
    (iternextfunc)silkPyRepoIter_iternext, /* tp_iternext */
    0,                          /* tp_methods */
    0,                          /* tp_members */
    0,                          /* tp_getset */
    0,                          /* tp_base */
    0,                          /* tp_dict */
    0,                          /* tp_descr_get */
    0,                          /* tp_descr_set */
    0,                          /* tp_dictoffset */
    (initproc)silkPyRepoIter_init, /* tp_init */
    0,                          /* tp_alloc */
    0,                          /* tp_new */
    0,                          /* tp_free */
    0,                          /* tp_is_gc */
    0,                          /* tp_bases */
    0,                          /* tp_mro */
    0,                          /* tp_cache */
    0,                          /* tp_subclasses */
    0,                          /* tp_weaklist */
    0                           /* tp_del */
#if PY_VERSION_HEX >= 0x02060000
    ,0                          /* tp_version_tag */
#endif
};

/* macro and function defintions */
#define silkPyRepoIter_Check(op)                \
    PyObject_TypeCheck(op, &silkPyRepoIterType)

static void silkPyRepoIter_dealloc(
    silkPyRepoIter *self)
{
    sksiteRepoIteratorDestroy(&self->iter);
    Py_TYPE(self)->tp_free((PyObject*)self);
}

static int silkPyRepoIter_init(
    silkPyRepoIter *self,
    PyObject       *args,
    PyObject       *kwds)
{
    static char *kwlist[] = {"start", "end", "flowtypes",
                             "sensors", "missing", NULL};
    PyObject *start     = NULL;
    PyObject *end       = NULL;
    PyObject *flowtypes = NULL;
    PyObject *sensors   = NULL;
    PyObject *missing   = NULL;
    PyObject *fast      = NULL;
    sk_vector_t *ft_vec     = NULL;
    sk_vector_t *sensor_vec = NULL;
    sktime_t starttime, endtime;
    flowtype_iter_t ft_iter;
    flowtypeID_t ft;
    uint32_t flags;
    int sprec;
    int eprec;
    int rv;

    CHECK_SITE(-1);

    ft_vec = skVectorNew(sizeof(flowtypeID_t));
    if (ft_vec == NULL) {
        PyErr_NoMemory();
        return -1;
    }

    if (!PyArg_ParseTupleAndKeywords(args, kwds, "OO|OOO", kwlist,
                                     &start, &end, &flowtypes,
                                     &sensors, &missing))
    {
        goto error;
    }

    /* Calculate starttime */
    if (PyDate_Check(start)) {
        rv = silkPyDatetimeToSktime(&starttime, start);
        if (rv != 0) {
            goto error;
        }
        sprec = PyDateTime_Check(start) ? 4 : 3;
    } else if (IS_STRING(start)) {
        PyObject *bytes = bytes_from_string(start);
        if (bytes == NULL) {
            goto error;
        }
        rv = skStringParseDatetime(&starttime, PyBytes_AS_STRING(bytes),
                                   &sprec);
        Py_DECREF(bytes);
        if (rv != 0) {
            PyErr_SetString(PyExc_ValueError, skStringParseStrerror(rv));
            goto error;
        }
    } else {
        PyErr_SetString(PyExc_TypeError,
                        "start must be a string or a "
                        "datetime.date[time] object");
        goto error;
    }
    starttime -= starttime % 3600000;

    /* Calculate endtime */
    if (end == NULL || end == Py_None) {
        end = NULL;
    } else if (PyDate_Check(end)) {
        rv = silkPyDatetimeToSktime(&endtime, end);
        if (rv != 0) {
            goto error;
        }
        eprec = PyDateTime_Check(end) ? 4 : 3;
    } else if (IS_STRING(end)) {
        PyObject *bytes = bytes_from_string(end);
        if (bytes == NULL) {
            goto error;
        }
        rv = skStringParseDatetime(&endtime, PyBytes_AS_STRING(bytes),
                                   &eprec);
        Py_DECREF(bytes);
        if (rv != 0) {
            PyErr_SetString(PyExc_ValueError, skStringParseStrerror(rv));
            goto error;
        }
    } else {
        PyErr_SetString(PyExc_TypeError,
                        "end must be a string or a "
                        "datetime.date[time] object");
        goto error;
    }

    /* End-time mashup */
    if (end) {
        if (sprec == 3) {
            /* when no starting hour given, we look at the full days,
             * regardless of the precision of the ending time; go to
             * the last hour of the ending day. */
            if (skDatetimeCeiling(&endtime, &endtime, sprec)) {
                PyErr_SetString(PyExc_ValueError,
                                "Could not determine end time");
                goto error;
            }
            endtime -= endtime % 3600000;
        } else if (eprec < 4) {
            /* starting time has an hour but ending time does not; use
             * same hour for ending time */
#if  SK_ENABLE_LOCALTIME
            time_t t;
            struct tm work_tm;
            int work_hour;

            /* get starting hour */
            t = starttime / 1000;
            localtime_r(&t, &work_tm);
            work_hour = work_tm.tm_hour;
            /* break apart end time */
            t = endtime / 1000;
            localtime_r(&t, &work_tm);
            /* set end hour to start hour and re-combine */
            work_tm.tm_hour = work_hour;
            t = mktime(&work_tm);
            endtime = sktimeCreate((t - (t % 3600)), 0);
#else
            endtime = endtime - (endtime % 86400000) + (starttime % 86400000);
#endif
        } else {
            endtime -= endtime % 3600000;
        }
    } else if (sprec >= 4) {
        /* no ending time was given and the starting time contains an
         * hour; we only look at that single hour */
        endtime = starttime;
    } else {
        /* no ending time was given and the starting time was to the
         * day; look at that entire day */
        if (skDatetimeCeiling(&endtime, &starttime, sprec)) {
            PyErr_SetString(PyExc_ValueError,
                            "Could not determine end time");
            goto error;
        }
        endtime -= endtime % 3600000;
    }

    if (starttime > endtime) {
        PyErr_SetString(PyExc_ValueError,
                        "start must be less or equal to end");
        goto error;
    }

    /* Calculate flowtypes */
    if (flowtypes == NULL || flowtypes == Py_None) {
        sksiteFlowtypeIterator(&ft_iter);
        while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
            rv = skVectorAppendValue(ft_vec, &ft);
            if (rv != 0) {
                PyErr_NoMemory();
                goto error;
            }
        }
    } else if (PySequence_Check(flowtypes)) {
        Py_ssize_t len;
        PyObject **items;
        fast = PySequence_Fast(flowtypes, "flowtypes must be a sequence");
        if (fast == NULL) {
            goto error;
        }
        len = PySequence_Fast_GET_SIZE(fast);
        items = PySequence_Fast_ITEMS(fast);
        for (/*empty*/; len; len--, items++) {
            const char *class_name, *type_name;
            if (!PyArg_ParseTuple(*items, "ss", &class_name, &type_name)) {
                goto error;
            }
            ft = sksiteFlowtypeLookupByClassType(class_name, type_name);
            if (ft == SK_INVALID_FLOWTYPE) {
                PyErr_SetString(PyExc_ValueError,
                                "Invalid (class, type) pair");
                return -1;
            }
            rv = skVectorAppendValue(ft_vec, &ft);
            if (rv != 0) {
                PyErr_NoMemory();
                goto error;
            }
        }
        Py_CLEAR(fast);
    } else {
        PyErr_SetString(PyExc_TypeError,
                        "flowtypes should be a sequence (class, type) pairs");
        goto error;
    }

    /* Calculate sensors */
    if (sensors && PySequence_Check(sensors)) {
        Py_ssize_t len;
        PyObject **items;
        sensorID_t sensor;

        sensor_vec = skVectorNew(sizeof(sensorID_t));
        if (sensor_vec == NULL) {
            PyErr_NoMemory();
            goto error;
        }

        fast = PySequence_Fast(sensors, "sensors must be a sequence");
        if (fast == NULL) {
            goto error;
        }
        len = PySequence_Fast_GET_SIZE(fast);
        items = PySequence_Fast_ITEMS(fast);
        for (/*empty*/; len; len--, items++) {
            PyObject *bytes;
            if (!IS_STRING(*items)) {
                PyErr_SetString(PyExc_TypeError,
                                "sensors must be strings");
                goto error;
            }
            bytes = bytes_from_string(*items);
            if (bytes == NULL) {
                goto error;
            }
            sensor = sksiteSensorLookup(PyBytes_AS_STRING(bytes));
            if (sensor == SK_INVALID_SENSOR) {
                PyErr_SetString(PyExc_ValueError, "Invalid sensor name");
                goto error;
            }
            rv = skVectorAppendValue(sensor_vec, &sensor);
            if (rv != 0) {
                PyErr_NoMemory();
                goto error;
            }
        }
        Py_CLEAR(fast);
    } else if (sensors != NULL && sensors != Py_None) {
        PyErr_SetString(PyExc_TypeError,
                        "sensors should be a sequence of strings");
        goto error;
    }

    if (missing && PyObject_IsTrue(missing)) {
        flags = RETURN_MISSING;
    } else {
        flags = 0;
    }

    rv = sksiteRepoIteratorCreate(
        &self->iter, ft_vec, sensor_vec, starttime, endtime, flags);
    if (rv != 0) {
        PyErr_NoMemory();
        goto error;
    }

    rv = 0;

  cleanup:
    Py_XDECREF(fast);
    if (ft_vec) {
        skVectorDestroy(ft_vec);
    }
    if (sensor_vec) {
        skVectorDestroy(sensor_vec);
    }

    return rv;

  error:
    rv = -1;
    goto cleanup;
}

static PyObject *silkPyRepoIter_iternext(
    silkPyRepoIter *self)
{
    char path[PATH_MAX];
    int missing;
    int rv;

    rv = sksiteRepoIteratorNextPath(self->iter, path, sizeof(path), &missing);
    if (rv == SK_ITERATOR_NO_MORE_ENTRIES) {
        PyErr_SetNone(PyExc_StopIteration);
        return NULL;
    }

    return Py_BuildValue("sO", path, missing ? Py_False : Py_True);
}


/*
 *************************************************************************
 *   Misc Globals
 *************************************************************************
 */

/* function prototypes */
static PyObject *silk_class_info(void);
static PyObject *silk_flowtype_info(void);
static PyObject *silk_get_rootdir(void);
static PyObject *silk_get_siteconf(void);
static PyObject *silk_have_site_config(void);
static PyObject *silk_init_country_codes(
    PyObject    UNUSED(*self),
    PyObject           *args);
static int silk_init_set_envvar(
    const char *value,
    const char *envvar);
static PyObject *silk_init_site(
    PyObject    UNUSED(*self),
    PyObject           *args,
    PyObject           *kwds);
static PyObject *silk_initial_tcpflags_enabled(void);
static PyObject *silk_ipset_supports_ipv6(void);
static PyObject *silk_ipv6_enabled(void);
static silkPyRawRWRec *silk_raw_rwrec_copy(
    PyObject    UNUSED(*self),
    PyObject           *c_rec);
static PyObject *silk_sensor_info(void);
static PyObject *silk_set_rootdir(
    PyObject    UNUSED(*self),
    PyObject           *args);
static PyObject *silk_version(void);

static PyMethodDef silk_methods[] = {
    {"ipv6_enabled", (PyCFunction)silk_ipv6_enabled,
     METH_NOARGS,
     ("Return whether IPv6 was enabled at compile-time")},
    {"ipset_supports_ipv6", (PyCFunction)silk_ipset_supports_ipv6,
     METH_NOARGS,
     ("Return whether IPv6-support for IPsets was enabled at compile-time")},
    {"initial_tcpflags_enabled", (PyCFunction)silk_initial_tcpflags_enabled,
     METH_NOARGS,
     ("Return whether initial tcpflagewere enabled at compile-time")},
    {"init_site", (PyCFunction)silk_init_site,
     METH_VARARGS | METH_KEYWORDS,
     ("init_site([siteconf][, rootdir])\n"
      "Initialize the silk site using the given siteconf file name\n"
      "and rootdir.\n"
      "If the siteconf is not supplied, the value of the environment\n"
      "variable " SILK_CONFIG_FILE_ENVAR " will be used if available.\n"
      "Otherwise, PySiLK will look for a file named 'silk.conf' in the\n"
      "following directories: the rootdir, the directories\n"
      "'$SILK_PATH/share/silk/' and '$SILK_PATH/share/'; and the\n"
      "'share/silk/' and 'share/' directories parallel to the\n"
      "application's directory.\n"
      "If the rootdir is not supplied, SiLK's default value will be\n"
      "used.\n"
      "Will throw an exception if the site is already initialized.")},
    {"have_site_config", (PyCFunction)silk_have_site_config,
     METH_NOARGS,
     ("Return whether the site configuration file has been loaded")},
    {"get_site_config", (PyCFunction)silk_get_siteconf,
     METH_NOARGS,
     ("Return the current site configuration file; None if not set")},
    {"set_data_rootdir", (PyCFunction)silk_set_rootdir,
     METH_VARARGS,
     ("Change the data root directory to the given path")},
    {"get_data_rootdir", (PyCFunction)silk_get_rootdir,
     METH_NOARGS,
     ("Return the current root directory")},
    {"sensor_info", (PyCFunction)silk_sensor_info,
     METH_NOARGS,
     ("Returns a list of information for configured sensors")},
    {"class_info", (PyCFunction)silk_class_info,
     METH_NOARGS,
     ("Return a list of information for configured classes")},
    {"flowtype_info", (PyCFunction)silk_flowtype_info,
     METH_NOARGS,
     ("Return a list of information for configured flowtypes")},
    {"silk_version", (PyCFunction)silk_version,
     METH_NOARGS,
     ("Return the version of SiLK that PySilk was linked against")},
    {"init_country_codes", (PyCFunction)silk_init_country_codes,
     METH_VARARGS,
     ("Initialize the country codes from the given file (can be left blank)")},
    {"_raw_rwrec_copy", (PyCFunction)silk_raw_rwrec_copy,
     METH_O,
     ("Create a RawRWRec from a C rwrec PyCObject, copying the value")},
    {NULL, NULL, 0, NULL}       /* Sentinel */
};

static PyObject *silk_class_info(void)
{
    CHECK_SITE(NULL);

    Py_INCREF(GLOBALS->classes);
    return GLOBALS->classes;
}

static PyObject *silk_flowtype_info(void)
{
    CHECK_SITE(NULL);

    Py_INCREF(GLOBALS->flowtypes);
    return GLOBALS->flowtypes;
}

static PyObject *silk_get_rootdir(void)
{
    char rootdir[PATH_MAX];

    sksiteGetRootDir(rootdir, sizeof(rootdir));
    return PyUnicode_InternFromString(rootdir);
}

static PyObject *silk_get_siteconf(void)
{
    char siteconf[PATH_MAX];

    sksiteGetConfigPath(siteconf, sizeof(siteconf));
    return PyUnicode_InternFromString(siteconf);
}

static PyObject *silk_have_site_config(void)
{
    Py_INCREF(GLOBALS->havesite);
    return GLOBALS->havesite;
}

static PyObject *silk_init_country_codes(
    PyObject    UNUSED(*self),
    PyObject           *args)
{
    int   rv;
    char *filename = NULL;

    rv = PyArg_ParseTuple(args, "|et",
                          Py_FileSystemDefaultEncoding, &filename);
    if (!rv) {
        return NULL;
    }

    skCountryTeardown();
    rv = skCountrySetup(filename, error_printf);
    PyMem_Free(filename);
    if (rv != 0) {
        PyErr_SetString(PyExc_RuntimeError, error_buffer);
        return NULL;
    }

    Py_RETURN_NONE;
}

static int silk_init_set_envvar(
    const char *value,
    const char *envvar)
{
    static char env_buf[101 + PATH_MAX];
    PyObject *os;
    int rv;

    if (value == NULL) {
        return 0;
    }

    /* setenv() does not exist on Solaris 9, so we use putenv()
     * instead */
    rv = snprintf(env_buf, sizeof(env_buf),
                  "%s=%s", envvar, value);
    if (rv >= (int)sizeof(env_buf) || putenv(env_buf) != 0) {
        PyErr_SetString(PyExc_RuntimeError,
                        ("Could not set " SILK_CONFIG_FILE_ENVAR));
        return -1;
    }

    /* Attempt to add the environment variable to Python's
     * environment list as well */
    os = PyImport_ImportModule("os");
    if (os != NULL) {
        PyObject *env = PyObject_GetAttrString(os, "environ");
        if (env != NULL) {
            PyObject *s = PyUnicode_Decode(value,
                                           strlen(value),
                                           Py_FileSystemDefaultEncoding,
                                           "strict");
            if (s != NULL) {
                PyMapping_SetItemString(env, (char*)envvar, s);
                Py_DECREF(s);
            }
            Py_DECREF(env);
        }
        Py_DECREF(os);
    }

    return 0;
}

static PyObject *silk_init_site(
    PyObject    UNUSED(*self),
    PyObject           *args,
    PyObject           *kwds)
{
    static char *kwlist[] = {"siteconf", "rootdir", NULL};
    char *siteconf = NULL;
    char *rootdir  = NULL;
    int   rv;

    rv = PyArg_ParseTupleAndKeywords(args, kwds, "|etet", kwlist,
                                     Py_FileSystemDefaultEncoding, &siteconf,
                                     Py_FileSystemDefaultEncoding, &rootdir);
    if (!rv) {
        goto error;
    }

    if (GLOBALS->site_configured) {
        PyErr_SetString(PyExc_RuntimeError, "Site already initialized");
        goto error;
    }

    if (siteconf) {
        rv = sksiteSetConfigPath(siteconf);
        assert(rv == 0);
    }

    if (rootdir) {
        if (!skDirExists(rootdir)) {
            PyErr_Format(PyExc_IOError,
                         "The directory %s does not exist", rootdir);
            goto error;
        }
        rv = sksiteSetRootDir(rootdir);
        if (rv != 0) {
            PyErr_SetString(PyExc_ValueError, "Illegal root directory");
            goto error;
        }
    }

    if (init_site(siteconf) != 0) {
        goto error;
    }

    /* These are needed for subprocess calls to silk */
    if (silk_init_set_envvar(siteconf, SILK_CONFIG_FILE_ENVAR)) {
        goto error;
    }
    if (silk_init_set_envvar(rootdir, SILK_DATA_ROOTDIR_ENVAR)) {
        goto error;
    }

    Py_INCREF(GLOBALS->havesite);
    return GLOBALS->havesite;

  error:
    PyMem_Free(siteconf);
    PyMem_Free(rootdir);

    return NULL;
}

static PyObject *silk_initial_tcpflags_enabled(void)
{
    Py_RETURN_TRUE;
}

static PyObject *silk_ipset_supports_ipv6(void)
{
#if SK_ENABLE_IPV6 && SK_ENABLE_SILK3_IPSETS
    Py_RETURN_TRUE;
#else
    Py_RETURN_FALSE;
#endif
}

static PyObject *silk_ipv6_enabled(void)
{
#if SK_ENABLE_IPV6
    Py_RETURN_TRUE;
#else
    Py_RETURN_FALSE;
#endif
}

static silkPyRawRWRec *silk_raw_rwrec_copy(
    PyObject    UNUSED(*self),
    PyObject           *c_rec)
{
    silkPyRawRWRec *pyrec;
    rwRec       *rec;

    if (!COBJ_CHECK(c_rec)) {
        PyErr_SetString(PyExc_TypeError, "Illegal argument type");
        return NULL;
    }

    pyrec = (silkPyRawRWRec*)silkPyRawRWRecType.tp_alloc(
        &silkPyRawRWRecType, 0);
    if (pyrec != NULL) {
        rec = (rwRec*)COBJ_PTR(c_rec);
        if (rec != NULL) {
            RWREC_COPY(&pyrec->rec, rec);
        }
    }

    return pyrec;
}

static PyObject *silk_sensor_info(void)
{
    CHECK_SITE(NULL);

    Py_INCREF(GLOBALS->sensors);
    return GLOBALS->sensors;
}

static PyObject *silk_set_rootdir(
    PyObject    UNUSED(*self),
    PyObject           *args)
{
    int   rv;
    char *rootdir = NULL;

    CHECK_SITE(NULL);

    rv = PyArg_ParseTuple(args, "|et",
                          Py_FileSystemDefaultEncoding, &rootdir);
    if (!rv) {
        return NULL;
    }
    if (!skDirExists(rootdir)) {
        PyErr_Format(PyExc_IOError,
                     "The directory %s does not exist", rootdir);
        PyMem_Free(rootdir);
        return NULL;
    }
    rv = sksiteSetRootDir(rootdir);
    PyMem_Free(rootdir);
    if (rv != 0) {
        PyErr_SetString(PyExc_ValueError, "Illegal root directory");
        return NULL;
    }

    Py_RETURN_NONE;
}

static PyObject *silk_version(void)
{
    return PyUnicode_InternFromString(SK_PACKAGE_VERSION);
}


/*
 *************************************************************************
 *   SUPPORT FUNCTIONS
 *************************************************************************
 */

static PyObject *any_obj_error(
    PyObject   *exc,
    const char *format,
    PyObject   *obj)
{
    PyObject *pformat = PyUnicode_FromString(format);
    PyObject *msg = PyUnicode_Format(pformat, obj);
    PyErr_SetObject(exc, msg);
    Py_DECREF(pformat);
    Py_DECREF(msg);
    return NULL;
}

#ifndef TEST_PRINTF_FORMATS
static int error_printf(
    const char *fmt,
    ...)
{
    int rv;

    va_list args;
    va_start(args, fmt);
    rv = vsnprintf(error_buffer, sizeof(error_buffer), fmt, args);
    error_buffer[sizeof(error_buffer) - 1] = '\0';
    va_end(args);

    return rv;
}
#endif  /* TEST_PRINTF_FORMATS */

static int init_classes(void)
{
    class_iter_t  iter;
    classID_t     class_id;
    char          name[SK_MAX_STRLEN_FLOWTYPE+1];
    PyObject     *list;
    PyObject     *dict;
    PyObject     *classes;
    PyObject     *val;
    PyObject     *class_data;
    int           rv;

    classes = PyDict_New();
    if (classes == NULL) {
        goto error;
    }
    class_id = sksiteClassGetDefault();
    if (class_id == SK_INVALID_CLASS) {
        val = Py_None;
        Py_INCREF(val);
    } else {
        val = PyInt_FromLong(sksiteClassGetDefault());
        if (val == NULL) {
            goto error;
        }
    }
    rv = PyDict_SetItemString(classes, "default", val);
    Py_DECREF(val);
    if (rv != 0) {
        goto error;
    }

    class_data = PyDict_New();
    if (class_data == NULL) {
        goto error;
    }
    rv = PyDict_SetItemString(classes, "data", class_data);
    Py_DECREF(class_data);
    if (rv != 0) {
        goto error;
    }

    sksiteClassIterator(&iter);
    while (sksiteClassIteratorNext(&iter, &class_id)) {
        sensor_iter_t    sensor_iter;
        sensorID_t       sensor;
        flowtype_iter_t  flowtype_iter;
        flowtypeID_t     flowtype;

        dict = PyDict_New();
        if (dict == NULL) {
            goto error;
        }
        val = PyInt_FromLong(class_id);
        if (val == NULL) {
            Py_DECREF(dict);
            goto error;
        }
        rv = PyDict_SetItem(class_data, val, dict);
        Py_DECREF(dict);
        if (rv != 0) {
            Py_DECREF(val);
            goto error;
        }
        rv = PyDict_SetItemString(dict, "id", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        sksiteClassGetName(name, sizeof(name), class_id);
        val = PyUnicode_InternFromString(name);
        if (val == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "name", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        list = PyList_New(0);
        if (list == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "sensors", list);
        Py_DECREF(list);
        if (rv != 0) {
            goto error;
        }
        sksiteClassSensorIterator(class_id, &sensor_iter);
        while (sksiteSensorIteratorNext(&sensor_iter, &sensor)) {
            val = PyInt_FromLong(sensor);
            if (val == NULL) {
                goto error;
            }
            rv = PyList_Append(list, val);
            Py_DECREF(val);
            if (rv != 0) {
                goto error;
            }
        }

        list = PyList_New(0);
        if (list == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "flowtypes", list);
        Py_DECREF(list);
        if (rv != 0) {
            goto error;
        }
        sksiteClassFlowtypeIterator(class_id, &flowtype_iter);
        while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
            val = PyInt_FromLong(flowtype);
            if (val == NULL) {
                goto error;
            }
            rv = PyList_Append(list, val);
            Py_DECREF(val);
            if (rv != 0) {
                goto error;
            }
        }

        list = PyList_New(0);
        if (list == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "default_flowtypes", list);
        Py_DECREF(list);
        if (rv != 0) {
            goto error;
        }
        sksiteClassDefaultFlowtypeIterator(class_id, &flowtype_iter);
        while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
            val = PyInt_FromLong(flowtype);
            if (val == NULL) {
                goto error;
            }
            rv = PyList_Append(list, val);
            Py_DECREF(val);
            if (rv != 0) {
                goto error;
            }
        }
    }

    GLOBALS->classes = classes;
    return 0;

  error:
    Py_XDECREF(classes);

    return -1;
}

static int init_flowtypes(void)
{
    flowtype_iter_t  flowtype_iter;
    flowtypeID_t     flowtype;
    char             name[SK_MAX_STRLEN_SENSOR+1];
    PyObject        *dict;
    PyObject        *flowtypes;
    int              rv;

    flowtypes = PyDict_New();
    if (flowtypes == NULL) {
        goto error;
    }

    sksiteFlowtypeIterator(&flowtype_iter);
    while (sksiteFlowtypeIteratorNext(&flowtype_iter, &flowtype)) {
        classID_t     class_id;
        PyObject     *val;

        dict = PyDict_New();
        if (dict == NULL) {
            goto error;
        }
        val = PyInt_FromLong(flowtype);
        if (val == NULL) {
            Py_DECREF(dict);
            goto error;
        }
        rv = PyDict_SetItem(flowtypes, val, dict);
        Py_DECREF(dict);
        if (rv != 0) {
            Py_DECREF(val);
            goto error;
        }
        rv = PyDict_SetItemString(dict, "id", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        sksiteFlowtypeGetName(name, sizeof(name), flowtype);
        val = PyUnicode_InternFromString(name);
        if (val == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "name", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        sksiteFlowtypeGetType(name, sizeof(name), flowtype);
        val = PyUnicode_InternFromString(name);
        if (val == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "type", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        class_id = sksiteFlowtypeGetClassID(flowtype);
        val = PyInt_FromLong(class_id);
        if (val == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "class", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }
    }

    GLOBALS->flowtypes = flowtypes;
    return 0;

  error:
    Py_XDECREF(flowtypes);

    return -1;
}

static int init_sensors(void)
{
    sensor_iter_t  sensor_iter;
    sensorID_t     sensor;
    char           name[SK_MAX_STRLEN_SENSOR+1];
    PyObject      *list;
    PyObject      *dict;
    PyObject      *sensors;
    int            rv;

    sensors = PyDict_New();
    if (sensors == NULL) {
        goto error;
    }

    sksiteSensorIterator(&sensor_iter);
    while (sksiteSensorIteratorNext(&sensor_iter, &sensor)) {
        class_iter_t  class_iter;
        classID_t     class_id;
        PyObject     *val;
        const char   *desc;

        dict = PyDict_New();
        if (dict == NULL) {
            goto error;
        }
        val = PyInt_FromLong(sensor);
        if (val == NULL) {
            Py_DECREF(dict);
            goto error;
        }
        rv = PyDict_SetItem(sensors, val, dict);
        Py_DECREF(dict);
        if (rv != 0) {
            Py_DECREF(val);
            goto error;
        }
        rv = PyDict_SetItemString(dict, "id", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        sksiteSensorGetName(name, sizeof(name), sensor);
        val = PyUnicode_InternFromString(name);
        if (val == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "name", val);
        Py_DECREF(val);
        if (rv != 0) {
            goto error;
        }

        desc = sksiteSensorGetDescription(sensor);
        if (desc) {
            val = PyUnicode_FromString(desc);
            if (val == NULL) {
                goto error;
            }
            rv = PyDict_SetItemString(dict, "description", val);
            Py_DECREF(val);
            if (rv != 0) {
                goto error;
            }
        }

        list = PyList_New(0);
        if (list == NULL) {
            goto error;
        }
        rv = PyDict_SetItemString(dict, "classes", list);
        Py_DECREF(list);
        if (rv != 0) {
            goto error;
        }
        sksiteSensorClassIterator(sensor, &class_iter);
        while (sksiteClassIteratorNext(&class_iter, &class_id)) {
            val = PyInt_FromLong(class_id);
            if (val == NULL) {
                goto error;
            }
            rv = PyList_Append(list, val);
            Py_DECREF(val);
            if (rv != 0) {
                goto error;
            }
        }
    }

    GLOBALS->sensors = sensors;
    return 0;

  error:
    Py_XDECREF(sensors);

    return -1;
}

static int init_silkfile_module(
    PyObject   *mod)
{
    int rv;

    PyModule_AddIntConstant(mod, "IGNORE", SK_IPV6POLICY_IGNORE);
    PyModule_AddIntConstant(mod, "ASV4", SK_IPV6POLICY_ASV4);
    PyModule_AddIntConstant(mod, "MIX", SK_IPV6POLICY_MIX);
    PyModule_AddIntConstant(mod, "FORCE", SK_IPV6POLICY_FORCE);
    PyModule_AddIntConstant(mod, "ONLY", SK_IPV6POLICY_ONLY);

    PyModule_AddIntConstant(mod, "READ", SK_IO_READ);
    PyModule_AddIntConstant(mod, "WRITE", SK_IO_WRITE);
    PyModule_AddIntConstant(mod, "APPEND", SK_IO_APPEND);

    PyModule_AddIntConstant(mod, "DEFAULT", NOT_SET);
    PyModule_AddIntConstant(mod, "NO_COMPRESSION", SK_COMPMETHOD_NONE);
    PyModule_AddIntConstant(mod, "ZLIB", SK_COMPMETHOD_ZLIB);
    PyModule_AddIntConstant(mod, "LZO1X", SK_COMPMETHOD_LZO1X);

    PyModule_AddObject(mod, "BAG_COUNTER_MAX",
                       PyLong_FromUnsignedLongLong(SKBAG_COUNTER_MAX));

    silkPySilkFileType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPySilkFileType) < 0) {
        return -1;
    }
    rv = PyModule_AddObject(mod, "SilkFileBase",
                            (PyObject*)&silkPySilkFileType);
    if (rv != 0) {
        return -1;
    }

    return 0;
}

static int init_site(
    const char *site_file)
{
    int rv;
    int siterv;
    int retval = 0;

    if (GLOBALS->site_configured) {
        return 0;
    }

    siterv = sksiteConfigure(0);
    if (siterv == 0) {
        GLOBALS->havesite = Py_True;
    } else if (siterv == -2) {
        GLOBALS->havesite = Py_False;
        if (site_file) {
            Py_INCREF(GLOBALS->havesite);
            PyErr_Format(PyExc_IOError,
                         "could not read site file %s", site_file);
            retval = -1;
        }
    } else {
        GLOBALS->havesite = Py_False;
        PyErr_SetString(PyExc_RuntimeError,
                        "error parsing site configuration file");
        retval = -1;
    }
    Py_INCREF(GLOBALS->havesite);
    rv = PyModule_AddObject(GLOBALS->silkmod, "_havesite", GLOBALS->havesite);
    if (rv != 0) {
        return -1;
    }

    rv = init_sensors();
    if (rv != 0) {
        return -1;
    }
    rv = PyModule_AddObject(GLOBALS->silkmod, "_sensors", GLOBALS->sensors);
    if (rv != 0) {
        return -1;
    }

    rv = init_classes();
    if (rv != 0) {
        return -1;
    }
    rv = PyModule_AddObject(GLOBALS->silkmod, "_classes", GLOBALS->classes);
    if (rv != 0) {
        return -1;
    }

    rv = init_flowtypes();
    if (rv != 0) {
        return -1;
    }
    rv = PyModule_AddObject(GLOBALS->silkmod, "_flowtypes",
                            GLOBALS->flowtypes);
    if (rv != 0) {
        return -1;
    }

    if (siterv == 0) {
        GLOBALS->site_configured = 1;
    }

    return retval;
}

static PyObject *iter_iter(
    PyObject   *self)
{
    Py_INCREF(self);
    return self;
}

static void obj_dealloc(
    PyObject   *obj)
{
    Py_TYPE(obj)->tp_free(obj);
}

static PyObject *obj_error(
    const char *format,
    PyObject   *obj)
{
    return any_obj_error(PyExc_ValueError, format, obj);
}

static PyObject *reduce_error(
    PyObject   *obj)
{
    if (Py_TYPE(obj) && Py_TYPE(obj)->tp_name) {
        PyErr_Format(PyExc_TypeError, "can't pickle %s objects",
                     Py_TYPE(obj)->tp_name);
    } else {
        PyErr_SetString(PyExc_TypeError, "This object cannot be pickled");
    }
    return NULL;
}

static int silkPyDatetimeToSktime(
    sktime_t   *silktime,
    PyObject   *datetime)
{
    PyObject *delta = NULL;
    PyObject *days = NULL;
    PyObject *secs = NULL;
    PyObject *usecs = NULL;
    int64_t millisecs;
    int retval = -1;

    if (!PyDateTime_Check(datetime)) {
        if (PyDate_Check(datetime)) {
            datetime = PyDateTime_FromDateAndTime(
                PyDateTime_GET_YEAR(datetime),
                PyDateTime_GET_MONTH(datetime),
                PyDateTime_GET_DAY(datetime),
                0, 0, 0, 0);
            if (datetime == NULL) {
                return -1;
            }
        } else {
            PyErr_SetString(PyExc_TypeError, "Expected a datetime.date");
            return -1;
        }
    } else {
        Py_INCREF(datetime);
    }
    if (PyObject_RichCompareBool(datetime, GLOBALS->zerotime, Py_LT)) {
        PyErr_SetString(PyExc_OverflowError, "Minimum time is Jan 1, 1970");
        Py_DECREF(datetime);
        return -1;
    }
    delta = PyNumber_Subtract(datetime, GLOBALS->zerotime);
    Py_DECREF(datetime);
    days = PyObject_GetAttrString(delta, "days");
    secs = PyObject_GetAttrString(delta, "seconds");
    usecs = PyObject_GetAttrString(delta, "microseconds");
    millisecs = (int64_t)PyLong_AsLong(days) * 1000 * 24 * 3600 +
                (int64_t)PyLong_AsLong(secs) * 1000 +
                PyLong_AsLong(usecs) / 1000;
    if (!PyErr_Occurred()) {
        *silktime = millisecs;
        retval = 0;
    }
    Py_XDECREF(delta);
    Py_XDECREF(days);
    Py_XDECREF(secs);
    Py_XDECREF(usecs);

    return retval;
}

#if !SK_ENABLE_IPV6
static PyObject *silkPyNotImplemented(
    PyObject    UNUSED(*self),
    PyObject    UNUSED(*args),
    PyObject    UNUSED(*kwds))
{
    return PyErr_Format(PyExc_NotImplementedError,
                        "SiLK was not built with IPv6 support.");
}
#endif  /* !SK_ENABLE_IPV6 */


static PyObject *initpysilkbase(
    char*   name)
{
#if PY_MAJOR_VERSION >= 3
    /* Module information for Python 3.0 */
    static struct PyModuleDef pysilk_module_static = {
        PyModuleDef_HEAD_INIT,
        NULL,                       /* m_name */
        NULL,                       /* m_doc */
        sizeof(silkpy_globals_t),   /* m_size */
        silk_methods,               /* m_methods */
        NULL,                       /* m_reaload (unused) */
        NULL,                       /* m_traverse */
        NULL,                       /* m_clear */
        NULL                        /* m_free */
    };
#endif

    PyObject         *silkmod;
    PyObject         *tmp;
    silkpy_globals_t *globals;

    PyDateTime_IMPORT;

#if PY_MAJOR_VERSION >= 3
    pysilk_module = &pysilk_module_static;
    pysilk_module->m_name = name;
    silkmod = PyModule_Create(pysilk_module);
    if (silkmod == NULL) {
        skAppPrintErr("Could not create module silk");
        goto err;
    }
    globals = (silkpy_globals_t*)PyModule_GetState(silkmod);
#else
    /* Globals are in the static global variable */
    globals = &silkpy_globals_static;
    silkmod = Py_InitModule3(name, silk_methods, "SiLK extension module");
    if (silkmod == NULL) {
        skAppPrintErr("Could not create module silk");
        goto err;
    }
#endif  /* #else of #if PY_MAJOR_VERSION >= 3 */

    memset(globals, 0, sizeof(*globals));
    globals->silkmod = silkmod;
    globals->havesite = Py_False;
    Py_INCREF(globals->havesite);

    if (init_silkfile_module(silkmod)) {
        goto err;
    }

    if (silkPyIPAddr_setup(silkmod) != 0) {
        goto err;
    }

    if (PyType_Ready(&silkPyIPv4AddrType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPv4Addr",
                                     (PyObject*)&silkPyIPv4AddrType),
                  int, 0);

    if (PyType_Ready(&silkPyIPv6AddrType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPv6Addr",
                                     (PyObject*)&silkPyIPv6AddrType),
                  int, 0);

    if (PyType_Ready(&silkPyIPWildcardType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPWildcard",
                                     (PyObject*)&silkPyIPWildcardType),
                  int, 0);

    silkPyIPWildcardIterType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyIPWildcardIterType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPWildcardIter",
                                     (PyObject*)&silkPyIPWildcardIterType),
                  int, 0);

    silkPyIPSetType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyIPSetType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPSetBase",
                                     (PyObject*)&silkPyIPSetType),
                  int, 0);

    silkPyIPSetIterType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyIPSetIterType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "IPSetIter",
                                     (PyObject*)&silkPyIPSetIterType),
                  int, 0);

    silkPyPmapType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyPmapType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "PMapBase",
                                     (PyObject*)&silkPyPmapType),
                  int, 0);

    silkPyPmapIterType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyPmapIterType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "PMapBaseIter",
                                     (PyObject*)&silkPyPmapIterType),
                  int, 0);

    if (silkPyBag_setup(silkmod) != 0) {
        goto err;
    }

    silkPyBagIterType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyBagIterType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "BagBaseIter",
                                     (PyObject*)&silkPyBagIterType),
                  int, 0);

    silkPyRepoIterType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyRepoIterType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "RepoIter",
                                     (PyObject*)&silkPyRepoIterType),
                  int, 0);

    if (silkPyTCPFlags_setup(silkmod)) {
        goto err;
    }

    if (PyType_Ready(&silkPyRawRWRecType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "RawRWRec",
                                     (PyObject*)&silkPyRawRWRecType),
                  int, 0);

    silkPyRWRecType.tp_new = PyType_GenericNew;
    if (PyType_Ready(&silkPyRWRecType) < 0) {
        goto err;
    }
    ASSERT_RESULT(PyModule_AddObject(silkmod, "RWRecBase",
                                     (PyObject*)&silkPyRWRecType),
                  int, 0);

    tmp = PyImport_ImportModule("datetime");
    if (tmp == NULL) {
        skAppPrintErr("Failed to import datetime module");
        goto err;
    }

    globals->timedelta = PyObject_GetAttrString(tmp, "timedelta");
    assert(globals->timedelta != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_timedelta", globals->timedelta),
                  int, 0);

    globals->datetime = PyObject_GetAttrString(tmp, "datetime");
    assert(globals->datetime != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_datetime", globals->datetime),
                  int, 0);

    Py_DECREF(tmp);

    globals->maxelapsed = PyObject_CallFunction(globals->timedelta,
                                                "iiik", 0, 0, 0, UINT32_MAX);
    assert(globals->maxelapsed != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_maxelapsed",
                                     globals->maxelapsed),
                  int, 0);

    globals->minelapsed = PyObject_CallObject(globals->timedelta, NULL);
    assert(globals->minelapsed != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_minelapsed",
                                     globals->minelapsed),
                  int, 0);

    globals->zerotime = PyObject_CallFunction(globals->datetime, "iii",
                                              1970, 1, 1);
    assert(globals->zerotime != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_zerotime", globals->zerotime),
                  int, 0);

    globals->thousand = PyFloat_FromDouble(1000.0);
    assert(globals->thousand != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_thousand", globals->thousand),
                  int, 0);

    globals->maxintipv4 = PyLong_FromString("0xffffffff", NULL, 0);
    assert(globals->maxintipv4 != NULL);
    ASSERT_RESULT(PyModule_AddObject(globals->silkmod, "_maxintipv4",
                                     globals->maxintipv4),
                  int, 0);

#if SK_ENABLE_IPV6
    globals->maxintipv6 =
        PyLong_FromString("0xffffffffffffffffffffffffffffffff", NULL, 0);
    assert(globals->maxintipv6 != NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_maxintipv6",
                                     globals->maxintipv6),
                  int, 0);
#endif  /* SK_ENABLE_IPV6 */

    globals->newrawrec = PyObject_CallFunctionObjArgs(
        (PyObject *)&silkPyRawRWRecType, NULL);
    ASSERT_RESULT(PyModule_AddObject(silkmod, "_newrawrec",
                                     globals->newrawrec),
                  int, 0);

    return silkmod;

  err:
    if (silkmod) {
        Py_DECREF(silkmod);
    }
#if PY_MAJOR_VERSION >= 3
    return NULL;
#else /* PY_MAJOR_VERSION < 3 */
    if (PyErr_Occurred()) {
        PyErr_Print();
    }
    exit(EXIT_FAILURE);
#endif  /* PY_MAJOR_VERSION */
}

PyMODINIT_FUNC PYSILK_INIT(void)
{
    PyObject *nameobj;

    nameobj = BYTES_FROM_XCHAR(Py_GetProgramName());

    if (nameobj == NULL) {
        skAppRegister("PySiLK_program");
    } else {
        skAppRegister(PyBytes_AS_STRING(nameobj));
        Py_DECREF(nameobj);
    }
    INIT_RETURN(initpysilkbase(STR(PYSILK_NAME)));
}

PyMODINIT_FUNC PYSILK_NL_INIT(void)
{
    INIT_RETURN(initpysilkbase(STR(PYSILK_NL_NAME)));
}


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-25 13:41                             ` Michael Welsh Duggan
@ 2012-10-28 11:36                               ` Alan Mackenzie
  2012-11-04  3:43                                 ` Chong Yidong
  2012-11-04 20:39                                 ` Alan Mackenzie
  0 siblings, 2 replies; 55+ messages in thread
From: Alan Mackenzie @ 2012-10-28 11:36 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hello again, Michael.

On Thu, Oct 25, 2012 at 09:41:11AM -0400, Michael Welsh Duggan wrote:
> A new recipe.  This is a strange one.  I hope it works for you as well.

> emacs -Q
> M-x tool-bar-mode
> resize the frame to be height 56 (according to the window manager)
> Load the included file
> M-x c-toggle-parse-state-debug
> C-s FIXME C-s
> Move cursor to the "o" on the next line (1175).
> Type: 
> PyTYPE( 
> C-f 
> )

> I get errors at the first open paren, and the close paren.  Resizing the
> fame is important!  I think it's due to caching that happens during font
> locking. 

Thanks for this one.

The cause was the cache invalidation function being called from
after-change-functions.  The newly inserted parens were fouling up the
invalidation algorithm.  :-(  The solution is to call that function from
before-change-functions instead.

The changes are currently as follows.  Would you try out the patch as
usual, please, and let me know how it goes.



diff -r ac6584d14c06 cc-engine.el
--- a/cc-engine.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-engine.el	Sun Oct 28 11:31:48 2012 +0000
@@ -2560,8 +2560,11 @@
 	      start-point cache-pos)))
 
     ;; Might we be better off starting from the top level, two defuns back,
-    ;; instead?
-    (when (> how-far c-state-cache-too-far)
+    ;; instead?  This heuristic no longer works well in C++, where
+    ;; declarations inside namespace brace blocks are frequently placed at
+    ;; column zero.
+    (when (and (not (c-major-mode-is 'c++-mode))
+	       (> how-far c-state-cache-too-far))
       (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
       (if (< (- here BOD-pos) how-far)
 	  (setq strategy 'BOD
@@ -2648,17 +2651,19 @@
 	;; If we're essentially repeating a fruitless search, just give up.
 	(unless (and c-state-brace-pair-desert
 		     (eq cache-pos (car c-state-brace-pair-desert))
+		     (> from (car c-state-brace-pair-desert))
 		     (<= from (cdr c-state-brace-pair-desert)))
-	  ;; DESERT-LIM.  Only search what we absolutely need to,
+	  ;; DESERT-LIM.  Avoid repeated searching through the cached desert.
 	  (let ((desert-lim
 		 (and c-state-brace-pair-desert
 		      (eq cache-pos (car c-state-brace-pair-desert))
+		      (>= from (cdr c-state-brace-pair-desert))
 		      (cdr c-state-brace-pair-desert)))
 		;; CACHE-LIM.  This limit will be necessary when an opening
 		;; paren at `cache-pos' has just had its matching close paren
-		;; inserted.  `cache-pos' continues to be a search bound, even
-		;; though the algorithm below would skip over the new paren
-		;; pair.
+		;; inserted into the buffer.  `cache-pos' continues to be a
+		;; search bound, even though the algorithm below would skip
+		;; over the new paren pair.
 		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
 	    (narrow-to-region
 		(cond
@@ -3354,13 +3359,19 @@
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 
+(defvar c-parse-state-point nil)
 (defvar c-parse-state-state nil)
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
+  (setq c-parse-state-point (point))
   (setq c-parse-state-state
 	(mapcar
 	 (lambda (arg)
-	   (cons arg (symbol-value arg)))
+	   (let ((val (symbol-value arg)))
+	     (cons arg
+		   (if (consp val)
+		       (copy-tree val)
+		     val))))
 	 '(c-state-cache
 	   c-state-cache-good-pos
 	   c-state-nonlit-pos-cache
@@ -3373,7 +3384,8 @@
 	   c-state-point-min-lit-start
 	   c-state-min-scan-pos
 	   c-state-old-cpp-beg
-	   c-state-old-cpp-end))))
+	   c-state-old-cpp-end
+	   c-parse-state-point))))
 (defun c-replay-parse-state-state ()
   (message
    (concat "(setq "
@@ -3416,7 +3428,8 @@
       (message "Old state:")
       (c-replay-parse-state-state))
     (c-record-parse-state-state)
-    res1))
+    res2 ; res1 correct a cascading series of errors ASAP
+    ))
 
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")
diff -r ac6584d14c06 cc-mode.el
--- a/cc-mode.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-mode.el	Sun Oct 28 11:31:48 2012 +0000
@@ -1058,7 +1058,10 @@
 	      (mapc (lambda (fn)
 		      (funcall fn beg end))
 		    c-get-state-before-change-functions))
-	  )))))
+	  )))
+    ;; The following must be done here rather than in `c-after-change' because
+    ;; newly inserted parens would foul up the invalidation algorithm.
+    (c-invalidate-state-cache beg)))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)
@@ -1108,7 +1111,7 @@
 
 	(c-trim-found-types beg end old-len) ; maybe we don't need all of these.
 	(c-invalidate-sws-region-after beg end)
-	(c-invalidate-state-cache beg)
+	;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
 	(c-invalidate-find-decl-cache beg)
 
 	(when c-recognize-<>-arglists


> 
> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-28 11:36                               ` Alan Mackenzie
@ 2012-11-04  3:43                                 ` Chong Yidong
  2012-11-04 20:42                                   ` Alan Mackenzie
  2012-11-21 20:58                                   ` Alan Mackenzie
  2012-11-04 20:39                                 ` Alan Mackenzie
  1 sibling, 2 replies; 55+ messages in thread
From: Chong Yidong @ 2012-11-04  3:43 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Michael Welsh Duggan, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> The cause was the cache invalidation function being called from
> after-change-functions.  The newly inserted parens were fouling up the
> invalidation algorithm.  :-(  The solution is to call that function from
> before-change-functions instead.
>
> The changes are currently as follows.  Would you try out the patch as
> usual, please, and let me know how it goes.

Hi Alan,

When you are ready to commit this, please commit to the emacs-24 branch
(as opposed to the trunk).  I think this should be fixed for Emacs 24.3.
Thanks.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-10-28 11:36                               ` Alan Mackenzie
  2012-11-04  3:43                                 ` Chong Yidong
@ 2012-11-04 20:39                                 ` Alan Mackenzie
  2012-11-04 21:04                                   ` Kim Storm
  2012-11-14 16:52                                   ` Michael Welsh Duggan
  1 sibling, 2 replies; 55+ messages in thread
From: Alan Mackenzie @ 2012-11-04 20:39 UTC (permalink / raw)
  To: Kim Storm, Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org

Kim,

could you please try out this patch on your C++ files, and let me know
if the main problem has been resolved.

Michael,

there was a rather crass bug in last week's patch.  Sorry.  It's fixed
now, below.  M-x c-toggle-parse-state-debug has been enhanced to display
messages when the state-cache is intrinsically invalid.  It also now
gives a message when you {en,dis}able it.  Would you try out this patch
now, please.

Thanks to you both!

On Sun, Oct 28, 2012 at 11:36:10AM +0000, Alan Mackenzie wrote:

> On Thu, Oct 25, 2012 at 09:41:11AM -0400, Michael Welsh Duggan wrote:
> > A new recipe.  This is a strange one.  I hope it works for you as well.

> > emacs -Q
> > M-x tool-bar-mode
> > resize the frame to be height 56 (according to the window manager)
> > Load the included file
> > M-x c-toggle-parse-state-debug
> > C-s FIXME C-s
> > Move cursor to the "o" on the next line (1175).
> > Type: 
> > PyTYPE( 
> > C-f 
> > )

> > I get errors at the first open paren, and the close paren.  Resizing the
> > fame is important!  I think it's due to caching that happens during font
> > locking. 

> Thanks for this one.

> The cause was the cache invalidation function being called from
> after-change-functions.  The newly inserted parens were fouling up the
> invalidation algorithm.  :-(  The solution is to call that function from
> before-change-functions instead.



diff -r ac6584d14c06 cc-engine.el
--- a/cc-engine.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-engine.el	Sun Nov 04 20:24:06 2012 +0000
@@ -2560,8 +2560,11 @@
 	      start-point cache-pos)))
 
     ;; Might we be better off starting from the top level, two defuns back,
-    ;; instead?
-    (when (> how-far c-state-cache-too-far)
+    ;; instead?  This heuristic no longer works well in C++, where
+    ;; declarations inside namespace brace blocks are frequently placed at
+    ;; column zero.
+    (when (and (not (c-major-mode-is 'c++-mode))
+	       (> how-far c-state-cache-too-far))
       (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
       (if (< (- here BOD-pos) how-far)
 	  (setq strategy 'BOD
@@ -2648,17 +2651,20 @@
 	;; If we're essentially repeating a fruitless search, just give up.
 	(unless (and c-state-brace-pair-desert
 		     (eq cache-pos (car c-state-brace-pair-desert))
+		     (or (null (car c-state-brace-pair-desert))
+			 (> from (car c-state-brace-pair-desert)))
 		     (<= from (cdr c-state-brace-pair-desert)))
-	  ;; DESERT-LIM.  Only search what we absolutely need to,
+	  ;; DESERT-LIM.  Avoid repeated searching through the cached desert.
 	  (let ((desert-lim
 		 (and c-state-brace-pair-desert
 		      (eq cache-pos (car c-state-brace-pair-desert))
+		      (>= from (cdr c-state-brace-pair-desert))
 		      (cdr c-state-brace-pair-desert)))
 		;; CACHE-LIM.  This limit will be necessary when an opening
 		;; paren at `cache-pos' has just had its matching close paren
-		;; inserted.  `cache-pos' continues to be a search bound, even
-		;; though the algorithm below would skip over the new paren
-		;; pair.
+		;; inserted into the buffer.  `cache-pos' continues to be a
+		;; search bound, even though the algorithm below would skip
+		;; over the new paren pair.
 		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
 	    (narrow-to-region
 		(cond
@@ -3354,13 +3360,19 @@
   (fset 'c-real-parse-state (symbol-function 'c-parse-state)))
 (cc-bytecomp-defun c-real-parse-state)
 
+(defvar c-parse-state-point nil)
 (defvar c-parse-state-state nil)
 (make-variable-buffer-local 'c-parse-state-state)
 (defun c-record-parse-state-state ()
+  (setq c-parse-state-point (point))
   (setq c-parse-state-state
 	(mapcar
 	 (lambda (arg)
-	   (cons arg (symbol-value arg)))
+	   (let ((val (symbol-value arg)))
+	     (cons arg
+		   (if (consp val)
+		       (copy-tree val)
+		     val))))
 	 '(c-state-cache
 	   c-state-cache-good-pos
 	   c-state-nonlit-pos-cache
@@ -3373,7 +3385,8 @@
 	   c-state-point-min-lit-start
 	   c-state-min-scan-pos
 	   c-state-old-cpp-beg
-	   c-state-old-cpp-end))))
+	   c-state-old-cpp-end
+	   c-parse-state-point))))
 (defun c-replay-parse-state-state ()
   (message
    (concat "(setq "
@@ -3383,6 +3396,16 @@
      c-parse-state-state "  ")
     ")")))
 
+(defun c-debug-parse-state-double-cons (state)
+  (let (state-car conses-not-ok)
+    (while state
+      (setq state-car (car state)
+	    state (cdr state))
+      (if (and (consp state-car)
+	       (consp (car state)))
+	  (setq conses-not-ok t)))
+    conses-not-ok))
+
 (defun c-debug-parse-state ()
   (let ((here (point)) (res1 (c-real-parse-state)) res2)
     (let ((c-state-cache nil)
@@ -3415,8 +3438,16 @@
 	       here res1 res2)
       (message "Old state:")
       (c-replay-parse-state-state))
+
+    (when (c-debug-parse-state-double-cons res1)
+      (message "c-parse-state INVALIDITY at %s: %s"
+	       here res1)
+      (message "Old state:")
+      (c-replay-parse-state-state))
+
     (c-record-parse-state-state)
-    res1))
+    res2 ; res1 correct a cascading series of errors ASAP
+    ))
 
 (defun c-toggle-parse-state-debug (&optional arg)
   (interactive "P")
@@ -3424,7 +3455,9 @@
   (fset 'c-parse-state (symbol-function (if c-debug-parse-state
 					    'c-debug-parse-state
 					  'c-real-parse-state)))
-  (c-keep-region-active))
+  (c-keep-region-active)
+  (message "c-debug-parse-state %sabled"
+	   (if c-debug-parse-state "en" "dis")))
 (when c-debug-parse-state
   (c-toggle-parse-state-debug 1))
 
diff -r ac6584d14c06 cc-mode.el
--- a/cc-mode.el	Sun Sep 09 11:15:13 2012 +0000
+++ b/cc-mode.el	Sun Nov 04 20:24:06 2012 +0000
@@ -1058,7 +1058,10 @@
 	      (mapc (lambda (fn)
 		      (funcall fn beg end))
 		    c-get-state-before-change-functions))
-	  )))))
+	  )))
+    ;; The following must be done here rather than in `c-after-change' because
+    ;; newly inserted parens would foul up the invalidation algorithm.
+    (c-invalidate-state-cache beg)))
 
 (defvar c-in-after-change-fontification nil)
 (make-variable-buffer-local 'c-in-after-change-fontification)
@@ -1108,7 +1111,7 @@
 
 	(c-trim-found-types beg end old-len) ; maybe we don't need all of these.
 	(c-invalidate-sws-region-after beg end)
-	(c-invalidate-state-cache beg)
+	;; (c-invalidate-state-cache beg) ; moved to `c-before-change'.
 	(c-invalidate-find-decl-cache beg)
 
 	(when c-recognize-<>-arglists


> > -- 
> > Michael Welsh Duggan
> > (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-04  3:43                                 ` Chong Yidong
@ 2012-11-04 20:42                                   ` Alan Mackenzie
  2012-11-21 20:58                                   ` Alan Mackenzie
  1 sibling, 0 replies; 55+ messages in thread
From: Alan Mackenzie @ 2012-11-04 20:42 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 11749, Michael Welsh Duggan, Kim Storm

Hi, Yidong,

On Sun, Nov 04, 2012 at 11:43:26AM +0800, Chong Yidong wrote:
> Alan Mackenzie <acm@muc.de> writes:

> Hi Alan,

> When you are ready to commit this, please commit to the emacs-24 branch
> (as opposed to the trunk).  I think this should be fixed for Emacs 24.3.
> Thanks.

Will do!  I agree it should be fixed for 24.3, as it has become a rather
"popular" bug out in the wild.  :-(  I'm hoping I'm close to a fix, now.

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-04 20:39                                 ` Alan Mackenzie
@ 2012-11-04 21:04                                   ` Kim Storm
  2012-11-14 16:52                                   ` Michael Welsh Duggan
  1 sibling, 0 replies; 55+ messages in thread
From: Kim Storm @ 2012-11-04 21:04 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Michael Welsh Duggan

On 2012-11-04 21:39, Alan Mackenzie wrote:
> Kim,
>
> could you please try out this patch on your C++ files, and let me know
> if the main problem has been resolved.
>
> Michael,
Hi Michael and Alan

Sorry for the silence on this bug - I've worked on some other projects 
where the
bug has only shown up once or twice, so I couldn't really do any useful 
testing.

Also, my files are all C and not C++, so I didn't think the fixes you 
discussed would
be relevant for me.

In any case, I will install the patch and see what happens.

Kim






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-04 20:39                                 ` Alan Mackenzie
  2012-11-04 21:04                                   ` Kim Storm
@ 2012-11-14 16:52                                   ` Michael Welsh Duggan
  2012-11-21 21:33                                     ` Alan Mackenzie
  1 sibling, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-11-14 16:52 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 1469 bytes --]

Alan Mackenzie <acm@muc.de> writes:

> there was a rather crass bug in last week's patch.  Sorry.  It's fixed
> now, below.  M-x c-toggle-parse-state-debug has been enhanced to display
> messages when the state-cache is intrinsically invalid.  It also now
> gives a message when you {en,dis}able it.  Would you try out this patch
> now, please.

Sorry it has taken me so long to respond.  I was working in non-C-based
languages for a while.  today I started working in C again, and ran into
issues like this:

Error during redisplay: (jit-lock-function 3411) signaled (wrong-type-argument number-or-marker-p nil)
c-parse-state inconsistency at 3599: using cache: nil, from scratch: ((3409 . 3599))
Old state:
(setq c-state-cache '((3409 . 3599))  c-state-cache-good-pos 3599  c-state-nonlit-pos-cache '(6307 3307)  c-state-nonlit-pos-cache-limit 3592  c-state-semi-nonlit-pos-cache '(3307)  c-state-semi-nonlit-pos-cache-limit 3592  c-state-brace-pair-desert '(nil . 3396)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  c-parse-state-point 3600)

I have finally managed to come up with a recipe for this one.  I am
using "110803 rgm@gnu.org-20121105111732-ilq2sbfo09xg9i9z" with your
patches.

emacs -Q rwfileinfo.c
M-x c-toggle-parse-state-debug
C-x 4 b *Messages* RET
C-s enum RET
C-M-f C-p C-e ,

Error occurs after the comma (should be on line 197).


[-- Attachment #2: rwfileinfo.c --]
[-- Type: text/plain, Size: 24828 bytes --]

/*
** Copyright (C) 2003-2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  rwfileinfo
**
**  Prints information about an rw-file:
**    file type
**    file version
**    byte order
**    compression level
**    header size
**    record size
**    record count
**    file size
**    command line args used to generate file
**
*/


#include <silk/silk.h>

RCSIDENT("$Id$");

#include <silk/sksite.h>
#include <silk/utils.h>
#include <silk/skstream.h>
#include <silk/skstringmap.h>


/* LOCAL DEFINES AND TYPEDEFS */

/* where to write --help output */
#define USAGE_FH stdout

/* when determining number of records in file, number of bytes to
 * request at one time */
#define RWINFO_BLOCK_SIZE 0x40000

/* format for a label */
#define LABEL_FMT "  %-20s"

/* format for a label that is a number, such as when printing command lines */
#define LABEL_NUM_FMT "%20d  "

/* A list of the properties that can be printed; keep in sync with the
 * info_props[] array below */
enum info_fileinfo_id {
    RWINFO_FORMAT,
    RWINFO_VERSION,
    RWINFO_BYTE_ORDER,
    RWINFO_COMPRESSION,
    RWINFO_HEADER_LENGTH,
    RWINFO_RECORD_LENGTH,
    RWINFO_COUNT_RECORDS,
    RWINFO_FILE_SIZE,
    RWINFO_COMMAND_LINES,
    RWINFO_RECORD_VERSION,
    RWINFO_SILK_VERSION,
    RWINFO_PACKED_FILE_INFO,
    RWINFO_PROBE_NAME,
    RWINFO_ANNOTIONS,
    RWINFO_PREFIX_MAP,
    RWINFO_IPSET,
    RWINFO_BAG,
    /* Last item is used to get a count of the above; it must be last */
    RWINFO_PROPERTY_COUNT
};

/* A property */
typedef struct info_property_st {
    /* property's label */
    const char   *label;
    /* nonzero if printed */
    unsigned      will_print :1;
} info_property_t;


/* LOCAL VARIABLES */

/* keep in sync with the info_fileinfo_id enum above */
static info_property_t info_props[RWINFO_PROPERTY_COUNT] = {
    {"format(id)",          1},
    {"version",             1},
    {"byte-order",          1},
    {"compression(id)",     1},
    {"header-length",       1},
    {"record-length",       1},
    {"count-records",       1},
    {"file-size",           1},
    {"command-lines",       1},
    {"record-version",      1},
    {"silk-version",        1},
    {"packed-file-info",    1},
    {"probe-name",          1},
    {"annotations",         1},
    {"prefix-map",          1},
    {"ipset",               1},
    {"bag",                 1}
};

/* whether to print the summary */
static int print_summary = 0;

/* whether to not print titles (0==print titles, 1==no titles) */
static int no_titles = 0;

/* for looping over files on the command line */
static sk_options_ctx_t *optctx = NULL;


/* OPTIONS SETUP */

/* Create constants for the option processor */
typedef enum rwinfoOptionIds {
    OPT_FIELDS,
    OPT_SUMMARY,
    OPT_NO_TITLES
} appOptionsEnum;

static struct option appOptions[] = {
    {"fields",          REQUIRED_ARG, 0, OPT_FIELDS},
    {"summary",         NO_ARG,       0, OPT_SUMMARY},
    {"no-titles",       NO_ARG,       0, OPT_NO_TITLES},
    {0,0,0,0}           /* sentinel entry */
};

static const char *appHelp[] = {
    NULL, /* built dynamically */
    "Print a summary of total files, file sizes, and records",
    ("Do not print file names or field names; only print the\n"
     "\tvalues, one per line"),
    (char *)NULL /* sentinel entry */
};


/* LOCAL FUNCTION PROTOTYPES */

static int  appOptionsHandler(clientData cData, int opt_index, char *opt_arg);
static int  parseFields(const char *field_str);
static int  printFileInfo(
    const char *path,
    int64_t    *recs,
    int64_t    *bytes);


/* FUNCTION DEFINITIONS */

/*
 *  appUsageLong();
 *
 *    Print complete usage information to USAGE_FH.  Pass this
 *    function to skOptionsSetUsageCallback(); skOptionsParse() will
 *    call this funciton and then exit the program when the --help
 *    option is given.
 */
static void appUsageLong(void)
{
#define USAGE_MSG                                                       \
    ("[SWITCHES] <FILES>\n"                                             \
     "\tPrint information (type, version, etc.) about a SiLK Flow,\n"   \
     "\tIPset, or Bag file.  Use the fields switch to control what\n"   \
     "\tinformation is printed.\n")

    FILE *fh = USAGE_FH;
    int i, j;

    fprintf(fh, "%s %s", skAppName(), USAGE_MSG);
    fprintf(fh, "\nSWITCHES:\n");
    skOptionsDefaultUsage(fh);
    for (i = 0; appOptions[i].name; ++i) {
        fprintf(fh, "--%s %s. ", appOptions[i].name,
                SK_OPTION_HAS_ARG(appOptions[i]));
        switch (appOptions[i].val) {
          case OPT_FIELDS:
            fprintf(fh,
                    ("List of fields to print; specify by name or by value.\n"
                     "\tDef. All fields.  Available fields:"));
            for (j = 0; j < RWINFO_PROPERTY_COUNT; ++j) {
                fprintf(fh, "\n\t  %3d %s", 1+j, info_props[j].label);
            }
            break;

          default:
            fprintf(fh, "%s", appHelp[i]);
            break;
        }
        fprintf(fh, "\n");
    }
    skOptionsCtxOptionsUsage(optctx, fh);
    sksiteOptionsUsage(fh);
}


/*
 *  appTeardown()
 *
 *    Teardown all modules, close all files, and tidy up all
 *    application state.
 *
 *    This function is idempotent.
 */
static void appTeardown(void)
{
    static int teardownFlag = 0;

    if (teardownFlag) {
        return;
    }
    teardownFlag = 1;

    skOptionsCtxDestroy(&optctx);
    skAppUnregister();
}


/*
 *  appSetup(argc, argv);
 *
 *    Perform all the setup for this application include setting up
 *    required modules, parsing options, etc.  This function should be
 *    passed the same arguments that were passed into main().
 *
 *    Returns to the caller if all setup succeeds.  If anything fails,
 *    this function will cause the application to exit with a FAILURE
 *    exit status.
 */
static void appSetup(int argc, char **argv)
{
    SILK_FEATURES_DEFINE_STRUCT(features);
    int optctx_flags;
    int rv;

    /* verify same number of options and help strings */
    assert((sizeof(appHelp)/sizeof(char *)) ==
           (sizeof(appOptions)/sizeof(struct option)));

    /* register the application */
    skAppRegister(argv[0]);
    skAppVerifyFeatures(&features, NULL);
    skOptionsSetUsageCallback(&appUsageLong);

    optctx_flags = (SK_OPTIONS_CTX_INPUT_BINARY);

    /* register the options */
    if (skOptionsCtxCreate(&optctx, optctx_flags)
        || skOptionsCtxOptionsRegister(optctx)
        || skOptionsRegister(appOptions, &appOptionsHandler, NULL)
        || sksiteOptionsRegister(SK_SITE_FLAG_CONFIG_FILE))
    {
        skAppPrintErr("Unable to register options");
        exit(EXIT_FAILURE);
    }

    /* register the teardown handler */
    if (atexit(appTeardown) < 0) {
        skAppPrintErr("Unable to register appTeardown() with atexit()");
        appTeardown();
        exit(EXIT_FAILURE);
    }

    /* parse options */
    rv = skOptionsCtxOptionsParse(optctx, argc, argv);
    if (rv < 0) {
        skAppUsage();  /* never returns */
    }

    /* try to load the site file to resolve sensor information */
    sksiteConfigure(0);

    return;  /* OK */
}


/*
 *  status = appOptionsHandler(cData, opt_index, opt_arg);
 *
 *    Called by skOptionsParse(), this handles a user-specified switch
 *    that the application has registered, typically by setting global
 *    variables.  Returns 1 if the switch processing failed or 0 if it
 *    succeeded.  Returning a non-zero from from the handler causes
 *    skOptionsParse() to return a negative value.
 *
 *    The clientData in 'cData' is typically ignored; 'opt_index' is
 *    the index number that was specified as the last value for each
 *    struct option in appOptions[]; 'opt_arg' is the user's argument
 *    to the switch for options that have a REQUIRED_ARG or an
 *    OPTIONAL_ARG.
 */
static int appOptionsHandler(
    clientData  UNUSED(cData),
    int         opt_index,
    char       *opt_arg)
{
    switch ((appOptionsEnum)opt_index) {
      case OPT_FIELDS:
        if (parseFields(opt_arg)) {
            return 1;
        }
        break;

      case OPT_SUMMARY:
        print_summary = 1;
        break;

      case OPT_NO_TITLES:
        no_titles = 1;
        break;
    }

    return 0;
}


/*
 *  ok = parseFields(field_list);
 *
 *    Parse the user's field list, setting the appropriate flags in
 *    the info_props[] vector.
 */
static int parseFields(const char *field_str)
{
    sk_stringmap_t *str_map = NULL;
    sk_stringmap_status_t rv_map;
    sk_stringmap_entry_t *map_entry;
    sk_stringmap_entry_t insert_entry[2];
    sk_stringmap_iter_t *iter = NULL;
    char *fieldnum_string = NULL;
    char *cp;
    size_t len;
    int sz;
    uint32_t i;
    int rv = -1;

    /* create a char array to hold the field values as strings */
    len = 11 * RWINFO_PROPERTY_COUNT;
    fieldnum_string = (char*)calloc(len, sizeof(char));
    if (fieldnum_string == NULL) {
        skAppPrintErr("Unable to create string");
        goto END;
    }

    /* create a stringmap of the available entries */
    if (SKSTRINGMAP_OK != skStringMapCreate(&str_map)) {
        skAppPrintErr("Unable to create stringmap");
        goto END;
    }

    cp = fieldnum_string;
    for (i = 0; i < RWINFO_PROPERTY_COUNT; ++i) {
        sz = snprintf(cp, len, ("%" PRIu32), (uint32_t)(i+1));
        if ((size_t)sz > len) {
            skAppPrintErr("Internal buffer too small");
            skAbort();
        }
        memset(insert_entry, 0, sizeof(insert_entry));
        insert_entry[0].name = info_props[i].label;
        insert_entry[0].id = i;
        insert_entry[1].name = cp;
        insert_entry[1].id = i;
        if (skStringMapAddEntries(str_map, 2, insert_entry)
            != SKSTRINGMAP_OK)
        {
            goto END;
        }
        cp += sz + 1;
        len -= sz + 1;
    }

    /* attempt to match */
    rv_map = skStringMapParse(str_map, field_str, SKSTRINGMAP_DUPES_KEEP,
                              &iter, &cp);
    if (rv_map) {
        skAppPrintErr("Invalid %s: %s", appOptions[OPT_FIELDS].name, cp);
        goto END;
    }

    /* turn off printing for all fields */
    for (i = 0; i < RWINFO_PROPERTY_COUNT; ++i) {
        info_props[i].will_print = 0;
    }

    /* enable fields user listed */
    while (skStringMapIterNext(iter, &map_entry, NULL) == SK_ITERATOR_OK) {
        info_props[map_entry->id].will_print = 1;
    }

    rv = 0;

  END:
    if (str_map) {
        skStringMapDestroy(str_map);
    }
    if (iter) {
        skStringMapIterDestroy(iter);
    }
    if (fieldnum_string) {
        free(fieldnum_string);
    }
    return rv;
}


/*
 *  status = getNumberRecs(stream, record_size, &count);
 *
 *    Given 'stream' to the opened file, read the file to determine
 *    the number of 'record_size' records in the file, and set 'count'
 *    to that value.  If the file was successfully read, return 0.  If
 *    an error occurs while reading the file, return -1.
 */
static int getNumberRecs(
    skstream_t *stream,
    size_t      rec_size,
    int64_t    *count)
{
    size_t block_size = RWINFO_BLOCK_SIZE;
    int64_t bytes = 0;
    ssize_t saw;
    imaxdiv_t rec;
    int rv = 0;

    if (0 == rec_size) {
        rec_size = 1;
    }

    /* modify block_size to read an integer number of records */
    if (rec_size > block_size) {
        block_size = rec_size;
    } else {
        block_size -= block_size % rec_size;
    }

    /* get number of bytes in file */
    while ((saw = skStreamRead(stream, NULL, block_size)) > 0) {
        bytes += saw;
    }
    if (saw != 0) {
        skStreamPrintLastErr(stream, saw, &skAppPrintErr);
        rv = -1;
    }

    /* compute number of records */
    rec = imaxdiv(bytes, rec_size);
    if (rec.rem != 0) {
        skAppPrintErr("Short read (%" PRIdMAX "/%lu)",
                      rec.rem, (unsigned long)rec_size);
        rv = -1;
    }
    *count = (int64_t)rec.quot;
    return rv;
}


/*
 *  status = printFileInfo(info, &total_recs, &total_bytes);
 *
 *    Given the file information in the 'info' structure, print the
 *    fields requested by the user---given in the 'info_props'
 *    global---to the standard output.  Update the values pointed at
 *    by 'total_recs' and 'total_bytes' with the number of records and
 *    bytes in this file.  Return -1 if there is a problem opening or
 *    reading the file.  Return 0 otherwise.
 */
static int printFileInfo(
    const char *path,
    int64_t    *recs,
    int64_t    *bytes)
{
    char buf[1024];
    int count;
    int64_t rec_count;
    skstream_t *stream = NULL;
    sk_file_header_t *hdr;
    sk_header_entry_t *he;
    sk_hentry_iterator_t iter;
    int rv = SKSTREAM_OK;
    int retval = 0;

    if (SKSTREAM_OK == rv) {
        rv = skStreamCreate(&stream, SK_IO_READ, SK_CONTENT_SILK);
    }
    if (SKSTREAM_OK == rv) {
        rv = skStreamBind(stream, path);
    }
    if (SKSTREAM_OK == rv) {
        rv = skStreamOpen(stream);
    }
    if (SKSTREAM_OK == rv) {
        rv = skStreamReadSilkHeaderStart(stream);
    }

    /* Give up if we can't read the beginning of the silk header */
    if (rv != SKSTREAM_OK) {
        skStreamPrintLastErr(stream, rv, &skAppPrintErr);
        skStreamDestroy(&stream);
        return -1;
    }

    /* print file name */
    if (!no_titles) {
        printf("%s:\n", path);
    }

    /* read the header */
    rv = skStreamReadSilkHeader(stream, &hdr);
    switch (rv) {
      case SKSTREAM_OK:
        break;
      case SKHEADER_ERR_LEGACY:
        /* unrecognized file format.  disable printing of record
         * version and record size */
        info_props[RWINFO_HEADER_LENGTH].will_print = 0;
        info_props[RWINFO_RECORD_LENGTH].will_print = 0;
        info_props[RWINFO_RECORD_VERSION].will_print = 0;
        info_props[RWINFO_SILK_VERSION].will_print = 0;
        info_props[RWINFO_COUNT_RECORDS].will_print = 0;
        break;
      default:
        /* print an error but continue */
        skStreamPrintLastErr(stream, rv, &skAppPrintErr);
        retval = -1;
        break;
    }

    if (info_props[RWINFO_FORMAT].will_print) {
        sksiteFileformatGetName(buf, sizeof(buf),
                                skHeaderGetFileFormat(hdr));
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_FORMAT].label);
        }
        printf("%s(0x%02x)\n", buf, skHeaderGetFileFormat(hdr));
    }

    if (info_props[RWINFO_VERSION].will_print) {
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_VERSION].label);
        }
        printf("%u\n", skHeaderGetFileVersion(hdr));
    }

    if (info_props[RWINFO_BYTE_ORDER].will_print) {
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_BYTE_ORDER].label);
        }
        printf("%s\n", ((skHeaderGetByteOrder(hdr) == SILK_ENDIAN_BIG)
                        ? "BigEndian"
                        : "littleEndian"));
    }

    if (info_props[RWINFO_COMPRESSION].will_print) {
        sksiteCompmethodGetName(buf, sizeof(buf),
                                skHeaderGetCompressionMethod(hdr));
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_COMPRESSION].label);
        }
        printf("%s(%u)\n", buf, skHeaderGetCompressionMethod(hdr));
    }

    if (info_props[RWINFO_HEADER_LENGTH].will_print) {
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_HEADER_LENGTH].label);
        }
        printf("%u\n", (unsigned int)skHeaderGetLength(hdr));
    }

    if (info_props[RWINFO_RECORD_LENGTH].will_print) {
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_RECORD_LENGTH].label);
        }
        printf("%u\n", (unsigned int)skHeaderGetRecordLength(hdr));
    }

    if (info_props[RWINFO_RECORD_VERSION].will_print) {
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_RECORD_VERSION].label);
        }
        printf("%d\n", skHeaderGetRecordVersion(hdr));
    }

    if (info_props[RWINFO_SILK_VERSION].will_print) {
        uint32_t vers = skHeaderGetSilkVersion(hdr);
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_SILK_VERSION].label);
        }
        if (vers == 0) {
            printf("0\n");
        } else {
            printf(("%" PRId32 ".%" PRId32 ".%" PRId32 "\n"),
                   (vers / 1000000), (vers / 1000 % 1000), (vers % 1000));
        }
    }

    if (info_props[RWINFO_COUNT_RECORDS].will_print) {
        rv = getNumberRecs(stream, skHeaderGetRecordLength(hdr), &rec_count);
        if (rv) {
            retval = -1;
        }
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_COUNT_RECORDS].label);
        }
        printf(("%" PRId64 "\n"), rec_count);
        *recs += rec_count;
    }

    if (info_props[RWINFO_FILE_SIZE].will_print) {
        int64_t sz = (int64_t)skFileSize(path);
        if (!no_titles) {
            printf(LABEL_FMT, info_props[RWINFO_FILE_SIZE].label);
        }
        printf(("%" PRId64 "\n"), sz);
        *bytes += sz;
    }

    if (info_props[RWINFO_PACKED_FILE_INFO].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_PACKEDFILE_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (!no_titles) {
                if (count == 0) {
                    printf(LABEL_FMT,
                           info_props[RWINFO_PACKED_FILE_INFO].label);
                } else {
                    printf(LABEL_FMT, "");
                }
            }
            ++count;
            skHentryPackedfilePrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_PROBE_NAME].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_PROBENAME_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (!no_titles) {
                if (count == 0) {
                    printf(LABEL_FMT, info_props[RWINFO_PROBE_NAME].label);
                } else {
                    printf(LABEL_FMT, "");
                }
            }
            ++count;
            skHentryProbenamePrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_PREFIX_MAP].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_PREFIXMAP_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (!no_titles) {
                if (count == 0) {
                    printf(LABEL_FMT, info_props[RWINFO_PREFIX_MAP].label);
                } else {
                    printf(LABEL_FMT, "");
                }
            }
            ++count;
            skHentryPrefixmapPrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_IPSET].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_IPSET_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (!no_titles) {
                if (count == 0) {
                    printf(LABEL_FMT, info_props[RWINFO_IPSET].label);
                } else {
                    printf(LABEL_FMT, "");
                }
            }
            ++count;
            skHentryIPSetPrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_BAG].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_BAG_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (!no_titles) {
                if (count == 0) {
                    printf(LABEL_FMT, info_props[RWINFO_BAG].label);
                } else {
                    printf(LABEL_FMT, "");
                }
            }
            ++count;
            skHentryBagPrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_COMMAND_LINES].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_INVOCATION_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (count == 0 && !no_titles) {
                printf((LABEL_FMT "\n"),
                       info_props[RWINFO_COMMAND_LINES].label);
            }
            ++count;
            if (!no_titles) {
                printf(LABEL_NUM_FMT, count);
            }
            skHentryInvocationPrint(he, stdout);
            printf("\n");
        }
    }

    if (info_props[RWINFO_ANNOTIONS].will_print) {
        count = 0;
        skHeaderIteratorBindType(&iter, hdr, SK_HENTRY_ANNOTATION_ID);
        while ((he = skHeaderIteratorNext(&iter)) != NULL) {
            if (count == 0 && !no_titles) {
                printf((LABEL_FMT "\n"), info_props[RWINFO_ANNOTIONS].label);
            }
            ++count;
            if (!no_titles) {
                printf(LABEL_NUM_FMT, count);
            }
            skHentryAnnotationPrint(he, stdout);
            printf("\n");
        }
    }

    skStreamDestroy(&stream);
    return retval;
}


/*
 *  For each file, get the file's info then print it
 */
int main(int argc, char **argv)
{
    int64_t total_files = 0;
    int64_t total_bytes = 0;
    int64_t total_recs = 0;
    int rv = EXIT_SUCCESS;
    char *path;

    appSetup(argc, argv);       /* never returns on error */

    while (skOptionsCtxNextArgument(optctx, &path) == 0) {
        if (printFileInfo(path, &total_recs, &total_bytes)) {
            rv = EXIT_FAILURE;
        }
        ++total_files;
    }

    if (print_summary) {
        if (!no_titles) {
            printf("**SUMMARY**:\n");
            printf(LABEL_FMT, "number-files");
        }
            printf(("%" PRId64 "\n"), total_files);
        if (info_props[RWINFO_COUNT_RECORDS].will_print) {
            if (!no_titles) {
                printf(LABEL_FMT, "total-records");
            }
            printf(("%" PRId64 "\n"), total_recs);
        }
        if (info_props[RWINFO_FILE_SIZE].will_print) {
            if (!no_titles) {
                printf(LABEL_FMT, "all-file-sizes");
            }
            printf(("%" PRId64 "\n"), total_bytes);
        }
    }

    /* done */
    return rv;
}


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-04  3:43                                 ` Chong Yidong
  2012-11-04 20:42                                   ` Alan Mackenzie
@ 2012-11-21 20:58                                   ` Alan Mackenzie
  2012-11-22 14:52                                     ` Stefan Monnier
  1 sibling, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-11-21 20:58 UTC (permalink / raw)
  To: Chong Yidong; +Cc: 11749, Michael Welsh Duggan, Kim Storm

Hello, Yidong.

On Sun, Nov 04, 2012 at 11:43:26AM +0800, Chong Yidong wrote:
> Alan Mackenzie <acm@muc.de> writes:

> > The cause was the cache invalidation function being called from
> > after-change-functions.  The newly inserted parens were fouling up the
> > invalidation algorithm.  :-(  The solution is to call that function from
> > before-change-functions instead.

> > The changes are currently as follows.  Would you try out the patch as
> > usual, please, and let me know how it goes.

> Hi Alan,

> When you are ready to commit this, please commit to the emacs-24 branch
> (as opposed to the trunk).  I think this should be fixed for Emacs 24.3.
> Thanks.

I've just committed the current state of the bug fixes to Emacs-24 in
anticipation of the coming pretest.  (I also bumped CC Mode's version
number.)  Can I assume that you or Stefan will copy the changes to the
trunk?

There is, however, at least one outstanding bug, as reported by Michael
on 2012-11-14.  I'm trying to track this one down, but at the moment I
can't reproduce it.

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-14 16:52                                   ` Michael Welsh Duggan
@ 2012-11-21 21:33                                     ` Alan Mackenzie
  2012-11-26 13:25                                       ` Michael Welsh Duggan
  0 siblings, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2012-11-21 21:33 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael.

On Wed, Nov 14, 2012 at 11:52:41AM -0500, Michael Welsh Duggan wrote:

> ... Today I started working in C again, and ran into issues like this:

> Error during redisplay: (jit-lock-function 3411) signaled (wrong-type-argument number-or-marker-p nil)
> c-parse-state inconsistency at 3599: using cache: nil, from scratch: ((3409 . 3599))
> Old state:
> (setq c-state-cache '((3409 . 3599))  c-state-cache-good-pos 3599  c-state-nonlit-pos-cache '(6307 3307)  c-state-nonlit-pos-cache-limit 3592  c-state-semi-nonlit-pos-cache '(3307)  c-state-semi-nonlit-pos-cache-limit 3592  c-state-brace-pair-desert '(nil . 3396)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  c-parse-state-point 3600)

> I have finally managed to come up with a recipe for this one.  I am
> using "110803 rgm@gnu.org-20121105111732-ilq2sbfo09xg9i9z" with your
> patches.

> emacs -Q rwfileinfo.c
> M-x c-toggle-parse-state-debug
> C-x 4 b *Messages* RET

I assumed a C-x o here.  ;-)

> C-s enum RET
> C-M-f C-p C-e ,

> Error occurs after the comma (should be on line 197).

I find myself on L96.  I can't reproduce this error, neither on a tty or
in X windows.  I tried repeating the C-M-f, so that the C-p C-e brought
point to just after "RWINFO_PROPERTY_COUNT" and typing a comma there.
That still didn't signal an error.

I've just committed the current state of the fixes to the Emacs-24 branch
at savannah, for the pretest next weekend.

Thanks again for all the input.

> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-21 20:58                                   ` Alan Mackenzie
@ 2012-11-22 14:52                                     ` Stefan Monnier
  0 siblings, 0 replies; 55+ messages in thread
From: Stefan Monnier @ 2012-11-22 14:52 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749, Chong Yidong, Michael Welsh Duggan, Kim Storm

> I've just committed the current state of the bug fixes to Emacs-24 in
> anticipation of the coming pretest.  (I also bumped CC Mode's version
> number.)

Thanks.

> Can I assume that you or Stefan will copy the changes to the trunk?

Could also be someone else, but yes you can assume it will happen within
a few days.  Except we call it "merge" rather than "copy" ;-)

> There is, however, at least one outstanding bug, as reported by Michael
> on 2012-11-14.  I'm trying to track this one down, but at the moment I
> can't reproduce it.

I wish you luck,


        Stefan





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-21 21:33                                     ` Alan Mackenzie
@ 2012-11-26 13:25                                       ` Michael Welsh Duggan
  2012-12-10  3:35                                         ` Michael Welsh Duggan
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-11-26 13:25 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 1957 bytes --]

Alan Mackenzie <acm@muc.de> writes:

> Hi, Michael.
>
> On Wed, Nov 14, 2012 at 11:52:41AM -0500, Michael Welsh Duggan wrote:
>
>> ... Today I started working in C again, and ran into issues like this:
>
>> Error during redisplay: (jit-lock-function 3411) signaled
>> (wrong-type-argument number-or-marker-p nil)
>> c-parse-state inconsistency at 3599: using cache: nil, from scratch:
>> ((3409 . 3599))
>> Old state:
>> (setq c-state-cache '((3409 . 3599)) c-state-cache-good-pos 3599
>> c-state-nonlit-pos-cache '(6307 3307) c-state-nonlit-pos-cache-limit
>> 3592 c-state-semi-nonlit-pos-cache '(3307)
>> c-state-semi-nonlit-pos-cache-limit 3592 c-state-brace-pair-desert
>> (nil . 3396) c-state-point-min 1 c-state-point-min-lit-type nil
>> c-state-point-min-lit-start nil c-state-min-scan-pos 1
>> c-state-old-cpp-beg nil c-state-old-cpp-end nil c-parse-state-point
>> 3600)
>
>> I have finally managed to come up with a recipe for this one.  I am
>> using "110803 rgm@gnu.org-20121105111732-ilq2sbfo09xg9i9z" with your
>> patches.
>
>> emacs -Q rwfileinfo.c
>> M-x c-toggle-parse-state-debug
>> C-x 4 b *Messages* RET
>
> I assumed a C-x o here.  ;-)
>
>> C-s enum RET
>> C-M-f C-p C-e ,
>
>> Error occurs after the comma (should be on line 197).
>
> I find myself on L96.  I can't reproduce this error, neither on a tty or
> in X windows.  I tried repeating the C-M-f, so that the C-p C-e brought
> point to just after "RWINFO_PROPERTY_COUNT" and typing a comma there.
> That still didn't signal an error.

I'm sorry.  I realized that I attached the wrong file.  And the line
number should have been 97, not 197.  Unfortunately, I cannot reliably
trigger the problem using the above recipe using a recent Emacs trunk
check-out.  Even more unfortunately, I have still encountered the
problem (but have been unable to recreate it).  All in all, though, I
think your changes have been beneficial.  I'll try to isolate an example
over the next few days.


[-- Attachment #2: rwsiteinfo.c --]
[-- Type: text/plain, Size: 61958 bytes --]

/*
** Copyright (C) 2011-2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  Prints information about SiLK site configurations
**
**  Michael Duggan
**  September 2011
*/


#include <silk/silk.h>

RCSIDENT("$Id$");

#include <silk/skstream.h>
#include <silk/skstringmap.h>
#include <silk/sksite.h>
#include <silk/utils.h>


/* LOCAL DEFINES AND TYPEDEFS */

/* where to write --help output */
#define USAGE_FH stdout

/*
 *  Printer function typedef.
 *
 *    rwsiteinfo "prints" the output twice.  In the first pass, it
 *    uses a print function that does not produce output but instead
 *    determines the sizes of what it would print.  In the second
 *    pass, it uses an actual print function (fprintf) to produce the
 *    output.
 */
typedef int (*rws_fprintf_t)(FILE *f, const char *fmt, ...);


/* Sub-iterator types */
typedef enum {
    RWS_NULL,
    RWS_FLOWTYPE,
    RWS_CLASS,
    RWS_SENSOR,
    RWS_CLASS_FROM_SENSOR,
    RWS_SENSOR_FROM_CLASS,
    RWS_FLOWTYPE_FROM_CLASS,
    RWS_DEFAULT_FLOWTYPE_FROM_CLASS
} rws_iter_type_t;

/* Site iterator */
typedef struct rws_iter_st {
    /* The iterators */
    flowtype_iter_t flowtype_iter;
    class_iter_t    class_iter;
    sensor_iter_t   sensor_iter;

    /* The values */
    flowtypeID_t    flowtype_id;
    classID_t       class_id;
    sensorID_t      sensor_id;

    /* Order and type of iterators */
    rws_iter_type_t order[3];
    /* Number of iterators  */
    int             level;
    /* Highest bound iterator */
    int             bound;
    /* Highest started iterator */
    int             started;

    /* Whether RWS_DEFAULT_FLOWTYPE_FROM_CLASS is one of the
     * iterators */
    unsigned        default_type : 1;
} rws_iter_t;


/* LOCAL VARIABLE DEFINITIONS */

/* Masks for flowtypes, classes, and sensors as set by the --classes,
 * --types, --flowtypes, and --sensors switches.  When the bitmap is
 * NULL, all values are printed; when the bitmap is not NULL, only
 * values where the bit is high are printed. */
static sk_bitmap_t *flowtype_mask = NULL;
static sk_bitmap_t *class_mask   = NULL;
static sk_bitmap_t *sensor_mask   = NULL;

/* paging program */
static const char *pager;

/* the output stream, set by --output-path or --pager */
static sk_fileptr_t output;

/* raw filter arguments */
static char *classes_arg   = NULL;
static char *types_arg     = NULL;
static char *flowtypes_arg = NULL;
static char *sensors_arg   = NULL;
static char *fields_arg    = NULL;

/* delimiters */
static char column_separator = '|';
static char list_separator   = ',';

/* how to format output */
static int no_columns         = 0;
static int no_final_delimiter = 0;
static int no_titles          = 0;

/* final delimiter */
static char final_delim[] = {'\0', '\0'};

/* Field types */
typedef enum {
    RWST_CLASS,
    RWST_TYPE,
    RWST_FLOWTYPE,
    RWST_FLOWTYPE_ID,
    RWST_SENSOR,
    RWST_SENSOR_ID,
    RWST_SENSOR_DESC,
    RWST_DEFAULT_CLASS,
    RWST_DEFAULT_TYPE,
    RWST_MARK_DEFAULTS,
    RWST_CLASS_LIST,
    RWST_TYPE_LIST,
    RWST_FLOWTYPE_LIST,
    RWST_FLOWTYPE_ID_LIST,
    RWST_SENSOR_LIST,
    RWST_SENSOR_ID_LIST,
    RWST_DEFAULT_CLASS_LIST,
    RWST_DEFAULT_TYPE_LIST,
    /* Number of field types */
    RWST_MAX_FIELD_COUNT
} rws_field_t;

/* Field names, types, descriptions, and titles.  MUST be in the same
 * order as the rws_field_t enumeration. */
static const sk_stringmap_entry_t field_map_entries[] = {
    {"class",              RWST_CLASS,
     "class name",                             "Class"},
    {"type",               RWST_TYPE,
     "type name",                              "Type"},
    {"flowtype",           RWST_FLOWTYPE,
     "flowtype name",                          "Flowtype"},
    {"id-flowtype",        RWST_FLOWTYPE_ID,
     "flowtype integer identifier",            "Flowtype-ID"},
    {"sensor",             RWST_SENSOR,
     "sensor name",                            "Sensor"},
    {"id-sensor",          RWST_SENSOR_ID,
     "sensor integer identifier",              "Sensor-ID"},
    {"describe-sensor",    RWST_SENSOR_DESC,
     "sensor description",                     "Sensor-Description"},
    {"default-class",      RWST_DEFAULT_CLASS,
     "default class name",                     "Default-Class"},
    {"default-type",       RWST_DEFAULT_TYPE,
     "default type name",                      "Default-Type"},
    {"mark-defaults",      RWST_MARK_DEFAULTS,
     "'+' for default classes, '*' for types", "Defaults"},
    {"class:list",         RWST_CLASS_LIST,
     "list of class names",                    "Class:list"},
    {"type:list",          RWST_TYPE_LIST,
     "list of type names",                     "Type:list"},
    {"flowtype:list",      RWST_FLOWTYPE_LIST,
     "list of flowtype names",                 "Flowtype:list"},
    {"id-flowtype:list",   RWST_FLOWTYPE_ID_LIST,
     "list of flowtype integer identifier",    "Flowtype-ID:list"},
    {"sensor:list",        RWST_SENSOR_LIST,
     "list of sensor names",                   "Sensor:list"},
    {"id-sensor:list",     RWST_SENSOR_ID_LIST,
     "list of sensor integer identifiers",     "Sensor-ID:list"},
    {"default-class:list", RWST_DEFAULT_CLASS_LIST,
     "list of default class names",            "Default-Class:list"},
    {"default-type:list",  RWST_DEFAULT_TYPE_LIST,
     "list of default type names",             "Default-Type:list"},
    SK_STRINGMAP_SENTINEL
};

/* Fields to print, in the order in which to print them */
static rws_field_t fields[RWST_MAX_FIELD_COUNT];

/* Number of fields in list */
static size_t num_fields = 0;

/* Width of the columns, where index is an rws_field_t. */
static int col_width[RWST_MAX_FIELD_COUNT];


/* OPTIONS SETUP */

typedef enum {
    OPT_FIELDS, OPT_CLASSES, OPT_TYPES, OPT_FLOWTYPES,
    OPT_SENSORS, OPT_NO_TITLES, OPT_NO_COLUMNS, OPT_COLUMN_SEPARATOR,
    OPT_NO_FINAL_DELIMITER, OPT_DELIMITED, OPT_LIST_DELIMETER,
    OPT_PAGER, OPT_DATA_ROOTDIR
} appOptionsEnum;

static struct option appOptions[] = {
    {"fields",              REQUIRED_ARG, 0, OPT_FIELDS},
    {"classes",             REQUIRED_ARG, 0, OPT_CLASSES},
    {"types",               REQUIRED_ARG, 0, OPT_TYPES},
    {"flowtypes",           REQUIRED_ARG, 0, OPT_FLOWTYPES},
    {"sensors",             REQUIRED_ARG, 0, OPT_SENSORS},
    {"no-titles",           NO_ARG,       0, OPT_NO_TITLES},
    {"no-columns",          NO_ARG,       0, OPT_NO_COLUMNS},
    {"column-separator",    REQUIRED_ARG, 0, OPT_COLUMN_SEPARATOR},
    {"no-final-delimiter",  NO_ARG,       0, OPT_NO_FINAL_DELIMITER},
    {"delimited",           OPTIONAL_ARG, 0, OPT_DELIMITED},
    {"list-delimiter",      REQUIRED_ARG, 0, OPT_LIST_DELIMETER},
    {"pager",               REQUIRED_ARG, 0, OPT_PAGER},
    {"data-rootdir",        REQUIRED_ARG, 0, OPT_DATA_ROOTDIR},
    {0,0,0,0}               /* sentinel entry */
};

static const char *appHelp[] = {
    ("Print the fields named in this comma-separated list. Choices:"),
    ("Restrict the output using classes named in this comma-\n"
     "\tseparated list. Use '@' to designate the default class.\n"
     "\tDef. Print data for all classes"),
    ("Restrict the output using the types named in this comma-\n"
     "\tseparated list. Use '@' to designate the default type(s) for a class.\n"
     "\tDef. Print data for all types"),
    ("Restrict the output using the class/type pairs named in\n"
     "\tthis comma-separated list. May use 'all' for class and/or type. This\n"
     "\tis an alternate way to specify class/type; switch may not be used\n"
     "\twith --class or --type. Def. Print data for all class/type pairs"),
    ("Restrict the output using the sensors named in this comma-\n"
     "\tseparated list. Sensors may be designated by name, ID (integer),\n"
     "\tand/or ranges of IDs. Def. Print data for all sensors"),
    ("Do not print column headers. Def. Print titles"),
    ("Disable fixed-width columnar output. Def. Columnar"),
    ("Use specified character between columns. Def. '|'"),
    ("Suppress column delimiter at end of line. Def. No"),
    ("Shortcut for --no-columns --no-final-del --column-sep=CHAR"),
    ("Use specified character between items in FIELD:list\n"
     "\tfields. Def. ','"),
    ("Program to invoke to page output. Def. $SILK_PAGER or $PAGER"),
    ("Root of directory tree containing packed data."),
    (char *)NULL
};



/* LOCAL FUNCTION PROTOTYPES */

static int  appOptionsHandler(clientData cData, int opt_index, char *opt_arg);
static sk_stringmap_t *createStringmap(void);
static int rws_parse_fields(void);
static int rws_parse_restrictions(void);
static int rws_print_list_field(
    rws_fprintf_t  printer,
    FILE          *fd,
    rws_iter_t    *iter,
    rws_field_t    field,
    int            width);
static int fprintf_size(FILE *stream, const char *format, ...);


/* FUNCTION DEFINITIONS */

/*
 *  appUsageLong();
 *
 *    Print complete usage information to USAGE_FH.  Pass this
 *    function to skOptionsSetUsageCallback(); skOptionsParse() will
 *    call this funciton and then exit the program when the --help
 *    option is given.
 */
static void appUsageLong(void)
{
#define MIN_TEXT_ON_LINE  15
#define MAX_TEXT_ON_LINE  72
#define USAGE_MSG                                                            \
    ("--fields=<FIELDS> [SWITCHES]\n"                                        \
     "\tPrint selected information about the classes, types, flowtypes\n"    \
     "\tand sensors defined in the SiLK site configuration file.  By\n"      \
     "\tdefault, the selected information is printed for every class,\n"     \
     "\ttype, and sensor defined in the file; to restrict the output,\n"     \
     "\tspecify one or more of --classes, --types, --flowtypes, or\n"        \
     "\t--sensors.\n")

    FILE *fh = USAGE_FH;
    char *cp, *ep, *sp;
    char buf[2 * PATH_MAX];
    char path[PATH_MAX];
    int i;

    fprintf(fh, "%s %s", skAppName(), USAGE_MSG);
    fprintf(fh, "\nSWITCHES:\n");
    skOptionsDefaultUsage(fh);

    for (i = 0; appOptions[i].name; i++ ) {
        fprintf(fh, "--%s %s. ",
                appOptions[i].name, SK_OPTION_HAS_ARG(appOptions[i]));
        /* Print the static help text from the appHelp array */
        fprintf(fh, "%s\n", appHelp[i]);
        switch (appOptions[i].val) {
          case OPT_FIELDS:
            {
                sk_stringmap_t *map = createStringmap();
                if (map == NULL) {
                    skAppPrintErr("Error creating string map");
                    exit(EXIT_FAILURE);
                }
                skStringMapPrintUsage(map, fh, 8);
                skStringMapDestroy(map);
            }
            break;
          case OPT_DATA_ROOTDIR:
            /* put the text into a buffer, and then wrap the text in
             * the buffer at space characters. */
            snprintf(buf, sizeof(buf),
                     ("Currently '%s'. Def. $" SILK_DATA_ROOTDIR_ENVAR
                      " or '%s'"),
                     sksiteGetRootDir(path, sizeof(path)),
                     sksiteGetDefaultRootDir());
            sp = buf;
            while (strlen(sp) > MAX_TEXT_ON_LINE) {
                cp = &sp[MIN_TEXT_ON_LINE];
                while ((ep = strchr(cp+1, ' ')) != NULL) {
                    /* text is now too long */
                    if (ep - sp > MAX_TEXT_ON_LINE) {
                        if (cp == &sp[MIN_TEXT_ON_LINE]) {
                            /* this is the first space character we have
                             * on this line; so use it */
                            cp = ep;
                        }
                        break;
                    }
                    cp = ep;
                }
                if (cp == &sp[MIN_TEXT_ON_LINE]) {
                    /* no space characters anywhere on the line */
                    break;
                }
                assert(' ' == *cp);
                *cp = '\0';
                fprintf(fh, "\t%s\n", sp);
                sp = cp + 1;
            }
            if (*sp) {
                fprintf(fh, "\t%s\n", sp);
            }
            break;
          default:
            break;
        }
    }

    sksiteOptionsUsage(fh);
}


/*
 *  appTeardown()
 *
 *    Teardown all modules, close all files, and tidy up all
 *    application state.
 *
 *    This function is idempotent.
 */
static void appTeardown(void)
{
    static int teardownFlag = 0;

    if (teardownFlag) {
        return;
    }
    teardownFlag = 1;

    /* close the output file or process */
    if (output.of_name) {
        skFileptrClose(&output, &skAppPrintErr);
    }

    skBitmapDestroy(&flowtype_mask);
    skBitmapDestroy(&class_mask);
    skBitmapDestroy(&sensor_mask);

    skAppUnregister();
}


/*
 *  appSetup(argc, argv);
 *
 *    Perform all the setup for this application include setting up
 *    required modules, parsing options, etc.  This function should be
 *    passed the same arguments that were passed into main().
 *
 *    Returns to the caller if all setup succeeds.  If anything fails,
 *    this function will cause the application to exit with a FAILURE
 *    exit status.
 */
static void appSetup(int argc, char **argv)
{
    SILK_FEATURES_DEFINE_STRUCT(features);
    int arg_index;
    int rv;

    /* verify same number of options and help strings */
    assert((sizeof(appHelp)/sizeof(char *)) ==
           (sizeof(appOptions)/sizeof(struct option)));

    /* register the application */
    skAppRegister(argv[0]);
    skAppVerifyFeatures(&features, NULL);
    skOptionsSetUsageCallback(&appUsageLong);

    /* initialize globals */
    memset(&output, 0, sizeof(output));
    output.of_fp = stdout;

    /* register the options */
    if (skOptionsRegister(appOptions, &appOptionsHandler, NULL)
        || sksiteOptionsRegister(SK_SITE_FLAG_CONFIG_FILE))
    {
        skAppPrintErr("Unable to register options");
        exit(EXIT_FAILURE);
    }

    /* register the teardown handler */
    if (atexit(appTeardown) < 0) {
        skAppPrintErr("Unable to register appTeardown() with atexit()");
        appTeardown();
        exit(EXIT_FAILURE);
    }

    /* parse the options */
    arg_index = skOptionsParse(argc, argv);
    if (arg_index < 0) {
        skAppUsage();           /* never returns */
    }

    /* try to load site config file; if it fails, we will not be able
     * to resolve flowtype and sensor from input file names */
    if (sksiteConfigure(1)) {
        exit(EXIT_FAILURE);
    }

    /* parse fields */
    if (rws_parse_fields()) {
        exit(EXIT_FAILURE);
    }

    /* parse restrictions (--classes, --types, etc) */
    if (rws_parse_restrictions()) {
        exit(EXIT_FAILURE);
    }

    /* check for extraneous arguments */
    if (arg_index != argc) {
        skAppPrintErr("Too many arguments or unrecognized switch '%s'",
                      argv[arg_index]);
        skAppUsage();           /* never returns */
    }

    /* Initialize column widths */
    if (no_titles || no_columns) {
        memset(col_width, 0, sizeof(col_width));
    } else {
        size_t i;
        for (i = 0; i < RWST_MAX_FIELD_COUNT; i++) {
            col_width[i] = strlen((char *)field_map_entries[i].userdata);

            /* While looping through, verify that the
             * field_map_entries is in the same order as the
             * enumeration. */
            assert(i == field_map_entries[i].id);
        }
    }

    /* Set the final delimiter, if used */
    if (!no_final_delimiter) {
        final_delim[0] = column_separator;
    }

    rv = skFileptrOpenPager(&output, pager);
    if (rv && rv != SK_FILEPTR_PAGER_IGNORED) {
        skAppPrintErr("Unable to invoke pager");
    }

    return;  /* OK */
}


/*
 *  status = appOptionsHandler(cData, opt_index, opt_arg);
 *
 *    This function is passed to skOptionsRegister(); it will be called
 *    by skOptionsParse() for each user-specified switch that the
 *    application has registered; it should handle the switch as
 *    required---typically by setting global variables---and return 1
 *    if the switch processing failed or 0 if it succeeded.  Returning
 *    a non-zero from from the handler causes skOptionsParse() to return
 *    a negative value.
 *
 *    The clientData in 'cData' is typically ignored; 'opt_index' is
 *    the index number that was specified as the last value for each
 *    struct option in appOptions[]; 'opt_arg' is the user's argument
 *    to the switch for options that have a REQUIRED_ARG or an
 *    OPTIONAL_ARG.
 */
static int appOptionsHandler(
    clientData  UNUSED(cData),
    int         opt_index,
    char       *opt_arg)
{
    switch ((appOptionsEnum)opt_index) {
      case OPT_DATA_ROOTDIR:
        if (!skDirExists(opt_arg)) {
            skAppPrintErr("Root data directory '%s' does not exist", opt_arg);
            return -1;
        }
        if (sksiteSetRootDir(opt_arg)) {
            skAppPrintErr("Unable to set root data directory to %s", opt_arg);
            return -1;
        }
        break;

      case OPT_CLASSES:
        if (classes_arg != NULL) {
            skAppPrintErr("Invalid %s: Switch specified multiple times",
                          appOptions[opt_index].name);
            return -1;
        }
        classes_arg = opt_arg;
        break;

      case OPT_TYPES:
        if (types_arg != NULL) {
            skAppPrintErr("Invalid %s: Switch specified multiple times",
                          appOptions[opt_index].name);
            return -1;
        }
        types_arg = opt_arg;
        break;

      case OPT_FLOWTYPES:
        if (flowtypes_arg != NULL) {
            skAppPrintErr("Invalid %s: Switch specified multiple times",
                          appOptions[opt_index].name);
            return -1;
        }
        flowtypes_arg = opt_arg;
        break;

      case OPT_SENSORS:
        if (sensors_arg != NULL) {
            skAppPrintErr("Invalid %s: Switch specified multiple times",
                          appOptions[opt_index].name);
            return -1;
        }
        sensors_arg = opt_arg;
        break;

      case OPT_FIELDS:
        if (fields_arg != NULL) {
            skAppPrintErr("Invalid %s: Switch specified multiple times",
                          appOptions[opt_index].name);
            return -1;
        }
        fields_arg = opt_arg;
        break;

      case OPT_NO_TITLES:
        no_titles = 1;
        break;

      case OPT_NO_COLUMNS:
        no_columns = 1;
        break;

      case OPT_COLUMN_SEPARATOR:
        column_separator = opt_arg[0];
        break;

      case OPT_NO_FINAL_DELIMITER:
        no_final_delimiter = 1;
        break;

      case OPT_DELIMITED:
        no_columns = 1;
        no_final_delimiter = 1;
        if (opt_arg) {
            column_separator = opt_arg[0];
        }
        break;

      case OPT_LIST_DELIMETER:
        list_separator = opt_arg[0];
        break;

      case OPT_PAGER:
        pager = opt_arg;
        break;
    }

    return 0;  /* OK */
}


/*
 *  stringmap = createStringmap();
 *
 *    Create the string map that is used to parse the --fields
 *    paramater.
 */
static sk_stringmap_t *createStringmap(void)
{
    sk_stringmap_t *field_map;

    /* Create the map */
    if (SKSTRINGMAP_OK != skStringMapCreate(&field_map)) {
        return NULL;
    }

    /* add entries */
    if (skStringMapAddEntries(field_map, -1, field_map_entries)
        != SKSTRINGMAP_OK)
    {
        skStringMapDestroy(field_map);
        return NULL;
    }

    return field_map;
}


/*
 *  status = rws_parse_fields();
 *
 *     Parse the --fields argument.  Return 0 on success, -1 on
 *     failure.
 */
static int rws_parse_fields(void)
{
    sk_stringmap_t *field_map = NULL;
    sk_stringmap_iter_t *iter = NULL;
    sk_stringmap_entry_t *entry;
    char *errmsg;
    int rv = -1;

    if (fields_arg == NULL) {
        skAppPrintErr("The --%s switch is required",
                      appOptions[OPT_FIELDS].name);
        return rv;
    }
    field_map = createStringmap();
    if (NULL == field_map) {
        skAppPrintOutOfMemory(NULL);
        goto END;
    }

    /* parse the field-list */
    if (skStringMapParse(field_map, fields_arg, SKSTRINGMAP_DUPES_ERROR,
                         &iter, &errmsg))
    {
        skAppPrintErr("Invalid %s: %s",
                      appOptions[OPT_FIELDS].name, errmsg);
        goto END;
    }

    /* add the selected fields to the 'fields[]' array */
    while (skStringMapIterNext(iter, &entry, NULL) == SK_ITERATOR_OK) {
        assert(num_fields < RWST_MAX_FIELD_COUNT);
        fields[num_fields] = (rws_field_t)entry->id;
         ++num_fields;
    }

    rv = 0;

  END:
    if (iter != NULL) {
        skStringMapIterDestroy(iter);
    }
    if (field_map != NULL) {
        skStringMapDestroy(field_map);
    }
    return rv;
}


/*
 *  status = rws_parse_sensors(sn_bitmap);
 *
 *      Parse the --sensors argument from the global 'sensors_arg'.
 *      Set a bit in 'sn_bitmap' for each sensor we see.  Return 0 on
 *      success, or -1 if any invalid sensors are found.
 */
static int rws_parse_sensors(
    sk_bitmap_t    *sn_bitmap)
{
    char *user_arg = NULL;
    char *user_arg_freeable = NULL;
    char *sensor_token = NULL;
    uint32_t min_sensor_id;
    uint32_t max_sensor_id;
    uint32_t val_min, val_max;
    sensorID_t sid = SK_INVALID_SENSOR;
    int p_err;
    int rv = 0;

    /* nothing to do when no --sensors switch is given */
    if (NULL == sensors_arg) {
        return 0;
    }

    assert(sn_bitmap);
    assert(skBitmapGetSize(sn_bitamp) > sksiteSensorGetMaxID());

    min_sensor_id = sksiteSensorGetMinID();
    max_sensor_id = sksiteSensorGetMaxID();

    /* create a copy of the input string and maintain a reference to
     * it so we can free it */
    user_arg = strdup(sensors_arg);
    user_arg_freeable = user_arg;
    if (user_arg == NULL) {
        skAppPrintOutOfMemory(NULL);
        rv = -1;
        goto END;
    }

    /* parse the sensors as a comma separated list of tokens */
    while ((sensor_token = strsep(&user_arg, ",")) != NULL) {
        /* check for empty token (e.g., double comma) */
        if ('\0' == *sensor_token) {
            continue;
        }

        /* look up sensor_token as a sensor name */
        sid = sksiteSensorLookup(sensor_token);
        if (SK_INVALID_SENSOR != sid) {
            /* found it. add it to our lists and continue */
            skBitmapSetBit(sn_bitmap, sid);
            continue;
        }

        /* parsing failed. does the token look like a number? */
        if (!isdigit((int)(*sensor_token))) {
            /* not a number: error */
            skAppPrintErr("Invalid %s '%s': Unknown sensor name",
                          appOptions[OPT_SENSORS].name, sensor_token);
            rv = -1;
            continue;
        }

        /* it is a digit: parse the token as a single number or a
         * range */
        p_err = skStringParseRange32(&val_min, &val_max, sensor_token,
                                     min_sensor_id, max_sensor_id,
                                     SKUTILS_RANGE_NO_OPEN);
        if (p_err != 0) {
            /* an error */
            skAppPrintErr("Invalid %s '%s': %s",
                          appOptions[OPT_SENSORS].name, sensor_token,
                          skStringParseStrerror(p_err));
            rv = -1;
            continue;
        }

        /* verify that start of range is valid */
        sid = (sensorID_t)val_min;
        if (!sksiteSensorExists(sid)) {
            skAppPrintErr(("Invalid %s: Value %" PRIu32
                           " is not a valid sensor id"),
                          appOptions[OPT_SENSORS].name, val_min);
            rv = -1;
            continue;
        }

        /* verify that end of range is valid */
        if (val_min != val_max && !sksiteSensorExists((sensorID_t)val_max)) {
            skAppPrintErr(("Invalid %s: Value %" PRIu32
                           " is not a valid sensor id"),
                          appOptions[OPT_SENSORS].name, val_max);
            rv = -1;
            continue;
        }

        /* add all sensor IDs in range */
        skBitmapRangeSet(sn_bitmap, sid, val_max);
    }

    /* did we find any sensors? */
    if ((0 == rv) && (0 == skBitmapGetHighCount(sn_bitmap))) {
        skAppPrintErr("Invalid %s: No valid sensors",
                      appOptions[OPT_SENSORS].name);
        rv = -1;
    }

  END:
    if (user_arg_freeable) {
        free(user_arg_freeable);
    }
    return rv;
}


/*
 *  status = rws_parse_flowtypes(cl_bitmap, ft_bitmap);
 *
 *    Parse the --flowtypes argument from the global 'flowtypes_arg'.
 *    Set a bit on 'cl_bitmap' for each valid class and and a bit on
 *    'ft_bitmap' for each valid flowtype.  Return 0 on success, or -1
 *    on if any class/type value is not a valid pair.
 */
static int rws_parse_flowtypes(
    sk_bitmap_t    *cl_bitmap,
    sk_bitmap_t    *ft_bitmap)
{
    char *user_arg = NULL;
    char *user_arg_freeable = NULL;
    char *class_name;
    char *type_name;
    flowtype_iter_t ft_iter;
    flowtypeID_t ft;
    classID_t class_id;
    int rv = 0;

    /* nothing to do when no --flowtypes switch is given */
    if (NULL == flowtypes_arg) {
        return 0;
    }

    /* create a modifiable version of the user's input. store a
     * pointer to it we can free it */
    user_arg = strdup(flowtypes_arg);
    user_arg_freeable = user_arg;
    if (NULL == user_arg) {
        skAppPrintOutOfMemory(NULL);
        rv = -1;
        goto END;
    }

    /* parse user's string as a comma separated list */
    while ((class_name = strsep(&user_arg, ",")) != NULL) {
        if (class_name[0] == '\0') {
            /* empty token (e.g., double comma) */
            continue;
        }

        /* break token into class and type separated by '/' */
        type_name = strchr(class_name, '/');
        if (type_name == NULL) {
            skAppPrintErr("Invalid %s: Missing '/' in token '%s'",
                          appOptions[OPT_FLOWTYPES].name, class_name);
            rv = -1;
            continue;
        }
        *type_name = '\0';
        ++type_name;

        /* find class and type.  if lookup fails, test for special
         * "all" keyword */
        ft = sksiteFlowtypeLookupByClassType(class_name, type_name);
        if (SK_INVALID_FLOWTYPE != ft) {
            /* Yay!  Class and type are specific */
            skBitmapSetBit(ft_bitmap, ft);
            skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));

        } else if (0 == strcmp(class_name, "all")) {
            if (0 == strcmp(type_name, "all")) {
                /* Use all classes and all types. */
                sksiteFlowtypeIterator(&ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
                    skBitmapSetBit(ft_bitmap, ft);
                    skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));
                }
            } else {
                /* Loop over all classes and add flowtype if type_name
                 * is valid for that class.  Don't complain unless the
                 * type is not valid for any class. */
                class_iter_t ci;
                int found_type = 0;

                sksiteClassIterator(&ci);
                while (sksiteClassIteratorNext(&ci, &class_id)) {
                    ft = sksiteFlowtypeLookupByClassIDType(class_id,type_name);
                    if (SK_INVALID_FLOWTYPE != ft) {
                        ++found_type;
                        skBitmapSetBit(ft_bitmap, ft);
                        skBitmapSetBit(cl_bitmap, class_id);
                    }
                }
                if (!found_type) {
                    skAppPrintErr(("Invalid %s:"
                                   " Type '%s' not valid for any class"),
                                  appOptions[OPT_FLOWTYPES].name, type_name);
                    rv = -1;
                }
            }

        } else if (0 == strcmp(type_name, "all")) {
            /* Use all types in the specified class */
            class_id = sksiteClassLookup(class_name);
            if (SK_INVALID_CLASS == class_id) {
                skAppPrintErr("Invalid %s: Invalid class '%s'",
                              appOptions[OPT_FLOWTYPES].name, class_name);
                rv = -1;
            } else {
                skBitmapSetBit(cl_bitmap, class_id);
                sksiteClassFlowtypeIterator(class_id, &ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
                    skBitmapSetBit(ft_bitmap, ft);
                }
            }

        } else {
            /* Invalid class/type */
            skAppPrintErr("Invalid %s: Unknown class/type pair '%s/%s'",
                          appOptions[OPT_FLOWTYPES].name,
                          class_name, type_name);
            rv = -1;
        }
    }

    if ((rv == 0) && (skBitmapGetHighCount(ft_bitmap) == 0)) {
        skAppPrintErr("Invalid %s: No valid class/type pairs",
                      appOptions[OPT_FLOWTYPES].name);
        rv = -1;
    }

  END:
    if (user_arg_freeable) {
        free(user_arg_freeable);
    }
    return rv;
}


/*
 *  status = rws_parse_classes_and_types();
 *
 *    Parse the --classes and/or --types arguments from the globals
 *    'classes_arg' and 'types_arg'.  Set a bit on 'cl_bitmap' for
 *    each valid class and and a bit on 'ft_bitmap' for each valid
 *    flowtype.  Return 0 on success, or -1 on if any class/type value
 *    is not a valid pair.
 */
static int rws_parse_classes_and_types(
    sk_bitmap_t    *cl_bitmap,
    sk_bitmap_t    *ft_bitmap)
{
    sk_bitmap_iter_t bmap_iter;
    uint32_t bmap_val;
    class_iter_t ci;
    flowtype_iter_t ft_iter;
    char *user_arg = NULL;
    char *user_arg_freeable = NULL;
    char *class_token = NULL;
    char *type_token = NULL;
    classID_t class_id;
    flowtypeID_t ft;
    int found_type;
    int rv = 0;

    if (NULL == classes_arg) {
        /* temporarily enable all classes */
        sksiteClassIterator(&ci);
        while (sksiteClassIteratorNext(&ci, &class_id)) {
            skBitmapSetBit(cl_bitmap, class_id);
        }

    } else {
        /* create a copy of the input string and maintain a reference to
         * it so we can free it */
        user_arg = strdup(classes_arg);
        user_arg_freeable = user_arg;
        if (user_arg == NULL) {
            skAppPrintOutOfMemory(NULL);
            rv = -1;
            goto END;
        }

        /* parse the classes as a comma separated list of tokens */
        while ((class_token = strsep(&user_arg, ",")) != NULL) {
            /* check for empty token (e.g., double comma) */
            if ('\0' == *class_token) {
                continue;
            }

            /* Handle default class token */
            if (strcmp(class_token, "@") == 0) {
                skBitmapSetBit(cl_bitmap, sksiteClassGetDefault());
                continue;
            }

            /* look up class_token as a class name */
            class_id = sksiteClassLookup(class_token);
            if (SK_INVALID_CLASS != class_id) {
                /* found it. add it to our lists and continue */
                skBitmapSetBit(cl_bitmap, class_id);
                continue;
            }

            skAppPrintErr("Invalid %s '%s': Unknown class name",
                          appOptions[OPT_CLASSES].name, class_token);
            rv = -1;
            continue;
        }

        free(user_arg_freeable);
        user_arg_freeable = NULL;

        /* did we find any classes? */
        if ((0 == rv) && (0 == skBitmapGetHighCount(cl_bitmap))) {
            skAppPrintErr("Invalid %s: No valid classes",
                          appOptions[OPT_CLASSES].name);
            rv = -1;
        }

        if (NULL == types_arg) {
            if (rv != 0) {
                goto END;
            }
            /* there is no --types; enable all flowtypes that exist in
             * the specified class(es) */
            skBitmapIteratorBind(cl_bitmap, &bmap_iter);
            while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK)
            {
                class_id = (classID_t)bmap_val;
                sksiteClassFlowtypeIterator(class_id, &ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
                    skBitmapSetBit(ft_bitmap, ft);
                }
            }
            goto END;
        }
    }

    /* create a modifiable version of the user's input. store a
     * pointer to it we can free */
    user_arg = strdup(types_arg);
    user_arg_freeable = user_arg;
    if (NULL == user_arg) {
        skAppPrintOutOfMemory(NULL);
        rv = -1;
        goto END;
    }

    /* parse user's string as a comma separated list */
    while ((type_token = strsep(&user_arg, ",")) != NULL) {
        found_type = 0;
        if (type_token[0] == '\0') {
            /* empty token (e.g., double comma) */
            continue;
        }

        /* check for the type in all the classes we found above */
        skBitmapIteratorBind(cl_bitmap, &bmap_iter);
        while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
            class_id = (classID_t)bmap_val;

            /* find class and type */
            ft = sksiteFlowtypeLookupByClassIDType(class_id, type_token);
            if (SK_INVALID_FLOWTYPE != ft) {
                /* Yay!  Class and type are specific */
                skBitmapSetBit(ft_bitmap, ft);
                ++found_type;

            } else if (0 == strcmp(type_token, "all")) {
                /* Use all types in the specified class */
                sksiteClassFlowtypeIterator(class_id, &ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
                    ++found_type;
                    skBitmapSetBit(ft_bitmap, ft);
                }

            } else if (0 == strcmp(type_token, "@")) {
                sksiteClassDefaultFlowtypeIterator(class_id, &ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &ft)) {
                    ++found_type;
                    skBitmapSetBit(ft_bitmap, ft);
                }
            }
        }

        if (!found_type) {
            skAppPrintErr("Invalid %s: Type '%s' not valid for %s",
                          appOptions[OPT_TYPES].name, type_token,
                          (classes_arg ? "specified classes" : "any class"));
            rv = -1;
        }
    }

    if ((rv == 0) && (skBitmapGetHighCount(ft_bitmap) == 0)) {
        skAppPrintErr("Invalid --%s: No valid types",
                      appOptions[OPT_TYPES].name);
        rv = -1;
    }

    if ((rv == 0) && (NULL == classes_arg)) {
        /* no --classes were specified.  reset the cl_bitmap based on
         * the flowtypes we found */
        skBitmapClearAllBits(cl_bitmap);

        skBitmapIteratorBind(ft_bitmap, &bmap_iter);
        while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
            ft = (flowtypeID_t)bmap_val;
            skBitmapSetBit(cl_bitmap, sksiteFlowtypeGetClassID(ft));
        }
    }

  END:
    if (user_arg_freeable) {
        free(user_arg_freeable);
    }
    return rv;
}


/*
 *  status = rws_parse_restrictions();
 *
 *    Parse the --classes, --types, --flowtypes, and --sensors options
 *    and create/fill bitmaps that restrict the output.
 *
 *    Returns 0 on success, -1 on error.
 */
static int rws_parse_restrictions(void)
{
    sk_bitmap_iter_t bmap_iter;
    uint32_t bmap_val;
    sk_bitmap_t *cl_mask = NULL;
    sk_bitmap_t *ft_mask = NULL;
    sk_bitmap_t *sn_mask = NULL;
    class_iter_t class_iter;
    flowtype_iter_t ft_iter;
    sensor_iter_t sensor_iter;
    classID_t class_id;
    sensorID_t sensor_id;
    flowtypeID_t flowtype_id;
    int sensors_only = 0;
    int rv = 0;

    if (!classes_arg && !types_arg && !flowtypes_arg) {
        if (!sensors_arg) {
            /* nothing to do */
            return 0;
        }
        /* else, only need to process --sensors */
        sensors_only = 1;
    }

    /* create the global bitmaps for all classes, all flowtypes, and
     * all sensors */
    if (skBitmapCreate(&class_mask, 1 + sksiteClassGetMaxID())) {
        skAppPrintOutOfMemory("class bitmap");
        return -1;
    }
    if (skBitmapCreate(&flowtype_mask, 1 + sksiteFlowtypeGetMaxID())) {
        skAppPrintOutOfMemory("flowtype bitmap");
        return -1;
    }
    if (skBitmapCreate(&sensor_mask, 1 + sksiteSensorGetMaxID())) {
        skAppPrintOutOfMemory("sensor bitmap");
        return -1;
    }

    if (!sensors_only && sensors_arg) {
        /* need to create temporary bitmaps */
        if (skBitmapCreate(&cl_mask, 1 + sksiteClassGetMaxID())) {
            skAppPrintOutOfMemory("class bitmap");
            rv = -1;
            goto END;
        }
        if (skBitmapCreate(&ft_mask, 1 + sksiteFlowtypeGetMaxID())) {
            skAppPrintOutOfMemory("flowtype bitmap");
            rv = -1;
            goto END;
        }
        if (skBitmapCreate(&sn_mask, 1 + sksiteSensorGetMaxID())) {
            skAppPrintOutOfMemory("sensor bitmap");
            rv = -1;
            goto END;
        }
    } else {
        /* else we can point the temporaries at the real thing */
        cl_mask = class_mask;
        ft_mask = flowtype_mask;
        sn_mask = sensor_mask;
    }

    if (sensors_arg) {
        rv = rws_parse_sensors(sensor_mask);

        if (sensors_only && rv != 0) {
            goto END;
        }

        /* set class_mask and flowtype_mask based on the sensors we saw */
        skBitmapIteratorBind(sensor_mask, &bmap_iter);
        while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
            sensor_id = (sensorID_t)bmap_val;
            sksiteSensorClassIterator(sensor_id, &class_iter);
            while (sksiteClassIteratorNext(&class_iter, &class_id)) {
                skBitmapSetBit(cl_mask, class_id);
                sksiteClassFlowtypeIterator(class_id, &ft_iter);
                while (sksiteFlowtypeIteratorNext(&ft_iter, &flowtype_id)) {
                    skBitmapSetBit(ft_mask, flowtype_id);
                }
            }
        }

        if (sensors_only) {
            return 0;
        }
    }

    /* handle case when --flowtypes is given */
    if (flowtypes_arg) {
        if (classes_arg || types_arg) {
            skAppPrintErr(("Cannot use --%s when either --%s or --%s is"
                           " specified"),
                          appOptions[OPT_FLOWTYPES].name,
                          appOptions[OPT_CLASSES].name,
                          appOptions[OPT_TYPES].name);
            goto END;
        }
        rv |= rws_parse_flowtypes(class_mask, flowtype_mask);
        if (rv != 0) {
            goto END;
        }
    } else {
        assert(classes_arg || types_arg);
        rv |= rws_parse_classes_and_types(class_mask, flowtype_mask);
        if (rv != 0) {
            goto END;
        }
    }

    /* set sensor_mask based on the classes we saw */
    skBitmapIteratorBind(class_mask, &bmap_iter);
    while (skBitmapIteratorNext(&bmap_iter, &bmap_val)==SK_ITERATOR_OK) {
        class_id = (classID_t)bmap_val;
        sksiteClassSensorIterator(class_id, &sensor_iter);
        while (sksiteSensorIteratorNext(&sensor_iter, &sensor_id)) {
            skBitmapSetBit(sn_mask, sensor_id);
        }
    }

    /* perform the intersection of the masks with the temporaries */
    if (sn_mask && sn_mask != sensor_mask) {
        skBitmapIntersection(sensor_mask, sn_mask);
        skBitmapDestroy(&sn_mask);
    }
    if (cl_mask && cl_mask != class_mask) {
        skBitmapIntersection(class_mask, cl_mask);
        skBitmapDestroy(&cl_mask);
    }
    if (ft_mask && ft_mask != flowtype_mask) {
        skBitmapIntersection(flowtype_mask, ft_mask);
        skBitmapDestroy(&ft_mask);
    }

  END:
    if (sn_mask && sn_mask != sensor_mask) {
        skBitmapDestroy(&sn_mask);
    }
    if (cl_mask && cl_mask != class_mask) {
        skBitmapDestroy(&cl_mask);
    }
    if (ft_mask && ft_mask != flowtype_mask) {
        skBitmapDestroy(&ft_mask);
    }
    return rv;
}


/*
 *  rws_iter_bind(&iter, level);
 *
 *    Bind the sub-iterator of a site iterator at the given level.
 */
static void rws_iter_bind(
    rws_iter_t *iter,
    int         level)
{
    assert(iter);
    assert(iter->level >= level);

    /* Negative level is for a non-iterable iterator.  This is used
     * for options that require no iteration, like
     * --fields=class-default. */
    if (level >= 0) {
        switch (iter->order[level]) {
          case RWS_FLOWTYPE:
            sksiteFlowtypeIterator(&iter->flowtype_iter);
            break;
          case RWS_CLASS:
            sksiteClassIterator(&iter->class_iter);
            break;
          case RWS_SENSOR:
            sksiteSensorIterator(&iter->sensor_iter);
            break;
          case RWS_FLOWTYPE_FROM_CLASS:
            sksiteClassFlowtypeIterator(iter->class_id, &iter->flowtype_iter);
            break;
          case RWS_CLASS_FROM_SENSOR:
            sksiteSensorClassIterator(iter->sensor_id, &iter->class_iter);
            break;
          case RWS_SENSOR_FROM_CLASS:
            sksiteClassSensorIterator(iter->class_id, &iter->sensor_iter);
            break;
          case RWS_DEFAULT_FLOWTYPE_FROM_CLASS:
            sksiteClassDefaultFlowtypeIterator(
                iter->class_id, &iter->flowtype_iter);
            iter->default_type = 1;
            break;
          case RWS_NULL:
            skAbortBadCase(iter->order[level]);
            break;
        }
    }

    /* We are now bound at this level */
    iter->bound = level;

    /* But mark as not having stared iteration yet */
    iter->started = level - 1;
}


/*
 *  status = rws_iter_next(iter, level);
 *
 *    Site iterator iteration, at a particular sub-iterator level.
 *    Returns 1 on success, 0 if the iteration is complete at the
 *    given level.
 */
static int rws_iter_next(
    rws_iter_t *iter,
    int         level)
{
    int rv;

    assert(iter);
    assert(iter->level >= level);

    /* Prevent re-iteration after already having completed
     * iteration */
    if (iter->bound < level) {
        assert(level == 0);
        return 0;
    }

    do {
        /* Iterate at the next level if we've already started
         * iteration on this level */
        if (iter->started >= level && level < iter->level) {
            if (iter->bound == level) {
                rws_iter_bind(iter, level + 1);
            }
            rv = rws_iter_next(iter, level + 1);
            if (rv != 0) {
                /* Leaf iter succeeded */
                return 1;
            }
        }

        /* Iterate at the current level */
        switch (iter->order[level]) {
          case RWS_FLOWTYPE:
          case RWS_FLOWTYPE_FROM_CLASS:
          case RWS_DEFAULT_FLOWTYPE_FROM_CLASS:
            /* Flowtype iteration */
            while ((rv = sksiteFlowtypeIteratorNext(&iter->flowtype_iter,
                                                    &iter->flowtype_id))
                   && flowtype_mask != NULL
                   && !skBitmapGetBit(flowtype_mask, iter->flowtype_id))
                ; /* empty */
            /* Set class from flowtype */
            if (rv) {
                iter->class_id = sksiteFlowtypeGetClassID(iter->flowtype_id);
            }
            break;

          case RWS_CLASS:
          case RWS_CLASS_FROM_SENSOR:
            /* Class iteration */
            while ((rv = sksiteClassIteratorNext(&iter->class_iter,
                                                 &iter->class_id))
                   && class_mask != NULL
                   && !skBitmapGetBit(class_mask, iter->class_id))
                ; /* empty */
            break;

          case RWS_SENSOR:
          case RWS_SENSOR_FROM_CLASS:
            /* Sensor iteration */
            while ((rv = sksiteSensorIteratorNext(&iter->sensor_iter,
                                                  &iter->sensor_id))
                   && sensor_mask != NULL
                   && !skBitmapGetBit(sensor_mask, iter->sensor_id))
                ; /* empty */
            break;

          default:
            skAbortBadCase(iter->order[level]);
        }

        /* Mark that we've started iterating at the current level */
        if (iter->started < level) {
            iter->started = level;
        }

        if (rv && level == iter->level) {
            /* return success at leaf */
            return 1;
        }

        /* Iterate until a leaf iteration succeeds, or we fail to
         * iterate at this level. */
    } while (rv);

    /* Iteration is over.  We are no longer bound at this level.  */
    iter->bound = level - 1;

    return 0;
}


/*
 *  len = rws_print_field(printer, fd, iter, field, width);
 *
 *    Print a 'width'-wide column containing the value for 'field'
 *    using the fprintf-style function 'printer' to the FILE pointer
 *    'fd', where 'iter' is the current context.
 *
 *    Return the number of characters printed.
 */
static int rws_print_field(
    rws_fprintf_t  printer,
    FILE          *fd,
    rws_iter_t    *iter,
    rws_field_t    field,
    int            width)
{
    /* buffer large enough to hold a single sensor name or flowtype
     * name */
    char buf[SK_MAX_STRLEN_SENSOR + SK_MAX_STRLEN_FLOWTYPE];
    const char *s;
    int rv = 0;

    switch (field) {
      case RWST_CLASS:
        if (iter->class_id != SK_INVALID_CLASS) {
            sksiteClassGetName(buf, sizeof(buf), iter->class_id);
            rv = printer(fd, "%*s", width, buf);
        }
        break;

      case RWST_DEFAULT_TYPE:
        if (!iter->default_type) {
            /* When there's no default_type iterator, we can't do a
             * default_type */
            break;
        }
        /* Fall through */
      case RWST_TYPE:
        if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
            sksiteFlowtypeGetType(buf, sizeof(buf), iter->flowtype_id);
            rv = printer(fd, "%*s", width, buf);
        }
        break;

      case RWST_FLOWTYPE:
        if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
            sksiteFlowtypeGetName(buf, sizeof(buf), iter->flowtype_id);
            rv = printer(fd, "%*s", width, buf);
        }
        break;

      case RWST_FLOWTYPE_ID:
        if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
            rv = printer(fd, "%*" PRIu8, width, iter->flowtype_id);
        }
        break;

      case RWST_SENSOR:
        if (iter->sensor_id != SK_INVALID_SENSOR) {
            sksiteSensorGetName(buf, sizeof(buf), iter->sensor_id);
            rv = printer(fd, "%*s", width, buf);
        }
        break;

      case RWST_SENSOR_ID:
        if (iter->sensor_id != SK_INVALID_SENSOR) {
            rv = printer(fd, "%*" PRIu16, width, iter->sensor_id);
        }
        break;

      case RWST_SENSOR_DESC:
        if (iter->sensor_id != SK_INVALID_SENSOR) {
            s = sksiteSensorGetDescription(iter->sensor_id);
            if (s != NULL) {
                rv = printer(fd, "%*s", width, s);
            }
        }
        break;

      case RWST_DEFAULT_CLASS:
      case RWST_DEFAULT_CLASS_LIST:
        {
            classID_t cid = sksiteClassGetDefault();
            if (cid != SK_INVALID_CLASS) {
                sksiteClassGetName(buf, sizeof(buf), cid);
                rv = printer(fd, "%*s", width, buf);
            }
        }
        break;

      case RWST_MARK_DEFAULTS:
        {
            char mark[3] = {' ', ' ', '\0'};
            int i = 0;
            if (iter->class_id != SK_INVALID_CLASS) {
                if (no_columns) {
                    memset(mark, 0, sizeof(mark));
                }
                if (iter->class_id == sksiteClassGetDefault())
                {
                    mark[0] = '+';
                    ++i;
                }
                if (iter->flowtype_id != SK_INVALID_FLOWTYPE) {
                    flowtype_iter_t fi;
                    flowtypeID_t ft;

                    /* See if this type is a default for this class */
                    sksiteClassDefaultFlowtypeIterator(iter->class_id, &fi);
                    while (sksiteFlowtypeIteratorNext(&fi, &ft)) {
                        if (iter->flowtype_id == ft) {
                            mark[no_columns ? i : 1] = '*';
                            ++i;
                            break;
                        }
                    }
                }
            }
            rv = printer(fd, "%*s", width, mark);
        }
        break;

      case RWST_CLASS_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_CLASS, width);
        break;
      case RWST_TYPE_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_TYPE, width);
        break;
      case RWST_FLOWTYPE_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_FLOWTYPE, width);
        break;
      case RWST_FLOWTYPE_ID_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_FLOWTYPE_ID, width);
        break;
      case RWST_SENSOR_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_SENSOR, width);
        break;
      case RWST_SENSOR_ID_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_SENSOR_ID, width);
        break;
      case RWST_DEFAULT_TYPE_LIST:
        rv = rws_print_list_field(printer, fd, iter, RWST_DEFAULT_TYPE, width);
        break;

      case RWST_MAX_FIELD_COUNT:
        skAbortBadCase(field);
    }

    /* Fill in any missing spaces. */
    if (rv < width) {
        printer(fd, "%*s", width - rv, "");
    }

    return rv;
}


/*
 *  len = rws_print_list_field(printer, fd, iter, field, width);
 *
 *    Print a 'width'-wide column containing the value for 'field'
 *    (where 'field' represents a "FIELD:list" field) using the
 *    fprintf-style function 'printer' to the FILE pointer 'fd', where
 *    'iter' is the current context.
 *
 *    Return the number of characters printed.
 */
static int rws_print_list_field(
    rws_fprintf_t  printer,
    FILE          *fd,
    rws_iter_t    *iter,
    rws_field_t    field,
    int            width)
{
    int total = 0;
    int len;
    rws_iter_t subiter;
    int first;

    /* Create a site iterator containing a single sub-iterator of the
     * correct type.  */
    memset(&subiter, 0, sizeof(subiter));
    switch (field) {
      case RWST_CLASS:
        if (iter->sensor_id == SK_INVALID_SENSOR) {
            subiter.order[0] = RWS_CLASS;
        } else {
            subiter.order[0] = RWS_CLASS_FROM_SENSOR;
        }
        subiter.sensor_id = iter->sensor_id;
        break;
      case RWST_TYPE:
      case RWST_FLOWTYPE:
      case RWST_FLOWTYPE_ID:
        if (iter->class_id == SK_INVALID_CLASS) {
            subiter.order[0] = RWS_FLOWTYPE;
        } else {
            subiter.order[0] = RWS_FLOWTYPE_FROM_CLASS;
        }
        subiter.class_id = iter->class_id;
        subiter.flowtype_id = iter->flowtype_id;
        break;
      case RWST_SENSOR:
      case RWST_SENSOR_ID:
        if (iter->class_id == SK_INVALID_CLASS) {
            subiter.order[0] = RWS_SENSOR;
        } else {
            subiter.order[0] = RWS_SENSOR_FROM_CLASS;
        }
        subiter.class_id = iter->class_id;
        break;
      case RWST_DEFAULT_TYPE:
        if (iter->class_id == SK_INVALID_CLASS) {
            return 0;
        }
        subiter.order[0] = RWS_DEFAULT_FLOWTYPE_FROM_CLASS;
        subiter.class_id = iter->class_id;
        break;
      default:
        skAbortBadCase(field);
    }
    rws_iter_bind(&subiter, 0);

    /* Call ourself with the fake-fprintf to determine the number of
     * printed characters in this field, and then print the padding */
    if (width != 0) {
        len = rws_print_list_field(fprintf_size, NULL, iter, field, 0);
        if (len < width) {
            total += printer(fd, "%*s", width - len, "");
        }
    }

    /* Iterate over the fields, printing each */
    first = 1;
    while (rws_iter_next(&subiter, 0)) {
        if (!first) {
            len = printer(fd, "%c", list_separator);
            total += len;
        }
        len = rws_print_field(printer, fd, &subiter, field, 0);
        total += len;
        first = 0;
    }

    return total;
}


/*
 *  rws_print_row(iter);
 *
 *    Print a single row from an iterator.
 */
static void rws_print_row(
    rws_iter_t *iter)
{
    size_t i;

    for (i = 0; i < num_fields; ++i) {
        if (i > 0) {
            fprintf(output.of_fp, "%c", column_separator);
        }
        rws_print_field(fprintf, output.of_fp, iter,
                        fields[i], col_width[fields[i]]);
    }
    fprintf(output.of_fp, "%s\n", final_delim);
}


/*
 *  len = fprintf_size(fs, format, ...);
 *
 *    Used to calculate print sizes.  This fprintf() variation does
 *    not produce outout, it simply returns how many charcters it
 *    WOULD have printed.
 */
static int fprintf_size(
    FILE    UNUSED(*stream),
    const char     *format,
    ...)
{
    char buf;
    int len;
    va_list ap;
    va_start(ap, format);
    len = vsnprintf(&buf, 0, format, ap);
    va_end(ap);
    return len;
}


/*
 *  rws_calcsize_row(iter);
 *
 *    Updates column sizes based on a single row that would be printed
 *    from the given iterator.
 */
static void rws_calcsize_row(
    rws_iter_t *iter)
{
    size_t i;
    int len;

    for (i = 0; i < num_fields; i++) {
        len = rws_print_field(fprintf_size, NULL, iter, fields[i], 0);
        if (len > col_width[fields[i]]) {
            col_width[fields[i]] = len;
        }
    }
}


/*
 *  rws_print_titles();
 *
 *    Print the column headings unless --no-titles was specified.
 */
static void rws_print_titles(void)
{
    size_t i;

    if (no_titles) {
        return;
    }

    for (i = 0; i < num_fields; ++i) {
        if (i > 0) {
            fprintf(output.of_fp, "%c", column_separator);
        }
        fprintf(output.of_fp, "%*s", col_width[fields[i]],
                (char *)field_map_entries[fields[i]].userdata);
    }
    fprintf(output.of_fp, "%s\n", final_delim);
}


/*
 *  status = rws_setup_iter_from_fields(iter);
 *
 *    Set up the iterator for iterating based on the field list.
 *
 *    Return 0 for normal iteration.  Return -1 for no output (other
 *    than titles).  Return 1 for outputting a single non-iterated
 *    entry.
 */
static int rws_setup_iter_from_fields(
    rws_iter_t *iter)
{
    size_t i;
    /* Next iterator level to initialize */
    int level = 0;
    /* Boolean: class iterator set? */
    int class_set = 0;
    /* Boolean: flowtype iterator set? */
    int flowtype_set = 0;
    /* Boolean: sensor iterator set? */
    int sensor_set = 0;
    /* Default-type iterator set at this level (0 == none, since
     * default-type cannot exist at level 0. */
    int default_type = 0;
    /* Boolean: could be a non-iterable singleton */
    int singleton = 0;

    memset(iter, 0, sizeof(*iter));
    iter->level = -1;

    for (i = 0; i < num_fields; i++) {
        switch (fields[i]) {
          case RWST_CLASS:
          case RWST_DEFAULT_TYPE_LIST:
            /* Need classes to generate default types */
            if (class_set || flowtype_set) {
                break;
            }
            iter->order[level] = sensor_set ? RWS_CLASS_FROM_SENSOR : RWS_CLASS;
            iter->level = level;
            ++level;
            class_set = 1;
            break;
          case RWST_TYPE:
          case RWST_FLOWTYPE:
          case RWST_FLOWTYPE_ID:
            if (flowtype_set) {
                break;
            }
            if (default_type) {
                /* Replace default type, as flowtype and default type
                   is nonsensical */
                iter->order[default_type] =
                    class_set ? RWS_FLOWTYPE_FROM_CLASS : RWS_FLOWTYPE;
                default_type = 0;
            } else {
                iter->order[level] =
                    class_set ? RWS_FLOWTYPE_FROM_CLASS : RWS_FLOWTYPE;
                iter->level = level;
                ++level;
            }
            flowtype_set = 1;
            break;
          case RWST_SENSOR:
          case RWST_SENSOR_ID:
          case RWST_SENSOR_DESC:
            if (sensor_set) {
                break;
            }
            iter->order[level] = class_set ? RWS_SENSOR_FROM_CLASS : RWS_SENSOR;
            iter->level = level;
            ++level;
            sensor_set = 1;
            break;
          case RWST_DEFAULT_TYPE:
            assert(!default_type);
            if (flowtype_set) {
                break;
            }
            if (!class_set) {
                /* Default-type needs a class iterator, so add one */
                iter->order[level] =
                    sensor_set ? RWS_CLASS_FROM_SENSOR : RWS_CLASS;
                ++level;
                class_set = 1;
            }
            iter->order[level] = RWS_DEFAULT_FLOWTYPE_FROM_CLASS;
            iter->level = level;
            ++level;
            default_type = level;
            break;
          case RWST_DEFAULT_CLASS:
          case RWST_CLASS_LIST:
          case RWST_TYPE_LIST:
          case RWST_FLOWTYPE_LIST:
          case RWST_FLOWTYPE_ID_LIST:
          case RWST_SENSOR_LIST:
          case RWST_SENSOR_ID_LIST:
          case RWST_DEFAULT_CLASS_LIST:
            /* These fields can generate null-iterators with a single
             * row of output. */
            singleton = 1;
            break;
          case RWST_MARK_DEFAULTS:
            break;
          case RWST_MAX_FIELD_COUNT:
          default:
            skAbortBadCase(fields[i]);
        }
    }

    /* Bind the iterator (at level -1 if this is a null-iterator) */
    iter->flowtype_id = SK_INVALID_FLOWTYPE;
    iter->class_id    = SK_INVALID_CLASS;
    iter->sensor_id   = SK_INVALID_SENSOR;
    rws_iter_bind(iter, level ? 0 : -1);

    if (level != 0) {
        /* Return 0 if this is not a null iterator */
        return 0;
    }

    /* Return 1 if this is a singleton null-iterator.  -1 otherwise */
    return singleton ? 1 : -1;
}


int main(int argc, char **argv)
{
    rws_iter_t iter;
    rws_iter_t calciter;
    int rv;

    appSetup(argc, argv);       /* never returns on error */

    /* Set up site iterator */
    rv = rws_setup_iter_from_fields(&iter);
    if (rv == -1) {
        /* Nothing to do */
        rws_print_titles();
        return EXIT_SUCCESS;
    }

    /* Calculate column sizes */
    if (!no_columns) {
        calciter = iter;
        if (rv == 1) {
            /* Null iterator case */
            rws_calcsize_row(&calciter);
        } else {
            while (rws_iter_next(&calciter, 0)) {
                rws_calcsize_row(&calciter);
            }
        }
    }

    /* Print titles */
    rws_print_titles();

    /* Print rows */
    if (rv == 1) {
        /* Null iterator case */
        rws_print_row(&iter);
    } else {
        while (rws_iter_next(&iter, 0)) {
            rws_print_row(&iter);
        }
    }

    return EXIT_SUCCESS;
}


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-11-26 13:25                                       ` Michael Welsh Duggan
@ 2012-12-10  3:35                                         ` Michael Welsh Duggan
  2013-01-07 12:09                                           ` Alan Mackenzie
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2012-12-10  3:35 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: Alan Mackenzie, 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 199 bytes --]

Here's another case.  

emacs -Q rwrec.h
M-x c-toggle-parse-state-debug
C-v {about 24-27 times}

This is with current bzr.  
111170 rgm@gnu.org-20121210020042-arkhaf5eej6ujgtn

rwrec.h is attached.


[-- Warning: decoded text below may be mangled, UTF-8 assumed --]
[-- Attachment #2: rwrec.h --]
[-- Type: text/x-chdr, Size: 81424 bytes --]

/*
** Copyright (C) 2001-2012 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  rwrec.h
**
**    The SiLK Flow record (rwRec) definition and functions/macros for
**    manipulating it.
**
*/
#ifndef _RWREC_H
#define _RWREC_H
#ifdef __cplusplus
extern "C" {
#endif

#include <silk/silk.h>

RCSIDENTVAR(rcsID_RWREC_H, "$Id$");

#include <silk/silk_types.h>

#ifndef RWREC_OPAQUE
#  define RWREC_OPAQUE 0
#  include <silk/skipaddr.h>
#endif


/*
 * The following documents macros defined in this file that work to
 * access and manipulate the data in an rwRec.  Although these are
 * macros, they have been documented as functions in order to convey
 * the expected types of the arguments.
 *
 * ****  Convenience macros  ****
 *
 *   void RWREC_CLEAR(rwRec *r);
 *    Zero out the record, and set Sensor ID and Flowtype to invalid
 *    values.
 *
 *   void RWREC_COPY(rwRec *dst, const rwRec *src);
 *    Copy the rwRec from 'src' to 'dst'.
 *
 *   int rwRecIsICMP(const rwRec *r);
 *    Returns non-zero if the record is an ICMP record, zero otherwise.
 *
 *   int rwRecIsWeb(const rwRec *r);
 *    Returns non-zero if the record can be represented using the SiLK
 *    web-specific file formats, zero otherwise.
 *
 *
 * **** More macros ****
 *
 * Function versions of all of the following macros exist.  Simply
 * change the "rwRec" prefix of the macro to "rwrec_" to use the
 * function version.
 *
 * ***  Whether a record is IPv6  ***
 *
 * int      rwRecIsIPv6(const rwRec *r);
 *
 * ***  Set record as IPv4 or IPv6  ***
 *
 * void     rwRecSetIPv6(rwRec *r);
 * void     rwRecSetIPv4(rwRec *r);
 *
 * It is important to note that the above two macros do not do any
 * conversions on the contained IP addresses.  They are primarily to
 * be used when creating a new rwRec from scratch.  See the following
 * for conversion.
 *
 * ***  Convert record to IPv4 or IPv6  ***
 *
 * int      rwRecConvertToIPv4(rwRec *r);
 * void     rwRecConvertToIPv6(rwRec *r);
 *
 * These macros convert an rwRec to IPv4 or IPv6.  The latter always
 * succeeds.  The former will return -1 if unable to convert due to
 * the existence of IPv6 addresses that cannot be represented as IPv4
 * (and return zero on success).
 *
 * ****  rwRec accessor macros ****
 *
 * Most of the following accessor macros come in five standard
 * variations:
 *
 *   <fieldtype> rwRecGet<field>(const reRec *r)
 *    Gets the value of the field directly
 *
 *   void rwRecSet<field>(rwRec *r, <fieldtype> in_v)
 *    Sets the value of the field to 'in_v'
 *
 *   void rwRecMemGet<field>(const rwRec *r, <fieldtype> *out_vp)
 *    Copies the value of the field to location out_vp
 *
 *   void rwRecMemSet<field>(rwRec *r, const <fieldtype> *in_vp)
 *    Copies the value in location in_vp into the field
 *
 *   int rwRecMemCmp<field>(const rwRec *r, const <fieldtype> *vp)
 *    Compares the field to the value in location vp, returning a
 *    negative integer if the field is less than vp, 0 if equal, and a
 *    positive integer if greater than vp.
 *
 * For the rwRecMem{Get,Set,Cmp}<field>() macros, we use of
 * <fieldtype> in the comment to explain the size of the data
 * involved.  With the exception of those dealing the skipaddr_t
 * objects, the actual functions use void pointers; as a result, those
 * macros do not require the value pointer to be aligned.  The macros
 * that handle values larger than uint8_t use memcpy() or memcmp() to
 * copy or compare the values.
 *
 * ** IP Address Macros **
 *
 * For handling IP addresses, there are three sets of macros: one for
 * IPv4 addresses: one for IPv6 addresses, and one for skipaddr_t
 * objects, which can represent either an IPv4 address or and IPv6
 * object.
 *
 * In addition to the Get, Set, and Comparison macros, the follow
 * macro exists in IPv4, IPv6, and skipaddr_t varieties:
 *
 *   void rwRecApplyMask<field>(rwRec *r, const <fieldtype> mask);
 *    Modify the rwRec's <field> IP addresses by applying the
 *    specified mask (using a bit-wise AND) to that IP address.
 *
 * All of the macros that deal with IPv4 addresses assume that you
 * know the rwRec holds IPv4 addresses.  No conversion of the rwRec or
 * of the address occurs.
 *
 * Using the Get macros for IPv6 on an rwRec that contains V4 data
 * will return a properly encoded IPv4-in-IPv6 address.  All other
 * macros for IPv6 assume you know that the rwRec holds IPv6
 * addresses.  For IPv6, the rwRecGet<field>() and rwRecSet<field>()
 * macros do not exist; you must use the rwRecMemGet<field>() and
 * rwRecMemSet<field>() versions.
 *
 * Since an skipaddr_t can hold an IPv4 or an IPv6 address, the macros
 * that use skipaddr_t objects will correctly handle with rwRecs that
 * hold IPv4 or IPv6 data.  Setting or masking an IPv4 rwRec with an
 * IPv6 skipaddr_t may convert the record to IPv6.  The comparison
 * macros will operate in IPv6 space if either argument involves IPv6.
 * Unlike all other rwRecMem{Get,Set,Cmp}<field>() macros, the
 * functions that work with skipaddr_t pointers require the skipaddr_t
 * to be properly aligned.
 *
 * The IPv4 macros include an extra DEPRECATED macro:
 *
 *   uint32_t rwRecGetMask<field>v4(rwRec *r, uint32_t mask)
 *    Gets the value of the field with the given bit-mask applied
 *
 * ***  Source IPv4 Address (sIP)  ***
 *
 * uint32_t rwRecGetSIPv4(const rwRec *r);
 * void     rwRecSetSIPv4(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetSIPv4(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetSIPv4(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpSIPv4(const rwRec *r, const uint32_t *vp);
 * void     rwRecApplyMaskSIPv4(rwRec *r, uint32_t mask);
 * uint32_t rwRecGetMaskSIPv4(const rwRec *r, uint32_t mask);
 *
 * ***  Source IPv6 Address (sIP)  ***
 *
 * void     rwRecMemGetSIPv6(const rwRec *r, uint8_t[16] out_vp);
 * void     rwRecMemSetSIPv6(rwRec *r, const uint8_t[16] in_vp);
 * int      rwRecMemCmpSIPv6(const rwRec *r, const uint8_t[16] vp);
 * void     rwRecApplyMaskSIPv6(rwRec *r, const uint8_t[16] mask);
 *
 * ***  Source IP Address (sIP) as skipaddr_t  ***
 *
 * void     rwRecMemGetSIP(const rwRec *r, skipaddr_t *out_addr);
 * void     rwRecMemSetSIP(rwRec *r, const skipaddr_t *in_addr);
 * int      rwRecMemCmpSIP(const rwRec *r, const skipaddr_t *addr);
 * void     rwRecApplyMaskSIP(rwRec *r, const skipaddr_t *mask);
 *
 * ***  Destination IP Address (dIP)  ***
 *
 * uint32_t rwRecGetDIPv4(const rwRec *r);
 * void     rwRecSetDIPv4(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetDIPv4(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetDIPv4(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpDIPv4(const rwRec *r, const uint32_t *vp);
 * void     rwRecApplyMaskDIPv4(rwRec *r, uint32_t mask);
 * uint32_t rwRecGetMaskDIPv4(const rwRec *r, uint32_t mask);
 *
 * ***  Destination IPv6 Address (dIP)  ***
 *
 * void     rwRecMemGetDIPv6(const rwRec *r, uint8_t[16] out_vp);
 * void     rwRecMemSetDIPv6(rwRec *r, const uint8_t[16] in_vp);
 * int      rwRecMemCmpDIPv6(const rwRec *r, const uint8_t[16] vp);
 * void     rwRecApplyMaskDIPv6(rwRec *r, const uint8_t[16] mask);
 *
 * ***  Destination IP Address (dIP) as skipaddr_t  ***
 *
 * void     rwRecMemGetDIP(const rwRec *r, skipaddr_t *out_addr);
 * void     rwRecMemSetDIP(rwRec *r, const skipaddr_t *in_addr);
 * int      rwRecMemCmpDIP(const rwRec *r, const skipaddr_t *addr);
 * void     rwRecApplyMaskDIP(rwRec *r, const skipaddr_t *mask);
 *
 * ***  Next Hop IP Address  ***
 *
 * uint32_t rwRecGetNhIPv4(const rwRec *r);
 * void     rwRecSetNhIPv4(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetNhIPv4(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetNhIPv4(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpNhIPv4(const rwRec *r, const uint32_t *vp);
 * void     rwRecApplyMaskNhIPv4(rwRec *r, uint32_t mask);
 * uint32_t rwRecGetMaskNhIPv4(const rwRec *r, uint32_t mask);
 *
 * ***  Next Hop IPv6 Address (nhIP)  ***
 *
 * void     rwRecMemGetNhIPv6(const rwRec *r, uint8_t[16] out_vp);
 * void     rwRecMemSetNhIPv6(rwRec *r, const uint8_t[16] in_vp);
 * int      rwRecMemCmpNhIPv6(const rwRec *r, const uint8_t[16] vp);
 * void     rwRecApplyMaskNhIPv6(rwRec *r, const uint8_t[16] mask);
 *
 * ***  Next Hop IP Address (nhIP) as skipaddr_t  ***
 *
 * void     rwRecMemGetNhIP(const rwRec *r, skipaddr_t *out_addr);
 * void     rwRecMemSetNhIP(rwRec *r, const skipaddr_t *in_addr);
 * int      rwRecMemCmpNhIP(const rwRec *r, const skipaddr_t *addr);
 * void     rwRecApplyMaskNhIP(rwRec *r, const skipaddr_t *mask);
 *
 * ***  Source Port (sPort)  ***
 *
 * uint16_t rwRecGetSPort(const rwRec *r);
 * void     rwRecSetSPort(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetSPort(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetSPort(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpSPort(const rwRec *r, const uint16_t *vp);
 *
 * ***  Destination Port (dPort)  ***
 *
 * uint16_t rwRecGetDPort(const rwRec *r);
 * void     rwRecSetDPort(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetDPort(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetDPort(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpDPort(const rwRec *r, const uint16_t *vp);
 *
 * ***  Protocol  ***
 *
 * uint8_t  rwRecGetProto(const rwRec *r);
 * void     rwRecSetProto(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetProto(const rwRec *r, uint8_t *out_vp);
 * void     rwRecMemSetProto(rwRec *r, const uint8_t *in_vp);
 * int      rwRecMemCmpProto(const rwRec *r, const uint8_t *vp);
 *
 * ***  Packet Count (pkts)  ***
 *
 * uint32_t rwRecGetPkts(const rwRec *r);
 * void     rwRecSetPkts(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetPkts(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetPkts(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpPkts(const rwRec *r, const uint32_t *vp);
 *
 * ***  Byte count  ***
 *
 * uint32_t rwRecGetBytes(const rwRec *r);
 * void     rwRecSetBytes(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetBytes(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetBytes(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpBytes(const rwRec *r, const uint32_t *vp);
 *
 * ***  Bitwise OR of TCP Flags on ALL packets in flow  ***
 *
 * uint8_t  rwRecGetFlags(const rwRec *r);
 * void     rwRecSetFlags(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetFlags(const rwRec *r, uint8_t *out_vp);
 * void     rwRecMemSetFlags(rwRec *r, const uint8_t *in_vp);
 * int      rwRecMemCmpFlags(const rwRec *r, const uint8_t *vp);
 *
 * ***  TCP Flags seen on initial packet of flow  ***
 *
 * uint8_t  rwRecGetInitFlags(const rwRec *r);
 * void     rwRecSetInitFlags(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetInitFlags(const rwRec *r, uint8_t *out_vp);
 * void     rwRecMemSetInitFlags(rwRec *r, const uint8_t *in_vp);
 * int      rwRecMemCmpInitFlags(const rwRec *r, const uint8_t *vp);
 *
 * ***  Bitwise OR of TCP Flags on all packets in session except first  ***
 *
 * uint8_t  rwRecGetRestFlags(const rwRec *r);
 * void     rwRecSetRestFlags(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetRestFlags(const rwRec *r, uint8_t *out_vp);
 * void     rwRecMemSetRestFlags(rwRec *r, const uint8_t *in_vp);
 * int      rwRecMemCmpRestFlags(const rwRec *r, const uint8_t *vp);
 *
 * ***  Start Time as milliseconds since UNIX epoch (sTime)  ***
 *
 * sktime_t rwRecGetStartTime(const rwRec *r);
 * void     rwRecSetStartTime(rwRec *r, sktime_t in_v);
 * void     rwRecMemGetStartTime(const rwRec *r, sktime_t *out_vp);
 * void     rwRecMemSetStartTime(rwRec *r, const sktime_t *in_vp);
 * int      rwRecMemCmpStartTime(const rwRec *r, const sktime_t *vp);
 *
 * uint32_t rwRecGetStartSeconds(const rwRec *r);
 * void     rwRecMemGetStartSeconds(const rwRec *r, uint32_t *out_vp);
 * uint16_t rwRecGetStartMSec(const rwRec *r);
 * void     rwRecMemGetStartMSec(const rwRec *r, uint16_t *out_vp);
 *
 * The second set of macros return the integer number of seconds and
 * the millisecond remainder.  In particular:
 *
 *   rwRecGetStartTime(r) ==
 *     rwRecGetStartSeconds(r) * (uint64_t)1000 + rwRecGetStartMSec(r)
 *
 * ***  End Time is derived from the sTime and duration (eTime)  ***
 *
 * sktime_t rwRecGetEndTime(const rwRec *r);
 * void     rwRecMemGetEndTime(const rwRec *r, sktime_t *out_vp);
 *
 * uint32_t rwRecGetEndSeconds(const rwRec *r);
 * void     rwRecMemGetEndSeconds(const rwRec *r, uint32_t *out_vp);
 * uint16_t rwRecGetEndMSec(const rwRec *r);
 * void     rwRecMemGetEndMSec(const rwRec *r, uint16_t *out_vp);
 *
 * There are no setter macros for end time, because end time is
 * derived from start time and duration (elapsed time).
 *
 * The second set of macros return the integer number of seconds and
 * the millisecond remainder.  In particular:
 *
 *   rwRecGetEndTime(r) ==
 *     rwRecGetEndSeconds(r) * (uint64_t)1000 + rwRecGetEndMSec(r)
 *
 * ***  Elapsed (duration) of the flow, in milliseconds  ***
 *
 * uint32_t rwRecGetElapsed(const rwRec *r);
 * void     rwRecSetElapsed(rwRec *r, uint32_t in_v);
 * void     rwRecMemGetElapsed(const rwRec *r, uint32_t *out_vp);
 * void     rwRecMemSetElapsed(rwRec *r, const uint32_t *in_vp);
 * int      rwRecMemCmpElapsed(const rwRec *r, const uint32_t *vp);
 *
 * uint32_t rwRecGetElapsedSeconds(const rwRec *r);
 * void     rwRecMemGetElapsedSeconds(const rwRec *r, uint32_t *out_vp);
 * uint16_t rwRecGetElapsedMSec(const rwRec *r);
 * void     rwRecMemGetElapsedMSec(const rwRec *r, uint16_t *out_vp);
 *
 * The second set of macros return the integer number of seconds and
 * the millisecond remainder.  In particular:
 *
 *   rwRecGetElapsedTime(r) ==
 *     rwRecGetElapsedSeconds(r) * 1000 + rwRecGetElapsedMSec(r)
 *
 * ***  Sensor ID (sID)  ***
 *
 * sensorID_t rwRecGetSensor(const rwRec *r);
 * void     rwRecSetSensor(rwRec *r, sensorID_t in_v);
 * void     rwRecMemGetSensor(const rwRec *r, sensorID_t *out_vp);
 * void     rwRecMemSetSensor(rwRec *r, const sensorID_t *in_vp);
 * int      rwRecMemCmpSensor(const rwRec *r, const sensorID_t *vp);
 *
 * ***  FlowType holds Class and Type  ***
 *
 * flowtypeID_t rwRecGetFlowType(const rwRec *r);
 * void     rwRecSetFlowType(rwRec *r, flowtypeID_t in_v);
 * void     rwRecMemGetFlowType(const rwRec *r, flowtypeID_t *out_vp);
 * void     rwRecMemSetFlowType(rwRec *r, const flowtypeID_t *in_vp);
 * int      rwRecMemCmpFlowType(const rwRec *r, const flowtypeID_t *vp);
 *
 * ***  SNMP Input Value (Router incoming/ingress interface/vlanId) ***
 *
 * uint16_t rwRecGetInput(const rwRec *r);
 * void     rwRecSetInput(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetInput(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetInput(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpInput(const rwRec *r, const uint16_t *vp);
 *
 * ***  SNMP Output Value (Router outgoing/egress interface/postVlanId) ***
 *
 * uint16_t rwRecGetOutput(const rwRec *r);
 * void     rwRecSetOutput(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetOutput(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetOutput(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpOutput(const rwRec *r, const uint16_t *vp);
 *
 * ***  TCP State (the Attributes field)  ***
 *
 * uint8_t  rwRecGetTcpState(const rwRec *r);
 * void     rwRecSetTcpState(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetTcpState(const rwRec *r, uint8_t *out_vp);
 * void     rwRecMemSetTcpState(rwRec *r, const uint8_t *in_vp);
 * int      rwRecMemCmpTcpState(const rwRec *r, const uint8_t *vp);
 *
 * The TCP state field is a bit field which states certain miscellaneous
 * information about the flow record.  The following constants are
 * defined which represent this information:
 *
 * #define SK_TCPSTATE_EXPANDED              0x01
 *  Additional TCP-state machine information is available.  This must
 *  be set for every TCP flow where the init_flags and rest_flags
 *  fields are set.
 *
 * #define SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK  0x08
 *  Flow received packets following the FIN packet that were not ACK or
 *  RST packets.
 *
 * #define SK_TCPSTATE_UNIFORM_PACKET_SIZE   0x10
 *  Flow has packets all of the same size
 *
 * #define SK_TCPSTATE_TIMEOUT_KILLED        0x20
 *  Flow ends prematurely due to a timeout by the collector.
 *
 * #define SK_TCPSTATE_TIMEOUT_STARTED       0x40
 *  Flow is a continuation of a previous flow that was killed
 *  prematurely due to a timeout by the collector.
 *
 * Note: the most significant bit of tcp_state (0x80) is used as a flag
 * to mark a record as having IPv6 addresses.  The rwRecSetIPv4() and
 * rwRecSetIPv6() macros should be used to modify this bit.
 *
 * Be careful when setting the TCP state.  You usually want get the
 * current TCP state, add or remove specific bits by masking, then set it
 * with the resulting value.
 *
 * ***  Application  ***
 *
 * uint16_t rwRecGetApplication(const rwRec *r);
 * void     rwRecSetApplication(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetApplication(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetApplication(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpApplication(const rwRec *r, const uint16_t *vp);
 *
 * The application field can be set by the yaf flow generation
 * software when it is configured with the "applabel" feature.  This
 * feature causes yaf to inspect the packets in the flow and guess as
 * to the type of application (HTTP, SMTP, SSH, etc) the packets
 * represent.  The value for the field is the standard service port
 * for that service (80, 25, 22, etc).
 *
 * ***  Memo  ***
 *
 * uint16_t rwRecGetMemo(const rwRec *r);
 * void     rwRecSetMemo(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetMemo(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetMemo(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpMemo(const rwRec *r, const uint16_t *vp);
 *
 * Currently unused.
 *
 * ***  ICMP Type and Code is derived from the DPort  ***
 *
 * uint8_t  rwRecGetIcmpType(const rwRec *r);
 * void     rwRecSetIcmpType(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetIcmpType(const rwRec *r, uint8_t *out_vp);
 *
 * uint8_t  rwRecGetIcmpCode(const rwRec *r);
 * void     rwRecSetIcmpCode(rwRec *r, uint8_t in_v);
 * void     rwRecMemGetIcmpCode(const rwRec *r, uint8_t *out_vp);
 *
 * uint16_t rwRecGetIcmpTypeAndCode(const rwRec *r);
 * void     rwRecSetIcmpTypeAndCode(rwRec *r, uint16_t in_v);
 * void     rwRecMemGetIcmpTypeAndCode(const rwRec *r, uint16_t *out_vp);
 * void     rwRecMemSetIcmpTypeAndCode(rwRec *r, const uint16_t *in_vp);
 * int      rwRecMemCmpIcmpTypeAndCode(const rwRec *r, const uint16_t *vp);
 *
 * Since the ICMP Type and Code are stored in the dport field, modifying
 * these will modify the return value of rwRecGetDPort() and friends.
 */


#define SK_WEBPORT_CHECK(p) ((p) == 80 || (p) == 443 || (p) == 8080)
/*
 *    Return a true value if port 'p' is a "web" port; false otherwise
 */

#define RWREC_CLEAR(rec)                                     \
    do {                                                     \
        memset((rec), 0, sizeof(rwRec));                     \
        rwRecSetSensor((rec), SK_INVALID_SENSOR);            \
        rwRecSetFlowType((rec), SK_INVALID_FLOWTYPE);        \
    } while(0)
/*
 *    Zero out the record, and set Sensor ID and Flowtype to invalid
 *    values.
 */


#define RWREC_COPY(dst, src)                    \
    memcpy((dst), (src), sizeof(rwRec))
/*
 *    Copy the rwRec from 'src' to 'dst'.
 */


/*
 *  This is the generic SiLK Flow record returned from ANY file format
 *  containing packed SiLK Flow records.
 *
 *  typedef struct rwGenericRec_V5_st rwGenericRec_V5_t; // silk_types.h
 *  typedef rwGenericRec_V5_t rwRec;                     // silk_types.h
 */
struct rwGenericRec_V5_st {
#if RWREC_OPAQUE && !defined(RWREC_DEFINE_BODY)
#if SK_ENABLE_IPV6
    uint8_t         ar[88];
#else
    uint8_t         ar[52];
#endif
#else
    int64_t         sTime;       /*  0- 7  Flow start time in milliseconds
                                  *        since UNIX epoch */

    uint32_t        elapsed;     /*  8-11  Duration of flow in millisecs */

    uint16_t        sPort;       /* 12-13  Source port */
    uint16_t        dPort;       /* 14-15  Destination port */

    uint8_t         proto;       /* 16     IP protocol */
    flowtypeID_t    flow_type;   /* 17     Class & Type info */
    sensorID_t      sID;         /* 18-19  Sensor ID */

    uint8_t         flags;       /* 20     OR of all flags (Netflow flags) */
    uint8_t         init_flags;  /* 21     TCP flags in first packet
                                  *        or blank for "legacy" data */
    uint8_t         rest_flags;  /* 22     TCP flags on non-initial packet
                                  *        or blank for "legacy" data */
    uint8_t         tcp_state;   /* 23     TCP state machine info (below) */

    uint16_t        application; /* 24-25  "Service" port set by collector */
    uint16_t        memo;        /* 26-27  Application specific field */

    uint16_t        input;       /* 28-29  Router incoming SNMP interface */
    uint16_t        output;      /* 30-31  Router outgoing SNMP interface */

    uint32_t        pkts;        /* 32-35  Count of packets */
    uint32_t        bytes;       /* 36-39  Count of bytes */

    ipUnion         sIP;         /* 40-43  (or 40-55 if IPv6) Source IP */
    ipUnion         dIP;         /* 44-47  (or 56-71 if IPv6) Destination IP */
    ipUnion         nhIP;        /* 48-51  (or 72-87 if IPv6) Router Next Hop IP */
#endif  /* RWREC_OPAQUE && !defined(RWREC_DEFINE_BODY) */
};


/*
**  Values for tcp_state value in rwGeneric and packed formats
*/

/* No additional TCP-state machine information is available */
#define SK_TCPSTATE_NO_INFO               0x00

/* Additional TCP-state machine information is available.  This must
 * be set for every TCP flow where the init_flags and rest_flags
 * fields are set.  */
#define SK_TCPSTATE_EXPANDED              0x01

/* Flow received packets following the FIN packet that were not ACK or
 * RST packets. */
#define SK_TCPSTATE_FIN_FOLLOWED_NOT_ACK  0x08

/* Flow has packets all of the same size */
#define SK_TCPSTATE_UNIFORM_PACKET_SIZE   0x10

/* Flow ends prematurely due to a timeout by the collector. */
#define SK_TCPSTATE_TIMEOUT_KILLED        0x20

/* Flow is a continuation of a previous flow that was killed
 * prematurely due to a timeout by the collector. */
#define SK_TCPSTATE_TIMEOUT_STARTED       0x40

/* Note: the most significant bit of tcp_state (0x80) is used as a
 * flag to mark a record as having IPv6 addresses. */


/* the sizeof the fields in an rwRec */
#define RWREC_SIZEOF_SIPv4        4
#define RWREC_SIZEOF_DIPv4        4
#define RWREC_SIZEOF_NHIPv4       4
#define RWREC_SIZEOF_SPORT        2
#define RWREC_SIZEOF_DPORT        2
#define RWREC_SIZEOF_INPUT        2
#define RWREC_SIZEOF_OUTPUT       2
#define RWREC_SIZEOF_STIME        8
#define RWREC_SIZEOF_ELAPSED      4
#define RWREC_SIZEOF_PKTS         4
#define RWREC_SIZEOF_BYTES        4
#define RWREC_SIZEOF_PROTO        1
#define RWREC_SIZEOF_FLOW_TYPE    1
#define RWREC_SIZEOF_SID          2
#define RWREC_SIZEOF_FLAGS        1
#define RWREC_SIZEOF_INIT_FLAGS   1
#define RWREC_SIZEOF_REST_FLAGS   1
#define RWREC_SIZEOF_TCP_STATE    1
#define RWREC_SIZEOF_APPLICATION  2
#define RWREC_SIZEOF_MEMO         2
#define RWREC_SIZEOF_SIPv6       16
#define RWREC_SIZEOF_DIPv6       16
#define RWREC_SIZEOF_NHIPv6      16

#if !SK_ENABLE_IPV6
#  define RWREC_SIZEOF_SIP  RWREC_SIZEOF_SIPv4
#  define RWREC_SIZEOF_DIP  RWREC_SIZEOF_DIPv4
#  define RWREC_SIZEOF_NHIP RWREC_SIZEOF_NHIPv4
#else
#  define RWREC_SIZEOF_SIP  RWREC_SIZEOF_SIPv6
#  define RWREC_SIZEOF_DIP  RWREC_SIZEOF_DIPv6
#  define RWREC_SIZEOF_NHIP RWREC_SIZEOF_NHIPv6
#endif /* SK_ENABLE_IPV6 */


/* Helper macros */
#if 0
#  define MEMCPY8(dst, src)   { *((uint8_t*)(dst))  = *((uint8_t*)(src)); }
#  define MEMCPY16(dst, src)  { *((uint16_t*)(dst)) = *((uint16_t*)(src)); }
#  define MEMCPY32(dst, src)  { *((uint32_t*)(dst)) = *((uint32_t*)(src)); }
#else
#  define MEMCPY8(dst, src)   memcpy((dst), (src), sizeof(uint8_t))
#  define MEMCPY16(dst, src)  memcpy((dst), (src), sizeof(uint16_t))
#  define MEMCPY32(dst, src)  memcpy((dst), (src), sizeof(uint32_t))
#endif


/***  Whether record is ICMP  ***/

#define rwRecIsICMP(r)                                                  \
    ((IPPROTO_ICMP == rwRecGetProto(r))                                 \
     || (rwRecIsIPv6(r) && (IPPROTO_ICMPV6 == rwRecGetProto(r))))


/***  Whether record is WEB/HTTP  ***/

#define rwRecIsWeb(r)                                   \
    ((IPPROTO_TCP == rwRecGetProto(r))                  \
     && (SK_WEBPORT_CHECK(rwRecGetSPort(r))             \
         || SK_WEBPORT_CHECK(rwRecGetDPort(r))))


/***  Whether record is IPv6  ***/

#if !SK_ENABLE_IPV6
#  define rwRecIsIPv6(r)  0
#else

int  rwrec_IsIPv6(const rwRec *r);
void rwrec_SetIPv6(rwRec *r);
void rwrec_SetIPv4(rwRec *r);

#define _recIsIPv6(r)                           \
    (((r)->tcp_state & 0x80) ? 1 : 0)
#define _recSetIPv6(r)                          \
    { (r)->tcp_state |= 0x80; }
#define _recSetIPv4(r)                          \
    { (r)->tcp_state &= 0x7F; }

#if RWREC_OPAQUE
#  define rwRecIsIPv6(r)    rwrec_IsIPv6(r)
#  define rwRecSetIPv6(r)   rwrec_SetIPv6(r)
#  define rwRecSetIPv4(r)   rwrec_SetIPv4(r)
#else
#  define rwRecIsIPv6(r)    _recIsIPv6(r)
#  define rwRecSetIPv6(r)   _recSetIPv6(r)
#  define rwRecSetIPv4(r)   _recSetIPv4(r)
#endif /* RWREC_OPAQUE */

#endif  /* SK_ENABLE_IPV6 */


/***  Convert a Record to IPv6 or IPv4  ***/

#if SK_ENABLE_IPV6

void rwrec_ConvertToIPv6(rwRec *r);
int  rwrec_ConvertToIPv4(rwRec *r);

#define _recConvertToIPv6(r)                    \
    {                                           \
        ipUnion4to6(&(r)->sIP, &(r)->sIP);      \
        ipUnion4to6(&(r)->dIP, &(r)->dIP);      \
        ipUnion4to6(&(r)->nhIP, &(r)->nhIP);    \
        _recSetIPv6(r);                         \
    }

#if RWREC_OPAQUE
#  define rwRecConvertToIPv6(r)   rwrec_ConvertToIPv6(r)
#  define rwRecConvertToIPv4(r)   rwrec_ConvertToIPv4(r)
#else
#  define rwRecConvertToIPv6(r)   _recConvertToIPv6(r)
#  define rwRecConvertToIPv4(r)   rwrec_ConvertToIPv4(r)
#endif /* RWREC_OPAQUE */

#endif  /* SK_ENABLE_IPV6 */


/***  Source IPv4 Address (sIP)  ***/

uint32_t rwrec_GetSIPv4(const rwRec *r);
void     rwrec_SetSIPv4(rwRec *r, uint32_t in_v);
void     rwrec_MemGetSIPv4(const rwRec *r, void *out_vp);
void     rwrec_MemSetSIPv4(rwRec *r, const void *in_vp);
int      rwrec_MemCmpSIPv4(const rwRec *r, const void *vp);
uint32_t rwrec_GetMaskSIPv4(const rwRec *r, uint32_t mask);
void     rwrec_ApplyMaskSIPv4(rwRec *r, uint32_t mask);

#define _recGetSIPv4(r)                         \
    ((r)->sIP.ipu_ipv4)
#define _recSetSIPv4(r, in_v)                   \
    { ((r)->sIP.ipu_ipv4) = (in_v); }
#define _recMemGetSIPv4(r, out_vp)                              \
    memcpy((out_vp), &((r)->sIP.ipu_ipv4), RWREC_SIZEOF_SIPv4)
#define _recMemSetSIPv4(r, in_vp)                               \
    memcpy(&((r)->sIP.ipu_ipv4), (in_vp), RWREC_SIZEOF_SIPv4)
#define _recMemCmpSIPv4(r, vp)                          \
    memcmp(&((r)->sIP.ipu_ipv4), (vp), RWREC_SIZEOF_SIPv4)
#define _recGetMaskSIPv4(r, mask)               \
    (((r)->sIP.ipu_ipv4) & mask)
#define _recApplyMaskSIPv4(r, mask)             \
    ipUnionApplyMaskV4(&((r)->sIP), (mask))

#if RWREC_OPAQUE
#  define rwRecGetSIPv4(r)              rwrec_GetSIPv4(r)
#  define rwRecSetSIPv4(r, in_v)        rwrec_SetSIPv4(r, in_v)
#  define rwRecMemGetSIPv4(r, out_vp)   rwrec_MemGetSIPv4(r, out_vp)
#  define rwRecMemSetSIPv4(r, in_vp)    rwrec_MemSetSIPv4(r, in_vp)
#  define rwRecMemCmpSIPv4(r, vp)       rwrec_MemCmpSIPv4(r, vp)
#  define rwRecGetMaskSIPv4(r, mask)    rwrec_GetMaskSIPv4(r, mask)
#  define rwRecApplyMaskSIPv4(r, mask)  rwrec_ApplyMaskSIPv4(r, mask)
#else
#  define rwRecGetSIPv4(r)              _recGetSIPv4(r)
#  define rwRecSetSIPv4(r, in_v)        _recSetSIPv4(r, in_v)
#  define rwRecMemGetSIPv4(r, out_vp)   _recMemGetSIPv4(r, out_vp)
#  define rwRecMemSetSIPv4(r, in_vp)    _recMemSetSIPv4(r, in_vp)
#  define rwRecMemCmpSIPv4(r, vp)       _recMemCmpSIPv4(r, vp)
#  define rwRecGetMaskSIPv4(r, mask)    _recGetMaskSIPv4(r, mask)
#  define rwRecApplyMaskSIPv4(r, mask)  _recApplyMaskSIPv4(r, mask)
#endif /* RWREC_OPAQUE */


/***  Source IPv6 Address (sIP)  ***/

#if SK_ENABLE_IPV6

void     rwrec_MemGetSIPv6(const rwRec *r, void *out_vp);
void     rwrec_MemSetSIPv6(rwRec *r, const void *in_vp);
int      rwrec_MemCmpSIPv6(const rwRec *r, const void *vp);
void     rwrec_ApplyMaskSIPv6(rwRec *r, const void *mask_vp);

#define _recMemGetSIPv6(r, out_vp)                                      \
    if (_recIsIPv6(r)) {                                                \
        ipUnionGetV6(&((r)->sIP), (out_vp));                            \
    } else {                                                            \
        ipUnionGetV4AsV6(&((r)->sIP), (out_vp));                        \
    }
#define _recMemSetSIPv6(r, in_vp)                               \
    memcpy(&((r)->sIP.ipu_ipv6), (in_vp), RWREC_SIZEOF_SIPv6)
#define _recMemCmpSIPv6(r, vp)                                  \
    memcmp(&((r)->sIP.ipu_ipv6), (vp), RWREC_SIZEOF_SIPv6)
#define _recApplyMaskSIPv6(r, mask)             \
    ipUnionApplyMaskV6(&((r)->sIP), (mask))

#if RWREC_OPAQUE
#  define rwRecMemGetSIPv6(r, out_vp)   rwrec_MemGetSIPv6(r, out_vp)
#  define rwRecMemSetSIPv6(r, in_vp)    rwrec_MemSetSIPv6(r, in_vp)
#  define rwRecMemCmpSIPv6(r, vp)       rwrec_MemCmpSIPv6(r, vp)
#  define rwRecApplyMaskSIPv6(r, mask)  rwrec_ApplyMaskSIPv6(r, mask)
#else
#  define rwRecMemGetSIPv6(r, out_vp)   _recMemGetSIPv6(r, out_vp)
#  define rwRecMemSetSIPv6(r, in_vp)    _recMemSetSIPv6(r, in_vp)
#  define rwRecMemCmpSIPv6(r, vp)       _recMemCmpSIPv6(r, vp)
#  define rwRecApplyMaskSIPv6(r, mask)  _recApplyMaskSIPv6(r, mask)
#endif /* RWREC_OPAQUE */

#endif  /* SK_ENABLE_IPV6 */


/***  Source IP Address (sIP) as skipaddr_t  ***/

void     rwrec_MemGetSIP(const rwRec *r, skipaddr_t *out_addr);
void     rwrec_MemSetSIP(rwRec *r, const skipaddr_t *in_addr);
int      rwrec_MemCmpSIP(const rwRec *r, const skipaddr_t *addr);
void     rwrec_ApplyMaskSIP(rwRec *r, const skipaddr_t *mask_addr);

#if !SK_ENABLE_IPV6
#define _recMemGetSIP _recMemGetSIPv4
#define _recMemSetSIP _recMemSetSIPv4
#define _recMemCmpSIP(r, addr)                          \
    _recMemCmpSIPv4((r), &((addr)->ip_ip.ipu_ipv4))
#define _recApplyMaskSIP(r, addr)                       \
    _recApplyMaskSIPv4((r), (addr)->ip_ip.ipu_ipv4)
#else
#define _recMemGetSIP(r, out_addr)                      \
    do {                                                \
        memcpy(out_addr, &((r)->sIP), sizeof(ipUnion)); \
        skipaddrSetVersion((out_addr), _recIsIPv6(r));  \
    } while(0)
#define _recMemSetSIP(r, in_addr)                               \
    do {                                                        \
        if (skipaddrIsV6(in_addr) == _recIsIPv6(r)) {           \
            /* both are either V4 or V6 */                      \
            memcpy(&((r)->sIP), (in_addr), sizeof(ipUnion));    \
        } else if (_recIsIPv6(r)) {                             \
            /* convert V4 IP to V6 */                           \
            ipUnion4to6(&((in_addr)->ip_ip), &((r)->sIP));      \
        } else {                                                \
            /* must convert record to V6 */                     \
            _recConvertToIPv6(r);                               \
            memcpy(&((r)->sIP), (in_addr), sizeof(ipUnion));    \
        }                                                       \
    } while(0)
#define _recMemCmpSIP(r, addr)      rwrec_MemCmpSIP(r, addr)
#define _recApplyMaskSIP(r, addr)   rwrec_ApplyMaskSIP(r, addr)
#endif /* SK_ENABLE_IPV6 */

#if RWREC_OPAQUE
#  define rwRecMemGetSIP(r, out_addr)   rwrec_MemGetSIP(r, out_addr)
#  define rwRecMemSetSIP(r, in_addr)    rwrec_MemSetSIP(r, in_addr)
#  define rwRecMemCmpSIP(r, addr)       rwrec_MemCmpSIP(r, addr)
#  define rwRecApplyMaskSIP(r, addr)    rwrec_ApplyMaskSIP(r, addr)
#else
#  define rwRecMemGetSIP(r, out_addr)   _recMemGetSIP(r, out_addr)
#  define rwRecMemSetSIP(r, in_addr)    _recMemSetSIP(r, in_addr)
#  define rwRecMemCmpSIP(r, addr)       _recMemCmpSIP(r, addr)
#  define rwRecApplyMaskSIP(r, addr)    _recApplyMaskSIP(r, addr)
#endif /* RWREC_OPAQUE */


/***  Destination IP Address (dIP)  ***/

uint32_t rwrec_GetDIPv4(const rwRec *r);
void     rwrec_SetDIPv4(rwRec *r, uint32_t in_v);
void     rwrec_MemGetDIPv4(const rwRec *r, void *out_vp);
void     rwrec_MemSetDIPv4(rwRec *r, const void *in_vp);
int      rwrec_MemCmpDIPv4(const rwRec *r, const void *vp);
uint32_t rwrec_GetMaskDIPv4(const rwRec *r, uint32_t mask);
void     rwrec_ApplyMaskDIPv4(rwRec *r, uint32_t mask);

#define _recGetDIPv4(r)                         \
    ((r)->dIP.ipu_ipv4)
#define _recSetDIPv4(r, in_v)                   \
    { ((r)->dIP.ipu_ipv4) = (in_v); }
#define _recMemGetDIPv4(r, out_vp)                              \
    memcpy((out_vp), &((r)->dIP.ipu_ipv4), RWREC_SIZEOF_DIPv4)
#define _recMemSetDIPv4(r, in_vp)                               \
    memcpy(&((r)->dIP.ipu_ipv4), (in_vp), RWREC_SIZEOF_DIPv4)
#define _recMemCmpDIPv4(r, vp)                          \
    memcmp(&((r)->dIP.ipu_ipv4), (vp), RWREC_SIZEOF_DIPv4)
#define _recGetMaskDIPv4(r, mask)               \
    (((r)->dIP.ipu_ipv4) & mask)
#define _recApplyMaskDIPv4(r, mask)             \
    ipUnionApplyMaskV4(&((r)->dIP), (mask))


#if RWREC_OPAQUE
#  define rwRecGetDIPv4(r)              rwrec_GetDIPv4(r)
#  define rwRecSetDIPv4(r, in_v)        rwrec_SetDIPv4(r, in_v)
#  define rwRecMemGetDIPv4(r, out_vp)   rwrec_MemGetDIPv4(r, out_vp)
#  define rwRecMemSetDIPv4(r, in_vp)    rwrec_MemSetDIPv4(r, in_vp)
#  define rwRecMemCmpDIPv4(r, vp)       rwrec_MemCmpDIPv4(r, vp)
#  define rwRecGetMaskDIPv4(r, mask)    rwrec_GetMaskDIPv4(r, mask)
#  define rwRecApplyMaskDIPv4(r, mask)  rwrec_ApplyMaskDIPv4(r, mask)
#else
#  define rwRecGetDIPv4(r)              _recGetDIPv4(r)
#  define rwRecSetDIPv4(r, in_v)        _recSetDIPv4(r, in_v)
#  define rwRecMemGetDIPv4(r, out_vp)   _recMemGetDIPv4(r, out_vp)
#  define rwRecMemSetDIPv4(r, in_vp)    _recMemSetDIPv4(r, in_vp)
#  define rwRecMemCmpDIPv4(r, vp)       _recMemCmpDIPv4(r, vp)
#  define rwRecGetMaskDIPv4(r, mask)    _recGetMaskDIPv4(r, mask)
#  define rwRecApplyMaskDIPv4(r, mask)  _recApplyMaskDIPv4(r, mask)
#endif /* RWREC_OPAQUE */


/***  Destination IPv6 Address (dIP)  ***/

#if SK_ENABLE_IPV6

void     rwrec_MemGetDIPv6(const rwRec *r, void *out_vp);
void     rwrec_MemSetDIPv6(rwRec *r, const void *in_vp);
int      rwrec_MemCmpDIPv6(const rwRec *r, const void *vp);
void     rwrec_ApplyMaskDIPv6(rwRec *r, const void *mask_vp);

#define _recMemGetDIPv6(r, out_vp)                                      \
    if (_recIsIPv6(r)) {                                                \
        ipUnionGetV6(&((r)->dIP), (out_vp));                            \
    } else {                                                            \
        ipUnionGetV4AsV6(&((r)->dIP), (out_vp));                        \
    }
#define _recMemSetDIPv6(r, in_vp)                               \
    memcpy(&((r)->dIP.ipu_ipv6), (in_vp), RWREC_SIZEOF_DIPv6)
#define _recMemCmpDIPv6(r, vp)                                  \
    memcmp(&((r)->dIP.ipu_ipv6), (vp), RWREC_SIZEOF_DIPv6)
#define _recApplyMaskDIPv6(r, mask)             \
    ipUnionApplyMaskV6(&((r)->dIP), (mask))

#if RWREC_OPAQUE
#  define rwRecMemGetDIPv6(r, out_vp)   rwrec_MemGetDIPv6(r, out_vp)
#  define rwRecMemSetDIPv6(r, in_vp)    rwrec_MemSetDIPv6(r, in_vp)
#  define rwRecMemCmpDIPv6(r, vp)       rwrec_MemCmpDIPv6(r, vp)
#  define rwRecApplyMaskDIPv6(r, mask)  rwrec_ApplyMaskDIPv6(r, mask)
#else
#  define rwRecMemGetDIPv6(r, out_vp)   _recMemGetDIPv6(r, out_vp)
#  define rwRecMemSetDIPv6(r, in_vp)    _recMemSetDIPv6(r, in_vp)
#  define rwRecMemCmpDIPv6(r, vp)       _recMemCmpDIPv6(r, vp)
#  define rwRecApplyMaskDIPv6(r, mask)  _recApplyMaskDIPv6(r, mask)
#endif /* RWREC_OPAQUE */

#endif  /* SK_ENABLE_IPV6 */


/***  Destination IP Address (dIP) as skipaddr_t  ***/

void     rwrec_MemGetDIP(const rwRec *r, skipaddr_t *out_addr);
void     rwrec_MemSetDIP(rwRec *r, const skipaddr_t *in_addr);
int      rwrec_MemCmpDIP(const rwRec *r, const skipaddr_t *addr);
void     rwrec_ApplyMaskDIP(rwRec *r, const skipaddr_t *mask_addr);

#if !SK_ENABLE_IPV6
#define _recMemGetDIP _recMemGetDIPv4
#define _recMemSetDIP _recMemSetDIPv4
#define _recMemCmpDIP(r, addr)                          \
    _recMemCmpDIPv4((r), &((addr)->ip_ip.ipu_ipv4))
#define _recApplyMaskDIP(r, addr)                       \
    _recApplyMaskDIPv4((r), (addr)->ip_ip.ipu_ipv4)
#else
#define _recMemGetDIP(r, out_addr)                      \
    do {                                                \
        memcpy(out_addr, &((r)->dIP), sizeof(ipUnion)); \
        skipaddrSetVersion((out_addr), _recIsIPv6(r));  \
    } while(0)
#define _recMemSetDIP(r, in_addr)                               \
    do {                                                        \
        if (skipaddrIsV6(in_addr) == _recIsIPv6(r)) {           \
            /* both are either V4 or V6 */                      \
            memcpy(&((r)->dIP), (in_addr), sizeof(ipUnion));    \
        } else if (_recIsIPv6(r)) {                             \
            /* convert V4 IP to V6 */                           \
            ipUnion4to6(&((in_addr)->ip_ip), &((r)->dIP));      \
        } else {                                                \
            /* must convert record to V6 */                     \
            _recConvertToIPv6(r);                               \
            memcpy(&((r)->dIP), (in_addr), sizeof(ipUnion));    \
        }                                                       \
    } while(0)
#define _recMemCmpDIP(r, addr)      rwrec_MemCmpDIP(r, addr)
#define _recApplyMaskDIP(r, addr)   rwrec_ApplyMaskDIP(r, addr)
#endif /* SK_ENABLE_IPV6 */

#if RWREC_OPAQUE
#  define rwRecMemGetDIP(r, out_addr)   rwrec_MemGetDIP(r, out_addr)
#  define rwRecMemSetDIP(r, in_addr)    rwrec_MemSetDIP(r, in_addr)
#  define rwRecMemCmpDIP(r, addr)       rwrec_MemCmpDIP(r, addr)
#  define rwRecApplyMaskDIP(r, addr)    rwrec_ApplyMaskDIP(r, addr)
#else
#  define rwRecMemGetDIP(r, out_addr)   _recMemGetDIP(r, out_addr)
#  define rwRecMemSetDIP(r, in_addr)    _recMemSetDIP(r, in_addr)
#  define rwRecMemCmpDIP(r, addr)       _recMemCmpDIP(r, addr)
#  define rwRecApplyMaskDIP(r, addr)    _recApplyMaskDIP(r, addr)
#endif /* RWREC_OPAQUE */


/***  Next Hop IP (nhIP) Address  ***/

uint32_t rwrec_GetNhIPv4(const rwRec *r);
void     rwrec_SetNhIPv4(rwRec *r, uint32_t in_v);
void     rwrec_MemGetNhIPv4(const rwRec *r, void *out_vp);
void     rwrec_MemSetNhIPv4(rwRec *r, const void *in_vp);
int      rwrec_MemCmpNhIPv4(const rwRec *r, const void *vp);
uint32_t rwrec_GetMaskNhIPv4(const rwRec *r, uint32_t mask);
void     rwrec_ApplyMaskNhIPv4(rwRec *r, uint32_t mask);

#define _recGetNhIPv4(r)                        \
    ((r)->nhIP.ipu_ipv4)
#define _recSetNhIPv4(r, in_v)                  \
    { ((r)->nhIP.ipu_ipv4) = (in_v); }
#define _recMemGetNhIPv4(r, out_vp)                             \
    memcpy((out_vp), &((r)->nhIP.ipu_ipv4), RWREC_SIZEOF_NHIPv4)
#define _recMemSetNhIPv4(r, in_vp)                              \
    memcpy(&((r)->nhIP.ipu_ipv4), (in_vp), RWREC_SIZEOF_NHIPv4)
#define _recMemCmpNhIPv4(r, vp)                         \
    memcmp(&((r)->nhIP.ipu_ipv4), (vp), RWREC_SIZEOF_NHIPv4)
#define _recGetMaskNhIPv4(r, mask)              \
    (((r)->nhIP.ipu_ipv4) & mask)
#define _recApplyMaskNhIPv4(r, mask)            \
    ipUnionApplyMaskV4(&((r)->nhIP), (mask))


#if RWREC_OPAQUE
#  define rwRecGetNhIPv4(r)             rwrec_GetNhIPv4(r)
#  define rwRecSetNhIPv4(r, in_v)       rwrec_SetNhIPv4(r, in_v)
#  define rwRecMemGetNhIPv4(r, out_vp)  rwrec_MemGetNhIPv4(r, out_vp)
#  define rwRecMemSetNhIPv4(r, in_vp)   rwrec_MemSetNhIPv4(r, in_vp)
#  define rwRecMemCmpNhIPv4(r, vp)      rwrec_MemCmpNhIPv4(r, vp)
#  define rwRecGetMaskNhIPv4(r, mask)   rwrec_GetMaskNhIPv4(r, mask)
#  define rwRecApplyMaskNhIPv4(r, mask) rwrec_ApplyMaskNhIPv4(r, mask)
#else
#  define rwRecGetNhIPv4(r)             _recGetNhIPv4(r)
#  define rwRecSetNhIPv4(r, in_v)       _recSetNhIPv4(r, in_v)
#  define rwRecMemGetNhIPv4(r, out_vp)  _recMemGetNhIPv4(r, out_vp)
#  define rwRecMemSetNhIPv4(r, in_vp)   _recMemSetNhIPv4(r, in_vp)
#  define rwRecMemCmpNhIPv4(r, vp)      _recMemCmpNhIPv4(r, vp)
#  define rwRecGetMaskNhIPv4(r, mask)   _recGetMaskNhIPv4(r, mask)
#  define rwRecApplyMaskNhIPv4(r, mask) _recApplyMaskNhIPv4(r, mask)
#endif /* RWREC_OPAQUE */


/***  Next Hop IPv6 Address (nhIP)  ***/

#if SK_ENABLE_IPV6

void     rwrec_MemGetNhIPv6(const rwRec *r, void *out_vp);
void     rwrec_MemSetNhIPv6(rwRec *r, const void *in_vp);
int      rwrec_MemCmpNhIPv6(const rwRec *r, const void *vp);
void     rwrec_ApplyMaskNhIPv6(rwRec *r, const void *mask_vp);

#define _recMemGetNhIPv6(r, out_vp)                                     \
    if (_recIsIPv6(r)) {                                                \
        ipUnionGetV6(&((r)->nhIP), (out_vp));                           \
    } else {                                                            \
        ipUnionGetV4AsV6(&((r)->nhIP), (out_vp));                       \
    }
#define _recMemSetNhIPv6(r, in_vp)                              \
    memcpy(&((r)->nhIP.ipu_ipv6), (in_vp), RWREC_SIZEOF_NHIPv6)
#define _recMemCmpNhIPv6(r, vp)                                 \
    memcmp(&((r)->nhIP.ipu_ipv6), (vp), RWREC_SIZEOF_NHIPv6)
#define _recApplyMaskNhIPv6(r, mask)             \
    ipUnionApplyMaskV6(&((r)->nhIP), (mask))

#if RWREC_OPAQUE
#  define rwRecMemGetNhIPv6(r, out_vp)   rwrec_MemGetNhIPv6(r, out_vp)
#  define rwRecMemSetNhIPv6(r, in_vp)    rwrec_MemSetNhIPv6(r, in_vp)
#  define rwRecMemCmpNhIPv6(r, vp)       rwrec_MemCmpNhIPv6(r, vp)
#  define rwRecApplyMaskNhIPv6(r, mask)  rwrec_ApplyMaskNhIPv6(r, mask)
#else
#  define rwRecMemGetNhIPv6(r, out_vp)   _recMemGetNhIPv6(r, out_vp)
#  define rwRecMemSetNhIPv6(r, in_vp)    _recMemSetNhIPv6(r, in_vp)
#  define rwRecMemCmpNhIPv6(r, vp)       _recMemCmpNhIPv6(r, vp)
#  define rwRecApplyMaskNhIPv6(r, mask)  _recApplyMaskNhIPv6(r, mask)
#endif /* RWREC_OPAQUE */

#endif /* SK_ENABLE_IPV6 */


/***  Next Hop IP Address (nhIP) as skipaddr_t  ***/

void     rwrec_MemGetNhIP(const rwRec *r, skipaddr_t *out_addr);
void     rwrec_MemSetNhIP(rwRec *r, const skipaddr_t *in_addr);
int      rwrec_MemCmpNhIP(const rwRec *r, const skipaddr_t *addr);
void     rwrec_ApplyMaskNhIP(rwRec *r, const skipaddr_t *mask_addr);

#if !SK_ENABLE_IPV6
#define _recMemGetNhIP    _recMemGetNhIPv4
#define _recMemSetNhIP    _recMemSetNhIPv4
#define _recMemCmpNhIP(r, addr)                         \
    _recMemCmpNhIPv4((r), &((addr)->ip_ip.ipu_ipv4))
#define _recApplyMaskNhIP(r, addr)                      \
    _recApplyMaskNhIPv4((r), (addr)->ip_ip.ipu_ipv4)
#else
#define _recMemGetNhIP(r, out_addr)                             \
    do {                                                        \
        memcpy(out_addr, &((r)->nhIP), sizeof(ipUnion));        \
        skipaddrSetVersion((out_addr), _recIsIPv6(r));          \
    } while(0)
#define _recMemSetNhIP(r, in_addr)                              \
    do {                                                        \
        if (skipaddrIsV6(in_addr) == _recIsIPv6(r)) {           \
            /* both are either V4 or V6 */                      \
            memcpy(&((r)->nhIP), (in_addr), sizeof(ipUnion));   \
        } else if (_recIsIPv6(r)) {                             \
            /* convert V4 IP to V6 */                           \
            ipUnion4to6(&((in_addr)->ip_ip), &((r)->nhIP));     \
        } else {                                                \
            /* must convert record to V6 */                     \
            _recConvertToIPv6(r);                               \
            memcpy(&((r)->nhIP), (in_addr), sizeof(ipUnion));   \
        }                                                       \
    } while(0)
#define _recMemCmpNhIP(r, addr)     rwrec_MemCmpNhIP(r, addr)
#define _recApplyMaskNhIP(r, addr)  rwrec_ApplyMaskNhIP(r, addr)
#endif /* SK_ENABLE_IPV6 */

#if RWREC_OPAQUE
#  define rwRecMemGetNhIP(r, out_addr)  rwrec_MemGetNhIP(r, out_addr)
#  define rwRecMemSetNhIP(r, in_addr)   rwrec_MemSetNhIP(r, in_addr)
#  define rwRecMemCmpNhIP(r, addr)      rwrec_MemCmpNhIP(r, addr)
#  define rwRecApplyMaskNhIP(r, addr)   rwrec_ApplyMaskNhIP(r, addr)
#else
#  define rwRecMemGetNhIP(r, out_addr)  _recMemGetNhIP(r, out_addr)
#  define rwRecMemSetNhIP(r, in_addr)   _recMemSetNhIP(r, in_addr)
#  define rwRecMemCmpNhIP(r, addr)      _recMemCmpNhIP(r, addr)
#  define rwRecApplyMaskNhIP(r, addr)   _recApplyMaskNhIP(r, addr)
#endif /* RWREC_OPAQUE */


/***  Source Port (sPort)  ***/

uint16_t rwrec_GetSPort(const rwRec *r);
void     rwrec_SetSPort(rwRec *r, uint16_t in_v);
void     rwrec_MemGetSPort(const rwRec *r, void *out_vp);
void     rwrec_MemSetSPort(rwRec *r, const void *in_vp);
int      rwrec_MemCmpSPort(const rwRec *r, const void *vp);

#define _recGetSPort(r)                         \
    ((r)->sPort)
#define _recSetSPort(r, in_v)                   \
    { ((r)->sPort) = (in_v); }
#define _recMemGetSPort(r, out_vp)                      \
    memcpy((out_vp), &((r)->sPort), RWREC_SIZEOF_SPORT)
#define _recMemSetSPort(r, in_vp)                       \
    memcpy(&((r)->sPort), (in_vp), RWREC_SIZEOF_SPORT)
#define _recMemCmpSPort(r, vp)                          \
    memcmp(&((r)->sPort), (vp), RWREC_SIZEOF_SPORT)

#if RWREC_OPAQUE
#  define rwRecGetSPort(r)  rwrec_GetSPort(r)
#  define rwRecSetSPort(r, in_v)  rwrec_SetSPort(r, in_v)
#  define rwRecMemGetSPort(r, out_vp)  rwrec_MemGetSPort(r, out_vp)
#  define rwRecMemSetSPort(r, in_vp)  rwrec_MemSetSPort(r, in_vp)
#  define rwRecMemCmpSPort(r, vp)  rwrec_MemCmpSPort(r, vp)
#else
#  define rwRecGetSPort(r)  _recGetSPort(r)
#  define rwRecSetSPort(r, in_v)  _recSetSPort(r, in_v)
#  define rwRecMemGetSPort(r, out_vp)  _recMemGetSPort(r, out_vp)
#  define rwRecMemSetSPort(r, in_vp)  _recMemSetSPort(r, in_vp)
#  define rwRecMemCmpSPort(r, vp)  _recMemCmpSPort(r, vp)
#endif /* RWREC_OPAQUE */


/***  Destination Port (dPort)  ***/

uint16_t rwrec_GetDPort(const rwRec *r);
void     rwrec_SetDPort(rwRec *r, uint16_t in_v);
void     rwrec_MemGetDPort(const rwRec *r, void *out_vp);
void     rwrec_MemSetDPort(rwRec *r, const void *in_vp);
int      rwrec_MemCmpDPort(const rwRec *r, const void *vp);

#define _recGetDPort(r)                         \
    ((r)->dPort)
#define _recSetDPort(r, in_v)                   \
    { ((r)->dPort) = (in_v); }
#define _recMemGetDPort(r, out_vp)                      \
    memcpy((out_vp), &((r)->dPort), RWREC_SIZEOF_DPORT)
#define _recMemSetDPort(r, in_vp)                       \
    memcpy(&((r)->dPort), (in_vp), RWREC_SIZEOF_DPORT)
#define _recMemCmpDPort(r, vp)                          \
    memcmp(&((r)->dPort), (vp), RWREC_SIZEOF_DPORT)

#if RWREC_OPAQUE
#  define rwRecGetDPort(r)  rwrec_GetDPort(r)
#  define rwRecSetDPort(r, in_v)  rwrec_SetDPort(r, in_v)
#  define rwRecMemGetDPort(r, out_vp)  rwrec_MemGetDPort(r, out_vp)
#  define rwRecMemSetDPort(r, in_vp)  rwrec_MemSetDPort(r, in_vp)
#  define rwRecMemCmpDPort(r, vp)  rwrec_MemCmpDPort(r, vp)
#else
#  define rwRecGetDPort(r)  _recGetDPort(r)
#  define rwRecSetDPort(r, in_v)  _recSetDPort(r, in_v)
#  define rwRecMemGetDPort(r, out_vp)  _recMemGetDPort(r, out_vp)
#  define rwRecMemSetDPort(r, in_vp)  _recMemSetDPort(r, in_vp)
#  define rwRecMemCmpDPort(r, vp)  _recMemCmpDPort(r, vp)
#endif /* RWREC_OPAQUE */


/***  Protocol  ***/

uint8_t  rwrec_GetProto(const rwRec *r);
void     rwrec_SetProto(rwRec *r, uint8_t in_v);
void     rwrec_MemGetProto(const rwRec *r, void *out_vp);
void     rwrec_MemSetProto(rwRec *r, const void *in_vp);
int      rwrec_MemCmpProto(const rwRec *r, const void *vp);

#define _recGetProto(r)                         \
    ((r)->proto)
#define _recSetProto(r, in_v)                   \
    { ((r)->proto) = (in_v); }
#define _recMemGetProto(r, out_vp)                      \
    memcpy((out_vp), &((r)->proto), RWREC_SIZEOF_PROTO)
#define _recMemSetProto(r, in_vp)                       \
    memcpy(&((r)->proto), (in_vp), RWREC_SIZEOF_PROTO)
#define _recMemCmpProto(r, vp)                          \
    memcmp(&((r)->proto), (vp), RWREC_SIZEOF_PROTO)

#if RWREC_OPAQUE
#  define rwRecGetProto(r)  rwrec_GetProto(r)
#  define rwRecSetProto(r, in_v)  rwrec_SetProto(r, in_v)
#  define rwRecMemGetProto(r, out_vp)  rwrec_MemGetProto(r, out_vp)
#  define rwRecMemSetProto(r, in_vp)  rwrec_MemSetProto(r, in_vp)
#  define rwRecMemCmpProto(r, vp)  rwrec_MemCmpProto(r, vp)
#else
#  define rwRecGetProto(r)  _recGetProto(r)
#  define rwRecSetProto(r, in_v)  _recSetProto(r, in_v)
#  define rwRecMemGetProto(r, out_vp)  _recMemGetProto(r, out_vp)
#  define rwRecMemSetProto(r, in_vp)  _recMemSetProto(r, in_vp)
#  define rwRecMemCmpProto(r, vp)  _recMemCmpProto(r, vp)
#endif /* RWREC_OPAQUE */


/***  Packet Count (pkts)  ***/

uint32_t rwrec_GetPkts(const rwRec *r);
void     rwrec_SetPkts(rwRec *r, uint32_t in_v);
void     rwrec_MemGetPkts(const rwRec *r, void *out_vp);
void     rwrec_MemSetPkts(rwRec *r, const void *in_vp);
int      rwrec_MemCmpPkts(const rwRec *r, const void *vp);

#define _recGetPkts(r)                          \
    ((r)->pkts)
#define _recSetPkts(r, in_v)                    \
    { ((r)->pkts) = (in_v); }
#define _recMemGetPkts(r, out_vp)                       \
    memcpy((out_vp), &((r)->pkts), RWREC_SIZEOF_PKTS)
#define _recMemSetPkts(r, in_vp)                        \
    memcpy(&((r)->pkts), (in_vp), RWREC_SIZEOF_PKTS)
#define _recMemCmpPkts(r, vp)                           \
    memcmp(&((r)->pkts), (vp), RWREC_SIZEOF_PKTS)

#if RWREC_OPAQUE
#  define rwRecGetPkts(r)  rwrec_GetPkts(r)
#  define rwRecSetPkts(r, in_v)  rwrec_SetPkts(r, in_v)
#  define rwRecMemGetPkts(r, out_vp)  rwrec_MemGetPkts(r, out_vp)
#  define rwRecMemSetPkts(r, in_vp)  rwrec_MemSetPkts(r, in_vp)
#  define rwRecMemCmpPkts(r, vp)  rwrec_MemCmpPkts(r, vp)
#else
#  define rwRecGetPkts(r)  _recGetPkts(r)
#  define rwRecSetPkts(r, in_v)  _recSetPkts(r, in_v)
#  define rwRecMemGetPkts(r, out_vp)  _recMemGetPkts(r, out_vp)
#  define rwRecMemSetPkts(r, in_vp)  _recMemSetPkts(r, in_vp)
#  define rwRecMemCmpPkts(r, vp)  _recMemCmpPkts(r, vp)
#endif /* RWREC_OPAQUE */


/***  Byte count  ***/

uint32_t rwrec_GetBytes(const rwRec *r);
void     rwrec_SetBytes(rwRec *r, uint32_t in_v);
void     rwrec_MemGetBytes(const rwRec *r, void *out_vp);
void     rwrec_MemSetBytes(rwRec *r, const void *in_vp);
int      rwrec_MemCmpBytes(const rwRec *r, const void *vp);

#define _recGetBytes(r)                         \
    ((r)->bytes)
#define _recSetBytes(r, in_v)                   \
    { ((r)->bytes) = (in_v); }
#define _recMemGetBytes(r, out_vp)                      \
    memcpy((out_vp), &((r)->bytes), RWREC_SIZEOF_BYTES)
#define _recMemSetBytes(r, in_vp)                       \
    memcpy(&((r)->bytes), (in_vp), RWREC_SIZEOF_BYTES)
#define _recMemCmpBytes(r, vp)                          \
    memcmp(&((r)->bytes), (vp), RWREC_SIZEOF_BYTES)

#if RWREC_OPAQUE
#  define rwRecGetBytes(r)  rwrec_GetBytes(r)
#  define rwRecSetBytes(r, in_v)  rwrec_SetBytes(r, in_v)
#  define rwRecMemGetBytes(r, out_vp)  rwrec_MemGetBytes(r, out_vp)
#  define rwRecMemSetBytes(r, in_vp)  rwrec_MemSetBytes(r, in_vp)
#  define rwRecMemCmpBytes(r, vp)  rwrec_MemCmpBytes(r, vp)
#else
#  define rwRecGetBytes(r)  _recGetBytes(r)
#  define rwRecSetBytes(r, in_v)  _recSetBytes(r, in_v)
#  define rwRecMemGetBytes(r, out_vp)  _recMemGetBytes(r, out_vp)
#  define rwRecMemSetBytes(r, in_vp)  _recMemSetBytes(r, in_vp)
#  define rwRecMemCmpBytes(r, vp)  _recMemCmpBytes(r, vp)
#endif /* RWREC_OPAQUE */


/***  Bitwise OR of TCP Flags on ALL packets in flow  ***/

uint8_t  rwrec_GetFlags(const rwRec *r);
void     rwrec_SetFlags(rwRec *r, uint8_t in_v);
void     rwrec_MemGetFlags(const rwRec *r, void *out_vp);
void     rwrec_MemSetFlags(rwRec *r, const void *in_vp);
int      rwrec_MemCmpFlags(const rwRec *r, const void *vp);

#define _recGetFlags(r)                         \
    ((r)->flags)
#define _recSetFlags(r, in_v)                   \
    { ((r)->flags) = (in_v); }
#define _recMemGetFlags(r, out_vp)                      \
    memcpy((out_vp), &((r)->flags), RWREC_SIZEOF_FLAGS)
#define _recMemSetFlags(r, in_vp)                       \
    memcpy(&((r)->flags), (in_vp), RWREC_SIZEOF_FLAGS)
#define _recMemCmpFlags(r, vp)                          \
    memcmp(&((r)->flags), (vp), RWREC_SIZEOF_FLAGS)

#if RWREC_OPAQUE
#  define rwRecGetFlags(r)  rwrec_GetFlags(r)
#  define rwRecSetFlags(r, in_v)  rwrec_SetFlags(r, in_v)
#  define rwRecMemGetFlags(r, out_vp)  rwrec_MemGetFlags(r, out_vp)
#  define rwRecMemSetFlags(r, in_vp)  rwrec_MemSetFlags(r, in_vp)
#  define rwRecMemCmpFlags(r, vp)  rwrec_MemCmpFlags(r, vp)
#else
#  define rwRecGetFlags(r)  _recGetFlags(r)
#  define rwRecSetFlags(r, in_v)  _recSetFlags(r, in_v)
#  define rwRecMemGetFlags(r, out_vp)  _recMemGetFlags(r, out_vp)
#  define rwRecMemSetFlags(r, in_vp)  _recMemSetFlags(r, in_vp)
#  define rwRecMemCmpFlags(r, vp)  _recMemCmpFlags(r, vp)
#endif /* RWREC_OPAQUE */


/***  TCP Flags seen on initial packet of flow  ***/

uint8_t  rwrec_GetInitFlags(const rwRec *r);
void     rwrec_SetInitFlags(rwRec *r, uint8_t in_v);
void     rwrec_MemGetInitFlags(const rwRec *r, void *out_vp);
void     rwrec_MemSetInitFlags(rwRec *r, const void *in_vp);
int      rwrec_MemCmpInitFlags(const rwRec *r, const void *vp);

#define _recGetInitFlags(r)                     \
    ((r)->init_flags)
#define _recSetInitFlags(r, in_v)               \
    { ((r)->init_flags) = (in_v); }
#define _recMemGetInitFlags(r, out_vp)                                  \
    memcpy((out_vp), &((r)->init_flags), RWREC_SIZEOF_INIT_FLAGS)
#define _recMemSetInitFlags(r, in_vp)                                   \
    memcpy(&((r)->init_flags), (in_vp), RWREC_SIZEOF_INIT_FLAGS)
#define _recMemCmpInitFlags(r, vp)                              \
    memcmp(&((r)->init_flags), (vp), RWREC_SIZEOF_INIT_FLAGS)

#if RWREC_OPAQUE
#  define rwRecGetInitFlags(r)  rwrec_GetInitFlags(r)
#  define rwRecSetInitFlags(r, in_v)  rwrec_SetInitFlags(r, in_v)
#  define rwRecMemGetInitFlags(r, out_vp)  rwrec_MemGetInitFlags(r, out_vp)
#  define rwRecMemSetInitFlags(r, in_vp)  rwrec_MemSetInitFlags(r, in_vp)
#  define rwRecMemCmpInitFlags(r, vp)  rwrec_MemCmpInitFlags(r, vp)
#else
#  define rwRecGetInitFlags(r)  _recGetInitFlags(r)
#  define rwRecSetInitFlags(r, in_v)  _recSetInitFlags(r, in_v)
#  define rwRecMemGetInitFlags(r, out_vp)  _recMemGetInitFlags(r, out_vp)
#  define rwRecMemSetInitFlags(r, in_vp)  _recMemSetInitFlags(r, in_vp)
#  define rwRecMemCmpInitFlags(r, vp)  _recMemCmpInitFlags(r, vp)
#endif /* RWREC_OPAQUE */


/***  Bitwise OR of TCP Flags on all packets in session except first  ***/

uint8_t  rwrec_GetRestFlags(const rwRec *r);
void     rwrec_SetRestFlags(rwRec *r, uint8_t in_v);
void     rwrec_MemGetRestFlags(const rwRec *r, void *out_vp);
void     rwrec_MemSetRestFlags(rwRec *r, const void *in_vp);
int      rwrec_MemCmpRestFlags(const rwRec *r, const void *vp);

#define _recGetRestFlags(r)                     \
    ((r)->rest_flags)
#define _recSetRestFlags(r, in_v)               \
    { ((r)->rest_flags) = (in_v); }
#define _recMemGetRestFlags(r, out_vp)                                  \
    memcpy((out_vp), &((r)->rest_flags), RWREC_SIZEOF_REST_FLAGS)
#define _recMemSetRestFlags(r, in_vp)                                   \
    memcpy(&((r)->rest_flags), (in_vp), RWREC_SIZEOF_REST_FLAGS)
#define _recMemCmpRestFlags(r, vp)                              \
    memcmp(&((r)->rest_flags), (vp), RWREC_SIZEOF_REST_FLAGS)

#if RWREC_OPAQUE
#  define rwRecGetRestFlags(r)  rwrec_GetRestFlags(r)
#  define rwRecSetRestFlags(r, in_v)  rwrec_SetRestFlags(r, in_v)
#  define rwRecMemGetRestFlags(r, out_vp)  rwrec_MemGetRestFlags(r, out_vp)
#  define rwRecMemSetRestFlags(r, in_vp)  rwrec_MemSetRestFlags(r, in_vp)
#  define rwRecMemCmpRestFlags(r, vp)  rwrec_MemCmpRestFlags(r, vp)
#else
#  define rwRecGetRestFlags(r)  _recGetRestFlags(r)
#  define rwRecSetRestFlags(r, in_v)  _recSetRestFlags(r, in_v)
#  define rwRecMemGetRestFlags(r, out_vp)  _recMemGetRestFlags(r, out_vp)
#  define rwRecMemSetRestFlags(r, in_vp)  _recMemSetRestFlags(r, in_vp)
#  define rwRecMemCmpRestFlags(r, vp)  _recMemCmpRestFlags(r, vp)
#endif /* RWREC_OPAQUE */


/***  Start Time as milliseconds since UNIX epoch (sTime)  ***/

sktime_t rwrec_GetStartTime(const rwRec *r);
void     rwrec_SetStartTime(rwRec *r, sktime_t in_v);
void     rwrec_MemGetStartTime(const rwRec *r, void *out_vp);
void     rwrec_MemSetStartTime(rwRec *r, const void *in_vp);
int      rwrec_MemCmpStartTime(const rwRec *r, const void *vp);
uint32_t rwrec_GetStartSeconds(const rwRec *r);
void     rwrec_MemGetStartSeconds(const rwRec *r, void *out_vp);
uint16_t rwrec_GetStartMSec(const rwRec *r);
void     rwrec_MemGetStartMSec(const rwRec *r, void *out_vp);

#define _recGetStartTime(r)                     \
    ((r)->sTime)
#define _recSetStartTime(r, in_v)               \
    { ((r)->sTime = (in_v)); }
#define _recMemGetStartTime(r, out_vp)                  \
    memcpy((out_vp), &((r)->sTime), RWREC_SIZEOF_STIME)
#define _recMemSetStartTime(r, in_vp)                   \
    memcpy(&((r)->sTime), (in_vp), RWREC_SIZEOF_STIME)
#define _recMemCmpStartTime(r, vp)                      \
    memcmp(&((r)->sTime), (vp), RWREC_SIZEOF_STIME)

#define _recGetStartSeconds(r)                  \
    ((uint32_t)((r)->sTime / 1000))
#define _recMemGetStartSeconds(r, out_vp) {     \
        uint32_t _t = _recGetStartSeconds(r);   \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }

#define _recGetStartMSec(r)                     \
    ((uint16_t)((r)->sTime % 1000))
#define _recMemGetStartMSec(r, out_vp) {        \
        uint16_t _t = _recGetStartMSec(r);      \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }

#if RWREC_OPAQUE
#  define rwRecGetStartTime(r)  rwrec_GetStartTime(r)
#  define rwRecSetStartTime(r, in_v)  rwrec_SetStartTime(r, in_v)
#  define rwRecMemGetStartTime(r, out_vp)  rwrec_MemGetStartTime(r, out_vp)
#  define rwRecMemSetStartTime(r, in_vp)  rwrec_MemSetStartTime(r, in_vp)
#  define rwRecMemCmpStartTime(r, vp)  rwrec_MemCmpStartTime(r, vp)
#  define rwRecGetStartSeconds(r)  rwrec_GetStartSeconds(r)
#  define rwRecMemGetStartSeconds(r, out_vp)    \
    rwrec_MemGetStartSeconds(r, out_vp)
#  define rwRecGetStartMSec(r)  rwrec_GetStartMSec(r)
#  define rwRecMemGetStartMSec(r, out_vp)  rwrec_MemGetStartMSec(r, out_vp)
#else
#  define rwRecGetStartTime(r)  _recGetStartTime(r)
#  define rwRecSetStartTime(r, in_v)  _recSetStartTime(r, in_v)
#  define rwRecMemGetStartTime(r, out_vp)  _recMemGetStartTime(r, out_vp)
#  define rwRecMemSetStartTime(r, in_vp)  _recMemSetStartTime(r, in_vp)
#  define rwRecMemCmpStartTime(r, vp)  _recMemCmpStartTime(r, vp)
#  define rwRecGetStartSeconds(r)  _recGetStartSeconds(r)
#  define rwRecMemGetStartSeconds(r, out_vp)  _recMemGetStartSeconds(r, out_vp)
#  define rwRecGetStartMSec(r)  _recGetStartMSec(r)
#  define rwRecMemGetStartMSec(r, out_vp)  _recMemGetStartMSec(r, out_vp)
#endif /* RWREC_OPAQUE */


/***  Elapsed (duration) of the flow, in milliseconds  ***/

uint32_t rwrec_GetElapsed(const rwRec *r);
void     rwrec_SetElapsed(rwRec *r, sktime_t in_v);
void     rwrec_MemGetElapsed(const rwRec *r, void *out_vp);
void     rwrec_MemSetElapsed(rwRec *r, const void *in_vp);
int      rwrec_MemCmpElapsed(const rwRec *r, const void *vp);
uint32_t rwrec_GetElapsedSeconds(const rwRec *r);
void     rwrec_MemGetElapsedSeconds(const rwRec *r, void *out_vp);
uint16_t rwrec_GetElapsedMSec(const rwRec *r);
void     rwrec_MemGetElapsedMSec(const rwRec *r, void *out_vp);

#define _recGetElapsed(r)                       \
    ((r)->elapsed)
#define _recSetElapsed(r, in_v)                 \
    { (r)->elapsed = (uint32_t)(in_v); }
#define _recMemGetElapsed(r, out_vp)                            \
    memcpy((out_vp), &((r)->elapsed), RWREC_SIZEOF_ELAPSED)
#define _recMemSetElapsed(r, in_vp)                             \
    memcpy(&((r)->elapsed), (in_vp), RWREC_SIZEOF_ELAPSED)
#define _recMemCmpElapsed(r, vp)                                \
    memcmp(&((r)->elapsed), (vp), RWREC_SIZEOF_ELAPSED)

#define _recGetElapsedSeconds(r)                \
    ((uint32_t)((r)->elapsed / 1000))
#define _recMemGetElapsedSeconds(r, out_vp) {   \
        uint32_t _t = _recGetElapsedSeconds(r); \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }

#define _recGetElapsedMSec(r)                   \
    ((uint16_t)((r)->elapsed % 1000))
#define _recMemGetElapsedMSec(r, out_vp) {      \
        uint16_t _t = _recGetElapsedMSec(r);    \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }


#if RWREC_OPAQUE
#  define rwRecGetElapsed(r)  rwrec_GetElapsed(r)
#  define rwRecSetElapsed(r, in_v)  rwrec_SetElapsed(r, in_v)
#  define rwRecMemGetElapsed(r, out_vp)  rwrec_MemGetElapsed(r, out_vp)
#  define rwRecMemSetElapsed(r, in_vp)  rwrec_MemSetElapsed(r, in_vp)
#  define rwRecMemCmpElapsed(r, vp)  rwrec_MemCmpElapsed(r, vp)
#  define rwRecGetElapsedSeconds(r)  rwrec_GetElapsedSeconds(r)
#  define rwRecMemGetElapsedSeconds(r, out_vp)  \
    rwrec_MemGetElapsedSeconds(r, out_vp)
#  define rwRecGetElapsedMSec(r)  rwrec_GetElapsedMSec(r)
#  define rwRecMemGetElapsedMSec(r, out_vp)  rwrec_MemGetElapsedMSec(r, out_vp)
#else
#  define rwRecGetElapsed(r)  _recGetElapsed(r)
#  define rwRecSetElapsed(r, in_v)  _recSetElapsed(r, in_v)
#  define rwRecMemGetElapsed(r, out_vp)  _recMemGetElapsed(r, out_vp)
#  define rwRecMemSetElapsed(r, in_vp)  _recMemSetElapsed(r, in_vp)
#  define rwRecMemCmpElapsed(r, vp)  _recMemCmpElapsed(r, vp)
#  define rwRecGetElapsedSeconds(r)  _recGetElapsedSeconds(r)
#  define rwRecMemGetElapsedSeconds(r, out_vp)  \
    _recMemGetElapsedSeconds(r, out_vp)
#  define rwRecGetElapsedMSec(r)  _recGetElapsedMSec(r)
#  define rwRecMemGetElapsedMSec(r, out_vp)  _recMemGetElapsedMSec(r, out_vp)
#endif /* RWREC_OPAQUE */



/***  End Time is derived from the sTime and duration (eTime)  ***/

/* No Set macros/functions since this is a derived field */

sktime_t rwrec_GetEndTime(const rwRec *r);
void     rwrec_MemGetEndTime(const rwRec *r, void *out_vp);
uint32_t rwrec_GetEndSeconds(const rwRec *r);
void     rwrec_MemGetEndSeconds(const rwRec *r, void *out_vp);
uint16_t rwrec_GetEndMSec(const rwRec *r);
void     rwrec_MemGetEndMSec(const rwRec *r, void *out_vp);

#define _recGetEndTime(r)                               \
    ((sktime_t)_recGetStartTime(r) + _recGetElapsed(r))
#define _recMemGetEndTime(r, out_vp) {          \
        sktime_t _t = _recGetEndTime(r);        \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }
#define _recGetEndSeconds(r)                    \
    ((uint32_t)(_recGetEndTime(r) / 1000))
#define _recMemGetEndSeconds(r, out_vp) {       \
        uint32_t _t = rwRecGetEndSeconds(r);    \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }

#define _recGetEndMSec(r)                       \
    ((uint16_t)(_recGetEndTime(r) % 1000))
#define _recMemGetEndMSec(r, out_vp) {          \
        uint16_t _t = _recGetEndMSec(r);        \
        memcpy((out_vp), &_t, sizeof(_t));      \
    }

#if RWREC_OPAQUE
#  define rwRecGetEndTime(r)  rwrec_GetEndTime(r)
#  define rwRecMemGetEndTime(r, out_vp)  rwrec_MemGetEndTime(r, out_vp)
#  define rwRecGetEndSeconds(r)  rwrec_GetEndSeconds(r)
#  define rwRecMemGetEndSeconds(r, out_vp)  rwrec_MemGetEndSeconds(r, out_vp)
#  define rwRecGetEndMSec(r)  rwrec_GetEndMSec(r)
#  define rwRecMemGetEndMSec(r, out_vp)  rwrec_MemGetEndMSec(r, out_vp)
#else
#  define rwRecGetEndTime(r)  _recGetEndTime(r)
#  define rwRecMemGetEndTime(r, out_vp)  _recMemGetEndTime(r, out_vp)
#  define rwRecGetEndSeconds(r)  _recGetEndSeconds(r)
#  define rwRecMemGetEndSeconds(r, out_vp)  _recMemGetEndSeconds(r, out_vp)
#  define rwRecGetEndMSec(r)  _recGetEndMSec(r)
#  define rwRecMemGetEndMSec(r, out_vp)  _recMemGetEndMSec(r, out_vp)
#endif /* RWREC_OPAQUE */


/***  Sensor ID (sID)  ***/

sensorID_t rwrec_GetSensor(const rwRec *r);
void     rwrec_SetSensor(rwRec *r, sensorID_t in_v);
void     rwrec_MemGetSensor(const rwRec *r, void *out_vp);
void     rwrec_MemSetSensor(rwRec *r, const void *in_vp);
int      rwrec_MemCmpSensor(const rwRec *r, const void *vp);

#define _recGetSensor(r)                        \
    ((r)->sID)
#define _recSetSensor(r, in_v)                  \
    { ((r)->sID) = (in_v); }
#define _recMemGetSensor(r, out_vp)                     \
    memcpy((out_vp), &((r)->sID), RWREC_SIZEOF_SID)
#define _recMemSetSensor(r, in_vp)                      \
    memcpy(&((r)->sID), (in_vp), RWREC_SIZEOF_SID)
#define _recMemCmpSensor(r, vp)                 \
    memcmp(&((r)->sID), (vp), RWREC_SIZEOF_SID)

#if RWREC_OPAQUE
#  define rwRecGetSensor(r)  rwrec_GetSensor(r)
#  define rwRecSetSensor(r, in_v)  rwrec_SetSensor(r, in_v)
#  define rwRecMemGetSensor(r, out_vp)  rwrec_MemGetSensor(r, out_vp)
#  define rwRecMemSetSensor(r, in_vp)  rwrec_MemSetSensor(r, in_vp)
#  define rwRecMemCmpSensor(r, vp)  rwrec_MemCmpSensor(r, vp)
#else
#  define rwRecGetSensor(r)  _recGetSensor(r)
#  define rwRecSetSensor(r, in_v)  _recSetSensor(r, in_v)
#  define rwRecMemGetSensor(r, out_vp)  _recMemGetSensor(r, out_vp)
#  define rwRecMemSetSensor(r, in_vp)  _recMemSetSensor(r, in_vp)
#  define rwRecMemCmpSensor(r, vp)  _recMemCmpSensor(r, vp)
#endif /* RWREC_OPAQUE */


/***  FlowType holds Class and Type  ***/

flowtypeID_t rwrec_GetFlowType(const rwRec *r);
void         rwrec_SetFlowType(rwRec *r, flowtypeID_t in_v);
void         rwrec_MemGetFlowType(const rwRec *r, void *out_vp);
void         rwrec_MemSetFlowType(rwRec *r, const void *in_vp);
int          rwrec_MemCmpFlowType(const rwRec *r, const void *vp);

#define _recGetFlowType(r)                      \
    ((r)->flow_type)
#define _recSetFlowType(r, in_v)                \
    { ((r)->flow_type) = (in_v); }
#define _recMemGetFlowType(r, out_vp)                           \
    memcpy((out_vp), &((r)->flow_type), RWREC_SIZEOF_FLOW_TYPE)
#define _recMemSetFlowType(r, in_vp)                            \
    memcpy(&((r)->flow_type), (in_vp), RWREC_SIZEOF_FLOW_TYPE)
#define _recMemCmpFlowType(r, vp)                               \
    memcmp(&((r)->flow_type), (vp), RWREC_SIZEOF_FLOW_TYPE)

#if RWREC_OPAQUE
#  define rwRecGetFlowType(r)  rwrec_GetFlowType(r)
#  define rwRecSetFlowType(r, in_v)  rwrec_SetFlowType(r, in_v)
#  define rwRecMemGetFlowType(r, out_vp)  rwrec_MemGetFlowType(r, out_vp)
#  define rwRecMemSetFlowType(r, in_vp)  rwrec_MemSetFlowType(r, in_vp)
#  define rwRecMemCmpFlowType(r, vp)  rwrec_MemCmpFlowType(r, vp)
#else
#  define rwRecGetFlowType(r)  _recGetFlowType(r)
#  define rwRecSetFlowType(r, in_v)  _recSetFlowType(r, in_v)
#  define rwRecMemGetFlowType(r, out_vp)  _recMemGetFlowType(r, out_vp)
#  define rwRecMemSetFlowType(r, in_vp)  _recMemSetFlowType(r, in_vp)
#  define rwRecMemCmpFlowType(r, vp)  _recMemCmpFlowType(r, vp)
#endif /* RWREC_OPAQUE */


/***  SNMP Input Value (Router incoming/ingress interface)  ***/

uint16_t rwrec_GetInput(const rwRec *r);
void     rwrec_SetInput(rwRec *r, uint16_t in_v);
void     rwrec_MemGetInput(const rwRec *r, void *out_vp);
void     rwrec_MemSetInput(rwRec *r, const void *in_vp);
int      rwrec_MemCmpInput(const rwRec *r, const void *vp);

#define _recGetInput(r)                         \
    ((r)->input)
#define _recSetInput(r, in_v)                   \
    { ((r)->input) = (in_v); }
#define _recMemGetInput(r, out_vp)                      \
    memcpy((out_vp), &((r)->input), RWREC_SIZEOF_INPUT)
#define _recMemSetInput(r, in_vp)                       \
    memcpy(&((r)->input), (in_vp), RWREC_SIZEOF_INPUT)
#define _recMemCmpInput(r, vp)                          \
    memcmp(&((r)->input), (vp), RWREC_SIZEOF_INPUT)

#if RWREC_OPAQUE
#  define rwRecGetInput(r)  rwrec_GetInput(r)
#  define rwRecSetInput(r, in_v)  rwrec_SetInput(r, in_v)
#  define rwRecMemGetInput(r, out_vp)  rwrec_MemGetInput(r, out_vp)
#  define rwRecMemSetInput(r, in_vp)  rwrec_MemSetInput(r, in_vp)
#  define rwRecMemCmpInput(r, vp)  rwrec_MemCmpInput(r, vp)
#else
#  define rwRecGetInput(r)  _recGetInput(r)
#  define rwRecSetInput(r, in_v)  _recSetInput(r, in_v)
#  define rwRecMemGetInput(r, out_vp)  _recMemGetInput(r, out_vp)
#  define rwRecMemSetInput(r, in_vp)  _recMemSetInput(r, in_vp)
#  define rwRecMemCmpInput(r, vp)  _recMemCmpInput(r, vp)
#endif /* RWREC_OPAQUE */


/***  SNMP Output Value  (Router outgoing/egress interface)  ***/

uint16_t rwrec_GetOutput(const rwRec *r);
void     rwrec_SetOutput(rwRec *r, uint16_t in_v);
void     rwrec_MemGetOutput(const rwRec *r, void *out_vp);
void     rwrec_MemSetOutput(rwRec *r, const void *in_vp);
int      rwrec_MemCmpOutput(const rwRec *r, const void *vp);

#define _recGetOutput(r)                        \
    ((r)->output)
#define _recSetOutput(r, in_v)                  \
    { ((r)->output) = (in_v); }
#define _recMemGetOutput(r, out_vp)                             \
    memcpy((out_vp), &((r)->output), RWREC_SIZEOF_OUTPUT)
#define _recMemSetOutput(r, in_vp)                              \
    memcpy(&((r)->output), (in_vp), RWREC_SIZEOF_OUTPUT)
#define _recMemCmpOutput(r, vp)                         \
    memcmp(&((r)->output), (vp), RWREC_SIZEOF_OUTPUT)

#if RWREC_OPAQUE
#  define rwRecGetOutput(r)  rwrec_GetOutput(r)
#  define rwRecSetOutput(r, in_v)  rwrec_SetOutput(r, in_v)
#  define rwRecMemGetOutput(r, out_vp)  rwrec_MemGetOutput(r, out_vp)
#  define rwRecMemSetOutput(r, in_vp)  rwrec_MemSetOutput(r, in_vp)
#  define rwRecMemCmpOutput(r, vp)  rwrec_MemCmpOutput(r, vp)
#else
#  define rwRecGetOutput(r)  _recGetOutput(r)
#  define rwRecSetOutput(r, in_v)  _recSetOutput(r, in_v)
#  define rwRecMemGetOutput(r, out_vp)  _recMemGetOutput(r, out_vp)
#  define rwRecMemSetOutput(r, in_vp)  _recMemSetOutput(r, in_vp)
#  define rwRecMemCmpOutput(r, vp)  _recMemCmpOutput(r, vp)
#endif /* RWREC_OPAQUE */


/***  TCP State  ***/

uint8_t  rwrec_GetTcpState(const rwRec *r);
void     rwrec_SetTcpState(rwRec *r, uint8_t in_v);
void     rwrec_MemGetTcpState(const rwRec *r, void *out_vp);
void     rwrec_MemSetTcpState(rwRec *r, const void *in_vp);
int      rwrec_MemCmpTcpState(const rwRec *r, const void *vp);

#define _recGetTcpState(r)                      \
    ((uint8_t)((r)->tcp_state & 0x7F))
#define _recSetTcpState(r, in_v)                \
    { ((r)->tcp_state) = ((r)->tcp_state & 0x80) | (0x7F & (in_v)); }
#define _recMemGetTcpState(r, out_vp)                   \
    { *((uint8_t*)(out_vp)) = _recGetTcpState(r); }
#define _recMemSetTcpState(r, in_vp)            \
    _recSetTcpState((r), *((uint8_t*)(in_vp)))
#define _recMemCmpTcpState(r, vp)                                       \
    ((int)(_recGetTcpState(r) - (uint8_t)(0x7f & *((uint8_t*)(vp)))))

#if RWREC_OPAQUE
#  define rwRecGetTcpState(r)  rwrec_GetTcpState(r)
#  define rwRecSetTcpState(r, in_v)  rwrec_SetTcpState(r, in_v)
#  define rwRecMemGetTcpState(r, out_vp)  rwrec_MemGetTcpState(r, out_vp)
#  define rwRecMemSetTcpState(r, in_vp)  rwrec_MemSetTcpState(r, in_vp)
#  define rwRecMemCmpTcpState(r, vp)  rwrec_MemCmpTcpState(r, vp)
#else
#  define rwRecGetTcpState(r)  _recGetTcpState(r)
#  define rwRecSetTcpState(r, in_v)  _recSetTcpState(r, in_v)
#  define rwRecMemGetTcpState(r, out_vp)  _recMemGetTcpState(r, out_vp)
#  define rwRecMemSetTcpState(r, in_vp)  _recMemSetTcpState(r, in_vp)
#  define rwRecMemCmpTcpState(r, vp)  _recMemCmpTcpState(r, vp)
#endif /* RWREC_OPAQUE */


/***  Application  ***/

uint16_t rwrec_GetApplication(const rwRec *r);
void     rwrec_SetApplication(rwRec *r, uint16_t in_v);
void     rwrec_MemGetApplication(const rwRec *r, void *out_vp);
void     rwrec_MemSetApplication(rwRec *r, const void *in_vp);
int      rwrec_MemCmpApplication(const rwRec *r, const void *vp);

#define _recGetApplication(r)                   \
    ((r)->application)
#define _recSetApplication(r, in_v)             \
    { ((r)->application) = (in_v); }
#define _recMemGetApplication(r, out_vp)                                \
    memcpy((out_vp), &((r)->application), RWREC_SIZEOF_APPLICATION)
#define _recMemSetApplication(r, in_vp)                                 \
    memcpy(&((r)->application), (in_vp), RWREC_SIZEOF_APPLICATION)
#define _recMemCmpApplication(r, vp)                            \
    memcmp(&((r)->application), (vp), RWREC_SIZEOF_APPLICATION)

#if RWREC_OPAQUE
#  define rwRecGetApplication(r)  rwrec_GetApplication(r)
#  define rwRecSetApplication(r, in_v)  rwrec_SetApplication(r, in_v)
#  define rwRecMemGetApplication(r, out_vp)  rwrec_MemGetApplication(r, out_vp)
#  define rwRecMemSetApplication(r, in_vp)  rwrec_MemSetApplication(r, in_vp)
#  define rwRecMemCmpApplication(r, vp)  rwrec_MemCmpApplication(r, vp)
#else
#  define rwRecGetApplication(r)  _recGetApplication(r)
#  define rwRecSetApplication(r, in_v)  _recSetApplication(r, in_v)
#  define rwRecMemGetApplication(r, out_vp)  _recMemGetApplication(r, out_vp)
#  define rwRecMemSetApplication(r, in_vp)  _recMemSetApplication(r, in_vp)
#  define rwRecMemCmpApplication(r, vp)  _recMemCmpApplication(r, vp)
#endif /* RWREC_OPAQUE */


/***  Memo  ***/

uint16_t rwrec_GetMemo(const rwRec *r);
void     rwrec_SetMemo(rwRec *r, uint16_t in_v);
void     rwrec_MemGetMemo(const rwRec *r, void *out_vp);
void     rwrec_MemSetMemo(rwRec *r, const void *in_vp);
int      rwrec_MemCmpMemo(const rwRec *r, const void *vp);

#define _recGetMemo(r)                          \
    ((r)->memo)
#define _recSetMemo(r, in_v)                    \
    { ((r)->memo) = (in_v); }
#define _recMemGetMemo(r, out_vp)                       \
    memcpy((out_vp), &((r)->memo), RWREC_SIZEOF_MEMO)
#define _recMemSetMemo(r, in_vp)                        \
    memcpy(&((r)->memo), (in_vp), RWREC_SIZEOF_MEMO)
#define _recMemCmpMemo(r, vp)                           \
    memcmp(&((r)->memo), (vp), RWREC_SIZEOF_MEMO)

#if RWREC_OPAQUE
#  define rwRecGetMemo(r)  rwrec_GetMemo(r)
#  define rwRecSetMemo(r, in_v)  rwrec_SetMemo(r, in_v)
#  define rwRecMemGetMemo(r, out_vp)  rwrec_MemGetMemo(r, out_vp)
#  define rwRecMemSetMemo(r, in_vp)  rwrec_MemSetMemo(r, in_vp)
#  define rwRecMemCmpMemo(r, vp)  rwrec_MemCmpMemo(r, vp)
#else
#  define rwRecGetMemo(r)  _recGetMemo(r)
#  define rwRecSetMemo(r, in_v)  _recSetMemo(r, in_v)
#  define rwRecMemGetMemo(r, out_vp)  _recMemGetMemo(r, out_vp)
#  define rwRecMemSetMemo(r, in_vp)  _recMemSetMemo(r, in_vp)
#  define rwRecMemCmpMemo(r, vp)  _recMemCmpMemo(r, vp)
#endif /* RWREC_OPAQUE */


/***  ICMP Type and Code is derived from the DPort  ***/

/*
 *    In NetFlow, Cisco has traditionally encoded the ICMP type and
 *    code in the DESTPORT field as (type << 8 | code); however, some
 *    routers encode it in the SRCPORT field as (code << 8 | type)
 *    (basically byteswapping the 32-bit "SRCPORT DESTPORT" value).
 *
 *    Our current packing code will modify these odd SRCPORT encodings
 *    to be in the more traditional DESTPORT encoding when the record
 *    is initially packed, though these macros will work for the
 *    window before our packing code was modified.  If the DESTPORT is
 *    non-zero, we assume it contains the ICMP values; otherwise, we
 *    look at the SRCPORT values.  Note that these functions/macros do
 *    not check the protocol.
 */
uint8_t  rwrec_GetIcmpType(const rwRec *r);
void     rwrec_SetIcmpType(rwRec *r, uint8_t in_v);
void     rwrec_MemGetIcmpType(const rwRec *r, void *out_vp);
uint8_t  rwrec_GetIcmpCode(const rwRec *r);
void     rwrec_SetIcmpCode(rwRec *r, uint8_t in_v);
void     rwrec_MemGetIcmpCode(const rwRec *r, void *out_vp);

#define  rwrec_GetIcmpTypeAndCode    rwrec_GetDPort
#define  rwrec_SetIcmpTypeAndCode    rwrec_SetDPort
#define  rwrec_MemGetIcmpTypeAndCode rwrec_MemGetDPort
#define  rwrec_MemSetIcmpTypeAndCode rwrec_MemSetDPort
#define  rwrec_MemCmpIcmpTypeAndCode rwrec_MemCmpDPort

#define _recGetIcmpType(r)                      \
    ((uint8_t)(0xFF & ((r)->dPort >> 8)))
#define _recSetIcmpType(r, in_v)                                        \
    { (r)->dPort = ((((in_v) & 0xFF) << 8) | ((r)->dPort & 0x00FF)); }
#define _recMemGetIcmpType(r, out_vp)           \
    { *out_vp = _recGetIcmpType(r); }

#define _recGetIcmpCode(r)                      \
    ((uint8_t)(0xFF & (r)->dPort))
#define _recSetIcmpCode(r, in_v)                                \
    { (r)->dPort = (((r)->dPort & 0xFF00) | ((in_v) & 0xFF)); }
#define _recMemGetIcmpCode(r, out_vp)           \
    { *out_vp = rwRecGetIcmpCode(r); }

#if RWREC_OPAQUE
#  define rwRecGetIcmpType(r)  rwrec_GetIcmpType(r)
#  define rwRecSetIcmpType(r, in_v)  rwrec_SetIcmpType(r, in_v)
#  define rwRecMemGetIcmpType(r, out_vp)  rwrec_MemGetIcmpType(r, out_vp)

#  define rwRecGetIcmpCode(r)  rwrec_GetIcmpCode(r)
#  define rwRecSetIcmpCode(r, in_v)  rwrec_SetIcmpCode(r, in_v)
#  define rwRecMemGetIcmpCode(r, out_vp)  rwrec_MemGetIcmpCode(r, out_vp)

#  define rwRecGetIcmpTypeAndCode(r)  rwrec_GetIcmpTypeAndCode(r)
#  define rwRecSetIcmpTypeAndCode(r, in_v)  rwrec_SetIcmpTypeAndCode(r, in_v)
#  define rwRecMemGetIcmpTypeAndCode(r, out_vp) \
    rwrec_MemGetIcmpTypeAndCode(r, out_vp)
#  define rwRecMemSetIcmpTypeAndCode(r, in_vp)  \
    rwrec_MemSetIcmpTypeAndCode(r, in_vp)
#  define rwRecMemCmpIcmpTypeAndCode(r, vp)     \
    rwrec_MemCmpIcmpTypeAndCode(r, vp)
#else /* RWREC_OPAQUE */
#  define rwRecGetIcmpType(r)  _recGetIcmpType(r)
#  define rwRecSetIcmpType(r, in_v)  _recSetIcmpType(r, in_v)
#  define rwRecMemGetIcmpType(r, out_vp)  _recMemGetIcmpType(r, out_vp)

#  define rwRecGetIcmpCode(r)  _recGetIcmpCode(r)
#  define rwRecSetIcmpCode(r, in_v)  _recSetIcmpCode(r, in_v)
#  define rwRecMemGetIcmpCode(r, out_vp)  _recMemGetIcmpCode(r, out_vp)

#  define rwRecGetIcmpTypeAndCode(r)  _recGetDPort(r)
#  define rwRecSetIcmpTypeAndCode(r, in_v)  _recSetDPort(r, in_v)
#  define rwRecMemGetIcmpTypeAndCode(r, out_vp)  _recMemGetDPort(r, out_vp)
#  define rwRecMemSetIcmpTypeAndCode(r, in_vp)  _recMemSetDPort(r, in_vp)
#  define rwRecMemCmpIcmpTypeAndCode(r, vp)  _recMemCmpDPort(r, vp)
#endif /* RWREC_OPAQUE */


#ifdef __cplusplus
}
#endif
#endif /* _RWREC_H */

/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 42 bytes --]


-- 
Michael Welsh Duggan
(md5i@md5i.com)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-12-10  3:35                                         ` Michael Welsh Duggan
@ 2013-01-07 12:09                                           ` Alan Mackenzie
  2013-01-17 16:27                                             ` Michael Welsh Duggan
  0 siblings, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2013-01-07 12:09 UTC (permalink / raw)
  To: Michael Welsh Duggan
  Cc: 11749@debbugs.gnu.org, Michael Welsh Duggan, Kim Storm

Happy New Year, Michael!

On Sun, Dec 09, 2012 at 10:35:42PM -0500, Michael Welsh Duggan wrote:
> Here's another case.  

> emacs -Q rwrec.h
> M-x c-toggle-parse-state-debug
> C-v {about 24-27 times}

> This is with current bzr.  
> 111170 rgm@gnu.org-20121210020042-arkhaf5eej6ujgtn

> rwrec.h is attached.

Thanks.  I think the following patch should have sorted out this one.  It
is based on the cc-engine.el in the emacs-24 branch in savannah.  Could
you try it out as usual, please.



=== modified file 'lisp/progmodes/cc-engine.el'
*** lisp/progmodes/cc-engine.el	2012-12-11 19:06:57 +0000
--- lisp/progmodes/cc-engine.el	2013-01-06 21:52:00 +0000
***************
*** 2464,2471 ****
--- 2464,2475 ----
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Variables which keep track of preprocessor constructs.
+ (defvar c-state-old-cpp-beg-marker)
+ (make-variable-buffer-local 'c-state-old-cpp-beg-marker)
  (defvar c-state-old-cpp-beg nil)
  (make-variable-buffer-local 'c-state-old-cpp-beg)
+ (defvar c-state-old-cpp-end-marker)
+ (make-variable-buffer-local 'c-state-old-cpp-end-marker)
  (defvar c-state-old-cpp-end nil)
  (make-variable-buffer-local 'c-state-old-cpp-end)
  ;; These are the limits of the macro containing point at the previous call of
***************
*** 2653,2665 ****
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
!       (let ((bra from) ce		; Positions of "{" and "}".
! 	    new-cons
! 	    (cache-pos (c-state-cache-top-lparen)) ; might be nil.
! 	    (macro-start-or-from
! 	     (progn (goto-char from)
! 		    (c-beginning-of-macro)
! 		    (point))))
  	(or upper-lim (setq upper-lim from))
  
  	;; If we're essentially repeating a fruitless search, just give up.
--- 2657,2678 ----
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
! 
!       (let* (new-cons
! 	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
! 	     (macro-start-or-from
! 	      (progn (goto-char from)
! 		     (c-beginning-of-macro)
! 		     (point)))
! 	     (bra			; Position of "{".
! 	      ;; Don't start scanning in the middle of a CPP construct unless
! 	      ;; it contains HERE - these constructs, in Emacs, are "commented
! 	      ;; out" with category properties.
! 	      (if (eq (c-get-char-property macro-start-or-from 'category)
! 			'c-cpp-delimiter)
! 		    macro-start-or-from
! 		  from))
! 	     ce)			; Position of "}"
  	(or upper-lim (setq upper-lim from))
  
  	;; If we're essentially repeating a fruitless search, just give up.
***************
*** 2899,2905 ****
--- 2912,2920 ----
  		  (point-max)
  		(min (point-max) c-state-old-cpp-beg)))
  	(while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
+ 	  (setq scan-back-pos (car-safe (car c-state-cache)))
  	  (setq c-state-cache (cdr c-state-cache)))
+ 
  	;; If `upper-lim' is inside the last recorded brace pair, remove its
  	;; RBrace and indicate we'll need to search backwards for a previous
  	;; brace pair.
***************
*** 3324,3329 ****
--- 3339,3351 ----
       (c-with-cpps-commented-out
        (c-invalidate-state-cache-1 here)))))
  
+ (defmacro c-state-maybe-marker (place marker)
+   ;; If PLACE is non-nil, return a marker marking it, otherwise nil.
+   ;; We (re)use MARKER.
+   `(and ,place
+ 	(or ,marker (setq ,marker (make-marker)))
+ 	(set-marker ,marker ,place)))
+ 
  (defun c-parse-state ()
    ;; This is a wrapper over `c-parse-state-1'.  See that function for a
    ;; description of the functionality and return value.
***************
*** 3350,3358 ****
  	      (c-parse-state-1))
  	   (c-with-cpps-commented-out
  	    (c-parse-state-1))))
!       (setq c-state-old-cpp-beg (and here-cpp-beg (copy-marker here-cpp-beg t))
! 	    c-state-old-cpp-end (and here-cpp-end (copy-marker here-cpp-end t)))
!       )))
  
  ;; Debug tool to catch cache inconsistencies.  This is called from
  ;; 000tests.el.
--- 3372,3381 ----
  	      (c-parse-state-1))
  	   (c-with-cpps-commented-out
  	    (c-parse-state-1))))
!       (setq c-state-old-cpp-beg
! 	    (c-state-maybe-marker here-cpp-beg c-state-old-cpp-beg-marker)
! 	    c-state-old-cpp-end
! 	    (c-state-maybe-marker here-cpp-end c-state-old-cpp-end-marker)))))
  
  ;; Debug tool to catch cache inconsistencies.  This is called from
  ;; 000tests.el.



> -- 
> Michael Welsh Duggan
> (md5i@md5i.com)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#13385: 24.1; TAB in C file causes type error
@ 2013-01-08 13:49   ` Julian Stecklina
       [not found]     ` <handler.13385.D11749.1359830688892.notifdone@debbugs.gnu.org>
  0 siblings, 1 reply; 55+ messages in thread
From: Julian Stecklina @ 2013-01-08 13:49 UTC (permalink / raw)
  To: 13385

Hello,

While editing C files, I sometimes stumble upon the following error. I
cannot reliably reproduce its first occurence, but when it occurs it
will break indenting code until I kill the buffer and revisit the file.

I removed all cc-mode customization from my .emacs.el, but it doesn't
make a difference.

Debugger entered--Lisp error: (wrong-type-argument number-or-marker-p (51932 . 51982))
  c-looking-at-inexpr-block((51932 . 51982) (51932 . 51982))
  c-inside-bracelist-p(52112 ((51932 . 51982) 54476 (52112 . 54355) 54476 (52112 . 54355) 52112 (51932 . 51982) 52112 (51932 . 51982) 52112 (46073 . 46349) (51932 . 51982) 52112 (46073 . 46349) (51932 . 51982) 52112 (51932 . 51982) 52112 (51932 . 51982) 52112 (51932 . 51982) 52112 (51932 . 51982) 52112 (46073 . 46349) (51932 . 51982) 52112 (51932 . 51982) 52112 (46073 . 46349) (51932 . 51982) 52112 (51932 . 51982) 52112 (46073 . 46349) (51932 . 51982) 51213 51180 50702 (50307 . 50564)))
  c-guess-basic-syntax()
  c-indent-line()
  #[nil "\302\303 !\210\b\304>\203.^@\212\305 \210\306\307x\210\305 \210\310 )i\310 X\203'^@\311	!\202,^@\212\311	!))\207\b \207" [indent-line-function column syntax-propertize line-end-position (indent-relative indent-relative-maybe) beginning-of-line "\n 	" nil current-indentation indent-line-to] 2 2125346 nil]()
  c-indent-command(nil)
  c-indent-line-or-region(nil nil)
  call-interactively(c-indent-line-or-region nil nil)






^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
                   ` (3 preceding siblings ...)
  2012-09-05 13:11 ` bug#11749: I also have this issue Denis Zalevskiy
@ 2013-01-08 19:10 ` Glenn Morris
  2013-01-09 22:13   ` Alan Mackenzie
  2013-02-02 18:37 ` bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Alan Mackenzie
  5 siblings, 1 reply; 55+ messages in thread
From: Glenn Morris @ 2013-01-08 19:10 UTC (permalink / raw)
  To: Alan Mackenzie
  Cc: Michael Welsh Duggan, 11749@debbugs.gnu.org, Michael Welsh Duggan,
	Kim Storm


If you'd like to see this in the next pretest, please install this in
emacs-24 as soon as possible.

FWIW, here is some sanity checking from someone who knows nothing about
cc-mode (other than the terror that it brings). Just ignore any of these
comments if they are obviously wrong.

Alan Mackenzie wrote:

> + (defvar c-state-old-cpp-beg-marker)

I guess you wanted to give that an actual value, ie

(defvar c-state-old-cpp-beg-marker nil)

> + (defvar c-state-old-cpp-end-marker)

Likewise.

> + (defmacro c-state-maybe-marker (place marker)
> +   ;; If PLACE is non-nil, return a marker marking it, otherwise nil.
> +   ;; We (re)use MARKER.
> +   `(and ,place
> + 	(or ,marker (setq ,marker (make-marker)))
> + 	(set-marker ,marker ,place)))
> + 
[...]
> !       (setq c-state-old-cpp-beg (and here-cpp-beg (copy-marker here-cpp-beg t))
> ! 	    c-state-old-cpp-end (and here-cpp-end (copy-marker here-cpp-end t)))
> !       )))
>   
>   ;; Debug tool to catch cache inconsistencies.  This is called from
>   ;; 000tests.el.
> --- 3372,3381 ----
>   	      (c-parse-state-1))
>   	   (c-with-cpps-commented-out
>   	    (c-parse-state-1))))
> !       (setq c-state-old-cpp-beg
> ! 	    (c-state-maybe-marker here-cpp-beg c-state-old-cpp-beg-marker)
> ! 	    c-state-old-cpp-end
> ! 	    (c-state-maybe-marker here-cpp-end c-state-old-cpp-end-marker)))))

Looks like the marker insertion type has changed?





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-08 19:10 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Glenn Morris
@ 2013-01-09 22:13   ` Alan Mackenzie
  0 siblings, 0 replies; 55+ messages in thread
From: Alan Mackenzie @ 2013-01-09 22:13 UTC (permalink / raw)
  To: Glenn Morris
  Cc: Michael Welsh Duggan, 11749@debbugs.gnu.org, Michael Welsh Duggan,
	Kim Storm

Hi, Glenn.

On Tue, Jan 08, 2013 at 02:10:58PM -0500, Glenn Morris wrote:

> If you'd like to see this in the next pretest, please install this in
> emacs-24 as soon as possible.

DONE.  I'll be looking forward to the new pretest ?tomorrow.

> FWIW, here is some sanity checking from someone who knows nothing about
> cc-mode (other than the terror that it brings). Just ignore any of these
> comments if they are obviously wrong.

> Alan Mackenzie wrote:

> > + (defvar c-state-old-cpp-beg-marker)

> I guess you wanted to give that an actual value, ie

> (defvar c-state-old-cpp-beg-marker nil)

Sugar!  I must stop being caught out by this.  That construct merely
interns a symbol, leaving its value unbound.  Thanks very much for
catching this.

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-07 12:09                                           ` Alan Mackenzie
@ 2013-01-17 16:27                                             ` Michael Welsh Duggan
  2013-01-17 16:28                                               ` Michael Welsh Duggan
  2013-01-23 14:16                                               ` Alan Mackenzie
  0 siblings, 2 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2013-01-17 16:27 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Happy New Year, Michael!
>
> On Sun, Dec 09, 2012 at 10:35:42PM -0500, Michael Welsh Duggan wrote:
>> Here's another case.  
>
>> emacs -Q rwrec.h
>> M-x c-toggle-parse-state-debug
>> C-v {about 24-27 times}
>
>> This is with current bzr.  
>> 111170 rgm@gnu.org-20121210020042-arkhaf5eej6ujgtn
>
>> rwrec.h is attached.
>
> Thanks.  I think the following patch should have sorted out this one.  It
> is based on the cc-engine.el in the emacs-24 branch in savannah.  Could
> you try it out as usual, please.

This fixes this case, indeed.  Unfortunately, here's another.

emacs -Q rwtransfer.c
  M-x c-toggle-parse-state-debug
  M->
Then type M-v until the parse failure happens.  For me it happens at 
32% point in the file.  Please not that this particular problem only
happens when paging through the file in reverse order.

c-parse-state inconsistency at 15885: using cache: (15636 15181 (13849 . 15141)), from scratch: (15636 (15303 . 15493) 15181 (13849 . 15141))
Old state:
(setq c-state-cache '(16334 16271 16248 (16059 . 16193) 15181 (13849 . 15141))  c-state-cache-good-pos 16335  c-state-nonlit-pos-cache '(48473 45473 42473 39473 36473 33473 30473 27378 24378 21260 18015 15015 12015 9015 6015 3015)  c-state-nonlit-pos-cache-limit 48473  c-state-semi-nonlit-pos-cache '(48323 45323 42323 39323 36323 33260 30260 27260 24260 21260 18001 15001 12001 9001 6001 3001)  c-state-semi-nonlit-pos-cache-limit 48323  c-state-brace-pair-desert '(15181 . 17388)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  c-parse-state-point 16335)
c-parse-state inconsistency at 15885: using cache: (15636 15181 (13849 . 15141)), from scratch: (15636 (15303 . 15493) 15181 (13849 . 15141))

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-17 16:27                                             ` Michael Welsh Duggan
@ 2013-01-17 16:28                                               ` Michael Welsh Duggan
  2013-01-23 14:16                                               ` Alan Mackenzie
  1 sibling, 0 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2013-01-17 16:28 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

[-- Attachment #1: Type: text/plain, Size: 48 bytes --]

And here's the file I was supposed to include:


[-- Attachment #2: rwtransfer.c --]
[-- Type: text/plain, Size: 50818 bytes --]

/*
** Copyright (C) 2006-2013 by Carnegie Mellon University.
**
** @OPENSOURCE_HEADER_START@
**
** Use of the SILK system and related source code is subject to the terms
** of the following licenses:
**
** GNU Public License (GPL) Rights pursuant to Version 2, June 1991
** Government Purpose License Rights (GPLR) pursuant to DFARS 252.227.7013
**
** NO WARRANTY
**
** ANY INFORMATION, MATERIALS, SERVICES, INTELLECTUAL PROPERTY OR OTHER
** PROPERTY OR RIGHTS GRANTED OR PROVIDED BY CARNEGIE MELLON UNIVERSITY
** PURSUANT TO THIS LICENSE (HEREINAFTER THE "DELIVERABLES") ARE ON AN
** "AS-IS" BASIS. CARNEGIE MELLON UNIVERSITY MAKES NO WARRANTIES OF ANY
** KIND, EITHER EXPRESS OR IMPLIED AS TO ANY MATTER INCLUDING, BUT NOT
** LIMITED TO, WARRANTY OF FITNESS FOR A PARTICULAR PURPOSE,
** MERCHANTABILITY, INFORMATIONAL CONTENT, NONINFRINGEMENT, OR ERROR-FREE
** OPERATION. CARNEGIE MELLON UNIVERSITY SHALL NOT BE LIABLE FOR INDIRECT,
** SPECIAL OR CONSEQUENTIAL DAMAGES, SUCH AS LOSS OF PROFITS OR INABILITY
** TO USE SAID INTELLECTUAL PROPERTY, UNDER THIS LICENSE, REGARDLESS OF
** WHETHER SUCH PARTY WAS AWARE OF THE POSSIBILITY OF SUCH DAMAGES.
** LICENSEE AGREES THAT IT WILL NOT MAKE ANY WARRANTY ON BEHALF OF
** CARNEGIE MELLON UNIVERSITY, EXPRESS OR IMPLIED, TO ANY PERSON
** CONCERNING THE APPLICATION OF OR THE RESULTS TO BE OBTAINED WITH THE
** DELIVERABLES UNDER THIS LICENSE.
**
** Licensee hereby agrees to defend, indemnify, and hold harmless Carnegie
** Mellon University, its trustees, officers, employees, and agents from
** all claims or demands made against them (and any related losses,
** expenses, or attorney's fees) arising out of, or relating to Licensee's
** and/or its sub licensees' negligent use or willful misuse of or
** negligent conduct or willful misconduct regarding the Software,
** facilities, or other rights or assistance granted by Carnegie Mellon
** University under this License, including, but not limited to, any
** claims of product liability, personal injury, death, damage to
** property, or violation of any laws or regulations.
**
** Carnegie Mellon University Software Engineering Institute authored
** documents are sponsored by the U.S. Department of Defense under
** Contract FA8721-05-C-0003. Carnegie Mellon University retains
** copyrights in all material produced under this contract. The U.S.
** Government retains a non-exclusive, royalty-free license to publish or
** reproduce these documents, or allow others to do so, for U.S.
** Government purposes only pursuant to the copyright license under the
** contract clause at 252.227.7013.
**
** @OPENSOURCE_HEADER_END@
*/

/*
**  rwtransfer.c
**
**    This file contains functions that are common to rwsender and
**    rwreceiver, such as options processing and establishing the
**    connection.
**
*/


#include <silk/silk.h>

RCSIDENT("$Id$");

#include <silk/utils.h>
#include <silk/sklog.h>
#include <silk/skdaemon.h>
#include "rwtransfer.h"


/* LOCAL DEFINES AND TYPEDEFS */

#if SK_ENABLE_GNUTLS
#  define UNUSED_NO_GNUTLS(x) x
#else
#  define UNUSED_NO_GNUTLS(x) UNUSED(x)
#endif

/* Illegal ident characters */
#define ILLEGAL_IDENT_CHARS " \t:/\\.,"

/* Define lowest protocol version which we handle */
#define LOW_VERSION  1

/* Version protocol we emit */
#define EMIT_VERISION 2

/* Turn on PKCS12 support */
#define PKCS12 1

/* Environment variable used to turn off keepalive.  Used for
 * debugging. */
#define RWTRANSFER_TURN_OFF_KEEPALIVE "RWTRANSFER_TURN_OFF_KEEPALIVE"

/* Maximum expected size of connection information string*/
#define RWTRANSFER_CONNECTION_TYPE_SIZE_MAX 50

typedef struct connection_msg_data_st {
    const char *name;
    int32_t     size;
} connection_msg_data_t;


/* EXPORTED VARIABLE DEFINITIONS */

int main_retval = EXIT_SUCCESS;


/* LOCAL VARIABLE DEFINITIONS */

/* Mode (client/server) */
static enum {CLIENT, SERVER, NOT_SET} mode;

/* Marks last client/server-specific option*/
static int client_sentinel;
static int server_sentinel;

/* Daemon identity */
static char *identity;

#if SK_ENABLE_GNUTLS
/* Encryption and authentication files */
static char *tls_ca_file     = NULL;
static char *tls_cert_file   = NULL;
static char *tls_key_file    = NULL;
#ifdef PKCS12
static char *tls_pkcs12_file = NULL;
#endif
#endif /* SK_ENABLE_GNUTLS */

/* Message queue */
static sk_msg_queue_t *control;

/* Temporary transfer_t item */
static transfer_t *global_temp_item;

/* Control message thread */
static pthread_t control_thread;
static int       control_thread_valid;

/* Address upon which to listen for incoming connections */
static sk_sockaddr_array_t *listen_address = NULL;
static const char *listen_address_arg = NULL;

/* Locations which can be addressed as return values */
static void *exit_standard   = &exit_standard;
static void *exit_disconnect = &exit_disconnect;
static void *exit_failure    = &exit_failure;

/* Main thread */
static pthread_t main_thread;

/* Detached thread entry/exit control (see comment in serverMain()) */
static uint16_t detached_thread_count = 0;
static pthread_mutex_t detached_thread_mutex = PTHREAD_MUTEX_INITIALIZER;
static pthread_cond_t  detached_thread_cond  = PTHREAD_COND_INITIALIZER;

typedef int (*connection_fn_t)(
    sk_msg_queue_t *,
    struct sockaddr *,
    socklen_t,
    skm_channel_t *);

typedef struct conn_info_st {
    sk_msg_queue_t *queue;
    skm_channel_t   channel;
    transfer_t     *trnsfr;
    unsigned        tls;
} conn_info_t;

typedef enum {
    /* Global options */
    OPT_MODE, OPT_IDENT
#if SK_ENABLE_GNUTLS
    , OPT_TLS_CA,
    OPT_TLS_CERT,
    OPT_TLS_KEY
#ifdef PKCS12
    , OPT_TLS_PKCS12
#endif
#endif /* SK_ENABLE_GNUTLS */
} appOptionsEnum;

typedef enum {
    /* Client options */
    OPT_SERVER_ADDR,

    /* Unused */
    OPT_CLIENT_UNUSED
} appClientOptionsEnum;

typedef enum {
    /* Server options */
    OPT_SERVER_PORT, OPT_CLIENT_IDENT,

    /* Unused */
    OPT_SERVER_UNUSED
} appServerOptionsEnum;


static struct option appOptions[] = {
    {"mode",                 REQUIRED_ARG, 0, OPT_MODE},
    {"identifier",           REQUIRED_ARG, 0, OPT_IDENT},
#if SK_ENABLE_GNUTLS
    {"tls-ca",               REQUIRED_ARG, 0, OPT_TLS_CA},
    {"tls-cert",             REQUIRED_ARG, 0, OPT_TLS_CERT},
    {"tls-key",              REQUIRED_ARG, 0, OPT_TLS_KEY},
#ifdef PKCS12
    {"tls-pkcs12",           REQUIRED_ARG, 0, OPT_TLS_PKCS12},
#endif
#endif /* SK_ENABLE_GNUTLS */
    {0,0,0,0}           /* sentinel entry */
};

static const char *appHelp[] = {
    ("Whether to run as a client or a server ('client', 'server')"),
    ("Named identifier for the daemon"),
#if SK_ENABLE_GNUTLS
    ("Full path to CA cert PEM file. Def. None. Either --tls-key\n"
     "\tand --tls-key or --tls-pkcs12 must also be specified."),
    ("Full path to encryption cert PEM file. Def. None.  Requires\n"
     "\tthat --tls-ca and --tls-key also be specified."),
    ("Full path to encryption key PEM file. Def. None.  Requires\n"
     "\tthat --tls-ca and --tls-cert also be specified."),
#ifdef PKCS12
    ("Full path to encryption cert and key PKCS#12 file.\n"
     "\tDef. None.  Requires that --tls-ca also be specified."),
#endif
#endif /* SK_ENABLE_GNUTLS */
    (char *)NULL
};

static struct option appClientOptions[] = {
    {"server-address", REQUIRED_ARG, 0, OPT_SERVER_ADDR},
    {0,0,0,0}           /* sentinel entry */
};

static const char *appClientHelp[] = {
    ("A server to which to connect.  Repeatable.\n"
     "\t<ident>:<address>:<port>"),
    (char *)NULL
};

static struct option appServerOptions[] = {
    {"server-port",  REQUIRED_ARG, 0, OPT_SERVER_PORT},
    {"client-ident", REQUIRED_ARG, 0, OPT_CLIENT_IDENT},
    {0,0,0,0}           /* sentinel entry */
};

static const char *appServerHelp[] = {
    ("[HOST:]PORT upon which to listen for incoming client\n"
     "\tconnections"),
    ("The identifier of a client allowed to connect to\n"
     "\tthis server.  Repeatable."),
    (char *)NULL
};


/*
 *  Connection message textual representation and lengths.
 *
 *  Length of -1 indicates a variable length message (use of
 *  sendString() implies variable length).
 */
static connection_msg_data_t conn_msg_data[CONN_NUMBER_OF_CONNECTION_MESSAGES]=
    {
        {"CONN_SENDER_VERSION",    sizeof(uint32_t)},
        {"CONN_RECEIVER_VERSION",  sizeof(uint32_t)},
        {"CONN_IDENT",            -1},
        {"CONN_READY",             0},
        {"CONN_DISCONNECT_RETRY", -1},
        {"CONN_DISCONNECT",       -1},
        {"CONN_NEW_FILE",         -1},
        {"CONN_NEW_FILE_READY",    0},
        {"CONN_FILE_BLOCK",       -1},
        {"CONN_FILE_COMPLETE",     0},
        {"CONN_DUPLICATE_FILE",   -1},
        {"CONN_REJECT_FILE",      -1}
    };


/* LOCAL FUNCTION PROTOTYPES */

static void *clientMain(void *); /* Thread entry point */
static void *serverMain(void *); /* Thread entry point */
static int appOptionsHandler(
    clientData  cData,
    int         opt_index,
    char       *opt_arg);
static int appClientOptionsHandler(
    clientData  cData,
    int         opt_index,
    char       *opt_arg);
static int appServerOptionsHandler(
    clientData  cData,
    int         opt_index,
    char       *opt_arg);
static void parseServerAddress(
    const char *const_addr);
static void addIdent(
    const char *ident);


/* FUNCTION DEFINITIONS */

/* checkIdent();
 *
 *    Check to see if an ident is legal.  If illegal, print an error
 *    message to the error stream, end exit.
 */
int checkIdent(
    const char     *ident)
{
    const char *invalid;
    const char *c;

    if (ident == NULL || ident[0] == '\0') {
        skAppPrintErr("Identifiers must contain at least one character");
        exit(EXIT_FAILURE);
    }
    invalid = strpbrk(ident, ILLEGAL_IDENT_CHARS);
    if (invalid != NULL) {
        skAppPrintErr(("The identifier %s contains the illegal "
                       "character %c"), ident, *invalid);
        exit(EXIT_FAILURE);
    }
    for (c = ident; *c; c++) {
        if (!isprint((int)*c)) {
            skAppPrintErr(("The identifier %s contains the illegal "
                           "nonprintable character 0x%x"), ident, (int)*c);
            exit(EXIT_FAILURE);
        }
    }

    return 0;
}


/*
 * appModeUsage();
 *
 *    Print usage information for the mode named 'mode_str', using the
 *    given 'options' and 'help'.
 */
static void appModeUsage(
    FILE           *fh,
    const char     *mode_str,
    struct option   options[],
    const char     *help[])
{
    unsigned int i;

    fprintf(fh, "\n%s switches:\n", mode_str);
    for (i = 0; options[i].name; i++) {
        if (help[i]) {
            fprintf(fh, "--%s %s. %s\n", options[i].name,
                    SK_OPTION_HAS_ARG(options[i]), help[i]);
        }
    }
}


void transferUsageLong(
    FILE           *fh,
    const char     *usage,
    struct option   options[],
    const char     *help[])
{
    unsigned int i;
    fprintf(fh, "%s %s", skAppName(), usage);

    fprintf(fh, "\nCommon switches:\n");
    skOptionsDefaultUsage(fh);
    for (i = 0; appOptions[i].name; ++i) {
        fprintf(fh, "--%s %s. %s\n", appOptions[i].name,
                SK_OPTION_HAS_ARG(appOptions[i]), appHelp[i]);
    }
    for (i = 0; options[i].name; ++i) {
        fprintf(fh, "--%s %s. %s\n", options[i].name,
                SK_OPTION_HAS_ARG(options[i]), help[i]);
    }
    appModeUsage(fh, "Client", appClientOptions, appClientHelp);
    appModeUsage(fh, "Server", appServerOptions, appServerHelp);
    fprintf(fh, "\nLogging and daemon switches:\n");
    skdaemonOptionsUsage(fh);
}


int transferSetup(
    void)
{
    /* verify that the sizes of options and help match */
    assert((sizeof(appHelp)/sizeof(char*)) ==
           (sizeof(appOptions)/sizeof(struct option)));
    assert((sizeof(appClientHelp)/sizeof(char*)) ==
           (sizeof(appClientOptions)/sizeof(struct option)));
    assert((sizeof(appServerHelp)/sizeof(char*)) ==
           (sizeof(appServerOptions)/sizeof(struct option)));

    mode                  = NOT_SET;
    client_sentinel       = OPT_CLIENT_UNUSED;
    server_sentinel       = OPT_SERVER_UNUSED;
    identity              = NULL;
    global_temp_item      = NULL;
    control_thread_valid  = 0;

    /* register the options and handler */
    if (skOptionsRegister(appOptions, &appOptionsHandler, NULL))
    {
        skAppPrintErr("Unable to transfer application options");
        return -1;
    }

    /* register the client options and handler */
    if (skOptionsRegister(appClientOptions, &appClientOptionsHandler, NULL))
    {
        skAppPrintErr("Unable to register client options");
        return -1;
    }

    /* register the server options and handler */
    if (skOptionsRegister(appServerOptions, &appServerOptionsHandler, NULL))
    {
        skAppPrintErr("Unable to register server options");
        return -1;
    }

    return 0;
}


/*
 *  status = appOptionsHandler(cData, opt_index, opt_arg);
 *
 *    This function is passed to skOptionsRegister(); it will be called
 *    by skOptionsParse() for each user-specified switch that the
 *    application has registered; it should handle the switch as
 *    required---typically by setting global variables---and return 1
 *    if the switch processing failed or 0 if it succeeded.  Returning
 *    a non-zero from from the handler causes skOptionsParse() to return
 *    a negative value.
 *
 *    The clientData in 'cData' is typically ignored; 'opt_index' is
 *    the index number that was specified as the last value for each
 *    struct option in appOptions[]; 'opt_arg' is the user's argument
 *    to the switch for options that have a REQUIRED_ARG or an
 *    OPTIONAL_ARG.
 */
static int appOptionsHandler(
    clientData  UNUSED(cData),
    int         opt_index,
    char       *opt_arg)
{

    switch ((appOptionsEnum)opt_index) {

      case OPT_MODE:
        if (0 == strcmp(opt_arg, "server")) {
            mode = SERVER;
        } else if (0 == strcmp(opt_arg, "client")) {
            mode = CLIENT;
        } else {
            skAppPrintErr("Invalid --%s '%s'",
                          appOptions[opt_index].name, opt_arg);
            return 1;
        }
        break;

      case OPT_IDENT:
        checkIdent(opt_arg);
        identity = opt_arg;
        break;

#if SK_ENABLE_GNUTLS
      case OPT_TLS_CA:
        if (optionsFileCheck(appOptions[opt_index].name, opt_arg)) {
            return 1;
        }
        tls_ca_file = opt_arg;
        break;

      case OPT_TLS_CERT:
        if (optionsFileCheck(appOptions[opt_index].name, opt_arg)) {
            return 1;
        }
        tls_cert_file = opt_arg;
        break;

      case OPT_TLS_KEY:
        if (optionsFileCheck(appOptions[opt_index].name, opt_arg)) {
            return 1;
        }
        tls_key_file = opt_arg;
        break;

#ifdef PKCS12
      case OPT_TLS_PKCS12:
        if (optionsFileCheck(appOptions[opt_index].name, opt_arg)) {
            return 1;
        }
        tls_pkcs12_file = opt_arg;
        break;
#endif
#endif /* SK_ENABLE_GNUTLS */

    }

    return 0;  /* OK */
}


int transferVerifyOptions(
    void)
{
    RBLIST *list;
    transfer_t *item;
    int error_count = 0;

    /* Check mode options */
    if (mode == NOT_SET) {
        skAppPrintErr(("Client or server mode must be chosen "
                       "via the --%s switch"),
                      appOptions[OPT_MODE].name);
        ++error_count;
    }
    if ((mode == CLIENT && (server_sentinel != OPT_SERVER_UNUSED)) ||
        (mode == SERVER && (client_sentinel != OPT_CLIENT_UNUSED)))
    {
        int badopt = (mode == CLIENT) ? server_sentinel : client_sentinel;
        struct option *opts =
            (mode == CLIENT) ? appServerOptions : appClientOptions;
        const char *mode_string = (mode == CLIENT) ? "client" : "server";
        skAppPrintErr("The --%s switch cannot be used in %s mode",
                      opts[badopt].name, mode_string);
        return -1;
    }

    if (identity == NULL) {
        skAppPrintErr("The --%s switch is required",
                      appOptions[OPT_IDENT].name);
        ++error_count;
    }

    if (rbmin(transfers) == NULL && mode != NOT_SET) {
        skAppPrintErr("Must supply at least one --%s switch",
                      (mode == CLIENT) ?
                      appClientOptions[OPT_SERVER_ADDR].name :
                      appServerOptions[OPT_CLIENT_IDENT].name);
        ++error_count;
    }

#if SK_ENABLE_GNUTLS
#ifdef PKCS12
    if (tls_ca_file || tls_cert_file || tls_key_file || tls_pkcs12_file) {
        if (!tls_ca_file) {
            skAppPrintErr("A CA cert file must be specified for "
                          "encryption: --%s", appOptions[OPT_TLS_CA].name);
            ++error_count;
        }
        if (!(tls_cert_file && tls_key_file && !tls_pkcs12_file) &&
            !(!tls_cert_file && !tls_key_file && tls_pkcs12_file))
        {
            skAppPrintErr("When using encryption, you must specify --%s and "
                          "--%s, or just --%s",
                          appOptions[OPT_TLS_CERT].name,
                          appOptions[OPT_TLS_KEY].name,
                          appOptions[OPT_TLS_PKCS12].name);
            ++error_count;
        }
    }
#else /* !PKCS12 */
    if (tls_ca_file || tls_cert_file || tls_key_file) {
        if (!tls_ca_file) {
            skAppPrintErr("A CA cert file must be specified for "
                          "encryption: --%s", appOptions[OPT_TLS_CA]);
            ++error_count;
        }
        if (!(tls_cert_file && tls_key_file))
        {
            skAppPrintErr("When using encryption, you must specify --%s and "
                          "--%s",
                          appOptions[OPT_TLS_CERT].name,
                          appOptions[OPT_TLS_KEY].name);
            ++error_count;
        }
    }
#endif /* PKCS12 */
#endif /* SK_ENABLE_GNUTLS */

    switch (mode) {
      case SERVER:
        if (listen_address == NULL) {
            skAppPrintErr("Must supply a port using --%s in server mode",
                          appServerOptions[OPT_SERVER_PORT].name);
            ++error_count;
        }
        break;

      case CLIENT:
        list = rbopenlist(transfers);
        if (list == NULL) {
            skAppPrintErr("Memory allocation failure verifying options");
            return -1;
        }
        while ((item = (transfer_t *)rbreadlist(list)) != NULL) {
            if (item->address_exists == 0) {
                skAppPrintErr("Ident %s has no address associated with it",
                              item->ident);
                return -1;
            }
        }
        rbcloselist(list);
        break;

      case NOT_SET:
        break;
    }

    if (error_count) {
        return -1;
    }

    main_thread = pthread_self();

    return 0;
}


void transferShutdown(
    void)
{
    RBLIST *iter;
    transfer_t *trnsfr;
    int rv;

    assert(shuttingdown);

    skMsgQueueShutdownAll(control);

    iter = rbopenlist(transfers);
    CHECK_ALLOC(iter);
    while ((trnsfr = (transfer_t *)rbreadlist(iter)) != NULL) {
        rv = transferUnblock(trnsfr);
        if (rv != 0) {
            CRITMSG("Unexpected failure to unblock transfer");
            _exit(EXIT_FAILURE);
        }
    }
    rbcloselist(iter);
}


void transferTeardown(
    void)
{
    /* Wait for transfer threads to end.  In server mode, all these
     * threads are detached, and as such may not be joinable.  */
    if (mode != SERVER) {
        RBLIST *iter;
        transfer_t *trnsfr;

        iter = rbopenlist(transfers);
        CHECK_ALLOC(iter);
        while ((trnsfr = (transfer_t *)rbreadlist(iter)) != NULL) {
            if (trnsfr->thread_exists) {
                DEBUGMSG("Waiting for thread %s to end...", trnsfr->ident);
                pthread_join(trnsfr->thread, NULL);
                DEBUGMSG("Thread %s has ended.", trnsfr->ident);
            }
        }
        rbcloselist(iter);
    }

    /* Wait for control thread to end */
    if (control_thread_valid) {
        DEBUGMSG("Waiting for control thread to end...");
        pthread_join(control_thread, NULL);
        DEBUGMSG("Control thread has ended.");
    }

    /* Wait for detached threads to end */
    DEBUGMSG("Waiting for detached threads to end...");
    pthread_mutex_lock(&detached_thread_mutex);
    while (detached_thread_count) {
        pthread_cond_wait(&detached_thread_cond, &detached_thread_mutex);
    }
    pthread_mutex_unlock(&detached_thread_mutex);
    DEBUGMSG("Detached threads have ended.");

    /* Destroy stuff */
    skMsgQueueDestroy(control);
    if (listen_address) {
        skSockaddrArrayDestroy(listen_address);
        listen_address = NULL;
    }
    if (global_temp_item != NULL) {
        free(global_temp_item);
    }

#if SK_ENABLE_GNUTLS
    skMsgGnuTLSTeardown();
#endif
}


/*
 *  file_exists = optionsFileCheck(opt_name, opt_arg);
 *
 *    Verify that the file in 'opt_arg' exists and that we have a full
 *    path to the file.  Verify that the length is shorter than
 *    PATH_MAX.  If so, return 0; otherwise, print an error that the
 *    option named by 'opt_name' was bad and return -1.
 */
int optionsFileCheck(
    const char *opt_name,
    const char *opt_arg)
{
    if (!opt_arg || !opt_arg[0]) {
        skAppPrintErr("Invalid %s: The argument empty", opt_name);
        return -1;
    }

    if (strlen(opt_arg)+1 >= PATH_MAX) {
        skAppPrintErr("Invalid %s: Path is too long", opt_name);
        return -1;
    }

    if (!skFileExists(opt_arg)) {
        skAppPrintErr("Invalid %s: File '%s' does not exist",
                      opt_name, opt_arg);
        return -1;
    }

    if (opt_arg[0] != '/') {
        skAppPrintErr(("Invalid %s: Must use complete path"
                       " ('%s' does not begin with slash)"),
                      opt_name, opt_arg);
        return -1;
    }

    return 0;
}


static int appClientOptionsHandler(
    clientData  UNUSED(cData),
    int         opt_index,
    char       *opt_arg)
{
    client_sentinel = opt_index;

    switch ((appClientOptionsEnum)opt_index) {
      case OPT_SERVER_ADDR:
        parseServerAddress(opt_arg);
        break;

      default:
        /* Should not get here */
        ASSERT_ABORT(0);
    }

    return 0;  /* OK */
}


static int appServerOptionsHandler(
    clientData  UNUSED(cData),
    int         opt_index,
    char       *opt_arg)
{
    int rv;

    server_sentinel = opt_index;

    switch ((appServerOptionsEnum)opt_index) {
      case OPT_CLIENT_IDENT:
        addIdent(opt_arg);
        break;

      case OPT_SERVER_PORT:
        rv = skStringParseHostPortPair(&listen_address,
                                       opt_arg, PORT_REQUIRED);
        if (rv) {
            skAppPrintErr("Invalid %s '%s': %s",
                          appOptions[opt_index].name, opt_arg,
                          skStringParseStrerror(rv));
            return 1;
        }
        listen_address_arg = opt_arg;
        break;

      default:
        /* Should not get here */
        ASSERT_ABORT(0);
    }

    return 0;  /* OK */
}



/* String compare for receiver rbtree */
static int transferCompare(
    const void *va,
    const void *vb,
    const void *UNUSED(cbdata))
{
    const transfer_t *a = (const transfer_t *)va;
    const transfer_t *b = (const transfer_t *)vb;
    return strcmp(a->ident, b->ident);
}


struct rbtree *transferIdentTreeCreate(
    void)
{
    return rbinit(transferCompare, NULL);
}


/* Create temporary transfer_t objects */
transfer_t *initTemp(
    void)
{
    /* Allocate and/or clear the temporary item */
    if (global_temp_item == NULL) {
        global_temp_item = (transfer_t *)calloc(1, sizeof(*global_temp_item));
    } else {
        memset(global_temp_item, 0, sizeof(*global_temp_item));
    }
    return global_temp_item;
}

/* If a program wishes to keep a temporary transfer object, it should
   call this. */
void clearTemp(
    void)
{
    global_temp_item = NULL;
}


/* Parse a <ident>:<address>:<port> specification */
static void parseServerAddress(
    const char     *const_addr)
{
#define FMT_PARSE_FAILURE                               \
    ("Server address parse failure parsing '%s'\n"      \
     "\tCorrect form is <ident>:<address>:<port>")
#define FMT_MEM_FAILURE                                         \
    "Memory allocation failure when parsing server address %s"

    char *addr = strdup(const_addr);
    char *colon, *next;
    transfer_t *old;
    const void *test;
    int rv;
    transfer_t *temp_item;

    temp_item = initTemp();

    if (addr == NULL || temp_item == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, const_addr);
        exit(EXIT_FAILURE);
    }

    /* First, extract the ident */
    colon = strchr(addr, ':');
    if (colon == NULL) {
        free(addr);
        skAppPrintErr(FMT_PARSE_FAILURE, const_addr);
        exit(EXIT_FAILURE);
    }
    *colon = '\0';
    checkIdent(addr);
    temp_item->ident = addr;


    /* See if it has already been used */
    old = (transfer_t *)rbfind(temp_item, transfers);
    if (old != NULL) {
        if (!old->address_exists) {
            memcpy(temp_item, old, sizeof(*temp_item));
            test = rbdelete(old, transfers);
            assert(test == old);
            temp_item->ident = addr;
            free(old->ident);
            free(old);
        } else {
            free(addr);
            skAppPrintErr("Duplicate ident in server address %s", const_addr);
            exit(EXIT_FAILURE);
        }
    }

    /* Next, extract the address */
    next = colon + 1;
    rv = skStringParseHostPortPair(&temp_item->addr, next,
                                   HOST_REQUIRED | PORT_REQUIRED);
    if (rv < 0) {
        skAppPrintErr("Could not parse address: %s",
                      skStringParseStrerror(rv));
        exit(EXIT_FAILURE);
    }

    /* Add to our server list */
    temp_item->ident = strdup(temp_item->ident);
    free(addr);
    if (temp_item->ident == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, const_addr);
        exit(EXIT_FAILURE);
    }
    test = rbsearch(temp_item, transfers);
    if (test == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, const_addr);
        exit(EXIT_FAILURE);
    }
    temp_item->address_exists = 1;

    assert(test == temp_item);
    clearTemp();

#undef FMT_PARSE_FAILURE
#undef FMT_MEM_FAILURE
}


/* Add a bare ident to the transfer list */
static void addIdent(
    const char     *ident)
{
#define FMT_MEM_FAILURE "Memory allocation failure when parsing ident %s"
    const void *test;
    transfer_t *temp_item;

    checkIdent(ident);
    temp_item = initTemp();
    if (temp_item == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, ident);
        exit(EXIT_FAILURE);
    }
    temp_item->ident = (char *)ident;
    test = rbsearch(temp_item, transfers);
    if (test == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, ident);
        exit(EXIT_FAILURE);
    }
    if (test != temp_item) {
        skAppPrintErr("Duplicate ident %s", ident);
        exit(EXIT_FAILURE);
    }
    temp_item->ident = strdup(ident);
    if (temp_item->ident == NULL) {
        skAppPrintErr(FMT_MEM_FAILURE, ident);
        exit(EXIT_FAILURE);
    }
    clearTemp();
#undef FMT_MEM_FAILURE
}


static void getConnectionInformation(
    sk_msg_queue_t *queue,
    skm_channel_t   channel,
    char           *buffer,
    size_t          buffer_size)
{
    int rv;

    rv = skMsgGetConnectionInformation(queue, channel, buffer, buffer_size);
    if (rv == -1) {
        strncpy(buffer, "<unknown>", buffer_size);
    }
    buffer[buffer_size - 1] = '\0';
}


int handleDisconnect(
    sk_msg_t       *msg,
    const char     *type)
{
    skm_type_t msgtyp = skMsgType(msg);

    if (msgtyp == CONN_DISCONNECT || msgtyp == CONN_DISCONNECT_RETRY) {
        int length = MAX_ERROR_MESSAGE;

        if (skMsgLength(msg) < length) {
            length = skMsgLength(msg);
        }

        INFOMSG("Connection %s disconnected: %.*s",
                type, length, (char *)skMsgMessage(msg));

        return (msgtyp == CONN_DISCONNECT) ? -1 : 1;
    }

    return 0;
}


/*
 *    This function is used by servers and clients.  The function
 *    verifies the connection (version, ident), and then calls the
 *    transferFiles() function defined in rwsender.c or rwreceiver.c.
 *
 *    For a server, this is a THREAD ENTRY POINT.  Entry point for the
 *    "connection" thread, started from serverMain().  This thread is
 *    detached.
 *
 *    For a client, this function is called by startClientConnection()
 *    once the client has connected to a server.
 */
static void *handleConnection(
    void           *vinfo)
{
    conn_info_t *info = (conn_info_t *)vinfo;
    transfer_t target;
    transfer_t *trnsfr = NULL;
    transfer_t *found = NULL;
    uint32_t version;
    skm_channel_t channel;
    sk_msg_queue_t *q;
    enum conn_state {Version, Ident, Ready, Running, Disconnect} state;
    int proto_err;
    int fatal_err = 0;
    const char *ident = "<unassigned>";
    void *retval = exit_failure;
    char connection_type[RWTRANSFER_CONNECTION_TYPE_SIZE_MAX];
    int transferred_file = 0;

    DEBUG_PRINT1("connection thread started");

    q = info->queue;
    channel = info->channel;
    trnsfr = info->trnsfr;
    free(info);

    /* start by sending my version and waiting for remote's version */
    state = Version;
    version = htonl(EMIT_VERISION);
    proto_err = skMsgQueueSendMessage(q, channel, local_version_check,
                                      &version, sizeof(version));

    while (!shuttingdown && !proto_err && !fatal_err && state != Running) {
        int rv;
        sk_msg_t *msg;

        rv = skMsgQueueGetMessage(q, &msg);
        if (rv == -1) {
            ASSERT_ABORT(shuttingdown);
            continue;
        }
        DEBUG_PRINT3("handleConnection() state=%d, got msg type=%d",
                     (int)state, (int)skMsgType(msg));

        rv = handleDisconnect(msg, ident);
        if (rv) {
            proto_err = 1;
            retval = transferred_file ? exit_disconnect : exit_failure;
            state = Disconnect;
        }

        switch (state) {
          case Version:
            /* expecting remote's version. if not valid, close the
             * channel.  if valid, send my ident and wait for remote's
             * ident */
            if ((proto_err = checkMsg(msg, q, remote_version_check))) {
                DEBUG_PRINT2("checkMsg(%s) FAILED",
                             conn_msg_data[remote_version_check].name);
                retval = exit_failure;
                break;
            }
            DEBUG_PRINT2("Received %s",
                         conn_msg_data[remote_version_check].name);
            version = MSG_UINT32(msg);
            if (version < LOW_VERSION) {
                sendString(q, skMsgChannel(msg), EXTERNAL,
                           CONN_DISCONNECT, LOG_WARNING,
                           ("Unsupported version %" PRIu32), version);
                proto_err = 1;
                retval = exit_failure;
                break;
            }
            if (!getenv(RWTRANSFER_TURN_OFF_KEEPALIVE)) {
                rv = skMsgSetKeepalive(q, channel, KEEPALIVE_TIMEOUT);
                assert(rv == 0);
            }
            state = Ident;
            proto_err = skMsgQueueSendMessage(q, channel, CONN_IDENT,
                                              identity, strlen(identity) + 1);
            if (proto_err != 0) {
                retval = exit_failure;
            }
            break;

          case Ident:
            /* expecting remote's ident.  if not valid, close the
             * channel.  if valid, send CONN_READY and wait for remote
             * to say it is ready */
            if ((proto_err = checkMsg(msg, q, CONN_IDENT))) {
                DEBUG_PRINT1("checkMsg(CONN_IDENT) FAILED");
                retval = exit_failure;
                break;
            }
            DEBUG_PRINT1("Received CONN_IDENT");
            target.ident = MSG_CHARP(msg);
            found = (transfer_t *)rbfind(&target, transfers);
            if (found == NULL
                || (trnsfr != NULL && trnsfr != found)
                || (trnsfr == NULL && found->thread_exists))
            {
                const char *reason;
                if (found == NULL) {
                    reason = "Unknown ident";
                } else if (trnsfr != NULL && trnsfr != found) {
                    reason = "Unexpected ident";
                } else {
                    reason = "Duplicate ident";
                }

                sendString(q, skMsgChannel(msg), EXTERNAL,
                           CONN_DISCONNECT, LOG_WARNING,
                           "%s %s", reason, target.ident);
                proto_err = 1;
                retval = exit_failure;
                break;
            }
            ident = found->ident;
            found->thread = pthread_self();
            found->thread_exists = 1;
            found->channel = channel;
            found->channel_exists = 1;
            found->remote_version = version;

            getConnectionInformation(q, channel, connection_type,
                                     sizeof(connection_type));
            INFOMSG("Connected to remote %s (%s, Protocol v%" PRIu32 ")",
                    ident, connection_type, version);
            state = Ready;
            proto_err = skMsgQueueSendMessage(q, channel, CONN_READY, NULL, 0);
            if (proto_err != 0) {
                DEBUG_PRINT1("skMsgQueueSendMessage(CONN_READY) failed");
                retval = exit_failure;
            }
            break;

          case Ready:
            /* expecting remote to say it is ready. if ready, call
             * transferFiles() */
            if ((proto_err = checkMsg(msg, q, CONN_READY))) {
                DEBUG_PRINT1("checkMsg(CONN_READY) FAILED");
                retval = exit_failure;
                break;
            }
            DEBUGMSG("Remote %s is ready for messages", ident);
            state = Running;
            rv = transferFiles(q, channel, found);
            switch (rv) {
              case -1:
                fatal_err = 1;
                break;
              case 1:
                transferred_file = 1;
                break;
              default:
                break;
            }
            break;

          case Disconnect:
            DEBUG_PRINT1("Disconnecting");
            break;

          case Running:
            ASSERT_ABORT(0);
        }

        /* Free message */
        skMsgDestroy(msg);
    }

    if (found) {
        found->channel_exists = 0;
        found->disconnect = 0;
    }

    skMsgQueueDestroy(q);

    /* If running in server mode, this was a detached thread. */
    if (trnsfr == NULL) {
        if (found) {
            found->thread_exists = 0;
        }
        pthread_mutex_lock(&detached_thread_mutex);
        detached_thread_count--;
        pthread_cond_signal(&detached_thread_cond);
        pthread_mutex_unlock(&detached_thread_mutex);
    }

    DEBUG_PRINT2("connection thread ended (status = %s)",
                 ((fatal_err)
                  ? "exit_failure [from transferFiles()]"
                  : ((exit_standard == retval)
                     ? "exit_standard"
                     : ((exit_disconnect == retval)
                        ? "exit_disconnect"
                        : ((exit_failure == retval)
                           ? "exit_failure"
                           : "UNKNOWN")))));

    if (fatal_err) {
        threadExit(EXIT_FAILURE, exit_failure);
    }

    return retval;
}


static int attemptBind(
    const sk_sockaddr_array_t  *addr,
    unsigned                   *UNUSED_NO_GNUTLS(tls),
    const char                **UNUSED_NO_GNUTLS(connection_type))
{
#if SK_ENABLE_GNUTLS
    if (tls_ca_file) {
        *tls = 1;
        *connection_type = "TCP, TLS";
        return skMsgQueueBindTLS(control, addr);
    }
#endif /* SK_ENABLE_GNUTLS */

    return skMsgQueueBindTCP(control, addr);
}


/*
 *    THREAD ENTRY POINT
 *
 *    Entry point for the "server_main" thread, started from
 *    startTransferDaemon().
 */
static void *serverMain(
    void    UNUSED(*dummy))
{
    int rv;
    unsigned tls = 0;
    const char *connection_type = "TCP";

    control_thread_valid = 1;

    DEBUG_PRINT1("server_main() thread started");

    assert(listen_address);

    rv = attemptBind(listen_address, &tls, &connection_type);
    if (rv < 0) {
        CRITMSG("Failed to bind to %s for listening", listen_address_arg);
        threadExit(EXIT_FAILURE, NULL);
    }

    INFOMSG("Bound to %s for listening (%s)",
            listen_address_arg, connection_type);

    while (!shuttingdown) {
        sk_msg_t *msg;
        skm_channel_t channel;
        pthread_t thread;
        conn_info_t *info;
        transfer_t *item;
        RBLIST *list;
        sk_new_channel_info_t *addr_info;
        char buf[PATH_MAX];
        char conn_type[RWTRANSFER_CONNECTION_TYPE_SIZE_MAX];

        rv = skMsgQueueGetMessageFromChannel(control, SKMSG_CHANNEL_CONTROL,
                                             &msg);
        if (rv == -1) {
            ASSERT_ABORT(shuttingdown);
            continue;
        }

        switch (skMsgType(msg)) {

          case SKMSG_CTL_NEW_CONNECTION:
            DEBUG_PRINT1("Received SKMSG_CTL_NEW_CONNECTION");
            channel = SKMSG_CTL_MSG_GET_CHANNEL(msg);
            addr_info = (sk_new_channel_info_t *)skMsgMessage(msg);
            getConnectionInformation(control, channel, conn_type,
                                     sizeof(conn_type));
            if (addr_info->known) {
                skSockaddrString(buf, sizeof(buf), &addr_info->addr);
            }
            INFOMSG("Received connection from %s (%s)",
                    (addr_info->known ? buf :
                     "unknown address"), conn_type);
            info = (conn_info_t *)calloc(1, sizeof(*info));
            if (info == NULL) {
                CRITMSG("Memory allocation failure");
                threadExit(EXIT_FAILURE, NULL);
            }
            info->tls = tls;
            info->trnsfr = NULL;
            rv = skMsgChannelSplit(control, channel, &info->queue);
            if (rv != 0) {
                if (shuttingdown) {
                    break;
                }
                CRITMSG("Failed to split channel");
                threadExit(EXIT_FAILURE, NULL);
            }
            info->channel = channel;

            /* In server mode we don't have one thread per ident.
             * Instead we have one thread per entity that is
             * connecting to us.  Since there is no transfer object to
             * attach the thread to, we create a detached thread
             * instead, and use the detached_thread_mutex and
             * detached_thread_count to know when the threads have
             * ended. */
            pthread_mutex_lock(&detached_thread_mutex);
            rv = skthread_create_detached("connection", &thread,
                                          handleConnection, info);
            if (rv != 0) {
                pthread_mutex_unlock(&detached_thread_mutex);
                CRITMSG("Failed to create connection thread: %s",
                        strerror(rv));
                threadExit(EXIT_FAILURE, NULL);
            }
            detached_thread_count++;
            pthread_mutex_unlock(&detached_thread_mutex);
            break;

          case SKMSG_CTL_CHANNEL_DIED:
            DEBUG_PRINT1("Received SKMSG_CTL_CHANNEL_DIED");
            channel = SKMSG_CTL_MSG_GET_CHANNEL(msg);
            list = rbopenlist(transfers);
            CHECK_ALLOC(list);
            while ((item = (transfer_t *)rbreadlist(list)) != NULL) {
                if (item->channel_exists && channel == item->channel) {
                    INFOMSG("Channel to %s died", item->ident);
                    item->disconnect = 1;
                    rv = transferUnblock(item);
                    if (rv != 0) {
                        threadExit(EXIT_FAILURE, NULL);
                    }
                    break;
                }
            }
            rbcloselist(list);

            if (!shuttingdown) {
                sendString(control, channel, INTERNAL, CONN_DISCONNECT_RETRY,
                           LOG_INFO, "Remote side of channel died");
            }
            break;

          default:
            WARNINGMSG("Received unknown control message %d", skMsgType(msg));
        }

        skMsgDestroy(msg);
    }

    DEBUG_PRINT1("server_main() thread ended");

    return NULL;
}


/*
 *    THREAD ENTRY POINT
 *
 *    Entry point for the "connection" thread, started from
 *    clientMain().
 */
static void *startClientConnection(
    void           *vitem)
{
    transfer_t *item = (transfer_t *)vitem;
    void *exit_status = exit_standard;
    int waitsecs = 0;
    const char *connection_type = "TCP";
    connection_fn_t connection_function;
    socklen_t addrlen;
    int tls = 0;
    char buf[SK_NUM2DOT_STRLEN];


    item->thread_exists = 1;

    DEBUG_PRINT1("client_connection() thread started");

    while (!shuttingdown) {
        size_t i;
        int rv;
        skm_channel_t channel;

        if (waitsecs != 0) {
            int waitcount = waitsecs;

            DEBUG_PRINT2("Failure in connection, "
                         "waiting %d seconds", waitcount);
            while (waitcount-- && !shuttingdown) {
                sleep(1);
            }
            if (shuttingdown) {
                break;
            }
        }

        connection_function = skMsgQueueConnectTCP;
#if SK_ENABLE_GNUTLS
        if (tls_ca_file) {
            tls = 1;
            connection_function = skMsgQueueConnectTLS;
            connection_type = "TCP, TLS";
        }
#endif /* SK_ENABLE_GNUTLS */

        INFOMSG("Attempting to connect to %s (%s)...",
                item->ident, connection_type);

        for (rv = -1, i = 0;
             rv != 0 && i < skSockaddrArraySize(item->addr); i++)
        {
            sk_sockaddr_t *addr = skSockaddrArrayGet(item->addr, i);
            switch (addr->sa.sa_family) {
              case AF_INET:
                addrlen = sizeof(addr->v4);
                break;
              case AF_INET6:
                addrlen = sizeof(addr->v6);
                break;
              default:
                continue;
            }
            skSockaddrString(buf, sizeof(buf), addr);
            DEBUGMSG("Address for %s is %s", item->ident, buf);
            rv = connection_function(control, &addr->sa, addrlen, &channel);
        }

        if (rv != 0) {
            INFOMSG("Attempt to connect to %s failed (%s)",
                    item->ident, connection_type);
            if (waitsecs < 60) {
                waitsecs += 5;
            }
        } else {
            conn_info_t *info;
            char conn_type[RWTRANSFER_CONNECTION_TYPE_SIZE_MAX];

            getConnectionInformation(control, channel, conn_type,
                                     sizeof(conn_type));
            DEBUGMSG("Connected (expecting ident %s) (%s)",
                     item->ident, conn_type);
            info = (conn_info_t *)calloc(1, sizeof(*info));
            if (info == NULL) {
                CRITMSG("Memory allocation failure");
                threadExit(EXIT_FAILURE, exit_failure);
            }
            info->tls = tls;
            info->trnsfr = item;
            rv = skMsgChannelSplit(control, channel, &info->queue);
            if (rv != 0) {
                if (shuttingdown) {
                    break;
                }
                CRITMSG("Failed to split channel");
                threadExit(EXIT_FAILURE, exit_failure);
            }

            info->channel = channel;
            exit_status = handleConnection(info);
            if (exit_status != exit_failure) {
                waitsecs = 0;
            } else if (waitsecs < 60) {
                waitsecs += 5;
            }
        }
    }

    DEBUG_PRINT1("client_connection() thread ended");

    return exit_status;
}


/*
 *    THREAD ENTRY POINT
 *
 *    Entry point for the "client_main" thread, started from
 *    startTransferDaemon()
 */
static void *clientMain(
    void    UNUSED(*dummy))
{
    RBLIST *list;
    transfer_t *item;
    int rv;

    control_thread_valid = 1;

    DEBUG_PRINT1("client_main() thread started");

    list = rbopenlist(transfers);
    if (list == NULL) {
        skAppPrintErr("Memory allocation failure stating client thread");
        threadExit(EXIT_FAILURE, NULL);
    }

    /* Start client threads */
    while ((item = (transfer_t *)rbreadlist(list)) != NULL) {
        rv = skthread_create("connection", &item->thread,
                             startClientConnection, item);
        if (rv != 0) {
            CRITMSG("Failed to create connection thread: %s", strerror(rv));
            threadExit(EXIT_FAILURE, NULL);
        }
    }
    rbcloselist(list);

    /* Start control loop */
    while (!shuttingdown) {
        sk_msg_t *msg;
        skm_channel_t channel;

        rv = skMsgQueueGetMessageFromChannel(control, SKMSG_CHANNEL_CONTROL,
                                             &msg);
        if (rv == -1) {
            assert(shuttingdown);
            continue;
        }

        switch (skMsgType(msg)) {

          case SKMSG_CTL_NEW_CONNECTION:
            /* This can't happen, as we aren't bound */
            ASSERT_ABORT(0);
            break;

          case SKMSG_CTL_CHANNEL_DIED:
            DEBUG_PRINT1("Received SKMSG_CTL_CHANNEL_DIED");
            channel = SKMSG_CTL_MSG_GET_CHANNEL(msg);
            list = rbopenlist(transfers);
            CHECK_ALLOC(list);
            while ((item = (transfer_t *)rbreadlist(list)) != NULL) {
                if (item->channel_exists && channel == item->channel) {
                    INFOMSG("Channel to %s died", item->ident);
                    item->disconnect = 1;
                    rv = transferUnblock(item);
                    if (rv != 0) {
                        threadExit(EXIT_FAILURE, NULL);
                    }
                    break;
                }
            }
            rbcloselist(list);

            sendString(control, channel, INTERNAL, CONN_DISCONNECT_RETRY,
                       LOG_INFO, "Remote side of channel died");
            break;

          default:
            WARNINGMSG("Received unknown control message %d", skMsgType(msg));
        }

        skMsgDestroy(msg);
    }

    DEBUG_PRINT1("client_main() thread ended");
    return NULL;
}


int startTransferDaemon(
    void)
{
    int rv;

    /* Initialize the message queue */
    rv = skMsgQueueCreate(&control);
    if (rv != 0) {
        skAppPrintErr("Failed to initialize message queue");
        exit(EXIT_FAILURE);
    }

#if SK_ENABLE_GNUTLS
    if (tls_ca_file) {
        rv = skMsgQueueAddCA(control, tls_ca_file);
        if (rv != 0) {
            CRITMSG("Invalid Certificate Authority file: %s", tls_ca_file);
            return -1;
        }
#ifdef PKCS12
        if (tls_pkcs12_file) {
            const char *password = getenv(password_env);
            if (password == NULL) {
                password = "";
            }
            rv = skMsgQueueAddPKCS12(control, tls_pkcs12_file, password);
            if (rv != 0) {
                CRITMSG("Invalid encryption cert file: %s", tls_pkcs12_file);
                return -1;
            }
        } else
#endif /* PKCS12 */
        {
            rv = skMsgQueueAddCert(control, tls_cert_file, tls_key_file);
            if (rv != 0) {
                CRITMSG("Invalid encryption cert or key file: %s, %s",
                        tls_cert_file, tls_key_file);
                return -1;
            }
        }
    }
#endif /* SK_ENABLE_GNUTLS */

    switch (mode) {
      case CLIENT:
        rv = skthread_create("client_main", &control_thread,
                             clientMain, NULL);
        if (rv != 0) {
            CRITMSG("Failed to create primary client thread: %s",strerror(rv));
            return -1;
        }
        break;
      case SERVER:
        rv = skthread_create("server_main", &control_thread,
                             serverMain, NULL);
        if (rv != 0) {
            CRITMSG("Failed to create primary server thread: %s",strerror(rv));
            return -1;
        }
        break;
      default:
        ASSERT_ABORT(0);
    }

    return 0;
}


int checkMsg(
    sk_msg_t           *msg,
    sk_msg_queue_t     *q,
    connection_msg_t    type)
{
    skm_type_t t;
    skm_len_t  len;

    assert(msg);
    assert(q);
    assert(type < CONN_NUMBER_OF_CONNECTION_MESSAGES);

    t = skMsgType(msg);

    if (t != type) {
        sendString(q, skMsgChannel(msg), EXTERNAL,
                   CONN_DISCONNECT, LOG_WARNING,
                   "Protocol error: expected %s, got %s (0x%04x)",
                   conn_msg_data[type].name,
                   ((t >= CONN_NUMBER_OF_CONNECTION_MESSAGES)
                    ? "<unknown>"
                    : conn_msg_data[t].name),
                   t);
        return 1;
    }

    if (conn_msg_data[type].size == -1) {
        return 0;
    }

    len = skMsgLength(msg);
    if (len != conn_msg_data[type].size) {
        sendString(q, skMsgChannel(msg), EXTERNAL,
                   CONN_DISCONNECT, LOG_WARNING,
                   "Protocol error: type %s, expected len %" PRId32 ", got %d",
                   conn_msg_data[type].name,
                   conn_msg_data[type].size, len);
        return 1;
    }

    return 0;
}


#undef sendString
int sendString(
    sk_msg_queue_t *q,
    skm_channel_t   channel,
    int             internal,
    skm_type_t      type,
    int             loglevel,
    const char     *fmt,
    ...)
{
    int rv;
    va_list args;
    char msg[MAX_ERROR_MESSAGE];
    int len;

    va_start(args, fmt);
    len = vsnprintf(msg, sizeof(msg), fmt, args);
    if (len >= (int)sizeof(msg)) {
        len = sizeof(msg) - 1;
        msg[len] = '\0';
    }

    if (internal) {
        rv = skMsgQueueInjectMessage(q, channel, type, msg, len + 1);
    } else {
        rv = skMsgQueueSendMessage(q, channel, type, msg, len + 1);
    }

    if (!internal) {
        sklog(loglevel, "Sending \"%s\"", msg);
    }
    return rv;
}


void threadExit(
    int             status,
    void           *retval)
{
    DEBUG_PRINT1("threadExit called");
    main_retval = status;
    pthread_kill(main_thread, SIGQUIT);
    pthread_exit(retval);
}


/*
** Local Variables:
** mode:c
** indent-tabs-mode:nil
** c-basic-offset:4
** End:
*/

[-- Attachment #3: Type: text/plain, Size: 41 bytes --]


-- 
Michael Welsh Duggan
(mwd@cert.org)

^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-17 16:27                                             ` Michael Welsh Duggan
  2013-01-17 16:28                                               ` Michael Welsh Duggan
@ 2013-01-23 14:16                                               ` Alan Mackenzie
  2013-01-23 15:39                                                 ` Michael Welsh Duggan
  1 sibling, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2013-01-23 14:16 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael.

On Thu, Jan 17, 2013 at 11:27:04AM -0500, Michael Welsh Duggan wrote:
> Alan Mackenzie <acm@muc.de> writes:

> [This] fixes this case, indeed.  Unfortunately, here's another.

> emacs -Q rwtransfer.c
>   M-x c-toggle-parse-state-debug
>   M->
> Then type M-v until the parse failure happens.  For me it happens at 
> 32% point in the file.  Please not that this particular problem only
> happens when paging through the file in reverse order.

> c-parse-state inconsistency at 15885: using cache: (15636 15181 (13849 . 15141)), from scratch: (15636 (15303 . 15493) 15181 (13849 . 15141))
> Old state:
> (setq c-state-cache '(16334 16271 16248 (16059 . 16193) 15181 (13849 . 15141))  c-state-cache-good-pos 16335  c-state-nonlit-pos-cache '(48473 45473 42473 39473 36473 33473 30473 27378 24378 21260 18015 15015 12015 9015 6015 3015)  c-state-nonlit-pos-cache-limit 48473  c-state-semi-nonlit-pos-cache '(48323 45323 42323 39323 36323 33260 30260 27260 24260 21260 18001 15001 12001 9001 6001 3001)  c-state-semi-nonlit-pos-cache-limit 48323  c-state-brace-pair-desert '(15181 . 17388)  c-state-point-min 1  c-state-point-min-lit-type nil  c-state-point-min-lit-start nil  c-state-min-scan-pos 1  c-state-old-cpp-beg nil  c-state-old-cpp-end nil  c-parse-state-point 16335)
> c-parse-state inconsistency at 15885: using cache: (15636 15181 (13849 . 15141)), from scratch: (15636 (15303 . 15493) 15181 (13849 . 15141))

I think the following patch should fix that glitch.  I've also taken the
opportunity to simplify things a little (part of the global state was
being passed needlessly as a parameter) and to rename some variables for
more consistency.

Would you try this out and confirm it works, as usual, please.

However, this isn't the end of the story - 

(i) Start your test case in rwtransfer.c, and M-v until the top of the
  file.  (This shouldn't display any inconsistency messages)
(ii) M-x goto-char <ret> 20001 <ret>.  This should go to EOL 671, just
  after a "}".
(iii) Type <space> }.  (Two characters)
(iv) C-v, possibly twice.

This displays a message something like:
    c-parse-state inconsistency at 21070: using cache: ((20458 . 20935)),
    from scratch: ((20838 . 20877))
, together with a state dump.

This bug isn't a new one, but I've just come across it.  I'll be working
on it in the meantime.

Here's the patch, based on the savannah emacs-24 branch (which should be
identical to the trunk):



=== modified file 'lisp/progmodes/cc-engine.el'
*** lisp/progmodes/cc-engine.el	2013-01-09 21:33:00 +0000
--- lisp/progmodes/cc-engine.el	2013-01-23 13:36:33 +0000
***************
*** 2545,2558 ****
    ;;
    ;; The return value is a list, one of the following:
    ;;
!   ;; o - ('forward CACHE-POS START-POINT) - scan forward from START-POINT,
!   ;;                                        which is not less than CACHE-POS.
!   ;; o - ('backward CACHE-POS nil) - scan backwards (from HERE).
!   ;; o - ('BOD nil START-POINT) - scan forwards from START-POINT, which is at the
    ;;   top level.
!   ;; o - ('IN-LIT nil nil) - point is inside the literal containing point-min.
!   ;; , where CACHE-POS is the highest position recorded in `c-state-cache' at
!   ;; or below HERE.
    (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
  	BOD-pos		    ; position of 2nd BOD before HERE.
  	strategy	    ; 'forward, 'backward, 'BOD, or 'IN-LIT.
--- 2545,2556 ----
    ;;
    ;; The return value is a list, one of the following:
    ;;
!   ;; o - ('forward START-POINT) - scan forward from START-POINT,
!   ;;	 which is not less than the highest position in `c-state-cache' below here.
!   ;; o - ('backward nil) - scan backwards (from HERE).
!   ;; o - ('BOD START-POINT) - scan forwards from START-POINT, which is at the
    ;;   top level.
!   ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
    (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
  	BOD-pos		    ; position of 2nd BOD before HERE.
  	strategy	    ; 'forward, 'backward, 'BOD, or 'IN-LIT.
***************
*** 2590,2596 ****
  
      (list
       strategy
-      (and (memq strategy '(forward backward)) cache-pos)
       (and (memq strategy '(forward BOD)) start-point))))
  
  
--- 2588,2593 ----
***************
*** 2657,2663 ****
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
!       (let* (new-cons
  	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
  	     (macro-start-or-from
  	      (progn (goto-char from)
--- 2654,2661 ----
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
!       (let* ((here (point-max))
! 	     new-cons
  	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
  	     (macro-start-or-from
  	      (progn (goto-char from)
***************
*** 2692,2697 ****
--- 2690,2696 ----
  		;; search bound, even though the algorithm below would skip
  		;; over the new paren pair.
  		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
+ 	    (widen)
  	    (narrow-to-region
  		(cond
  		 ((and desert-lim cache-lim)
***************
*** 2711,2726 ****
  		  (while
  		      (and (setq ce (scan-lists bra -1 -1)) ; back past )/]/}; might signal
  			   (setq bra (scan-lists ce -1 1)) ; back past (/[/{; might signal
! 			   (or (> ce upper-lim)
! 			       (not (eq (char-after bra) ?\{))
! 			       (and (goto-char bra)
! 				    (c-beginning-of-macro)
! 				    (< (point) macro-start-or-from))))))
  		(and ce (< ce bra)))
  	    (setq bra ce))	; If we just backed over an unbalanced closing
  					; brace, ignore it.
  
! 	  (if (and ce (< bra ce) (eq (char-after bra) ?\{))
  	      ;; We've found the desired brace-pair.
  	      (progn
  		(setq new-cons (cons bra (1+ ce)))
--- 2710,2727 ----
  		  (while
  		      (and (setq ce (scan-lists bra -1 -1)) ; back past )/]/}; might signal
  			   (setq bra (scan-lists ce -1 1)) ; back past (/[/{; might signal
! 			   (or (> bra here) ;(> ce here)
! 			       (and
! 				(< ce here)
! 				(or (not (eq (char-after bra) ?\{))
! 				    (and (goto-char bra)
! 					 (c-beginning-of-macro)
! 					 (< (point) macro-start-or-from))))))))
  		(and ce (< ce bra)))
  	    (setq bra ce))	; If we just backed over an unbalanced closing
  					; brace, ignore it.
  
! 	  (if (and ce (< ce here) (< bra ce) (eq (char-after bra) ?\{))
  	      ;; We've found the desired brace-pair.
  	      (progn
  		(setq new-cons (cons bra (1+ ce)))
***************
*** 2734,2740 ****
  		 (t (setq c-state-cache (cons new-cons c-state-cache)))))
  
  	    ;; We haven't found a brace pair.  Record this in the cache.
! 	    (setq c-state-brace-pair-desert (cons cache-pos from))))))))
  
  (defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
    ;; If BRA+1 is nil, do nothing.  Otherwise, BRA+1 is the buffer position
--- 2735,2745 ----
  		 (t (setq c-state-cache (cons new-cons c-state-cache)))))
  
  	    ;; We haven't found a brace pair.  Record this in the cache.
! 	    (setq c-state-brace-pair-desert
! 		  (cons (if (and ce (< bra ce) (> ce here)) ; {..} straddling HERE?
! 			    bra
! 			  (point-min))
! 			(min here from)))))))))
  
  (defsubst c-state-push-any-brace-pair (bra+1 macro-start-or-here)
    ;; If BRA+1 is nil, do nothing.  Otherwise, BRA+1 is the buffer position
***************
*** 2852,2870 ****
         (paren+1)
         (t from)))))
  
! (defun c-remove-stale-state-cache (good-pos pps-point)
    ;; Remove stale entries from the `c-cache-state', i.e. those which will
    ;; not be in it when it is amended for position (point-max).
    ;; Additionally, the "outermost" open-brace entry before (point-max)
    ;; will be converted to a cons if the matching close-brace is scanned.
    ;;
!   ;; GOOD-POS is a "maximal" "safe position" - there must be no open
!   ;; parens/braces/brackets between GOOD-POS and (point-max).
    ;;
    ;; As a second thing, calculate the result of parse-partial-sexp at
!   ;; PPS-POINT, w.r.t. GOOD-POS.  The motivation here is that
    ;; `c-state-cache-good-pos' may become PPS-POINT, but the caller may need to
!   ;; adjust it to get outside a string/comment.  (Sorry about this!  The code
    ;; needs to be FAST).
    ;;
    ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
--- 2857,2875 ----
         (paren+1)
         (t from)))))
  
! (defun c-remove-stale-state-cache (start-point pps-point)
    ;; Remove stale entries from the `c-cache-state', i.e. those which will
    ;; not be in it when it is amended for position (point-max).
    ;; Additionally, the "outermost" open-brace entry before (point-max)
    ;; will be converted to a cons if the matching close-brace is scanned.
    ;;
!   ;; START-POINT is a "maximal" "safe position" - there must be no open
!   ;; parens/braces/brackets between START-POINT and (point-max).
    ;;
    ;; As a second thing, calculate the result of parse-partial-sexp at
!   ;; PPS-POINT, w.r.t. START-POINT.  The motivation here is that
    ;; `c-state-cache-good-pos' may become PPS-POINT, but the caller may need to
!   ;; adjust it to get outside a string/comment.	 (Sorry about this!  The code
    ;; needs to be FAST).
    ;;
    ;; Return a list (GOOD-POS SCAN-BACK-POS PPS-STATE), where
***************
*** 2872,2878 ****
    ;;   to be good (we aim for this to be as high as possible);
    ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
    ;;   preceding POS which needs to be recorded in `c-state-cache'.  It is a
!   ;;   position to scan backwards from.
    ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
    (save-restriction
      (narrow-to-region 1 (point-max))
--- 2877,2885 ----
    ;;   to be good (we aim for this to be as high as possible);
    ;; o - SCAN-BACK-POS, if not nil, indicates there may be a brace pair
    ;;   preceding POS which needs to be recorded in `c-state-cache'.  It is a
!   ;;   position to scan backwards from.  It is the position of the "{" of the
!   ;;   last element to be removed from `c-state-cache', when that elt is a
!   ;;   cons, otherwise nil.
    ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
    (save-restriction
      (narrow-to-region 1 (point-max))
***************
*** 2882,2902 ****
  		(goto-char (point-max))
  		(and (c-beginning-of-macro)
  		     (point))))
! 	     (good-pos-actual-macro-start ; Start of macro containing good-pos
! 					; or nil
! 	      (and (< good-pos (point-max))
  		   (save-excursion
! 		     (goto-char good-pos)
  		     (and (c-beginning-of-macro)
  			  (point)))))
! 	     (good-pos-actual-macro-end	; End of this macro, (maybe
  					; (point-max)), or nil.
! 	      (and good-pos-actual-macro-start
  		   (save-excursion
! 		     (goto-char good-pos-actual-macro-start)
  		     (c-end-of-macro)
  		     (point))))
! 	     pps-state 			; Will be 9 or 10 elements long.
  	     pos
  	     upper-lim	   ; ,beyond which `c-state-cache' entries are removed
  	     scan-back-pos
--- 2889,2909 ----
  		(goto-char (point-max))
  		(and (c-beginning-of-macro)
  		     (point))))
! 	     (start-point-actual-macro-start ; Start of macro containing
! 					     ; start-point or nil
! 	      (and (< start-point (point-max))
  		   (save-excursion
! 		     (goto-char start-point)
  		     (and (c-beginning-of-macro)
  			  (point)))))
! 	     (start-point-actual-macro-end ; End of this macro, (maybe
  					; (point-max)), or nil.
! 	      (and start-point-actual-macro-start
  		   (save-excursion
! 		     (goto-char start-point-actual-macro-start)
  		     (c-end-of-macro)
  		     (point))))
! 	     pps-state			; Will be 9 or 10 elements long.
  	     pos
  	     upper-lim	   ; ,beyond which `c-state-cache' entries are removed
  	     scan-back-pos
***************
*** 2926,2940 ****
  	;; The next loop jumps forward out of a nested level of parens each
  	;; time round; the corresponding elements in `c-state-cache' are
  	;; removed.  `pos' is just after the brace-pair or the open paren at
! 	;; (car c-state-cache).  There can be no open parens/braces/brackets
! 	;; between `good-pos'/`good-pos-actual-macro-start' and (point-max),
  	;; due to the interface spec to this function.
! 	(setq pos (if (and good-pos-actual-macro-end
! 			   (not (eq good-pos-actual-macro-start
  				    in-macro-start)))
! 		      (1+ good-pos-actual-macro-end) ; get outside the macro as
  					; marked by a `category' text property.
! 		    good-pos))
  	(goto-char pos)
  	(while (and c-state-cache
  		    (< (point) (point-max)))
--- 2933,2947 ----
  	;; The next loop jumps forward out of a nested level of parens each
  	;; time round; the corresponding elements in `c-state-cache' are
  	;; removed.  `pos' is just after the brace-pair or the open paren at
! 	;; (car c-state-cache).	 There can be no open parens/braces/brackets
! 	;; between `start-point'/`start-point-actual-macro-start' and (point-max),
  	;; due to the interface spec to this function.
! 	(setq pos (if (and start-point-actual-macro-end
! 			   (not (eq start-point-actual-macro-start
  				    in-macro-start)))
! 		      (1+ start-point-actual-macro-end) ; get outside the macro as
  					; marked by a `category' text property.
! 		    start-point))
  	(goto-char pos)
  	(while (and c-state-cache
  		    (< (point) (point-max)))
***************
*** 2993,3006 ****
  
  	(list pos scan-back-pos pps-state)))))
  
! (defun c-remove-stale-state-cache-backwards (here cache-pos)
    ;; Strip stale elements of `c-state-cache' by moving backwards through the
    ;; buffer, and inform the caller of the scenario detected.
    ;;
    ;; HERE is the position we're setting `c-state-cache' for.
!   ;; CACHE-POS is just after the latest recorded position in `c-state-cache'
!   ;;   before HERE, or a position at or near point-min which isn't in a
!   ;;   literal.
    ;;
    ;; This function must only be called only when (> `c-state-cache-good-pos'
    ;; HERE).  Usually the gap between CACHE-POS and HERE is large.  It is thus
--- 3000,3013 ----
  
  	(list pos scan-back-pos pps-state)))))
  
! (defun c-remove-stale-state-cache-backwards (here)
    ;; Strip stale elements of `c-state-cache' by moving backwards through the
    ;; buffer, and inform the caller of the scenario detected.
    ;;
    ;; HERE is the position we're setting `c-state-cache' for.
!   ;; CACHE-POS (a locally bound variable) is just after the latest recorded
!   ;;   position in `c-state-cache' before HERE, or a position at or near
!   ;;   point-min which isn't in a literal.
    ;;
    ;; This function must only be called only when (> `c-state-cache-good-pos'
    ;; HERE).  Usually the gap between CACHE-POS and HERE is large.  It is thus
***************
*** 3023,3032 ****
    ;; The comments in this defun use "paren" to mean parenthesis or square
    ;; bracket (as contrasted with a brace), and "(" and ")" likewise.
    ;;
!   ;;    .   {..} (..) (..)  ( .. {   }  ) (...)    ( ....          .  ..)
!   ;;    |                   |       |   |     |                    |
!   ;;    CP                  E      here D     C                   good
!   (let ((pos c-state-cache-good-pos)
  	pa ren	       ; positions of "(" and ")"
  	dropped-cons ; whether the last element dropped from `c-state-cache'
  		     ; was a cons (representing a brace-pair)
--- 3030,3040 ----
    ;; The comments in this defun use "paren" to mean parenthesis or square
    ;; bracket (as contrasted with a brace), and "(" and ")" likewise.
    ;;
!   ;;	.   {..} (..) (..)  ( .. {   }	) (...)	   ( ....	   .  ..)
!   ;;	|		    |	    |	|     |			   |
!   ;;	CP		    E	   here D     C			  good
!   (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
! 	(pos c-state-cache-good-pos)
  	pa ren	       ; positions of "(" and ")"
  	dropped-cons ; whether the last element dropped from `c-state-cache'
  		     ; was a cons (representing a brace-pair)
***************
*** 3263,3269 ****
  	 cache-pos	     ; highest position below HERE already existing in
  			     ; cache (or 1).
  	 good-pos
! 	 start-point
  	 bopl-state
  	 res
  	 scan-backward-pos scan-forward-p) ; used for 'backward.
--- 3271,3278 ----
  	 cache-pos	     ; highest position below HERE already existing in
  			     ; cache (or 1).
  	 good-pos
! 	 start-point ; (when scanning forward) a place below HERE where there
! 		     ; are no open parens/braces between it and HERE.
  	 bopl-state
  	 res
  	 scan-backward-pos scan-forward-p) ; used for 'backward.
***************
*** 3274,3281 ****
      ;; Strategy?
      (setq res (c-parse-state-get-strategy here c-state-cache-good-pos)
  	  strategy (car res)
! 	  cache-pos (cadr res)
! 	  start-point (nth 2 res))
  
      (when (eq strategy 'BOD)
        (setq c-state-cache nil
--- 3283,3289 ----
      ;; Strategy?
      (setq res (c-parse-state-get-strategy here c-state-cache-good-pos)
  	  strategy (car res)
! 	  start-point (cadr res))
  
      (when (eq strategy 'BOD)
        (setq c-state-cache nil
***************
*** 3302,3308 ****
  		good-pos)))
  
         ((eq strategy 'backward)
! 	(setq res (c-remove-stale-state-cache-backwards here cache-pos)
  	      good-pos (car res)
  	      scan-backward-pos (cadr res)
  	      scan-forward-p (car (cddr res)))
--- 3310,3316 ----
  		good-pos)))
  
         ((eq strategy 'backward)
! 	(setq res (c-remove-stale-state-cache-backwards here)
  	      good-pos (car res)
  	      scan-backward-pos (cadr res)
  	      scan-forward-p (car (cddr res)))



> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-23 14:16                                               ` Alan Mackenzie
@ 2013-01-23 15:39                                                 ` Michael Welsh Duggan
  2013-01-29 11:37                                                   ` Alan Mackenzie
       [not found]                                                   ` <20130129113737.GA4544@acm.acm>
  0 siblings, 2 replies; 55+ messages in thread
From: Michael Welsh Duggan @ 2013-01-23 15:39 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Hi, Michael.
>
> On Thu, Jan 17, 2013 at 11:27:04AM -0500, Michael Welsh Duggan wrote:
>> Alan Mackenzie <acm@muc.de> writes:
>
>> [This] fixes this case, indeed.  Unfortunately, here's another.
>

[...]

> I think the following patch should fix that glitch.  I've also taken the
> opportunity to simplify things a little (part of the global state was
> being passed needlessly as a parameter) and to rename some variables for
> more consistency.
>
> Would you try this out and confirm it works, as usual, please.

I can confirm that this fixes this particular problem.

> However, this isn't the end of the story - 
>
> (i) Start your test case in rwtransfer.c, and M-v until the top of the
>   file.  (This shouldn't display any inconsistency messages)
> (ii) M-x goto-char <ret> 20001 <ret>.  This should go to EOL 671, just
>   after a "}".
> (iii) Type <space> }.  (Two characters)
> (iv) C-v, possibly twice.
>
> This displays a message something like:
>     c-parse-state inconsistency at 21070: using cache: ((20458 . 20935)),
>     from scratch: ((20838 . 20877))
> , together with a state dump.
>
> This bug isn't a new one, but I've just come across it.  I'll be working
> on it in the meantime.

Oh, good.  I haven't reported any "type stuff" errors I have been
getting because they are harder to reproduce.  (Unless it is triggered
the first time you've typed in the buffer, it's hard to replicate the
exact scenario.)  I usually wait until you've fixed the last thing I
sent in before attempting to report another, just in case the thing you
are fixing is related.

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-01-23 15:39                                                 ` Michael Welsh Duggan
@ 2013-01-29 11:37                                                   ` Alan Mackenzie
       [not found]                                                   ` <20130129113737.GA4544@acm.acm>
  1 sibling, 0 replies; 55+ messages in thread
From: Alan Mackenzie @ 2013-01-29 11:37 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org, Kim Storm

Hi, Michael.

On Wed, Jan 23, 2013 at 10:39:34AM -0500, Michael Welsh Duggan wrote:
> Alan Mackenzie <acm@muc.de> writes:

> > However, this isn't the end of the story - 

> > (i) Start your test case in rwtransfer.c, and M-v until the top of the
> >   file.  (This shouldn't display any inconsistency messages)
> > (ii) M-x goto-char <ret> 20001 <ret>.  This should go to EOL 671, just
> >   after a "}".
> > (iii) Type <space> }.  (Two characters)
> > (iv) C-v, possibly twice.

> > This displays a message something like:
> >     c-parse-state inconsistency at 21070: using cache: ((20458 . 20935)),
> >     from scratch: ((20838 . 20877))
> > , together with a state dump.

> > This bug isn't a new one, but I've just come across it.  I'll be working
> > on it in the meantime.

> Oh, good.  I haven't reported any "type stuff" errors I have been
> getting because they are harder to reproduce.  (Unless it is triggered
> the first time you've typed in the buffer, it's hard to replicate the
> exact scenario.)  I usually wait until you've fixed the last thing I
> sent in before attempting to report another, just in case the thing you
> are fixing is related.

OK, I think I've fixed that above bug.  I've also done a moderate amount
of refactoring to simplify things for the next bug, if any.

I've removed the scanning strategy "start at the 2nd previous column-0
beginning-of-defun", because it was returning false results, even in C
Mode.  I'd already disabled it for C++ Mode (because hackers frequently
put things inside namespaces at column 0).  One consequence is that
running with `c-toggle-parse-state-debug' is somewhat slower.  Sorry for
that.

Could you try this new version, please.  The patch is based on the
emacs-24 branch of the savannah bzr repository.  This should be identical
to the trunk.



=== modified file 'lisp/progmodes/cc-engine.el'
*** lisp/progmodes/cc-engine.el	2013-01-23 18:58:11 +0000
--- lisp/progmodes/cc-engine.el	2013-01-29 11:03:35 +0000
***************
*** 2477,2496 ****
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
  ;; Defuns which analyze the buffer, yet don't change `c-state-cache'.
- (defun c-get-fallback-scan-pos (here)
-   ;; Return a start position for building `c-state-cache' from
-   ;; scratch.  This will be at the top level, 2 defuns back.
-   (save-excursion
-     ;; Go back 2 bods, but ignore any bogus positions returned by
-     ;; beginning-of-defun (i.e. open paren in column zero).
-     (goto-char here)
-     (let ((cnt 2))
-       (while (not (or (bobp) (zerop cnt)))
- 	(c-beginning-of-defun-1)	; Pure elisp BOD.
- 	(if (eq (char-after) ?\{)
- 	    (setq cnt (1- cnt)))))
-     (point)))
- 
  (defun c-state-balance-parens-backwards (here- here+ top)
    ;; Return the position of the opening paren/brace/bracket before HERE- which
    ;; matches the outermost close p/b/b between HERE+ and TOP.  Except when
--- 2477,2482 ----
***************
*** 2548,2594 ****
    ;; o - ('forward START-POINT) - scan forward from START-POINT,
    ;;	 which is not less than the highest position in `c-state-cache' below here.
    ;; o - ('backward nil) - scan backwards (from HERE).
-   ;; o - ('BOD START-POINT) - scan forwards from START-POINT, which is at the
-   ;;   top level.
    ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
    (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
! 	BOD-pos		    ; position of 2nd BOD before HERE.
! 	strategy	    ; 'forward, 'backward, 'BOD, or 'IN-LIT.
! 	start-point
! 	how-far)			; putative scanning distance.
      (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
      (cond
       ((< here (c-state-get-min-scan-pos))
!       (setq strategy 'IN-LIT
! 	    start-point nil
! 	    cache-pos nil
! 	    how-far 0))
       ((<= good-pos here)
        (setq strategy 'forward
! 	    start-point (max good-pos cache-pos)
! 	    how-far (- here start-point)))
       ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
!       (setq strategy 'backward
! 	    how-far (- good-pos here)))
       (t
        (setq strategy 'forward
! 	      how-far (- here cache-pos)
! 	      start-point cache-pos)))
! 
!     ;; Might we be better off starting from the top level, two defuns back,
!     ;; instead?  This heuristic no longer works well in C++, where
!     ;; declarations inside namespace brace blocks are frequently placed at
!     ;; column zero.
!     (when (and (not (c-major-mode-is 'c++-mode))
! 	       (> how-far c-state-cache-too-far))
!       (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
!       (if (< (- here BOD-pos) how-far)
! 	  (setq strategy 'BOD
! 		start-point BOD-pos)))
! 
!     (list
!      strategy
!      (and (memq strategy '(forward BOD)) start-point))))
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
--- 2534,2556 ----
    ;; o - ('forward START-POINT) - scan forward from START-POINT,
    ;;	 which is not less than the highest position in `c-state-cache' below here.
    ;; o - ('backward nil) - scan backwards (from HERE).
    ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
    (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
! 	strategy	    ; 'forward, 'backward, or 'IN-LIT.
! 	start-point)
      (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
      (cond
       ((< here (c-state-get-min-scan-pos))
!       (setq strategy 'IN-LIT))
       ((<= good-pos here)
        (setq strategy 'forward
! 	    start-point (max good-pos cache-pos)))
       ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
!       (setq strategy 'backward))
       (t
        (setq strategy 'forward
! 	    start-point cache-pos)))
!     (list strategy (and (eq strategy 'forward) start-point))))
  
  
  ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
***************
*** 2630,2636 ****
  
    (setq c-state-point-min (point-min)))
  
! (defun c-append-lower-brace-pair-to-state-cache (from &optional upper-lim)
    ;; If there is a brace pair preceding FROM in the buffer, at the same level
    ;; of nesting (not necessarily immediately preceding), push a cons onto
    ;; `c-state-cache' to represent it.  FROM must not be inside a literal.  If
--- 2592,2598 ----
  
    (setq c-state-point-min (point-min)))
  
! (defun c-append-lower-brace-pair-to-state-cache (from here &optional upper-lim)
    ;; If there is a brace pair preceding FROM in the buffer, at the same level
    ;; of nesting (not necessarily immediately preceding), push a cons onto
    ;; `c-state-cache' to represent it.  FROM must not be inside a literal.  If
***************
*** 2654,2661 ****
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
!       (let* ((here (point-max))
! 	     new-cons
  	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
  	     (macro-start-or-from
  	      (progn (goto-char from)
--- 2616,2622 ----
    ;; reduce the time wasted in repeated fruitless searches in brace deserts.
    (save-excursion
      (save-restriction
!       (let* (new-cons
  	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
  	     (macro-start-or-from
  	      (progn (goto-char from)
***************
*** 2690,2696 ****
  		;; search bound, even though the algorithm below would skip
  		;; over the new paren pair.
  		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
- 	    (widen)
  	    (narrow-to-region
  		(cond
  		 ((and desert-lim cache-lim)
--- 2651,2656 ----
***************
*** 2698,2704 ****
  		 (desert-lim)
  		 (cache-lim)
  		 ((point-min)))
! 		(point-max)))
  
  	  ;; In the next pair of nested loops, the inner one moves back past a
  	  ;; pair of (mis-)matching parens or brackets; the outer one moves
--- 2658,2666 ----
  		 (desert-lim)
  		 (cache-lim)
  		 ((point-min)))
! 		;; The top limit is EOB to ensure that `bra' is inside the
! 		;; accessible part of the buffer at the next scan operation.
! 		(1+ (buffer-size))))
  
  	  ;; In the next pair of nested loops, the inner one moves back past a
  	  ;; pair of (mis-)matching parens or brackets; the outer one moves
***************
*** 2765,2789 ****
  		      (if (consp (car c-state-cache))
  			  (cdr c-state-cache)
  			c-state-cache)))
! 	;; N.B.  This defsubst codes one method for the simple, normal case,
  	;; and a more sophisticated, slower way for the general case.  Don't
  	;; eliminate this defsubst - it's a speed optimization.
! 	(c-append-lower-brace-pair-to-state-cache (1- bra+1)))))
  
! (defun c-append-to-state-cache (from)
!   ;; Scan the buffer from FROM to (point-max), adding elements into
!   ;; `c-state-cache' for braces etc.  Return a candidate for
!   ;; `c-state-cache-good-pos'.
    ;;
    ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
    ;; any.  Typically, it is immediately after it.  It must not be inside a
    ;; literal.
!   (let ((here-bol (c-point 'bol (point-max)))
  	(macro-start-or-here
! 	 (save-excursion (goto-char (point-max))
  			 (if (c-beginning-of-macro)
  			     (point)
! 			   (point-max))))
  	pa+1		      ; pos just after an opening PAren (or brace).
  	(ren+1 from)	      ; usually a pos just after an closing paREN etc.
  			      ; Is actually the pos. to scan for a (/{/[ from,
--- 2727,2750 ----
  		      (if (consp (car c-state-cache))
  			  (cdr c-state-cache)
  			c-state-cache)))
! 	;; N.B.	 This defsubst codes one method for the simple, normal case,
  	;; and a more sophisticated, slower way for the general case.  Don't
  	;; eliminate this defsubst - it's a speed optimization.
! 	(c-append-lower-brace-pair-to-state-cache (1- bra+1) (point-max)))))
  
! (defun c-append-to-state-cache (from here)
!   ;; Scan the buffer from FROM to HERE, adding elements into `c-state-cache'
!   ;; for braces etc.  Return a candidate for `c-state-cache-good-pos'.
    ;;
    ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
    ;; any.  Typically, it is immediately after it.  It must not be inside a
    ;; literal.
!   (let ((here-bol (c-point 'bol here))
  	(macro-start-or-here
! 	 (save-excursion (goto-char here)
  			 (if (c-beginning-of-macro)
  			     (point)
! 			   here)))
  	pa+1		      ; pos just after an opening PAren (or brace).
  	(ren+1 from)	      ; usually a pos just after an closing paREN etc.
  			      ; Is actually the pos. to scan for a (/{/[ from,
***************
*** 2796,2870 ****
  	mstart)		      ; start of a macro.
  
      (save-excursion
!       ;; Each time round the following loop, we enter a successively deeper
!       ;; level of brace/paren nesting.  (Except sometimes we "continue at
!       ;; the existing level".)  `pa+1' is a pos inside an opening
!       ;; brace/paren/bracket, usually just after it.
!       (while
! 	  (progn
! 	    ;; Each time round the next loop moves forward over an opening then
! 	    ;; a closing brace/bracket/paren.  This loop is white hot, so it
! 	    ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
! 	    ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
! 	    ;; call of `scan-lists' signals an error, which happens when there
! 	    ;; are no more b/b/p's to scan.
! 	    (c-safe
! 	      (while t
! 		(setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
! 		      paren+1s (cons pa+1 paren+1s))
! 		(setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
! 		(if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
! 		    (setq bra+1 pa+1))
! 		(setcar paren+1s ren+1)))
  
! 	    (if (and pa+1 (> pa+1 ren+1))
! 		;; We've just entered a deeper nesting level.
! 		(progn
! 		  ;; Insert the brace pair (if present) and the single open
! 		  ;; paren/brace/bracket into `c-state-cache' It cannot be
! 		  ;; inside a macro, except one around point, because of what
! 		  ;; `c-neutralize-syntax-in-CPP' has done.
! 		  (c-state-push-any-brace-pair bra+1 macro-start-or-here)
! 		  ;; Insert the opening brace/bracket/paren position.
! 		  (setq c-state-cache (cons (1- pa+1) c-state-cache))
! 		  ;; Clear admin stuff for the next more nested part of the scan.
! 		  (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
! 		  t)			; Carry on the loop
! 
! 	      ;; All open p/b/b's at this nesting level, if any, have probably
! 	      ;; been closed by matching/mismatching ones.  We're probably
! 	      ;; finished - we just need to check for having found an
! 	      ;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
! 	      ;; macro, due the action of `c-neutralize-syntax-in-CPP'.
! 	      (c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
! 
!       ;; Record the final, innermost, brace-pair if there is one.
!       (c-state-push-any-brace-pair bra+1 macro-start-or-here)
! 
!       ;; Determine a good pos
!       (while (and (setq paren+1 (car paren+1s))
! 		  (> (if (> paren+1 macro-start-or-here)
! 			 paren+1
! 		       (goto-char paren+1)
! 		       (setq mstart (and (c-beginning-of-macro)
! 					 (point)))
! 		       (or mstart paren+1))
! 		     here-bol))
! 	(setq paren+1s (cdr paren+1s)))
!       (cond
!        ((and paren+1 mstart)
! 	(min paren+1 mstart))
!        (paren+1)
!        (t from)))))
  
! (defun c-remove-stale-state-cache (start-point pps-point)
    ;; Remove stale entries from the `c-cache-state', i.e. those which will
!   ;; not be in it when it is amended for position (point-max).
!   ;; Additionally, the "outermost" open-brace entry before (point-max)
!   ;; will be converted to a cons if the matching close-brace is scanned.
    ;;
    ;; START-POINT is a "maximal" "safe position" - there must be no open
!   ;; parens/braces/brackets between START-POINT and (point-max).
    ;;
    ;; As a second thing, calculate the result of parse-partial-sexp at
    ;; PPS-POINT, w.r.t. START-POINT.  The motivation here is that
--- 2757,2833 ----
  	mstart)		      ; start of a macro.
  
      (save-excursion
!       (save-restriction
! 	(narrow-to-region (point-min) here)
! 	;; Each time round the following loop, we enter a successively deeper
! 	;; level of brace/paren nesting.  (Except sometimes we "continue at
! 	;; the existing level".)  `pa+1' is a pos inside an opening
! 	;; brace/paren/bracket, usually just after it.
! 	(while
! 	    (progn
! 	      ;; Each time round the next loop moves forward over an opening then
! 	      ;; a closing brace/bracket/paren.  This loop is white hot, so it
! 	      ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
! 	      ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
! 	      ;; call of `scan-lists' signals an error, which happens when there
! 	      ;; are no more b/b/p's to scan.
! 	      (c-safe
! 		(while t
! 		  (setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
! 			paren+1s (cons pa+1 paren+1s))
! 		  (setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
! 		  (if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
! 		      (setq bra+1 pa+1))
! 		  (setcar paren+1s ren+1)))
  
! 	      (if (and pa+1 (> pa+1 ren+1))
! 		  ;; We've just entered a deeper nesting level.
! 		  (progn
! 		    ;; Insert the brace pair (if present) and the single open
! 		    ;; paren/brace/bracket into `c-state-cache' It cannot be
! 		    ;; inside a macro, except one around point, because of what
! 		    ;; `c-neutralize-syntax-in-CPP' has done.
! 		    (c-state-push-any-brace-pair bra+1 macro-start-or-here)
! 		    ;; Insert the opening brace/bracket/paren position.
! 		    (setq c-state-cache (cons (1- pa+1) c-state-cache))
! 		    ;; Clear admin stuff for the next more nested part of the scan.
! 		    (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
! 		    t)			; Carry on the loop
! 
! 		;; All open p/b/b's at this nesting level, if any, have probably
! 		;; been closed by matching/mismatching ones.  We're probably
! 		;; finished - we just need to check for having found an
! 		;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
! 		;; macro, due the action of `c-neutralize-syntax-in-CPP'.
! 		(c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
! 
! 	;; Record the final, innermost, brace-pair if there is one.
! 	(c-state-push-any-brace-pair bra+1 macro-start-or-here)
! 
! 	;; Determine a good pos
! 	(while (and (setq paren+1 (car paren+1s))
! 		    (> (if (> paren+1 macro-start-or-here)
! 			   paren+1
! 			 (goto-char paren+1)
! 			 (setq mstart (and (c-beginning-of-macro)
! 					   (point)))
! 			 (or mstart paren+1))
! 		       here-bol))
! 	  (setq paren+1s (cdr paren+1s)))
! 	(cond
! 	 ((and paren+1 mstart)
! 	  (min paren+1 mstart))
! 	 (paren+1)
! 	 (t from))))))
  
! (defun c-remove-stale-state-cache (start-point here pps-point)
    ;; Remove stale entries from the `c-cache-state', i.e. those which will
!   ;; not be in it when it is amended for position HERE.  Additionally, the
!   ;; "outermost" open-brace entry before HERE will be converted to a cons if
!   ;; the matching close-brace is scanned.
    ;;
    ;; START-POINT is a "maximal" "safe position" - there must be no open
!   ;; parens/braces/brackets between START-POINT and HERE.
    ;;
    ;; As a second thing, calculate the result of parse-partial-sexp at
    ;; PPS-POINT, w.r.t. START-POINT.  The motivation here is that
***************
*** 2881,2903 ****
    ;;   last element to be removed from `c-state-cache', when that elt is a
    ;;   cons, otherwise nil.
    ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
!   (save-restriction
!     (narrow-to-region 1 (point-max))
!     (save-excursion
!       (let* ((in-macro-start   ; start of macro containing (point-max) or nil.
  	      (save-excursion
! 		(goto-char (point-max))
  		(and (c-beginning-of-macro)
  		     (point))))
  	     (start-point-actual-macro-start ; Start of macro containing
  					     ; start-point or nil
! 	      (and (< start-point (point-max))
  		   (save-excursion
  		     (goto-char start-point)
  		     (and (c-beginning-of-macro)
  			  (point)))))
  	     (start-point-actual-macro-end ; End of this macro, (maybe
! 					; (point-max)), or nil.
  	      (and start-point-actual-macro-start
  		   (save-excursion
  		     (goto-char start-point-actual-macro-start)
--- 2844,2866 ----
    ;;   last element to be removed from `c-state-cache', when that elt is a
    ;;   cons, otherwise nil.
    ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
!   (save-excursion
!     (save-restriction
!       (narrow-to-region 1 (point-max))
!       (let* ((in-macro-start   ; start of macro containing HERE or nil.
  	      (save-excursion
! 		(goto-char here)
  		(and (c-beginning-of-macro)
  		     (point))))
  	     (start-point-actual-macro-start ; Start of macro containing
  					     ; start-point or nil
! 	      (and (< start-point here)
  		   (save-excursion
  		     (goto-char start-point)
  		     (and (c-beginning-of-macro)
  			  (point)))))
  	     (start-point-actual-macro-end ; End of this macro, (maybe
! 					; HERE), or nil.
  	      (and start-point-actual-macro-start
  		   (save-excursion
  		     (goto-char start-point-actual-macro-start)
***************
*** 2909,2922 ****
  	     scan-back-pos
  	     pair-beg pps-point-state target-depth)
  
! 	;; Remove entries beyond (point-max).  Also remove any entries inside
! 	;; a macro, unless (point-max) is in the same macro.
  	(setq upper-lim
  	      (if (or (null c-state-old-cpp-beg)
! 		      (and (> (point-max) c-state-old-cpp-beg)
! 			   (< (point-max) c-state-old-cpp-end)))
! 		  (point-max)
! 		(min (point-max) c-state-old-cpp-beg)))
  	(while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
  	  (setq scan-back-pos (car-safe (car c-state-cache)))
  	  (setq c-state-cache (cdr c-state-cache)))
--- 2872,2885 ----
  	     scan-back-pos
  	     pair-beg pps-point-state target-depth)
  
! 	;; Remove entries beyond HERE.  Also remove any entries inside
! 	;; a macro, unless HERE is in the same macro.
  	(setq upper-lim
  	      (if (or (null c-state-old-cpp-beg)
! 		      (and (> here c-state-old-cpp-beg)
! 			   (< here c-state-old-cpp-end)))
! 		  here
! 		(min here c-state-old-cpp-beg)))
  	(while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
  	  (setq scan-back-pos (car-safe (car c-state-cache)))
  	  (setq c-state-cache (cdr c-state-cache)))
***************
*** 2934,2940 ****
  	;; time round; the corresponding elements in `c-state-cache' are
  	;; removed.  `pos' is just after the brace-pair or the open paren at
  	;; (car c-state-cache).	 There can be no open parens/braces/brackets
! 	;; between `start-point'/`start-point-actual-macro-start' and (point-max),
  	;; due to the interface spec to this function.
  	(setq pos (if (and start-point-actual-macro-end
  			   (not (eq start-point-actual-macro-start
--- 2897,2903 ----
  	;; time round; the corresponding elements in `c-state-cache' are
  	;; removed.  `pos' is just after the brace-pair or the open paren at
  	;; (car c-state-cache).	 There can be no open parens/braces/brackets
! 	;; between `start-point'/`start-point-actual-macro-start' and HERE,
  	;; due to the interface spec to this function.
  	(setq pos (if (and start-point-actual-macro-end
  			   (not (eq start-point-actual-macro-start
***************
*** 2944,2950 ****
  		    start-point))
  	(goto-char pos)
  	(while (and c-state-cache
! 		    (< (point) (point-max)))
  	  (cond
  	   ((null pps-state)		; first time through
  	    (setq target-depth -1))
--- 2907,2915 ----
  		    start-point))
  	(goto-char pos)
  	(while (and c-state-cache
! 		    (or (numberp (car c-state-cache)) ; Have we a { at all? 
! 			(cdr c-state-cache))
! 		    (< (point) here))
  	  (cond
  	   ((null pps-state)		; first time through
  	    (setq target-depth -1))
***************
*** 2956,2962 ****
  	  ;; Scan!
  	  (setq pps-state
  		(parse-partial-sexp
! 		 (point) (if (< (point) pps-point) pps-point (point-max))
  		 target-depth
  		 nil pps-state))
  
--- 2921,2927 ----
  	  ;; Scan!
  	  (setq pps-state
  		(parse-partial-sexp
! 		 (point) (if (< (point) pps-point) pps-point here)
  		 target-depth
  		 nil pps-state))
  
***************
*** 3209,3215 ****
        ;; Do we need to add in an earlier brace pair, having lopped one off?
        (if (and dropped-cons
  	       (< too-high-pa (+ here c-state-cache-too-far)))
! 	  (c-append-lower-brace-pair-to-state-cache too-high-pa here-bol))
        (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
  				       (c-state-get-min-scan-pos)))))
  
--- 3174,3180 ----
        ;; Do we need to add in an earlier brace pair, having lopped one off?
        (if (and dropped-cons
  	       (< too-high-pa (+ here c-state-cache-too-far)))
! 	  (c-append-lower-brace-pair-to-state-cache too-high-pa here here-bol))
        (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
  				       (c-state-get-min-scan-pos)))))
  
***************
*** 3285,3331 ****
  	  strategy (car res)
  	  start-point (cadr res))
  
-     (when (eq strategy 'BOD)
-       (setq c-state-cache nil
- 	    c-state-cache-good-pos start-point))
- 
      ;; SCAN!
!     (save-restriction
!       (cond
!        ((memq strategy '(forward BOD))
! 	(narrow-to-region (point-min) here)
! 	(setq res (c-remove-stale-state-cache start-point here-bopl))
! 	(setq cache-pos (car res)
! 	      scan-backward-pos (cadr res)
! 	      bopl-state (car (cddr res))) ; will be nil if (< here-bopl
  					; start-point)
! 	(if scan-backward-pos
! 	    (c-append-lower-brace-pair-to-state-cache scan-backward-pos))
! 	(setq good-pos
! 	      (c-append-to-state-cache cache-pos))
! 	(setq c-state-cache-good-pos
! 	      (if (and bopl-state
! 		       (< good-pos (- here c-state-cache-too-far)))
! 		  (c-state-cache-non-literal-place here-bopl bopl-state)
! 		good-pos)))
! 
!        ((eq strategy 'backward)
! 	(setq res (c-remove-stale-state-cache-backwards here)
! 	      good-pos (car res)
! 	      scan-backward-pos (cadr res)
! 	      scan-forward-p (car (cddr res)))
! 	(if scan-backward-pos
! 	    (c-append-lower-brace-pair-to-state-cache
! 	     scan-backward-pos))
! 	(setq c-state-cache-good-pos
! 	      (if scan-forward-p
! 		  (progn (narrow-to-region (point-min) here)
! 			 (c-append-to-state-cache good-pos))
! 		good-pos)))
  
!        (t ; (eq strategy 'IN-LIT)
! 	(setq c-state-cache nil
! 	      c-state-cache-good-pos nil)))))
  
    c-state-cache)
  
--- 3250,3288 ----
  	  strategy (car res)
  	  start-point (cadr res))
  
      ;; SCAN!
!     (cond
!      ((eq strategy 'forward)
!       (setq res (c-remove-stale-state-cache start-point here here-bopl))
!       (setq cache-pos (car res)
! 	    scan-backward-pos (cadr res)
! 	    bopl-state (car (cddr res))) ; will be nil if (< here-bopl
  					; start-point)
!       (if scan-backward-pos
! 	  (c-append-lower-brace-pair-to-state-cache scan-backward-pos here))
!       (setq good-pos
! 	    (c-append-to-state-cache cache-pos here))
!       (setq c-state-cache-good-pos
! 	    (if (and bopl-state
! 		     (< good-pos (- here c-state-cache-too-far)))
! 		(c-state-cache-non-literal-place here-bopl bopl-state)
! 	      good-pos)))
! 
!      ((eq strategy 'backward)
!       (setq res (c-remove-stale-state-cache-backwards here)
! 	    good-pos (car res)
! 	    scan-backward-pos (cadr res)
! 	    scan-forward-p (car (cddr res)))
!       (if scan-backward-pos
! 	  (c-append-lower-brace-pair-to-state-cache scan-backward-pos here))
!       (setq c-state-cache-good-pos
! 	    (if scan-forward-p
! 		(c-append-to-state-cache good-pos here)
! 	      good-pos)))
  
!      (t					; (eq strategy 'IN-LIT)
!       (setq c-state-cache nil
! 	    c-state-cache-good-pos nil))))
  
    c-state-cache)
  
***************
*** 8559,8566 ****
     ))
  
  (defun c-looking-at-special-brace-list (&optional lim)
!   ;; If we're looking at the start of a pike-style list, ie `({ })',
!   ;; `([ ])', `(< >)' etc, a cons of a cons of its starting and ending
    ;; positions and its entry in c-special-brace-lists is returned, nil
    ;; otherwise.  The ending position is nil if the list is still open.
    ;; LIM is the limit for forward search.  The point may either be at
--- 8516,8523 ----
     ))
  
  (defun c-looking-at-special-brace-list (&optional lim)
!   ;; If we're looking at the start of a pike-style list, ie `({ })',
!   ;; `([ ])', `(< >)' etc, a cons of a cons of its starting and ending
    ;; positions and its entry in c-special-brace-lists is returned, nil
    ;; otherwise.  The ending position is nil if the list is still open.
    ;; LIM is the limit for forward search.  The point may either be at


> -- 
> Michael Welsh Duggan
> (mwd@cert.org)

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
       [not found]                                                   ` <20130129113737.GA4544@acm.acm>
@ 2013-02-01 22:18                                                     ` Michael Welsh Duggan
  2013-02-01 23:50                                                       ` Kim Storm
  0 siblings, 1 reply; 55+ messages in thread
From: Michael Welsh Duggan @ 2013-02-01 22:18 UTC (permalink / raw)
  To: Alan Mackenzie; +Cc: 11749@debbugs.gnu.org, Kim Storm

Alan Mackenzie <acm@muc.de> writes:

> Hi, Michael.

I've been running with this for a few days, and have yet to run into a
problem.  I'll let you know when/if I do in the future.


> On Wed, Jan 23, 2013 at 10:39:34AM -0500, Michael Welsh Duggan wrote:
>> Alan Mackenzie <acm@muc.de> writes:
>
>> > However, this isn't the end of the story - 
>
>> > (i) Start your test case in rwtransfer.c, and M-v until the top of the
>> >   file.  (This shouldn't display any inconsistency messages)
>> > (ii) M-x goto-char <ret> 20001 <ret>.  This should go to EOL 671, just
>> >   after a "}".
>> > (iii) Type <space> }.  (Two characters)
>> > (iv) C-v, possibly twice.
>
>> > This displays a message something like:
>> >     c-parse-state inconsistency at 21070: using cache: ((20458 . 20935)),
>> >     from scratch: ((20838 . 20877))
>> > , together with a state dump.
>
>> > This bug isn't a new one, but I've just come across it.  I'll be working
>> > on it in the meantime.
>
>> Oh, good.  I haven't reported any "type stuff" errors I have been
>> getting because they are harder to reproduce.  (Unless it is triggered
>> the first time you've typed in the buffer, it's hard to replicate the
>> exact scenario.)  I usually wait until you've fixed the last thing I
>> sent in before attempting to report another, just in case the thing you
>> are fixing is related.
>
> OK, I think I've fixed that above bug.  I've also done a moderate amount
> of refactoring to simplify things for the next bug, if any.
>
> I've removed the scanning strategy "start at the 2nd previous column-0
> beginning-of-defun", because it was returning false results, even in C
> Mode.  I'd already disabled it for C++ Mode (because hackers frequently
> put things inside namespaces at column 0).  One consequence is that
> running with `c-toggle-parse-state-debug' is somewhat slower.  Sorry for
> that.
>
> Could you try this new version, please.  The patch is based on the
> emacs-24 branch of the savannah bzr repository.  This should be identical
> to the trunk.
>
>
>
> === modified file 'lisp/progmodes/cc-engine.el'
> *** lisp/progmodes/cc-engine.el	2013-01-23 18:58:11 +0000
> --- lisp/progmodes/cc-engine.el	2013-01-29 11:03:35 +0000
> ***************
> *** 2477,2496 ****
>   
>   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
>   ;; Defuns which analyze the buffer, yet don't change `c-state-cache'.
> - (defun c-get-fallback-scan-pos (here)
> -   ;; Return a start position for building `c-state-cache' from
> -   ;; scratch.  This will be at the top level, 2 defuns back.
> -   (save-excursion
> -     ;; Go back 2 bods, but ignore any bogus positions returned by
> -     ;; beginning-of-defun (i.e. open paren in column zero).
> -     (goto-char here)
> -     (let ((cnt 2))
> -       (while (not (or (bobp) (zerop cnt)))
> - 	(c-beginning-of-defun-1)	; Pure elisp BOD.
> - 	(if (eq (char-after) ?\{)
> - 	    (setq cnt (1- cnt)))))
> -     (point)))
> - 
>   (defun c-state-balance-parens-backwards (here- here+ top)
>     ;; Return the position of the opening paren/brace/bracket before HERE- which
>     ;; matches the outermost close p/b/b between HERE+ and TOP.  Except when
> --- 2477,2482 ----
> ***************
> *** 2548,2594 ****
>     ;; o - ('forward START-POINT) - scan forward from START-POINT,
>     ;;	 which is not less than the highest position in `c-state-cache' below here.
>     ;; o - ('backward nil) - scan backwards (from HERE).
> -   ;; o - ('BOD START-POINT) - scan forwards from START-POINT, which is at the
> -   ;;   top level.
>     ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
>     (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
> ! 	BOD-pos		    ; position of 2nd BOD before HERE.
> ! 	strategy	    ; 'forward, 'backward, 'BOD, or 'IN-LIT.
> ! 	start-point
> ! 	how-far)			; putative scanning distance.
>       (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
>       (cond
>        ((< here (c-state-get-min-scan-pos))
> !       (setq strategy 'IN-LIT
> ! 	    start-point nil
> ! 	    cache-pos nil
> ! 	    how-far 0))
>        ((<= good-pos here)
>         (setq strategy 'forward
> ! 	    start-point (max good-pos cache-pos)
> ! 	    how-far (- here start-point)))
>        ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
> !       (setq strategy 'backward
> ! 	    how-far (- good-pos here)))
>        (t
>         (setq strategy 'forward
> ! 	      how-far (- here cache-pos)
> ! 	      start-point cache-pos)))
> ! 
> !     ;; Might we be better off starting from the top level, two defuns back,
> !     ;; instead?  This heuristic no longer works well in C++, where
> !     ;; declarations inside namespace brace blocks are frequently placed at
> !     ;; column zero.
> !     (when (and (not (c-major-mode-is 'c++-mode))
> ! 	       (> how-far c-state-cache-too-far))
> !       (setq BOD-pos (c-get-fallback-scan-pos here)) ; somewhat EXPENSIVE!!!
> !       (if (< (- here BOD-pos) how-far)
> ! 	  (setq strategy 'BOD
> ! 		start-point BOD-pos)))
> ! 
> !     (list
> !      strategy
> !      (and (memq strategy '(forward BOD)) start-point))))
>   
>   
>   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> --- 2534,2556 ----
>     ;; o - ('forward START-POINT) - scan forward from START-POINT,
>     ;;	 which is not less than the highest position in `c-state-cache' below here.
>     ;; o - ('backward nil) - scan backwards (from HERE).
>     ;; o - ('IN-LIT nil) - point is inside the literal containing point-min.
>     (let ((cache-pos (c-get-cache-scan-pos here))	; highest position below HERE in cache (or 1)
> ! 	strategy	    ; 'forward, 'backward, or 'IN-LIT.
> ! 	start-point)
>       (setq good-pos (or good-pos (c-state-get-min-scan-pos)))
>       (cond
>        ((< here (c-state-get-min-scan-pos))
> !       (setq strategy 'IN-LIT))
>        ((<= good-pos here)
>         (setq strategy 'forward
> ! 	    start-point (max good-pos cache-pos)))
>        ((< (- good-pos here) (- here cache-pos)) ; FIXME!!! ; apply some sort of weighting.
> !       (setq strategy 'backward))
>        (t
>         (setq strategy 'forward
> ! 	    start-point cache-pos)))
> !     (list strategy (and (eq strategy 'forward) start-point))))
>   
>   
>   ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
> ***************
> *** 2630,2636 ****
>   
>     (setq c-state-point-min (point-min)))
>   
> ! (defun c-append-lower-brace-pair-to-state-cache (from &optional upper-lim)
>     ;; If there is a brace pair preceding FROM in the buffer, at the same level
>     ;; of nesting (not necessarily immediately preceding), push a cons onto
>     ;; `c-state-cache' to represent it.  FROM must not be inside a literal.  If
> --- 2592,2598 ----
>   
>     (setq c-state-point-min (point-min)))
>   
> ! (defun c-append-lower-brace-pair-to-state-cache (from here &optional upper-lim)
>     ;; If there is a brace pair preceding FROM in the buffer, at the same level
>     ;; of nesting (not necessarily immediately preceding), push a cons onto
>     ;; `c-state-cache' to represent it.  FROM must not be inside a literal.  If
> ***************
> *** 2654,2661 ****
>     ;; reduce the time wasted in repeated fruitless searches in brace deserts.
>     (save-excursion
>       (save-restriction
> !       (let* ((here (point-max))
> ! 	     new-cons
>   	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
>   	     (macro-start-or-from
>   	      (progn (goto-char from)
> --- 2616,2622 ----
>     ;; reduce the time wasted in repeated fruitless searches in brace deserts.
>     (save-excursion
>       (save-restriction
> !       (let* (new-cons
>   	     (cache-pos (c-state-cache-top-lparen)) ; might be nil.
>   	     (macro-start-or-from
>   	      (progn (goto-char from)
> ***************
> *** 2690,2696 ****
>   		;; search bound, even though the algorithm below would skip
>   		;; over the new paren pair.
>   		(cache-lim (and cache-pos (< cache-pos from) cache-pos)))
> - 	    (widen)
>   	    (narrow-to-region
>   		(cond
>   		 ((and desert-lim cache-lim)
> --- 2651,2656 ----
> ***************
> *** 2698,2704 ****
>   		 (desert-lim)
>   		 (cache-lim)
>   		 ((point-min)))
> ! 		(point-max)))
>   
>   	  ;; In the next pair of nested loops, the inner one moves back past a
>   	  ;; pair of (mis-)matching parens or brackets; the outer one moves
> --- 2658,2666 ----
>   		 (desert-lim)
>   		 (cache-lim)
>   		 ((point-min)))
> ! 		;; The top limit is EOB to ensure that `bra' is inside the
> ! 		;; accessible part of the buffer at the next scan operation.
> ! 		(1+ (buffer-size))))
>   
>   	  ;; In the next pair of nested loops, the inner one moves back past a
>   	  ;; pair of (mis-)matching parens or brackets; the outer one moves
> ***************
> *** 2765,2789 ****
>   		      (if (consp (car c-state-cache))
>   			  (cdr c-state-cache)
>   			c-state-cache)))
> ! 	;; N.B.  This defsubst codes one method for the simple, normal case,
>   	;; and a more sophisticated, slower way for the general case.  Don't
>   	;; eliminate this defsubst - it's a speed optimization.
> ! 	(c-append-lower-brace-pair-to-state-cache (1- bra+1)))))
>   
> ! (defun c-append-to-state-cache (from)
> !   ;; Scan the buffer from FROM to (point-max), adding elements into
> !   ;; `c-state-cache' for braces etc.  Return a candidate for
> !   ;; `c-state-cache-good-pos'.
>     ;;
>     ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
>     ;; any.  Typically, it is immediately after it.  It must not be inside a
>     ;; literal.
> !   (let ((here-bol (c-point 'bol (point-max)))
>   	(macro-start-or-here
> ! 	 (save-excursion (goto-char (point-max))
>   			 (if (c-beginning-of-macro)
>   			     (point)
> ! 			   (point-max))))
>   	pa+1		      ; pos just after an opening PAren (or brace).
>   	(ren+1 from)	      ; usually a pos just after an closing paREN etc.
>   			      ; Is actually the pos. to scan for a (/{/[ from,
> --- 2727,2750 ----
>   		      (if (consp (car c-state-cache))
>   			  (cdr c-state-cache)
>   			c-state-cache)))
> ! 	;; N.B.	 This defsubst codes one method for the simple, normal case,
>   	;; and a more sophisticated, slower way for the general case.  Don't
>   	;; eliminate this defsubst - it's a speed optimization.
> ! 	(c-append-lower-brace-pair-to-state-cache (1- bra+1) (point-max)))))
>   
> ! (defun c-append-to-state-cache (from here)
> !   ;; Scan the buffer from FROM to HERE, adding elements into `c-state-cache'
> !   ;; for braces etc.  Return a candidate for `c-state-cache-good-pos'.
>     ;;
>     ;; FROM must be after the latest brace/paren/bracket in `c-state-cache', if
>     ;; any.  Typically, it is immediately after it.  It must not be inside a
>     ;; literal.
> !   (let ((here-bol (c-point 'bol here))
>   	(macro-start-or-here
> ! 	 (save-excursion (goto-char here)
>   			 (if (c-beginning-of-macro)
>   			     (point)
> ! 			   here)))
>   	pa+1		      ; pos just after an opening PAren (or brace).
>   	(ren+1 from)	      ; usually a pos just after an closing paREN etc.
>   			      ; Is actually the pos. to scan for a (/{/[ from,
> ***************
> *** 2796,2870 ****
>   	mstart)		      ; start of a macro.
>   
>       (save-excursion
> !       ;; Each time round the following loop, we enter a successively deeper
> !       ;; level of brace/paren nesting.  (Except sometimes we "continue at
> !       ;; the existing level".)  `pa+1' is a pos inside an opening
> !       ;; brace/paren/bracket, usually just after it.
> !       (while
> ! 	  (progn
> ! 	    ;; Each time round the next loop moves forward over an opening then
> ! 	    ;; a closing brace/bracket/paren.  This loop is white hot, so it
> ! 	    ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
> ! 	    ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
> ! 	    ;; call of `scan-lists' signals an error, which happens when there
> ! 	    ;; are no more b/b/p's to scan.
> ! 	    (c-safe
> ! 	      (while t
> ! 		(setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
> ! 		      paren+1s (cons pa+1 paren+1s))
> ! 		(setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
> ! 		(if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
> ! 		    (setq bra+1 pa+1))
> ! 		(setcar paren+1s ren+1)))
>   
> ! 	    (if (and pa+1 (> pa+1 ren+1))
> ! 		;; We've just entered a deeper nesting level.
> ! 		(progn
> ! 		  ;; Insert the brace pair (if present) and the single open
> ! 		  ;; paren/brace/bracket into `c-state-cache' It cannot be
> ! 		  ;; inside a macro, except one around point, because of what
> ! 		  ;; `c-neutralize-syntax-in-CPP' has done.
> ! 		  (c-state-push-any-brace-pair bra+1 macro-start-or-here)
> ! 		  ;; Insert the opening brace/bracket/paren position.
> ! 		  (setq c-state-cache (cons (1- pa+1) c-state-cache))
> ! 		  ;; Clear admin stuff for the next more nested part of the scan.
> ! 		  (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
> ! 		  t)			; Carry on the loop
> ! 
> ! 	      ;; All open p/b/b's at this nesting level, if any, have probably
> ! 	      ;; been closed by matching/mismatching ones.  We're probably
> ! 	      ;; finished - we just need to check for having found an
> ! 	      ;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
> ! 	      ;; macro, due the action of `c-neutralize-syntax-in-CPP'.
> ! 	      (c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
> ! 
> !       ;; Record the final, innermost, brace-pair if there is one.
> !       (c-state-push-any-brace-pair bra+1 macro-start-or-here)
> ! 
> !       ;; Determine a good pos
> !       (while (and (setq paren+1 (car paren+1s))
> ! 		  (> (if (> paren+1 macro-start-or-here)
> ! 			 paren+1
> ! 		       (goto-char paren+1)
> ! 		       (setq mstart (and (c-beginning-of-macro)
> ! 					 (point)))
> ! 		       (or mstart paren+1))
> ! 		     here-bol))
> ! 	(setq paren+1s (cdr paren+1s)))
> !       (cond
> !        ((and paren+1 mstart)
> ! 	(min paren+1 mstart))
> !        (paren+1)
> !        (t from)))))
>   
> ! (defun c-remove-stale-state-cache (start-point pps-point)
>     ;; Remove stale entries from the `c-cache-state', i.e. those which will
> !   ;; not be in it when it is amended for position (point-max).
> !   ;; Additionally, the "outermost" open-brace entry before (point-max)
> !   ;; will be converted to a cons if the matching close-brace is scanned.
>     ;;
>     ;; START-POINT is a "maximal" "safe position" - there must be no open
> !   ;; parens/braces/brackets between START-POINT and (point-max).
>     ;;
>     ;; As a second thing, calculate the result of parse-partial-sexp at
>     ;; PPS-POINT, w.r.t. START-POINT.  The motivation here is that
> --- 2757,2833 ----
>   	mstart)		      ; start of a macro.
>   
>       (save-excursion
> !       (save-restriction
> ! 	(narrow-to-region (point-min) here)
> ! 	;; Each time round the following loop, we enter a successively deeper
> ! 	;; level of brace/paren nesting.  (Except sometimes we "continue at
> ! 	;; the existing level".)  `pa+1' is a pos inside an opening
> ! 	;; brace/paren/bracket, usually just after it.
> ! 	(while
> ! 	    (progn
> ! 	      ;; Each time round the next loop moves forward over an opening then
> ! 	      ;; a closing brace/bracket/paren.  This loop is white hot, so it
> ! 	      ;; plays ugly tricks to go fast.  DON'T PUT ANYTHING INTO THIS
> ! 	      ;; LOOP WHICH ISN'T ABSOLUTELY NECESSARY!!!  It terminates when a
> ! 	      ;; call of `scan-lists' signals an error, which happens when there
> ! 	      ;; are no more b/b/p's to scan.
> ! 	      (c-safe
> ! 		(while t
> ! 		  (setq pa+1 (scan-lists ren+1 1 -1) ; Into (/{/[; might signal
> ! 			paren+1s (cons pa+1 paren+1s))
> ! 		  (setq ren+1 (scan-lists pa+1 1 1)) ; Out of )/}/]; might signal
> ! 		  (if (and (eq (char-before pa+1) ?{)) ; Check for a macro later.
> ! 		      (setq bra+1 pa+1))
> ! 		  (setcar paren+1s ren+1)))
>   
> ! 	      (if (and pa+1 (> pa+1 ren+1))
> ! 		  ;; We've just entered a deeper nesting level.
> ! 		  (progn
> ! 		    ;; Insert the brace pair (if present) and the single open
> ! 		    ;; paren/brace/bracket into `c-state-cache' It cannot be
> ! 		    ;; inside a macro, except one around point, because of what
> ! 		    ;; `c-neutralize-syntax-in-CPP' has done.
> ! 		    (c-state-push-any-brace-pair bra+1 macro-start-or-here)
> ! 		    ;; Insert the opening brace/bracket/paren position.
> ! 		    (setq c-state-cache (cons (1- pa+1) c-state-cache))
> ! 		    ;; Clear admin stuff for the next more nested part of the scan.
> ! 		    (setq ren+1 pa+1  pa+1 nil  bra+1 nil  bra+1s nil)
> ! 		    t)			; Carry on the loop
> ! 
> ! 		;; All open p/b/b's at this nesting level, if any, have probably
> ! 		;; been closed by matching/mismatching ones.  We're probably
> ! 		;; finished - we just need to check for having found an
> ! 		;; unmatched )/}/], which we ignore.  Such a )/}/] can't be in a
> ! 		;; macro, due the action of `c-neutralize-syntax-in-CPP'.
> ! 		(c-safe (setq ren+1 (scan-lists ren+1 1 1)))))) ; acts as loop control.
> ! 
> ! 	;; Record the final, innermost, brace-pair if there is one.
> ! 	(c-state-push-any-brace-pair bra+1 macro-start-or-here)
> ! 
> ! 	;; Determine a good pos
> ! 	(while (and (setq paren+1 (car paren+1s))
> ! 		    (> (if (> paren+1 macro-start-or-here)
> ! 			   paren+1
> ! 			 (goto-char paren+1)
> ! 			 (setq mstart (and (c-beginning-of-macro)
> ! 					   (point)))
> ! 			 (or mstart paren+1))
> ! 		       here-bol))
> ! 	  (setq paren+1s (cdr paren+1s)))
> ! 	(cond
> ! 	 ((and paren+1 mstart)
> ! 	  (min paren+1 mstart))
> ! 	 (paren+1)
> ! 	 (t from))))))
>   
> ! (defun c-remove-stale-state-cache (start-point here pps-point)
>     ;; Remove stale entries from the `c-cache-state', i.e. those which will
> !   ;; not be in it when it is amended for position HERE.  Additionally, the
> !   ;; "outermost" open-brace entry before HERE will be converted to a cons if
> !   ;; the matching close-brace is scanned.
>     ;;
>     ;; START-POINT is a "maximal" "safe position" - there must be no open
> !   ;; parens/braces/brackets between START-POINT and HERE.
>     ;;
>     ;; As a second thing, calculate the result of parse-partial-sexp at
>     ;; PPS-POINT, w.r.t. START-POINT.  The motivation here is that
> ***************
> *** 2881,2903 ****
>     ;;   last element to be removed from `c-state-cache', when that elt is a
>     ;;   cons, otherwise nil.
>     ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
> !   (save-restriction
> !     (narrow-to-region 1 (point-max))
> !     (save-excursion
> !       (let* ((in-macro-start   ; start of macro containing (point-max) or nil.
>   	      (save-excursion
> ! 		(goto-char (point-max))
>   		(and (c-beginning-of-macro)
>   		     (point))))
>   	     (start-point-actual-macro-start ; Start of macro containing
>   					     ; start-point or nil
> ! 	      (and (< start-point (point-max))
>   		   (save-excursion
>   		     (goto-char start-point)
>   		     (and (c-beginning-of-macro)
>   			  (point)))))
>   	     (start-point-actual-macro-end ; End of this macro, (maybe
> ! 					; (point-max)), or nil.
>   	      (and start-point-actual-macro-start
>   		   (save-excursion
>   		     (goto-char start-point-actual-macro-start)
> --- 2844,2866 ----
>     ;;   last element to be removed from `c-state-cache', when that elt is a
>     ;;   cons, otherwise nil.
>     ;; o - PPS-STATE is the parse-partial-sexp state at PPS-POINT.
> !   (save-excursion
> !     (save-restriction
> !       (narrow-to-region 1 (point-max))
> !       (let* ((in-macro-start   ; start of macro containing HERE or nil.
>   	      (save-excursion
> ! 		(goto-char here)
>   		(and (c-beginning-of-macro)
>   		     (point))))
>   	     (start-point-actual-macro-start ; Start of macro containing
>   					     ; start-point or nil
> ! 	      (and (< start-point here)
>   		   (save-excursion
>   		     (goto-char start-point)
>   		     (and (c-beginning-of-macro)
>   			  (point)))))
>   	     (start-point-actual-macro-end ; End of this macro, (maybe
> ! 					; HERE), or nil.
>   	      (and start-point-actual-macro-start
>   		   (save-excursion
>   		     (goto-char start-point-actual-macro-start)
> ***************
> *** 2909,2922 ****
>   	     scan-back-pos
>   	     pair-beg pps-point-state target-depth)
>   
> ! 	;; Remove entries beyond (point-max).  Also remove any entries inside
> ! 	;; a macro, unless (point-max) is in the same macro.
>   	(setq upper-lim
>   	      (if (or (null c-state-old-cpp-beg)
> ! 		      (and (> (point-max) c-state-old-cpp-beg)
> ! 			   (< (point-max) c-state-old-cpp-end)))
> ! 		  (point-max)
> ! 		(min (point-max) c-state-old-cpp-beg)))
>   	(while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
>   	  (setq scan-back-pos (car-safe (car c-state-cache)))
>   	  (setq c-state-cache (cdr c-state-cache)))
> --- 2872,2885 ----
>   	     scan-back-pos
>   	     pair-beg pps-point-state target-depth)
>   
> ! 	;; Remove entries beyond HERE.  Also remove any entries inside
> ! 	;; a macro, unless HERE is in the same macro.
>   	(setq upper-lim
>   	      (if (or (null c-state-old-cpp-beg)
> ! 		      (and (> here c-state-old-cpp-beg)
> ! 			   (< here c-state-old-cpp-end)))
> ! 		  here
> ! 		(min here c-state-old-cpp-beg)))
>   	(while (and c-state-cache (>= (c-state-cache-top-lparen) upper-lim))
>   	  (setq scan-back-pos (car-safe (car c-state-cache)))
>   	  (setq c-state-cache (cdr c-state-cache)))
> ***************
> *** 2934,2940 ****
>   	;; time round; the corresponding elements in `c-state-cache' are
>   	;; removed.  `pos' is just after the brace-pair or the open paren at
>   	;; (car c-state-cache).	 There can be no open parens/braces/brackets
> ! 	;; between `start-point'/`start-point-actual-macro-start' and (point-max),
>   	;; due to the interface spec to this function.
>   	(setq pos (if (and start-point-actual-macro-end
>   			   (not (eq start-point-actual-macro-start
> --- 2897,2903 ----
>   	;; time round; the corresponding elements in `c-state-cache' are
>   	;; removed.  `pos' is just after the brace-pair or the open paren at
>   	;; (car c-state-cache).	 There can be no open parens/braces/brackets
> ! 	;; between `start-point'/`start-point-actual-macro-start' and HERE,
>   	;; due to the interface spec to this function.
>   	(setq pos (if (and start-point-actual-macro-end
>   			   (not (eq start-point-actual-macro-start
> ***************
> *** 2944,2950 ****
>   		    start-point))
>   	(goto-char pos)
>   	(while (and c-state-cache
> ! 		    (< (point) (point-max)))
>   	  (cond
>   	   ((null pps-state)		; first time through
>   	    (setq target-depth -1))
> --- 2907,2915 ----
>   		    start-point))
>   	(goto-char pos)
>   	(while (and c-state-cache
> ! 		    (or (numberp (car c-state-cache)) ; Have we a { at all? 
> ! 			(cdr c-state-cache))
> ! 		    (< (point) here))
>   	  (cond
>   	   ((null pps-state)		; first time through
>   	    (setq target-depth -1))
> ***************
> *** 2956,2962 ****
>   	  ;; Scan!
>   	  (setq pps-state
>   		(parse-partial-sexp
> ! 		 (point) (if (< (point) pps-point) pps-point (point-max))
>   		 target-depth
>   		 nil pps-state))
>   
> --- 2921,2927 ----
>   	  ;; Scan!
>   	  (setq pps-state
>   		(parse-partial-sexp
> ! 		 (point) (if (< (point) pps-point) pps-point here)
>   		 target-depth
>   		 nil pps-state))
>   
> ***************
> *** 3209,3215 ****
>         ;; Do we need to add in an earlier brace pair, having lopped one off?
>         (if (and dropped-cons
>   	       (< too-high-pa (+ here c-state-cache-too-far)))
> ! 	  (c-append-lower-brace-pair-to-state-cache too-high-pa here-bol))
>         (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
>   				       (c-state-get-min-scan-pos)))))
>   
> --- 3174,3180 ----
>         ;; Do we need to add in an earlier brace pair, having lopped one off?
>         (if (and dropped-cons
>   	       (< too-high-pa (+ here c-state-cache-too-far)))
> ! 	  (c-append-lower-brace-pair-to-state-cache too-high-pa here here-bol))
>         (setq c-state-cache-good-pos (or (c-state-cache-after-top-paren)
>   				       (c-state-get-min-scan-pos)))))
>   
> ***************
> *** 3285,3331 ****
>   	  strategy (car res)
>   	  start-point (cadr res))
>   
> -     (when (eq strategy 'BOD)
> -       (setq c-state-cache nil
> - 	    c-state-cache-good-pos start-point))
> - 
>       ;; SCAN!
> !     (save-restriction
> !       (cond
> !        ((memq strategy '(forward BOD))
> ! 	(narrow-to-region (point-min) here)
> ! 	(setq res (c-remove-stale-state-cache start-point here-bopl))
> ! 	(setq cache-pos (car res)
> ! 	      scan-backward-pos (cadr res)
> ! 	      bopl-state (car (cddr res))) ; will be nil if (< here-bopl
>   					; start-point)
> ! 	(if scan-backward-pos
> ! 	    (c-append-lower-brace-pair-to-state-cache scan-backward-pos))
> ! 	(setq good-pos
> ! 	      (c-append-to-state-cache cache-pos))
> ! 	(setq c-state-cache-good-pos
> ! 	      (if (and bopl-state
> ! 		       (< good-pos (- here c-state-cache-too-far)))
> ! 		  (c-state-cache-non-literal-place here-bopl bopl-state)
> ! 		good-pos)))
> ! 
> !        ((eq strategy 'backward)
> ! 	(setq res (c-remove-stale-state-cache-backwards here)
> ! 	      good-pos (car res)
> ! 	      scan-backward-pos (cadr res)
> ! 	      scan-forward-p (car (cddr res)))
> ! 	(if scan-backward-pos
> ! 	    (c-append-lower-brace-pair-to-state-cache
> ! 	     scan-backward-pos))
> ! 	(setq c-state-cache-good-pos
> ! 	      (if scan-forward-p
> ! 		  (progn (narrow-to-region (point-min) here)
> ! 			 (c-append-to-state-cache good-pos))
> ! 		good-pos)))
>   
> !        (t ; (eq strategy 'IN-LIT)
> ! 	(setq c-state-cache nil
> ! 	      c-state-cache-good-pos nil)))))
>   
>     c-state-cache)
>   
> --- 3250,3288 ----
>   	  strategy (car res)
>   	  start-point (cadr res))
>   
>       ;; SCAN!
> !     (cond
> !      ((eq strategy 'forward)
> !       (setq res (c-remove-stale-state-cache start-point here here-bopl))
> !       (setq cache-pos (car res)
> ! 	    scan-backward-pos (cadr res)
> ! 	    bopl-state (car (cddr res))) ; will be nil if (< here-bopl
>   					; start-point)
> !       (if scan-backward-pos
> ! 	  (c-append-lower-brace-pair-to-state-cache scan-backward-pos here))
> !       (setq good-pos
> ! 	    (c-append-to-state-cache cache-pos here))
> !       (setq c-state-cache-good-pos
> ! 	    (if (and bopl-state
> ! 		     (< good-pos (- here c-state-cache-too-far)))
> ! 		(c-state-cache-non-literal-place here-bopl bopl-state)
> ! 	      good-pos)))
> ! 
> !      ((eq strategy 'backward)
> !       (setq res (c-remove-stale-state-cache-backwards here)
> ! 	    good-pos (car res)
> ! 	    scan-backward-pos (cadr res)
> ! 	    scan-forward-p (car (cddr res)))
> !       (if scan-backward-pos
> ! 	  (c-append-lower-brace-pair-to-state-cache scan-backward-pos here))
> !       (setq c-state-cache-good-pos
> ! 	    (if scan-forward-p
> ! 		(c-append-to-state-cache good-pos here)
> ! 	      good-pos)))
>   
> !      (t					; (eq strategy 'IN-LIT)
> !       (setq c-state-cache nil
> ! 	    c-state-cache-good-pos nil))))
>   
>     c-state-cache)
>   
> ***************
> *** 8559,8566 ****
>      ))
>   
>   (defun c-looking-at-special-brace-list (&optional lim)
> !   ;; If we're looking at the start of a pike-style list, ie `({ })',
> !   ;; `([ ])', `(< >)' etc, a cons of a cons of its starting and ending
>     ;; positions and its entry in c-special-brace-lists is returned, nil
>     ;; otherwise.  The ending position is nil if the list is still open.
>     ;; LIM is the limit for forward search.  The point may either be at
> --- 8516,8523 ----
>      ))
>   
>   (defun c-looking-at-special-brace-list (&optional lim)
> !   ;; If we're looking at the start of a pike-style list, ie `({ })',
> !   ;; `([ ])', `(< >)' etc, a cons of a cons of its starting and ending
>     ;; positions and its entry in c-special-brace-lists is returned, nil
>     ;; otherwise.  The ending position is nil if the list is still open.
>     ;; LIM is the limit for forward search.  The point may either be at
>
>
>> -- 
>> Michael Welsh Duggan
>> (mwd@cert.org)

-- 
Michael Welsh Duggan
(mwd@cert.org)





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-02-01 22:18                                                     ` Michael Welsh Duggan
@ 2013-02-01 23:50                                                       ` Kim Storm
  2013-02-02 19:35                                                         ` Alan Mackenzie
  0 siblings, 1 reply; 55+ messages in thread
From: Kim Storm @ 2013-02-01 23:50 UTC (permalink / raw)
  To: Michael Welsh Duggan; +Cc: Alan Mackenzie, 11749@debbugs.gnu.org

On 2013-02-01 23:18, Michael Welsh Duggan wrote:
> Alan Mackenzie <acm@muc.de> writes:
>
>> Hi, Michael.
> I've been running with this for a few days, and have yet to run into a
> problem.  I'll let you know when/if I do in the future.
>
>
Hi Alan

I have been running with the 24.2.91 pretest since it came out - and I 
have not run
into the problems I originally reported with the wrong-type-argument 
error in plain C sources.

So I assume that problem have been fixed  - or Murphy will tell me 
otherwise in 5 mintes :-).

Thank you
Kim





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: 24.1; C-mode indentation gives wrong-type-argument error.
  2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
                   ` (4 preceding siblings ...)
  2013-01-08 19:10 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Glenn Morris
@ 2013-02-02 18:37 ` Alan Mackenzie
  2013-01-08 13:49   ` bug#13385: 24.1; TAB in C file causes type error Julian Stecklina
  5 siblings, 1 reply; 55+ messages in thread
From: Alan Mackenzie @ 2013-02-02 18:37 UTC (permalink / raw)
  To: 11749-done

Bug fixed.





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.)
  2013-02-01 23:50                                                       ` Kim Storm
@ 2013-02-02 19:35                                                         ` Alan Mackenzie
  0 siblings, 0 replies; 55+ messages in thread
From: Alan Mackenzie @ 2013-02-02 19:35 UTC (permalink / raw)
  To: Kim Storm, Michael Welsh Duggan; +Cc: 11749@debbugs.gnu.org

Hi, Kim and Michael,

On Sat, Feb 02, 2013 at 12:50:39AM +0100, Kim Storm wrote:
> On 2013-02-01 23:18, Michael Welsh Duggan wrote:

> > I've been running with this for a few days, and have yet to run into a
> > problem.  I'll let you know when/if I do in the future.

It made my weekend, reading that.  :-)  Many thanks for all the testing
work.

> Hi Alan

> I have been running with the 24.2.91 pretest since it came out - and I 
> have not run
> into the problems I originally reported with the wrong-type-argument 
> error in plain C sources.

> So I assume that problem have been fixed  - or Murphy will tell me 
> otherwise in 5 minutes :-).

No, Murphy will wait until just after 24.3 has been released.  ;-(

Anyhow, I've closed bug#11749 as fixed.  Here's hoping that piece of CC
Mode code now has a modicum of stability about it.

> Thank you

Appreciated!

> Kim

-- 
Alan Mackenzie (Nuremberg, Germany).





^ permalink raw reply	[flat|nested] 55+ messages in thread

* bug#13385: closed (Re: 24.1; C-mode indentation gives wrong-type-argument error.)
       [not found]     ` <handler.13385.D11749.1359830688892.notifdone@debbugs.gnu.org>
@ 2013-02-03 13:00       ` Julian Stecklina
  0 siblings, 0 replies; 55+ messages in thread
From: Julian Stecklina @ 2013-02-03 13:00 UTC (permalink / raw)
  To: 13385

Is there a way to work around that bug in the latest release?






^ permalink raw reply	[flat|nested] 55+ messages in thread

end of thread, other threads:[~2013-02-03 13:00 UTC | newest]

Thread overview: 55+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-06-19 20:45 bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Kim F. Storm
2012-06-21  7:17 ` Glenn Morris
2012-06-21  9:34   ` Kim Storm
2012-08-28 16:17 ` bug#11749: 24.2; wrong-type-argument Kim F. Storm
     [not found] ` <handler.11749.B.13401389485673.ack@debbugs.gnu.org>
2012-08-28 22:49   ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Kim Storm
2012-08-31 11:01     ` Eli Zaretskii
2012-08-31 12:37       ` Kim Storm
2012-09-02 21:16     ` Alan Mackenzie
2012-09-03  9:47       ` Kim Storm
2012-09-03 13:56         ` Stefan Monnier
2012-09-03 14:20           ` Kim Storm
2012-09-03 18:52             ` Stefan Monnier
2012-09-05 20:48         ` Alan Mackenzie
2012-09-07  3:45           ` Michael Welsh Duggan
2012-09-07 14:53             ` Stefan Monnier
2012-09-07 16:16               ` Kim Storm
2012-09-08 21:14             ` Alan Mackenzie
2012-09-10 12:18               ` Michael Welsh Duggan
2012-09-10 12:48                 ` Michael Welsh Duggan
2012-09-21 17:47                   ` Michael Welsh Duggan
2012-10-07 10:59                     ` Alan Mackenzie
2012-10-09 14:05                       ` Michael Welsh Duggan
2012-10-10 20:00                         ` Alan Mackenzie
2012-10-14 17:06                           ` Alan Mackenzie
2012-10-23 16:13                             ` Michael Welsh Duggan
2012-10-25 13:41                             ` Michael Welsh Duggan
2012-10-28 11:36                               ` Alan Mackenzie
2012-11-04  3:43                                 ` Chong Yidong
2012-11-04 20:42                                   ` Alan Mackenzie
2012-11-21 20:58                                   ` Alan Mackenzie
2012-11-22 14:52                                     ` Stefan Monnier
2012-11-04 20:39                                 ` Alan Mackenzie
2012-11-04 21:04                                   ` Kim Storm
2012-11-14 16:52                                   ` Michael Welsh Duggan
2012-11-21 21:33                                     ` Alan Mackenzie
2012-11-26 13:25                                       ` Michael Welsh Duggan
2012-12-10  3:35                                         ` Michael Welsh Duggan
2013-01-07 12:09                                           ` Alan Mackenzie
2013-01-17 16:27                                             ` Michael Welsh Duggan
2013-01-17 16:28                                               ` Michael Welsh Duggan
2013-01-23 14:16                                               ` Alan Mackenzie
2013-01-23 15:39                                                 ` Michael Welsh Duggan
2013-01-29 11:37                                                   ` Alan Mackenzie
     [not found]                                                   ` <20130129113737.GA4544@acm.acm>
2013-02-01 22:18                                                     ` Michael Welsh Duggan
2013-02-01 23:50                                                       ` Kim Storm
2013-02-02 19:35                                                         ` Alan Mackenzie
2012-09-10 13:10                 ` Michael Welsh Duggan
2012-09-10 13:22                   ` Michael Welsh Duggan
2012-09-10 18:25                     ` Michael Welsh Duggan
2012-09-05 13:11 ` bug#11749: I also have this issue Denis Zalevskiy
2013-01-08 19:10 ` bug#11749: Acknowledgement (24.1; C-mode indentation gives wrong-type-argument error.) Glenn Morris
2013-01-09 22:13   ` Alan Mackenzie
2013-02-02 18:37 ` bug#11749: 24.1; C-mode indentation gives wrong-type-argument error Alan Mackenzie
2013-01-08 13:49   ` bug#13385: 24.1; TAB in C file causes type error Julian Stecklina
     [not found]     ` <handler.13385.D11749.1359830688892.notifdone@debbugs.gnu.org>
2013-02-03 13:00       ` bug#13385: closed (Re: 24.1; C-mode indentation gives wrong-type-argument error.) Julian Stecklina

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).