summary refs log tree commit diff stats
path: root/lib/system/exceptions.nim
blob: b5f4fc3255a2e37032e6f4cca25ddf74e67125d8 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
const NimStackTraceMsgs =
  when defined(nimHasStacktraceMsgs): compileOption("stacktraceMsgs")
  else: false

type
  RootEffect* {.compilerproc.} = object of RootObj ## \
    ## Base effect class.
    ##
    ## Each effect should inherit from `RootEffect` unless you know what
    ## you're doing.
  TimeEffect* = object of RootEffect   ## Time effect.
  IOEffect* = object of RootEffect     ## IO effect.
  ReadIOEffect* = object of IOEffect   ## Effect describing a read IO operation.
  WriteIOEffect* = object of IOEffect  ## Effect describing a write IO operation.
  ExecIOEffect* = object of IOEffect   ## Effect describing an executing IO operation.

  StackTraceEntry* = object ## In debug mode exceptions store the stack trace that led
                            ## to them. A `StackTraceEntry` is a single entry of the
                            ## stack trace.
    procname*: cstring      ## Name of the proc that is currently executing.
    line*: int              ## Line number of the proc that is currently executing.
    filename*: cstring      ## Filename of the proc that is currently executing.
    when NimStackTraceMsgs:
      frameMsg*: string     ## When a stacktrace is generated in a given frame and
                            ## rendered at a later time, we should ensure the stacktrace
                            ## data isn't invalidated; any pointer into PFrame is
                            ## subject to being invalidated so shouldn't be stored.
    when defined(nimStackTraceOverride):
      programCounter*: uint ## Program counter - will be used to get the rest of the info,
                            ## when `$` is called on this type. We can't use
                            ## "cuintptr_t" in here.
      procnameStr*, filenameStr*: string ## GC-ed objects holding the cstrings in "procname" and "filename"

  Exception* {.compilerproc, magic: "Exception".} = object of RootObj ## \
    ## Base exception class.
    ##
    ## Each exception has to inherit from `Exception`. See the full `exception
    ## hierarchy <manual.html#exception-handling-exception-hierarchy>`_.
    parent*: ref Exception ## Parent exception (can be used as a stack).
    name*: cstring         ## The exception's name is its Nim identifier.
                           ## This field is filled automatically in the
                           ## `raise` statement.
    msg* {.exportc: "message".}: string ## The exception's message. Not
                                        ## providing an exception message
                                        ## is bad style.
    when defined(js):
      trace: string
    else:
      trace: seq[StackTraceEntry]
    up: ref Exception # used for stacking exceptions. Not exported!

  Defect* = object of Exception ## \
    ## Abstract base class for all exceptions that Nim's runtime raises
    ## but that are strictly uncatchable as they can also be mapped to
    ## a `quit` / `trap` / `exit` operation.

  CatchableError* = object of Exception ## \
    ## Abstract class for all exceptions that are catchable.
  IOError* = object of CatchableError ## \
    ## Raised if an IO error occurred.
  EOFError* = object of IOError ## \
    ## Raised if an IO "end of file" error occurred.
  OSError* = object of CatchableError ## \
    ## Raised if an operating system service failed.
    errorCode*: int32 ## OS-defined error code describing this error.
  LibraryError* = object of OSError ## \
    ## Raised if a dynamic library could not be loaded.
  ResourceExhaustedError* = object of CatchableError ## \
    ## Raised if a resource request could not be fulfilled.
  ArithmeticDefect* = object of Defect ## \
    ## Raised if any kind of arithmetic error occurred.
  DivByZeroDefect* = object of ArithmeticDefect ## \
    ## Raised for runtime integer divide-by-zero errors.

  OverflowDefect* = object of ArithmeticDefect ## \
    ## Raised for runtime integer overflows.
    ##
    ## This happens for calculations whose results are too large to fit in the
    ## provided bits.
  AccessViolationDefect* = object of Defect ## \
    ## Raised for invalid memory access errors
  AssertionDefect* = object of Defect ## \
    ## Raised when assertion is proved wrong.
    ##
    ## Usually the result of using the `assert() template
    ## <assertions.html#assert.t,untyped,string>`_.
  ValueError* = object of CatchableError ## \
    ## Raised for string and object conversion errors.
  KeyError* = object of ValueError ## \
    ## Raised if a key cannot be found in a table.
    ##
    ## Mostly used by the `tables <tables.html>`_ module, it can also be raised
    ## by other collection modules like `sets <sets.html>`_ or `strtabs
    ## <strtabs.html>`_.
  OutOfMemDefect* = object of Defect ## \
    ## Raised for unsuccessful attempts to allocate memory.
  IndexDefect* = object of Defect ## \
    ## Raised if an array index is out of bounds.

  FieldDefect* = object of Defect ## \
    ## Raised if a record field is not accessible because its discriminant's
    ## value does not fit.
  RangeDefect* = object of Defect ## \
    ## Raised if a range check error occurred.
  StackOverflowDefect* = object of Defect ## \
    ## Raised if the hardware stack used for subroutine calls overflowed.
  ReraiseDefect* = object of Defect ## \
    ## Raised if there is no exception to reraise.
  ObjectAssignmentDefect* = object of Defect ## \
    ## Raised if an object gets assigned to its parent's object.
  ObjectConversionDefect* = object of Defect ## \
    ## Raised if an object is converted to an incompatible object type.
    ## You can use `of` operator to check if conversion will succeed.
  FloatingPointDefect* = object of Defect ## \
    ## Base class for floating point exceptions.
  FloatInvalidOpDefect* = object of FloatingPointDefect ## \
    ## Raised by invalid operations according to IEEE.
    ##
    ## Raised by `0.0/0.0`, for example.
  FloatDivByZeroDefect* = object of FloatingPointDefect ## \
    ## Raised by division by zero.
    ##
    ## Divisor is zero and dividend is a finite nonzero number.
  FloatOverflowDefect* = object of FloatingPointDefect ## \
    ## Raised for overflows.
    ##
    ## The operation produced a result that exceeds the range of the exponent.
  FloatUnderflowDefect* = object of FloatingPointDefect ## \
    ## Raised for underflows.
    ##
    ## The operation produced a result that is too small to be represented as a
    ## normal number.
  FloatInexactDefect* = object of FloatingPointDefect ## \
    ## Raised for inexact results.
    ##
    ## The operation produced a result that cannot be represented with infinite
    ## precision -- for example: `2.0 / 3.0, log(1.1)`
    ##
    ## **Note**: Nim currently does not detect these!
  DeadThreadDefect* = object of Defect ## \
    ## Raised if it is attempted to send a message to a dead thread.
  NilAccessDefect* = object of Defect ## \
    ## Raised on dereferences of `nil` pointers.
    ##
    ## This is only raised if the `segfaults module <segfaults.html>`_ was imported!

  ArithmeticError* {.deprecated: "See corresponding Defect".} = ArithmeticDefect
  DivByZeroError* {.deprecated: "See corresponding Defect".} = DivByZeroDefect
  OverflowError* {.deprecated: "See corresponding Defect".} = OverflowDefect
  AccessViolationError* {.deprecated: "See corresponding Defect".} = AccessViolationDefect
  AssertionError* {.deprecated: "See corresponding Defect".} = AssertionDefect
  OutOfMemError* {.deprecated: "See corresponding Defect".} = OutOfMemDefect
  IndexError* {.deprecated: "See corresponding Defect".} = IndexDefect

  FieldError* {.deprecated: "See corresponding Defect".} = FieldDefect
  RangeError* {.deprecated: "See corresponding Defect".} = RangeDefect
  StackOverflowError* {.deprecated: "See corresponding Defect".} = StackOverflowDefect
  ReraiseError* {.deprecated: "See corresponding Defect".} = ReraiseDefect
  ObjectAssignmentError* {.deprecated: "See corresponding Defect".} = ObjectAssignmentDefect
  ObjectConversionError* {.deprecated: "See corresponding Defect".} = ObjectConversionDefect
  FloatingPointError* {.deprecated: "See corresponding Defect".} = FloatingPointDefect
  FloatInvalidOpError* {.deprecated: "See corresponding Defect".} = FloatInvalidOpDefect
  FloatDivByZeroError* {.deprecated: "See corresponding Defect".} = FloatDivByZeroDefect
  FloatOverflowError* {.deprecated: "See corresponding Defect".} = FloatOverflowDefect
  FloatUnderflowError* {.deprecated: "See corresponding Defect".} = FloatUnderflowDefect
  FloatInexactError* {.deprecated: "See corresponding Defect".} = FloatInexactDefect
  DeadThreadError* {.deprecated: "See corresponding Defect".} = DeadThreadDefect
  NilAccessError* {.deprecated: "See corresponding Defect".} = NilAccessDefect
cfaabc69581b7095a79c4452bcf2c'>^
f8de2823 ^
f8de2823 ^
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
  

                 
                                                            
  






















                                                                       
 
                               
                
 
                          
                            
 
 


                       

                         



                        
                       
                    
                                


                         

  

                                           

                            

                                                    
    
                        
 
                                                                     


                                            
    

                         

                                          

 











                                                                             











                                                                   
    
                                                        


                                                                   
                          



                                                     








                                                                   
                          


                                                                           
                                                                                   



                                                        
 




                                                            
 
                                                 
 
                                                             
                                          
                                                       
                 









                                                                   
                          









                                                                   



                             

 
    
                                              
 
                                             

 
        
                                                      



                                                                   





                                                       





                                                                   





                                                     




                                                                   
                          
                                           
                                             
                             



        
                                                    



                                                                   





                                                     
        
                                                  



                                                                   





                                                   




                                                                   
                          



                                         
        
                                                                 
 
                                                                   
 
                          
                     
            
                                           
     

 





                                                                   
                          



                                                         


                                       
                          
                                 



                                                   
                      
     
 
/*
 * chat_session.c
 *
 * Copyright (C) 2012 - 2014 James Booth <boothj5@gmail.com>
 *
 * This file is part of Profanity.
 *
 * Profanity is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * Profanity is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with Profanity.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <stdlib.h>
#include <string.h>

#include <glib.h>

#include "chat_session.h"

#include "config/preferences.h"
#include "log.h"

#define PAUSED_TIMOUT 10.0
#define INACTIVE_TIMOUT 30.0


typedef enum {
    CHAT_STATE_STARTED,
    CHAT_STATE_ACTIVE,
    CHAT_STATE_PAUSED,
    CHAT_STATE_COMPOSING,
    CHAT_STATE_INACTIVE,
    CHAT_STATE_GONE
} chat_state_t;

struct chat_session_t {
    char *recipient;
    gboolean recipient_supports;
    chat_state_t state;
    GTimer *active_timer;
    gboolean sent;
};

typedef struct chat_session_t *ChatSession;

static GHashTable *sessions;

static void _chat_session_free(ChatSession session);

void
chat_sessions_init(void)
{
    sessions = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
        (GDestroyNotify)_chat_session_free);
}

void
chat_sessions_clear(void)
{
    if (sessions != NULL)
        g_hash_table_remove_all(sessions);
}

void
chat_session_start(const char * const recipient, gboolean recipient_supports)
{
    ChatSession new_session = malloc(sizeof(struct chat_session_t));
    new_session->recipient = strdup(recipient);
    new_session->recipient_supports = recipient_supports;
    new_session->state = CHAT_STATE_STARTED;
    new_session->active_timer = g_timer_new();
    new_session->sent = FALSE;
    g_hash_table_insert(sessions, strdup(recipient), new_session);
}

gboolean
chat_session_exists(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        return TRUE;
    } else {
        return FALSE;
    }
}

void
chat_session_set_composing(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        if (session->state != CHAT_STATE_COMPOSING) {
            session->sent = FALSE;
        }
        session->state = CHAT_STATE_COMPOSING;
        g_timer_start(session->active_timer);
    }
}

void
chat_session_no_activity(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        if (session->active_timer != NULL) {
            gdouble elapsed = g_timer_elapsed(session->active_timer, NULL);

            if ((prefs_get_gone() != 0) && (elapsed > (prefs_get_gone() * 60.0))) {
                if (session->state != CHAT_STATE_GONE) {
                    session->sent = FALSE;
                }
                session->state = CHAT_STATE_GONE;

            } else if (elapsed > INACTIVE_TIMOUT) {
                if (session->state != CHAT_STATE_INACTIVE) {
                    session->sent = FALSE;
                }
                session->state = CHAT_STATE_INACTIVE;

            } else if (elapsed > PAUSED_TIMOUT) {

                if (session->state == CHAT_STATE_COMPOSING) {
                    session->sent = FALSE;
                    session->state = CHAT_STATE_PAUSED;
                }
            }
        }
    }
}

void
chat_session_set_sent(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        session->sent = TRUE;
    }
}

gboolean
chat_session_get_sent(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return session->sent;
    }
}

void
chat_session_end(const char * const recipient)
{
    g_hash_table_remove(sessions, recipient);
}

gboolean
chat_session_is_inactive(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return (session->state == CHAT_STATE_INACTIVE);
    }
}

gboolean
chat_session_is_active(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return (session->state == CHAT_STATE_ACTIVE);
    }
}

void
chat_session_set_active(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        session->state = CHAT_STATE_ACTIVE;
        g_timer_start(session->active_timer);
        session->sent = TRUE;
    }
}

gboolean
chat_session_is_paused(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return (session->state == CHAT_STATE_PAUSED);
    }
}

gboolean
chat_session_is_gone(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return (session->state == CHAT_STATE_GONE);
    }
}

void
chat_session_set_gone(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        session->state = CHAT_STATE_GONE;
    }
}

gboolean
chat_session_get_recipient_supports(const char * const recipient)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session == NULL) {
        return FALSE;
    } else {
        return session->recipient_supports;
    }
}

void
chat_session_set_recipient_supports(const char * const recipient,
    gboolean recipient_supports)
{
    ChatSession session = g_hash_table_lookup(sessions, recipient);

    if (session != NULL) {
        session->recipient_supports = recipient_supports;
    }
}

static void
_chat_session_free(ChatSession session)
{
    if (session != NULL) {
        free(session->recipient);
        if (session->active_timer != NULL) {
            g_timer_destroy(session->active_timer);
            session->active_timer = NULL;
        }
        free(session);
    }
}