~ubuntu-branches/ubuntu/precise/krb5/precise-updates

« back to all changes in this revision

Viewing changes to src/windows/identity/kherr/kherr.c

  • Committer: Package Import Robot
  • Author(s): Sam Hartman
  • Date: 2011-12-01 19:34:41 UTC
  • mfrom: (28.1.14 sid)
  • Revision ID: package-import@ubuntu.com-20111201193441-9tipg3aru1jsidyv
Tags: 1.10+dfsg~alpha1-6
* Fix segfault with unknown hostnames in krb5_sname_to_principal,
  Closes: #650671
* Indicate that this library breaks libsmbclient versions that depend on
  krb5_locate_kdc, Closes: #650603, #650611

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/*
2
 
 * Copyright (c) 2005 Massachusetts Institute of Technology
3
 
 *
4
 
 * Permission is hereby granted, free of charge, to any person
5
 
 * obtaining a copy of this software and associated documentation
6
 
 * files (the "Software"), to deal in the Software without
7
 
 * restriction, including without limitation the rights to use, copy,
8
 
 * modify, merge, publish, distribute, sublicense, and/or sell copies
9
 
 * of the Software, and to permit persons to whom the Software is
10
 
 * furnished to do so, subject to the following conditions:
11
 
 *
12
 
 * The above copyright notice and this permission notice shall be
13
 
 * included in all copies or substantial portions of the Software.
14
 
 *
15
 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16
 
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17
 
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
18
 
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
19
 
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
20
 
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21
 
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
 
 * SOFTWARE.
23
 
 */
24
 
 
25
 
/* $Id$ */
26
 
 
27
 
#include<kherrinternal.h>
28
 
#include<assert.h>
29
 
#include<stdarg.h>
30
 
 
31
 
CRITICAL_SECTION cs_error;
32
 
DWORD tls_error = 0;
33
 
kherr_context * ctx_free_list = NULL;
34
 
kherr_context * ctx_root_list = NULL;
35
 
kherr_context * ctx_error_list = NULL;
36
 
kherr_event * evt_free_list = NULL;
37
 
 
38
 
kherr_handler_node * ctx_handlers = NULL;
39
 
khm_size n_ctx_handlers;
40
 
khm_size nc_ctx_handlers;
41
 
 
42
 
kherr_serial ctx_serial = 0;
43
 
 
44
 
#ifdef DEBUG
45
 
#define DEBUG_CONTEXT
46
 
 
47
 
KHMEXP void
48
 
kherr_debug_printf(wchar_t * fmt, ...)
49
 
{
50
 
    va_list vl;
51
 
    wchar_t buf[1024];
52
 
 
53
 
    va_start(vl, fmt);
54
 
    StringCbVPrintf(buf, sizeof(buf), fmt, vl);
55
 
    OutputDebugString(buf);
56
 
    va_end(vl);
57
 
}
58
 
#endif
59
 
 
60
 
KHMEXP void KHMAPI
61
 
kherr_add_ctx_handler(kherr_ctx_handler h,
62
 
                      khm_int32 filter,
63
 
                      kherr_serial serial)
64
 
{
65
 
    khm_size idx;
66
 
 
67
 
    assert(h);
68
 
 
69
 
    EnterCriticalSection(&cs_error);
70
 
    if( ctx_handlers == NULL) {
71
 
        nc_ctx_handlers = CTX_ALLOC_INCR;
72
 
        n_ctx_handlers = 0;
73
 
        ctx_handlers = PMALLOC(sizeof(*ctx_handlers) * nc_ctx_handlers);
74
 
        /* No need to initialize */
75
 
    } else if (n_ctx_handlers == nc_ctx_handlers) {
76
 
        khm_size new_nc;
77
 
        kherr_handler_node * new_ctxs;
78
 
 
79
 
        new_nc = nc_ctx_handlers + CTX_ALLOC_INCR;
80
 
        new_ctxs = PMALLOC(sizeof(*new_ctxs) * new_nc);
81
 
        memcpy(new_ctxs, ctx_handlers, n_ctx_handlers * sizeof(*new_ctxs));
82
 
 
83
 
        PFREE(ctx_handlers);
84
 
        ctx_handlers = new_ctxs;
85
 
        nc_ctx_handlers = new_nc;
86
 
    }
87
 
 
88
 
    if (filter == 0)
89
 
        filter = KHERR_CTX_BEGIN |
90
 
            KHERR_CTX_DESCRIBE |
91
 
            KHERR_CTX_END |
92
 
            KHERR_CTX_ERROR |
93
 
            KHERR_CTX_NEWCHILD |
94
 
            KHERR_CTX_FOLDCHILD;
95
 
 
96
 
    /* Since commit events are the most frequent, we put those
97
 
       handlers at the top of the list.  When dispatching a commit
98
 
       event, we stop looking at the list when we find a filter that
99
 
       doesn't filter for commit events. */
100
 
    if (filter & KHERR_CTX_EVTCOMMIT) {
101
 
        idx = 0;
102
 
        memmove(&ctx_handlers[1], &ctx_handlers[0],
103
 
                n_ctx_handlers * sizeof(ctx_handlers[0]));
104
 
    } else {
105
 
        idx = n_ctx_handlers;
106
 
    }
107
 
 
108
 
    ctx_handlers[idx].h = h;
109
 
    ctx_handlers[idx].filter = filter;
110
 
    ctx_handlers[idx].serial = serial;
111
 
 
112
 
    n_ctx_handlers++;
113
 
 
114
 
    LeaveCriticalSection(&cs_error);
115
 
}
116
 
 
117
 
KHMEXP void KHMAPI
118
 
kherr_remove_ctx_handler(kherr_ctx_handler h,
119
 
                         kherr_serial serial)
120
 
{
121
 
    khm_size i;
122
 
    EnterCriticalSection(&cs_error);
123
 
 
124
 
    for (i=0 ; i < n_ctx_handlers; i++) {
125
 
        if (ctx_handlers[i].h == h &&
126
 
            ctx_handlers[i].serial == serial) {
127
 
            break;
128
 
        }
129
 
    }
130
 
 
131
 
    if ( i < n_ctx_handlers ) {
132
 
        n_ctx_handlers --;
133
 
        for (; i < n_ctx_handlers; i++) {
134
 
            ctx_handlers[i] = ctx_handlers[i + 1];
135
 
        }
136
 
    }
137
 
 
138
 
    LeaveCriticalSection(&cs_error);
139
 
}
140
 
 
141
 
/* Called with cs_error held */
142
 
static void
143
 
notify_ctx_event(enum kherr_ctx_event e, kherr_context * c)
144
 
{
145
 
    khm_size i;
146
 
 
147
 
    kherr_ctx_handler h;
148
 
 
149
 
    for (i=0; i<n_ctx_handlers; i++) {
150
 
        if (ctx_handlers[i].h && (ctx_handlers[i].filter & e) &&
151
 
            (ctx_handlers[i].serial == 0 ||
152
 
             ctx_handlers[i].serial == c->serial)) {
153
 
            if (IsBadCodePtr((FARPROC) ctx_handlers[i].h)) {
154
 
                ctx_handlers[i].h = NULL;
155
 
            } else {
156
 
                h = ctx_handlers[i].h;
157
 
                (*h)(e,c);
158
 
 
159
 
                /* a context handler is allowed to remove itself
160
 
                   during a callback.  It is, however, not allowed to
161
 
                   remove anything else. */
162
 
                if (h != ctx_handlers[i].h)
163
 
                    i--;
164
 
            }
165
 
        } else if (e == KHERR_CTX_EVTCOMMIT &&
166
 
                   !(ctx_handlers[i].filter & KHERR_CTX_EVTCOMMIT)) {
167
 
            /* All handlers that filter for commit events are at the
168
 
               top of the list.  If this handler wasn't filtering for
169
 
               it, then there's no point in goint further down the
170
 
               list. */
171
 
            break;
172
 
        }
173
 
    }
174
 
}
175
 
 
176
 
void
177
 
attach_this_thread(void)
178
 
{
179
 
    kherr_thread * t;
180
 
 
181
 
    t = (kherr_thread *) TlsGetValue(tls_error);
182
 
    if (t)
183
 
        return;
184
 
 
185
 
    t = PMALLOC(sizeof(kherr_thread) +
186
 
                sizeof(kherr_context *) * THREAD_STACK_SIZE);
187
 
    t->nc_ctx = THREAD_STACK_SIZE;
188
 
    t->n_ctx = 0;
189
 
    t->ctx = (kherr_context **) &t[1];
190
 
 
191
 
    TlsSetValue(tls_error, t);
192
 
}
193
 
 
194
 
void
195
 
detach_this_thread(void)
196
 
{
197
 
    kherr_thread * t;
198
 
    khm_size i;
199
 
 
200
 
    t = (kherr_thread *) TlsGetValue(tls_error);
201
 
    if (t) {
202
 
        for(i=0; i < t->n_ctx; i++) {
203
 
            kherr_release_context(t->ctx[i]);
204
 
        }
205
 
        PFREE(t);
206
 
        TlsSetValue(tls_error, 0);
207
 
    }
208
 
}
209
 
 
210
 
static kherr_context *
211
 
peek_context(void)
212
 
{
213
 
    kherr_thread * t;
214
 
 
215
 
    t = (kherr_thread *) TlsGetValue(tls_error);
216
 
    if (t) {
217
 
        if (t->n_ctx > 0) {
218
 
            kherr_context * c;
219
 
 
220
 
            c = t->ctx[t->n_ctx - 1];
221
 
 
222
 
            assert(c == NULL || IS_KHERR_CTX(c));
223
 
 
224
 
            return c;
225
 
        } else {
226
 
            return NULL;
227
 
        }
228
 
    } else
229
 
        return NULL;
230
 
}
231
 
 
232
 
static void
233
 
push_context(kherr_context * c)
234
 
{
235
 
    kherr_thread * t;
236
 
 
237
 
    t = (kherr_thread *) TlsGetValue(tls_error);
238
 
    if (!t) {
239
 
        attach_this_thread();
240
 
        t = (kherr_thread *) TlsGetValue(tls_error);
241
 
        assert(t);
242
 
    }
243
 
 
244
 
    if (t->n_ctx == t->nc_ctx) {
245
 
        khm_size nc_new;
246
 
        khm_size cb_new;
247
 
        kherr_thread * nt;
248
 
 
249
 
        nc_new = t->nc_ctx + THREAD_STACK_SIZE;
250
 
        cb_new = sizeof(kherr_thread) +
251
 
            sizeof(kherr_context *) * nc_new;
252
 
 
253
 
        nt = PMALLOC(cb_new);
254
 
        memcpy(nt, t, sizeof(kherr_thread) +
255
 
               sizeof(kherr_context *) * t->n_ctx);
256
 
        nt->ctx = (kherr_context **) &nt[1];
257
 
        nt->nc_ctx = nc_new;
258
 
 
259
 
        PFREE(t);
260
 
        t = nt;
261
 
        TlsSetValue(tls_error, t);
262
 
    }
263
 
 
264
 
    assert(t->n_ctx < t->nc_ctx);
265
 
    t->ctx[t->n_ctx++] = c;
266
 
 
267
 
    kherr_hold_context(c);
268
 
}
269
 
 
270
 
/* returned pointer is still held */
271
 
static kherr_context *
272
 
pop_context(void)
273
 
{
274
 
    kherr_thread * t;
275
 
    kherr_context * c;
276
 
 
277
 
    t = (kherr_thread *) TlsGetValue(tls_error);
278
 
    if (t) {
279
 
        if (t->n_ctx > 0) {
280
 
            c = t->ctx[--(t->n_ctx)];
281
 
            assert(IS_KHERR_CTX(c));
282
 
            return c;
283
 
        } else
284
 
            return NULL;
285
 
    } else {
286
 
        return NULL;
287
 
    }
288
 
}
289
 
 
290
 
static kherr_event *
291
 
get_empty_event(void)
292
 
{
293
 
    kherr_event * e;
294
 
 
295
 
    EnterCriticalSection(&cs_error);
296
 
    if(evt_free_list) {
297
 
        LPOP(&evt_free_list, &e);
298
 
    } else {
299
 
        e = PMALLOC(sizeof(*e));
300
 
    }
301
 
    LeaveCriticalSection(&cs_error);
302
 
    ZeroMemory(e, sizeof(*e));
303
 
    e->severity = KHERR_NONE;
304
 
    e->magic = KHERR_EVENT_MAGIC;
305
 
 
306
 
    return e;
307
 
}
308
 
 
309
 
static void
310
 
free_event_params(kherr_event * e)
311
 
{
312
 
    assert(IS_KHERR_EVENT(e));
313
 
 
314
 
    if(parm_type(e->p1) == KEPT_STRINGT) {
315
 
        assert((void *) parm_data(e->p1));
316
 
        PFREE((void*) parm_data(e->p1));
317
 
    }
318
 
    ZeroMemory(&e->p1, sizeof(e->p1));
319
 
 
320
 
    if(parm_type(e->p2) == KEPT_STRINGT) {
321
 
        assert((void *) parm_data(e->p2));
322
 
        PFREE((void*) parm_data(e->p2));
323
 
    }
324
 
    ZeroMemory(&e->p2, sizeof(e->p2));
325
 
 
326
 
    if(parm_type(e->p3) == KEPT_STRINGT) {
327
 
        assert((void *) parm_data(e->p3));
328
 
        PFREE((void*) parm_data(e->p3));
329
 
    }
330
 
    ZeroMemory(&e->p3, sizeof(e->p3));
331
 
 
332
 
    if(parm_type(e->p4) == KEPT_STRINGT) {
333
 
        assert((void *) parm_data(e->p4));
334
 
        PFREE((void*) parm_data(e->p4));
335
 
    }
336
 
    ZeroMemory(&e->p4, sizeof(e->p4));
337
 
}
338
 
 
339
 
static void
340
 
free_event(kherr_event * e)
341
 
{
342
 
    EnterCriticalSection(&cs_error);
343
 
 
344
 
    assert(IS_KHERR_EVENT(e));
345
 
#ifdef DEBUG
346
 
    assert(LNEXT(e) == NULL);
347
 
    assert(LPREV(e) == NULL);
348
 
#endif
349
 
 
350
 
#ifdef DEBUG_CONTEXT
351
 
    if (!(e->flags & KHERR_RF_STR_RESOLVED))
352
 
        resolve_event_strings(e);
353
 
 
354
 
    if (e->short_desc && e->long_desc) {
355
 
        kherr_debug_printf(L"E:%s (%s)\n", e->short_desc, e->long_desc);
356
 
    } else if (e->short_desc) {
357
 
        kherr_debug_printf(L"E:%s\n", e->short_desc);
358
 
    } else if (e->long_desc) {
359
 
        kherr_debug_printf(L"E:%s\n", e->long_desc);
360
 
    } else {
361
 
        kherr_debug_printf(L"E:[No description for event 0x%p]\n", e);
362
 
    }
363
 
 
364
 
    if (e->suggestion)
365
 
        kherr_debug_printf(L"  Suggest:[%s]\n", e->suggestion);
366
 
    if (e->facility)
367
 
        kherr_debug_printf(L"  Facility:[%s]\n", e->facility);
368
 
#endif
369
 
 
370
 
    if(e->flags & KHERR_RF_FREE_SHORT_DESC) {
371
 
        assert(e->short_desc);
372
 
        PFREE((void *) e->short_desc);
373
 
    }
374
 
    if(e->flags & KHERR_RF_FREE_LONG_DESC) {
375
 
        assert(e->long_desc);
376
 
        PFREE((void *) e->long_desc);
377
 
    }
378
 
    if(e->flags & KHERR_RF_FREE_SUGGEST) {
379
 
        assert(e->suggestion);
380
 
        PFREE((void *) e->suggestion);
381
 
    }
382
 
 
383
 
    free_event_params(e);
384
 
 
385
 
    ZeroMemory(e, sizeof(e));
386
 
 
387
 
    LPUSH(&evt_free_list, e);
388
 
    LeaveCriticalSection(&cs_error);
389
 
}
390
 
 
391
 
static kherr_context *
392
 
get_empty_context(void)
393
 
{
394
 
    kherr_context * c;
395
 
 
396
 
    EnterCriticalSection(&cs_error);
397
 
    if(ctx_free_list)
398
 
        LPOP(&ctx_free_list, &c);
399
 
    else {
400
 
        c = PMALLOC(sizeof(kherr_context));
401
 
    }
402
 
 
403
 
    ZeroMemory(c,sizeof(*c));
404
 
    c->severity = KHERR_NONE;
405
 
    c->flags = KHERR_CF_UNBOUND;
406
 
    c->magic = KHERR_CONTEXT_MAGIC;
407
 
    c->serial = ++ctx_serial;
408
 
 
409
 
    LPUSH(&ctx_root_list, c);
410
 
 
411
 
    LeaveCriticalSection(&cs_error);
412
 
 
413
 
    return c;
414
 
}
415
 
 
416
 
 
417
 
/* Assumes that the context has been deleted from all relevant
418
 
   lists */
419
 
static void
420
 
free_context(kherr_context * c)
421
 
{
422
 
    kherr_context * ch;
423
 
    kherr_event * e;
424
 
 
425
 
    assert(IS_KHERR_CTX(c));
426
 
 
427
 
#ifdef DEBUG_CONTEXT
428
 
    kherr_debug_printf(L"Freeing context 0x%x\n", c);
429
 
#endif
430
 
 
431
 
    EnterCriticalSection(&cs_error);
432
 
 
433
 
    if (c->desc_event)
434
 
        free_event(c->desc_event);
435
 
    c->desc_event = NULL;
436
 
 
437
 
    TPOPCHILD(c, &ch);
438
 
    while(ch) {
439
 
        free_context(ch);
440
 
        TPOPCHILD(c, &ch);
441
 
    }
442
 
    QGET(c, &e);
443
 
    while(e) {
444
 
        free_event(e);
445
 
        QGET(c, &e);
446
 
    }
447
 
 
448
 
    c->serial = 0;
449
 
 
450
 
    LPUSH(&ctx_free_list,c);
451
 
    LeaveCriticalSection(&cs_error);
452
 
 
453
 
#ifdef DEBUG_CONTEXT
454
 
    kherr_debug_printf(L"Done with context 0x%x\n", c);
455
 
#endif
456
 
}
457
 
 
458
 
static void
459
 
add_event(kherr_context * c, kherr_event * e)
460
 
{
461
 
    kherr_event * te;
462
 
 
463
 
    assert(IS_KHERR_CTX(c));
464
 
    assert(IS_KHERR_EVENT(e));
465
 
#ifdef DEBUG
466
 
    assert(LPREV(e) == NULL && LNEXT(e) == NULL);
467
 
#endif
468
 
 
469
 
    EnterCriticalSection(&cs_error);
470
 
    te = QBOTTOM(c);
471
 
    if (te && !(te->flags & KHERR_RF_COMMIT)) {
472
 
        notify_ctx_event(KHERR_CTX_EVTCOMMIT, c);
473
 
        te->flags |= KHERR_RF_COMMIT;
474
 
    }
475
 
 
476
 
    QPUT(c,e);
477
 
    if(c->severity > e->severity) {
478
 
        if (e->severity <= KHERR_ERROR)
479
 
            notify_ctx_event(KHERR_CTX_ERROR, c);
480
 
 
481
 
        c->severity = e->severity;
482
 
        c->err_event = e;
483
 
        c->flags &= ~KHERR_CF_DIRTY;
484
 
    }
485
 
    LeaveCriticalSection(&cs_error);
486
 
}
487
 
 
488
 
static void
489
 
pick_err_event(kherr_context * c)
490
 
{
491
 
    kherr_event * e;
492
 
    kherr_event * ce = NULL;
493
 
    enum kherr_severity s;
494
 
 
495
 
    s = KHERR_RESERVED_BANK;
496
 
 
497
 
    EnterCriticalSection(&cs_error);
498
 
    e = QTOP(c);
499
 
    while(e) {
500
 
        if(!(e->flags & KHERR_RF_INERT) &&
501
 
           s >= e->severity) {
502
 
            ce = e;
503
 
            s = e->severity;
504
 
        }
505
 
        e = QNEXT(e);
506
 
    }
507
 
 
508
 
    if(ce) {
509
 
        c->err_event = ce;
510
 
        c->severity = ce->severity;
511
 
    } else {
512
 
        c->err_event = NULL;
513
 
        c->severity = KHERR_NONE;
514
 
    }
515
 
 
516
 
    c->flags &= ~KHERR_CF_DIRTY;
517
 
    LeaveCriticalSection(&cs_error);
518
 
}
519
 
 
520
 
static void
521
 
va_arg_from_param(va_list * parm, kherr_param p)
522
 
{
523
 
    int t = parm_type(p);
524
 
 
525
 
    khm_int32 * pi;
526
 
    wchar_t ** ps;
527
 
    void ** pptr;
528
 
    khm_int64 * pli;
529
 
 
530
 
    if (t != KEPT_NONE) {
531
 
        switch (t) {
532
 
        case KEPT_INT32:
533
 
        case KEPT_UINT32:
534
 
            pi = (khm_int32 *)(*parm);
535
 
            va_arg(*parm, khm_int32);
536
 
            *pi = (khm_int32) parm_data(p);
537
 
            break;
538
 
 
539
 
        case KEPT_STRINGC:
540
 
        case KEPT_STRINGT:
541
 
            ps = (wchar_t **) (*parm);
542
 
            va_arg(*parm, wchar_t *);
543
 
            *ps = (wchar_t *) parm_data(p);
544
 
            break;
545
 
 
546
 
        case KEPT_PTR:
547
 
            pptr = (void **) (*parm);
548
 
            va_arg(*parm, void *);
549
 
            *pptr = (void *) parm_data(p);
550
 
            break;
551
 
 
552
 
        case KEPT_INT64:
553
 
        case KEPT_UINT64:
554
 
            pli = (khm_int64 *) (*parm);
555
 
            va_arg(*parm, khm_int64);
556
 
            *pli = (khm_int64) parm_data(p);
557
 
            break;
558
 
 
559
 
#ifdef DEBUG
560
 
        default:
561
 
            assert(FALSE);
562
 
#endif
563
 
        }
564
 
    }
565
 
}
566
 
 
567
 
static void
568
 
va_args_from_event(va_list args, kherr_event * e, khm_size cb)
569
 
{
570
 
    ZeroMemory(args, cb);
571
 
 
572
 
    va_arg_from_param(&args, e->p1);
573
 
    va_arg_from_param(&args, e->p2);
574
 
    va_arg_from_param(&args, e->p3);
575
 
    va_arg_from_param(&args, e->p4);
576
 
}
577
 
 
578
 
static void
579
 
resolve_string_resource(kherr_event * e,
580
 
                        const wchar_t ** str,
581
 
                        va_list vl,
582
 
                        khm_int32 if_flag,
583
 
                        khm_int32 or_flag)
584
 
{
585
 
    wchar_t tfmt[KHERR_MAXCCH_STRING];
586
 
    wchar_t tbuf[KHERR_MAXCCH_STRING];
587
 
    size_t chars = 0;
588
 
    size_t bytes = 0;
589
 
 
590
 
    if(e->flags & if_flag) {
591
 
        if(e->h_module != NULL)
592
 
            chars = LoadString(e->h_module, (UINT)(INT_PTR) *str,
593
 
                               tfmt, ARRAYLENGTH(tbuf));
594
 
        if(e->h_module == NULL || chars == 0)
595
 
            *str = NULL;
596
 
        else {
597
 
            wchar_t * s;
598
 
 
599
 
            chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING, tfmt,
600
 
                                  0, 0, tbuf, ARRAYLENGTH(tbuf), &vl);
601
 
 
602
 
            if (chars == 0) {
603
 
                *str = NULL;
604
 
            } else {
605
 
                bytes = (chars + 1) * sizeof(wchar_t);
606
 
                s = PMALLOC(bytes);
607
 
                assert(s);
608
 
                StringCbCopy(s, bytes, tbuf);
609
 
                *str = s;
610
 
                e->flags |= or_flag;
611
 
            }
612
 
        }
613
 
        e->flags &= ~if_flag;
614
 
    }
615
 
}
616
 
 
617
 
static void
618
 
resolve_msg_resource(kherr_event * e,
619
 
                     const wchar_t ** str,
620
 
                     va_list vl,
621
 
                     khm_int32 if_flag,
622
 
                     khm_int32 or_flag)
623
 
{
624
 
    wchar_t tbuf[KHERR_MAXCCH_STRING];
625
 
    size_t chars = 0;
626
 
    size_t bytes = 0;
627
 
 
628
 
    if(e->flags & if_flag) {
629
 
        if(e->h_module != NULL) {
630
 
 
631
 
            chars = FormatMessage(FORMAT_MESSAGE_FROM_HMODULE,
632
 
                                  (LPCVOID) e->h_module,
633
 
                                  (DWORD)(DWORD_PTR) *str,
634
 
                                  0,
635
 
                                  tbuf,
636
 
                                  ARRAYLENGTH(tbuf),
637
 
                                  &vl);
638
 
        }
639
 
 
640
 
        if(e->h_module == NULL || chars == 0) {
641
 
            *str = NULL;
642
 
        } else {
643
 
            wchar_t * s;
644
 
 
645
 
            /* MC inserts trailing \r\n to each message unless the
646
 
               message is terminated with a %0.  We remove the last
647
 
               line break since it is irrelevant to our handling of
648
 
               the string in the UI. */
649
 
            if (tbuf[chars-1] == L'\n')
650
 
                tbuf[--chars] = L'\0';
651
 
            if (tbuf[chars-1] == L'\r')
652
 
                tbuf[--chars] = L'\0';
653
 
 
654
 
            bytes = (chars + 1) * sizeof(wchar_t);
655
 
            s = PMALLOC(bytes);
656
 
            assert(s);
657
 
            StringCbCopy(s, bytes, tbuf);
658
 
            *str = s;
659
 
            e->flags |= or_flag;
660
 
        }
661
 
        e->flags &= ~if_flag;
662
 
    }
663
 
}
664
 
 
665
 
static void
666
 
resolve_string(kherr_event * e,
667
 
               const wchar_t ** str,
668
 
               va_list vl,
669
 
               khm_int32 mask,
670
 
               khm_int32 free_if,
671
 
               khm_int32 or_flag)
672
 
{
673
 
    wchar_t tbuf[KHERR_MAXCCH_STRING];
674
 
    size_t chars;
675
 
    size_t bytes;
676
 
 
677
 
    if (((e->flags & mask) == 0 ||
678
 
         (e->flags & mask) == free_if) &&
679
 
        *str != NULL) {
680
 
 
681
 
        chars = FormatMessage(FORMAT_MESSAGE_FROM_STRING,
682
 
                              (LPCVOID) *str,
683
 
                              0,
684
 
                              0,
685
 
                              tbuf,
686
 
                              ARRAYLENGTH(tbuf),
687
 
                              &vl);
688
 
 
689
 
        if ((e->flags & mask) == free_if) {
690
 
            PFREE((void *) *str);
691
 
        }
692
 
 
693
 
        e->flags &= ~mask;
694
 
 
695
 
        if (chars == 0) {
696
 
            *str = 0;
697
 
        } else {
698
 
            wchar_t * s;
699
 
 
700
 
            bytes = (chars + 1) * sizeof(wchar_t);
701
 
            s = PMALLOC(bytes);
702
 
            assert(s);
703
 
            StringCbCopy(s, bytes, tbuf);
704
 
            *str = s;
705
 
            e->flags |= or_flag;
706
 
        }
707
 
    }
708
 
 
709
 
}
710
 
 
711
 
void
712
 
resolve_event_strings(kherr_event * e)
713
 
{
714
 
    DWORD_PTR args[8];
715
 
    va_list vl = (va_list) args;
716
 
 
717
 
    va_args_from_event(vl, e, sizeof(args));
718
 
 
719
 
    resolve_string(e, &e->short_desc, vl,
720
 
                   KHERR_RFMASK_SHORT_DESC,
721
 
                   KHERR_RF_FREE_SHORT_DESC,
722
 
                   KHERR_RF_FREE_SHORT_DESC);
723
 
 
724
 
    resolve_string(e, &e->long_desc, vl,
725
 
                   KHERR_RFMASK_LONG_DESC,
726
 
                   KHERR_RF_FREE_LONG_DESC,
727
 
                   KHERR_RF_FREE_LONG_DESC);
728
 
 
729
 
    resolve_string(e, &e->suggestion, vl,
730
 
                   KHERR_RFMASK_SUGGEST,
731
 
                   KHERR_RF_FREE_SUGGEST,
732
 
                   KHERR_RF_FREE_SUGGEST);
733
 
 
734
 
    resolve_string_resource(e, &e->short_desc, vl,
735
 
                            KHERR_RF_RES_SHORT_DESC,
736
 
                            KHERR_RF_FREE_SHORT_DESC);
737
 
 
738
 
    resolve_string_resource(e, &e->long_desc, vl,
739
 
                            KHERR_RF_RES_LONG_DESC,
740
 
                            KHERR_RF_FREE_LONG_DESC);
741
 
 
742
 
    resolve_string_resource(e, &e->suggestion, vl,
743
 
                            KHERR_RF_RES_SUGGEST,
744
 
                            KHERR_RF_FREE_SUGGEST);
745
 
 
746
 
    resolve_msg_resource(e, &e->short_desc, vl,
747
 
                         KHERR_RF_MSG_SHORT_DESC,
748
 
                         KHERR_RF_FREE_SHORT_DESC);
749
 
    resolve_msg_resource(e, &e->long_desc, vl,
750
 
                         KHERR_RF_MSG_LONG_DESC,
751
 
                         KHERR_RF_FREE_LONG_DESC);
752
 
    resolve_msg_resource(e, &e->suggestion, vl,
753
 
                         KHERR_RF_MSG_SUGGEST,
754
 
                         KHERR_RF_FREE_SUGGEST);
755
 
 
756
 
    /* get rid of dangling reference now that we have done everything
757
 
       we can with it.  Since we have already dealt with all the
758
 
       parameter inserts, we don't need the parameters anymore
759
 
       either. */
760
 
    free_event_params(e);
761
 
 
762
 
    e->h_module = NULL;
763
 
    e->flags |= KHERR_RF_STR_RESOLVED;
764
 
}
765
 
 
766
 
 
767
 
KHMEXP void KHMAPI
768
 
kherr_evaluate_event(kherr_event * e)
769
 
{
770
 
    if (!IS_KHERR_EVENT(e))
771
 
        return;
772
 
 
773
 
    EnterCriticalSection(&cs_error);
774
 
    resolve_event_strings(e);
775
 
    LeaveCriticalSection(&cs_error);
776
 
}
777
 
 
778
 
KHMEXP void KHMAPI
779
 
kherr_evaluate_last_event(void)
780
 
{
781
 
    kherr_context * c;
782
 
    kherr_event * e;
783
 
    DWORD tid;
784
 
 
785
 
    c = peek_context();
786
 
    if(!IS_KHERR_CTX(c))
787
 
        return;
788
 
    tid = GetCurrentThreadId();
789
 
 
790
 
    EnterCriticalSection(&cs_error);
791
 
    e = QBOTTOM(c);
792
 
    while (e != NULL && e->thread_id != tid)
793
 
        e = QPREV(e);
794
 
 
795
 
    if(!IS_KHERR_EVENT(e))
796
 
        goto _exit;
797
 
 
798
 
    resolve_event_strings(e);
799
 
 
800
 
 _exit:
801
 
    LeaveCriticalSection(&cs_error);
802
 
}
803
 
 
804
 
KHMEXP kherr_event * __cdecl
805
 
kherr_reportf(const wchar_t * long_desc_fmt, ...)
806
 
{
807
 
    va_list vl;
808
 
    wchar_t buf[1024];
809
 
    kherr_event * e;
810
 
 
811
 
    va_start(vl, long_desc_fmt);
812
 
    StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl);
813
 
#ifdef DEBUG
814
 
    OutputDebugString(buf);
815
 
#endif
816
 
    va_end(vl);
817
 
 
818
 
    e = kherr_report(KHERR_DEBUG_1,
819
 
                     NULL, NULL, NULL, buf, NULL, 0,
820
 
                     KHERR_SUGGEST_NONE, _vnull(), _vnull(), _vnull(), _vnull(),
821
 
                     KHERR_RF_CSTR_LONG_DESC
822
 
#ifdef _WIN32
823
 
                     ,NULL
824
 
#endif
825
 
                     );
826
 
    if (IS_KHERR_EVENT(e)) {
827
 
        kherr_evaluate_event(e);
828
 
    }
829
 
 
830
 
    return e;
831
 
}
832
 
 
833
 
KHMEXP kherr_event * __cdecl
834
 
kherr_reportf_ex(enum kherr_severity severity,
835
 
                 const wchar_t * facility,
836
 
                 khm_int32 facility_id,
837
 
#ifdef _WIN32
838
 
                 HMODULE hModule,
839
 
#endif
840
 
                 const wchar_t * long_desc_fmt, ...)
841
 
{
842
 
    va_list vl;
843
 
    wchar_t buf[1024];
844
 
    kherr_event * e;
845
 
 
846
 
    va_start(vl, long_desc_fmt);
847
 
    StringCbVPrintf(buf, sizeof(buf), long_desc_fmt, vl);
848
 
#ifdef DEBUG
849
 
    OutputDebugString(buf);
850
 
#endif
851
 
    va_end(vl);
852
 
 
853
 
    e = kherr_report(severity, NULL, facility, NULL, buf, NULL, facility_id,
854
 
                     KHERR_SUGGEST_NONE,
855
 
                     _vnull(),
856
 
                     _vnull(),
857
 
                     _vnull(),
858
 
                     _vnull(), KHERR_RF_CSTR_LONG_DESC
859
 
#ifdef _WIN32
860
 
                     ,hModule
861
 
#endif
862
 
                     );
863
 
    if (IS_KHERR_EVENT(e)) {
864
 
        kherr_evaluate_event(e);
865
 
    }
866
 
 
867
 
    return e;
868
 
}
869
 
 
870
 
KHMEXP kherr_event * KHMAPI
871
 
kherr_report(enum kherr_severity severity,
872
 
             const wchar_t * short_desc,
873
 
             const wchar_t * facility,
874
 
             const wchar_t * location,
875
 
             const wchar_t * long_desc,
876
 
             const wchar_t * suggestion,
877
 
             khm_int32 facility_id,
878
 
             enum kherr_suggestion suggestion_id,
879
 
             kherr_param p1,
880
 
             kherr_param p2,
881
 
             kherr_param p3,
882
 
             kherr_param p4,
883
 
             khm_int32 flags
884
 
#ifdef _WIN32
885
 
             ,HMODULE  h_module
886
 
#endif
887
 
             )
888
 
{
889
 
    kherr_context * c;
890
 
    kherr_event * e;
891
 
    khm_boolean invalid = FALSE;
892
 
 
893
 
    /* sanity check */
894
 
    if (!IS_POW2(flags & KHERR_RFMASK_SHORT_DESC) ||
895
 
        !IS_POW2(flags & KHERR_RFMASK_LONG_DESC) ||
896
 
        !IS_POW2(flags & KHERR_RFMASK_SUGGEST))
897
 
        invalid = TRUE;
898
 
 
899
 
    e = get_empty_event();
900
 
 
901
 
    e->thread_id = GetCurrentThreadId();
902
 
    e->time_ticks = GetTickCount();
903
 
    GetSystemTimeAsFileTime(&e->time_ft);
904
 
 
905
 
    e->severity = severity;
906
 
    e->short_desc = short_desc;
907
 
    e->facility = facility;
908
 
    e->location = location;
909
 
    e->long_desc = long_desc;
910
 
    e->suggestion = suggestion;
911
 
    e->facility_id = facility_id;
912
 
    e->suggestion_id = suggestion_id;
913
 
    e->p1 = p1;
914
 
    e->p2 = p2;
915
 
    e->p3 = p3;
916
 
    e->p4 = p4;
917
 
    e->flags = flags;
918
 
#ifdef _WIN32
919
 
    e->h_module = h_module;
920
 
#endif
921
 
 
922
 
    EnterCriticalSection(&cs_error);
923
 
    c = peek_context();
924
 
 
925
 
    if(!c || invalid) {
926
 
        /* the reason why we are doing it this way is because p1..p4,
927
 
           the descriptions and the suggestion may contain allocations
928
 
           that has to be freed. */
929
 
        free_event(e);
930
 
        e = NULL;
931
 
    } else {
932
 
        add_event(c,e);
933
 
    }
934
 
 
935
 
    LeaveCriticalSection(&cs_error);
936
 
 
937
 
    return e;
938
 
}
939
 
 
940
 
KHMEXP void KHMAPI
941
 
kherr_suggest(wchar_t * suggestion,
942
 
              enum kherr_suggestion suggestion_id,
943
 
              khm_int32 flags)
944
 
{
945
 
    kherr_context * c;
946
 
    kherr_event * e;
947
 
    DWORD tid;
948
 
 
949
 
    if (flags != KHERR_RF_CSTR_SUGGEST &&
950
 
        flags != KHERR_RF_RES_SUGGEST &&
951
 
        flags != KHERR_RF_MSG_SUGGEST &&
952
 
        flags != KHERR_RF_FREE_SUGGEST)
953
 
        return;
954
 
 
955
 
    c = peek_context();
956
 
    if(!IS_KHERR_CTX(c))
957
 
        return;
958
 
 
959
 
    tid = GetCurrentThreadId();
960
 
 
961
 
    EnterCriticalSection(&cs_error);
962
 
    e = QBOTTOM(c);
963
 
    while (e != NULL && e->thread_id != tid)
964
 
        e = QPREV(e);
965
 
 
966
 
    if(!IS_KHERR_EVENT(e))
967
 
        goto _exit;
968
 
 
969
 
    /* if strings have already been resolved in this event, we cant
970
 
       add any more unresolved strings. */
971
 
    if ((flags == KHERR_RF_RES_SUGGEST ||
972
 
         flags == KHERR_RF_MSG_SUGGEST) &&
973
 
        (e->flags & KHERR_RF_STR_RESOLVED))
974
 
        goto _exit;
975
 
 
976
 
    e->suggestion = suggestion;
977
 
    e->suggestion_id = suggestion_id;
978
 
    e->flags |= flags;
979
 
_exit:
980
 
    LeaveCriticalSection(&cs_error);
981
 
}
982
 
 
983
 
KHMEXP void KHMAPI
984
 
kherr_location(wchar_t * location)
985
 
{
986
 
    kherr_context * c;
987
 
    kherr_event * e;
988
 
    DWORD tid;
989
 
 
990
 
    c = peek_context();
991
 
    if(!IS_KHERR_CTX(c))
992
 
        return;
993
 
    tid = GetCurrentThreadId();
994
 
 
995
 
    EnterCriticalSection(&cs_error);
996
 
    e = QBOTTOM(c);
997
 
    while (e != NULL && e->thread_id != tid)
998
 
        e = QPREV(e);
999
 
 
1000
 
    if(!IS_KHERR_EVENT(e))
1001
 
        goto _exit;
1002
 
    e->location = location;
1003
 
_exit:
1004
 
    LeaveCriticalSection(&cs_error);
1005
 
}
1006
 
 
1007
 
KHMEXP void KHMAPI
1008
 
kherr_facility(wchar_t * facility,
1009
 
               khm_int32 facility_id)
1010
 
{
1011
 
    kherr_context * c;
1012
 
    kherr_event * e;
1013
 
    DWORD tid;
1014
 
 
1015
 
    c = peek_context();
1016
 
    if(!IS_KHERR_CTX(c))
1017
 
        return;
1018
 
    tid = GetCurrentThreadId();
1019
 
    EnterCriticalSection(&cs_error);
1020
 
    e = QBOTTOM(c);
1021
 
    while (e != NULL && e->thread_id != tid)
1022
 
        e = QPREV(e);
1023
 
 
1024
 
    if(!IS_KHERR_EVENT(e))
1025
 
        goto _exit;
1026
 
    e->facility = facility;
1027
 
    e->facility_id = facility_id;
1028
 
_exit:
1029
 
    LeaveCriticalSection(&cs_error);
1030
 
}
1031
 
 
1032
 
KHMEXP void KHMAPI
1033
 
kherr_set_desc_event(void)
1034
 
{
1035
 
    kherr_context * c;
1036
 
    kherr_event * e;
1037
 
    DWORD tid;
1038
 
 
1039
 
    c = peek_context();
1040
 
    if(!IS_KHERR_CTX(c))
1041
 
        return;
1042
 
    tid = GetCurrentThreadId();
1043
 
 
1044
 
    EnterCriticalSection(&cs_error);
1045
 
    e = QBOTTOM(c);
1046
 
    while (e != NULL && e->thread_id != tid)
1047
 
        e = QPREV(e);
1048
 
 
1049
 
    if(!IS_KHERR_EVENT(e) || c->desc_event)
1050
 
        goto _exit;
1051
 
 
1052
 
    QDEL(c,e);
1053
 
    c->desc_event = e;
1054
 
    e->severity = KHERR_NONE;
1055
 
    resolve_event_strings(e);
1056
 
 
1057
 
    notify_ctx_event(KHERR_CTX_DESCRIBE, c);
1058
 
 
1059
 
_exit:
1060
 
    LeaveCriticalSection(&cs_error);
1061
 
}
1062
 
 
1063
 
KHMEXP void KHMAPI
1064
 
kherr_del_last_event(void)
1065
 
{
1066
 
    kherr_context * c;
1067
 
    kherr_event * e;
1068
 
    DWORD tid;
1069
 
 
1070
 
    c = peek_context();
1071
 
 
1072
 
    if(!IS_KHERR_CTX(c))
1073
 
        return;
1074
 
 
1075
 
    tid = GetCurrentThreadId();
1076
 
 
1077
 
    EnterCriticalSection(&cs_error);
1078
 
    e = QBOTTOM(c);
1079
 
    while (e != NULL && e->thread_id != tid)
1080
 
        e = QPREV(e);
1081
 
 
1082
 
    if(IS_KHERR_EVENT(e)) {
1083
 
        QDEL(c, e);
1084
 
        if(c->err_event == e) {
1085
 
            pick_err_event(c);
1086
 
        }
1087
 
        free_event(e);
1088
 
    }
1089
 
    LeaveCriticalSection(&cs_error);
1090
 
}
1091
 
 
1092
 
KHMEXP void KHMAPI
1093
 
kherr_push_context(kherr_context * c)
1094
 
{
1095
 
    kherr_context * p = NULL;
1096
 
    int new_context = FALSE;
1097
 
 
1098
 
    if (!IS_KHERR_CTX(c))
1099
 
        return;
1100
 
 
1101
 
    EnterCriticalSection(&cs_error);
1102
 
    p = peek_context();
1103
 
    if(IS_KHERR_CTX(p) && (c->flags & KHERR_CF_UNBOUND)) {
1104
 
        LDELETE(&ctx_root_list, c);
1105
 
        TADDCHILD(p,c);
1106
 
        c->flags &= ~KHERR_CF_UNBOUND;
1107
 
        kherr_hold_context(p);
1108
 
        new_context = TRUE;
1109
 
    }
1110
 
    push_context(c);
1111
 
 
1112
 
    if (new_context && IS_KHERR_CTX(p)) {
1113
 
        notify_ctx_event(KHERR_CTX_BEGIN, c);
1114
 
        notify_ctx_event(KHERR_CTX_NEWCHILD, p);
1115
 
    }
1116
 
 
1117
 
    LeaveCriticalSection(&cs_error);
1118
 
}
1119
 
 
1120
 
KHMEXP void KHMAPI
1121
 
kherr_push_new_context(khm_int32 flags)
1122
 
{
1123
 
    kherr_context * p = NULL;
1124
 
    kherr_context * c;
1125
 
 
1126
 
    flags &= KHERR_CFMASK_INITIAL;
1127
 
 
1128
 
    EnterCriticalSection(&cs_error);
1129
 
    p = peek_context();
1130
 
    c = get_empty_context();
1131
 
    if(IS_KHERR_CTX(p)) {
1132
 
        LDELETE(&ctx_root_list, c);
1133
 
        TADDCHILD(p,c);
1134
 
        c->flags &= ~KHERR_CF_UNBOUND;
1135
 
        kherr_hold_context(p);
1136
 
    }
1137
 
    c->flags |= flags;
1138
 
    push_context(c);
1139
 
 
1140
 
    notify_ctx_event(KHERR_CTX_BEGIN, c);
1141
 
    if (IS_KHERR_CTX(p)) {
1142
 
        notify_ctx_event(KHERR_CTX_NEWCHILD, p);
1143
 
    }
1144
 
 
1145
 
    LeaveCriticalSection(&cs_error);
1146
 
}
1147
 
 
1148
 
static kherr_param
1149
 
dup_parm(kherr_param p)
1150
 
{
1151
 
    if(parm_type(p) == KEPT_STRINGT) {
1152
 
        wchar_t * d = PWCSDUP((wchar_t *)parm_data(p));
1153
 
        return kherr_val(KEPT_STRINGT, (khm_ui_8) d);
1154
 
    } else
1155
 
        return p;
1156
 
}
1157
 
 
1158
 
static kherr_event *
1159
 
fold_context(kherr_context * c)
1160
 
{
1161
 
    kherr_event * e;
1162
 
    kherr_event * g;
1163
 
 
1164
 
    if (!IS_KHERR_CTX(c))
1165
 
        return NULL;
1166
 
 
1167
 
    EnterCriticalSection(&cs_error);
1168
 
    if(!c->err_event || (c->flags & KHERR_CF_DIRTY)) {
1169
 
        pick_err_event(c);
1170
 
    }
1171
 
    if(c->err_event) {
1172
 
        g = c->err_event;
1173
 
        e = get_empty_event();
1174
 
        *e = *g;
1175
 
        g->short_desc = NULL;
1176
 
        g->long_desc = NULL;
1177
 
        g->suggestion = NULL;
1178
 
        g->flags &=
1179
 
            ~(KHERR_RF_FREE_SHORT_DESC |
1180
 
              KHERR_RF_FREE_LONG_DESC |
1181
 
              KHERR_RF_FREE_SUGGEST);
1182
 
        LINIT(e);
1183
 
        e->p1 = dup_parm(g->p1);
1184
 
        e->p2 = dup_parm(g->p2);
1185
 
        e->p3 = dup_parm(g->p3);
1186
 
        e->p4 = dup_parm(g->p4);
1187
 
    } else {
1188
 
        e = c->desc_event;
1189
 
        c->desc_event = NULL;
1190
 
    }
1191
 
 
1192
 
    if (IS_KHERR_EVENT(e))
1193
 
        e->flags |= KHERR_RF_CONTEXT_FOLD;
1194
 
 
1195
 
    LeaveCriticalSection(&cs_error);
1196
 
 
1197
 
    return e;
1198
 
}
1199
 
 
1200
 
KHMEXP void KHMAPI
1201
 
kherr_hold_context(kherr_context * c)
1202
 
{
1203
 
    if(!IS_KHERR_CTX(c))
1204
 
        return;
1205
 
 
1206
 
    EnterCriticalSection(&cs_error);
1207
 
    c->refcount++;
1208
 
    LeaveCriticalSection(&cs_error);
1209
 
}
1210
 
 
1211
 
KHMEXP void KHMAPI
1212
 
kherr_release_context(kherr_context * c)
1213
 
{
1214
 
    if (!IS_KHERR_CTX(c))
1215
 
        return;
1216
 
 
1217
 
    EnterCriticalSection(&cs_error);
1218
 
    c->refcount--;
1219
 
    if (c->refcount == 0) {
1220
 
        kherr_event * e;
1221
 
        kherr_context * p;
1222
 
 
1223
 
        e = QBOTTOM(c);
1224
 
        if (IS_KHERR_EVENT(e) && !(e->flags & KHERR_RF_COMMIT)) {
1225
 
            notify_ctx_event(KHERR_CTX_EVTCOMMIT, c);
1226
 
            e->flags |= KHERR_RF_COMMIT;
1227
 
        }
1228
 
 
1229
 
        notify_ctx_event(KHERR_CTX_END, c);
1230
 
 
1231
 
        p = TPARENT(c);
1232
 
        if (IS_KHERR_CTX(p)) {
1233
 
            e = fold_context(c);
1234
 
            if (e)
1235
 
                add_event(p, e);
1236
 
 
1237
 
            TDELCHILD(p, c);
1238
 
 
1239
 
            notify_ctx_event(KHERR_CTX_FOLDCHILD, p);
1240
 
 
1241
 
            kherr_release_context(p);
1242
 
        } else {
1243
 
            LDELETE(&ctx_root_list, c);
1244
 
        }
1245
 
        free_context(c);
1246
 
    }
1247
 
    LeaveCriticalSection(&cs_error);
1248
 
}
1249
 
 
1250
 
KHMEXP void KHMAPI
1251
 
kherr_pop_context(void)
1252
 
{
1253
 
    kherr_context * c;
1254
 
 
1255
 
    EnterCriticalSection(&cs_error);
1256
 
    c = pop_context();
1257
 
    if(IS_KHERR_CTX(c)) {
1258
 
        kherr_release_context(c);
1259
 
    }
1260
 
    LeaveCriticalSection(&cs_error);
1261
 
}
1262
 
 
1263
 
KHMEXP kherr_context * KHMAPI
1264
 
kherr_peek_context(void)
1265
 
{
1266
 
    kherr_context * c;
1267
 
 
1268
 
    c = peek_context();
1269
 
    if (IS_KHERR_CTX(c))
1270
 
        kherr_hold_context(c);
1271
 
 
1272
 
    return c;
1273
 
}
1274
 
 
1275
 
KHMEXP khm_boolean KHMAPI
1276
 
kherr_is_error(void)
1277
 
{
1278
 
    kherr_context * c = peek_context();
1279
 
    return kherr_is_error_i(c);
1280
 
}
1281
 
 
1282
 
KHMEXP khm_boolean KHMAPI
1283
 
kherr_is_error_i(kherr_context * c)
1284
 
{
1285
 
    if(IS_KHERR_CTX(c) && c->severity <= KHERR_ERROR)
1286
 
        return TRUE;
1287
 
    else
1288
 
        return FALSE;
1289
 
}
1290
 
 
1291
 
KHMEXP void KHMAPI
1292
 
kherr_clear_error(void)
1293
 
{
1294
 
    kherr_context * c = peek_context();
1295
 
    if (IS_KHERR_CTX(c))
1296
 
        kherr_clear_error_i(c);
1297
 
}
1298
 
 
1299
 
KHMEXP void KHMAPI
1300
 
kherr_clear_error_i(kherr_context * c)
1301
 
{
1302
 
    kherr_event * e;
1303
 
    if (IS_KHERR_CTX(c)) {
1304
 
        EnterCriticalSection(&cs_error);
1305
 
        e = QTOP(c);
1306
 
        while(e) {
1307
 
            assert(IS_KHERR_EVENT(e));
1308
 
 
1309
 
            e->flags |= KHERR_RF_INERT;
1310
 
            e = QNEXT(e);
1311
 
        }
1312
 
        c->severity = KHERR_NONE;
1313
 
        c->err_event = NULL;
1314
 
        c->flags &= ~KHERR_CF_DIRTY;
1315
 
        LeaveCriticalSection(&cs_error);
1316
 
    }
1317
 
}
1318
 
 
1319
 
/* does the context 'c' use it's own progress marker? If this is
1320
 
   false, the progress marker for the context is derived from the
1321
 
   progress markers of its children. */
1322
 
#define CTX_USES_OWN_PROGRESS(c) ((c)->progress_num != 0 || (c)->progress_denom != 0 || ((c)->flags & KHERR_CF_OWN_PROGRESS))
1323
 
 
1324
 
KHMEXP void KHMAPI
1325
 
kherr_set_progress(khm_ui_4 num, khm_ui_4 denom)
1326
 
{
1327
 
    kherr_context * c = peek_context();
1328
 
    if(IS_KHERR_CTX(c)) {
1329
 
        EnterCriticalSection(&cs_error);
1330
 
 
1331
 
        if (num > denom)
1332
 
            num = denom;
1333
 
 
1334
 
        if (c->progress_denom != denom ||
1335
 
            c->progress_num != denom) {
1336
 
 
1337
 
            kherr_context * p;
1338
 
 
1339
 
            c->progress_denom = denom;
1340
 
            c->progress_num = num;
1341
 
 
1342
 
            notify_ctx_event(KHERR_CTX_PROGRESS, c);
1343
 
 
1344
 
            for (p = TPARENT(c);
1345
 
                 IS_KHERR_CTX(p) && !CTX_USES_OWN_PROGRESS(p);
1346
 
                 p = TPARENT(p)) {
1347
 
 
1348
 
                notify_ctx_event(KHERR_CTX_PROGRESS, p);
1349
 
 
1350
 
            }
1351
 
        }
1352
 
        LeaveCriticalSection(&cs_error);
1353
 
    }
1354
 
}
1355
 
 
1356
 
KHMEXP void KHMAPI
1357
 
kherr_get_progress(khm_ui_4 * num, khm_ui_4 * denom)
1358
 
{
1359
 
    kherr_context * c = peek_context();
1360
 
    kherr_get_progress_i(c,num,denom);
1361
 
}
1362
 
 
1363
 
/* called with cs_error held */
1364
 
static void
1365
 
get_progress(kherr_context * c, khm_ui_4 * pnum, khm_ui_4 * pdenom)
1366
 
{
1367
 
    if (CTX_USES_OWN_PROGRESS(c)) {
1368
 
        *pnum = c->progress_num;
1369
 
        *pdenom = c->progress_denom;
1370
 
    } else {
1371
 
        khm_ui_4 num = 0;
1372
 
        khm_ui_4 denom = 0;
1373
 
 
1374
 
        kherr_context * cc;
1375
 
 
1376
 
        for (cc = TFIRSTCHILD(c);
1377
 
             cc;
1378
 
             cc = LNEXT(cc)) {
1379
 
 
1380
 
            khm_ui_4 cnum, cdenom;
1381
 
 
1382
 
            assert(IS_KHERR_CTX(cc));
1383
 
 
1384
 
            get_progress(cc, &cnum, &cdenom);
1385
 
 
1386
 
            if (cdenom == 0) {
1387
 
                cnum = 0;
1388
 
            } else {
1389
 
                if (cnum > cdenom)
1390
 
                    cnum = cdenom;
1391
 
 
1392
 
                if (cdenom != 256) {
1393
 
                    cnum = (cnum * 256) / cdenom;
1394
 
                    cdenom = 256;
1395
 
                }
1396
 
            }
1397
 
 
1398
 
            num += cnum;
1399
 
            denom += cdenom;
1400
 
        }
1401
 
 
1402
 
        *pnum = num;
1403
 
        *pdenom = denom;
1404
 
    }
1405
 
}
1406
 
 
1407
 
KHMEXP void KHMAPI
1408
 
kherr_get_progress_i(kherr_context * c,
1409
 
                     khm_ui_4 * num,
1410
 
                     khm_ui_4 * denom)
1411
 
{
1412
 
    if (num == NULL || denom == NULL)
1413
 
        return;
1414
 
 
1415
 
    if(IS_KHERR_CTX(c)) {
1416
 
        EnterCriticalSection(&cs_error);
1417
 
        get_progress(c, num, denom);
1418
 
        LeaveCriticalSection(&cs_error);
1419
 
    } else {
1420
 
        *num = 0;
1421
 
        *denom = 0;
1422
 
    }
1423
 
}
1424
 
 
1425
 
KHMEXP kherr_event * KHMAPI
1426
 
kherr_get_first_event(kherr_context * c)
1427
 
{
1428
 
    kherr_event * e;
1429
 
 
1430
 
    if (!IS_KHERR_CTX(c))
1431
 
        return NULL;
1432
 
 
1433
 
    EnterCriticalSection(&cs_error);
1434
 
    e = QTOP(c);
1435
 
    LeaveCriticalSection(&cs_error);
1436
 
    assert(e == NULL || IS_KHERR_EVENT(e));
1437
 
    return e;
1438
 
}
1439
 
 
1440
 
KHMEXP kherr_event * KHMAPI
1441
 
kherr_get_next_event(kherr_event * e)
1442
 
{
1443
 
    kherr_event * ee;
1444
 
 
1445
 
    if (!IS_KHERR_EVENT(e))
1446
 
        return NULL;
1447
 
 
1448
 
    EnterCriticalSection(&cs_error);
1449
 
    ee = QNEXT(e);
1450
 
    LeaveCriticalSection(&cs_error);
1451
 
    assert(ee == NULL || IS_KHERR_EVENT(ee));
1452
 
    return ee;
1453
 
}
1454
 
 
1455
 
KHMEXP kherr_event * KHMAPI
1456
 
kherr_get_prev_event(kherr_event * e)
1457
 
{
1458
 
    kherr_event * ee;
1459
 
 
1460
 
    if (!IS_KHERR_EVENT(e))
1461
 
        return NULL;
1462
 
 
1463
 
    EnterCriticalSection(&cs_error);
1464
 
    ee = QPREV(e);
1465
 
    LeaveCriticalSection(&cs_error);
1466
 
    assert(ee == NULL || IS_KHERR_EVENT(ee));
1467
 
    return ee;
1468
 
}
1469
 
 
1470
 
KHMEXP kherr_event * KHMAPI
1471
 
kherr_get_last_event(kherr_context * c)
1472
 
{
1473
 
    kherr_event * e;
1474
 
 
1475
 
    if (!IS_KHERR_CTX(c))
1476
 
        return NULL;
1477
 
 
1478
 
    EnterCriticalSection(&cs_error);
1479
 
    e = QBOTTOM(c);
1480
 
    LeaveCriticalSection(&cs_error);
1481
 
    assert(e == NULL || IS_KHERR_EVENT(e));
1482
 
    return e;
1483
 
}
1484
 
 
1485
 
KHMEXP kherr_context * KHMAPI
1486
 
kherr_get_first_context(kherr_context * c)
1487
 
{
1488
 
    kherr_context * cc;
1489
 
 
1490
 
    if (c != NULL && !IS_KHERR_CTX(c))
1491
 
        return NULL;
1492
 
 
1493
 
    EnterCriticalSection(&cs_error);
1494
 
    if (IS_KHERR_CTX(c)) {
1495
 
        cc = TFIRSTCHILD(c);
1496
 
        if (cc)
1497
 
            kherr_hold_context(cc);
1498
 
    } else {
1499
 
        cc = ctx_root_list;
1500
 
        if (cc)
1501
 
            kherr_hold_context(cc);
1502
 
    }
1503
 
    LeaveCriticalSection(&cs_error);
1504
 
    assert(cc == NULL || IS_KHERR_CTX(cc));
1505
 
    return cc;
1506
 
}
1507
 
 
1508
 
KHMEXP kherr_context * KHMAPI
1509
 
kherr_get_next_context(kherr_context * c)
1510
 
{
1511
 
    kherr_context * cc;
1512
 
 
1513
 
    if (!IS_KHERR_CTX(c))
1514
 
        return NULL;
1515
 
 
1516
 
    EnterCriticalSection(&cs_error);
1517
 
    cc = LNEXT(c);
1518
 
    if (cc)
1519
 
        kherr_hold_context(cc);
1520
 
    LeaveCriticalSection(&cs_error);
1521
 
    assert(cc == NULL || IS_KHERR_CTX(cc));
1522
 
    return cc;
1523
 
}
1524
 
 
1525
 
KHMEXP kherr_event * KHMAPI
1526
 
kherr_get_err_event(kherr_context * c)
1527
 
{
1528
 
    kherr_event * e;
1529
 
 
1530
 
    if (!IS_KHERR_CTX(c))
1531
 
        return NULL;
1532
 
 
1533
 
    EnterCriticalSection(&cs_error);
1534
 
    if(!c->err_event) {
1535
 
        pick_err_event(c);
1536
 
    }
1537
 
    e = c->err_event;
1538
 
    LeaveCriticalSection(&cs_error);
1539
 
    assert(e == NULL || IS_KHERR_EVENT(e));
1540
 
    return e;
1541
 
}
1542
 
 
1543
 
KHMEXP kherr_event * KHMAPI
1544
 
kherr_get_desc_event(kherr_context * c)
1545
 
{
1546
 
    kherr_event * e;
1547
 
 
1548
 
    if (!IS_KHERR_CTX(c))
1549
 
        return NULL;
1550
 
 
1551
 
    EnterCriticalSection(&cs_error);
1552
 
    e = c->desc_event;
1553
 
    LeaveCriticalSection(&cs_error);
1554
 
    assert(e == NULL || IS_KHERR_EVENT(e));
1555
 
    return e;
1556
 
}
1557
 
 
1558
 
KHMEXP kherr_param
1559
 
kherr_dup_string(const wchar_t * s)
1560
 
{
1561
 
    wchar_t * dest;
1562
 
    size_t cb_s;
1563
 
 
1564
 
    if (s == NULL)
1565
 
        return _vnull();
1566
 
 
1567
 
    if (FAILED(StringCbLength(s, KHERR_MAXCB_STRING, &cb_s)))
1568
 
        cb_s = KHERR_MAXCB_STRING;
1569
 
    else
1570
 
        cb_s += sizeof(wchar_t);
1571
 
 
1572
 
    dest = PMALLOC(cb_s);
1573
 
    assert(dest != NULL);
1574
 
    dest[0] = L'\0';
1575
 
 
1576
 
    StringCbCopy(dest, cb_s, s);
1577
 
 
1578
 
    return _tstr(dest);
1579
 
}