~stub/ubuntu/trusty/avro-c/trunk

« back to all changes in this revision

Viewing changes to src/errors.c

  • Committer: Stuart Bishop
  • Date: 2015-05-14 11:53:53 UTC
  • Revision ID: stuart@stuartbishop.net-20150514115353-0cvnrcyohcq5l7yj
Tags: upstream-1.7.7
ImportĀ upstreamĀ versionĀ 1.7.7

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/*
 
2
 * Licensed to the Apache Software Foundation (ASF) under one or more
 
3
 * contributor license agreements.  See the NOTICE file distributed with
 
4
 * this work for additional information regarding copyright ownership.
 
5
 * The ASF licenses this file to you under the Apache License, Version 2.0
 
6
 * (the "License"); you may not use this file except in compliance with
 
7
 * the License.  You may obtain a copy of the License at
 
8
 *
 
9
 * http://www.apache.org/licenses/LICENSE-2.0
 
10
 *
 
11
 * Unless required by applicable law or agreed to in writing, software
 
12
 * distributed under the License is distributed on an "AS IS" BASIS,
 
13
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
 
14
 * implied.  See the License for the specific language governing
 
15
 * permissions and limitations under the License.
 
16
 */
 
17
 
 
18
#include <stdarg.h>
 
19
#include <stdio.h>
 
20
#include <string.h>
 
21
#include <stdlib.h>
 
22
 
 
23
#include "avro/errors.h"
 
24
 
 
25
#if defined THREADSAFE && (defined __unix__ || defined __unix)
 
26
#include <pthread.h>
 
27
static pthread_key_t error_data_key;
 
28
static pthread_once_t error_data_key_once = PTHREAD_ONCE_INIT;
 
29
 
 
30
static void make_error_data_key()
 
31
{
 
32
    pthread_key_create(&error_data_key, free);
 
33
}
 
34
#endif
 
35
 
 
36
/* 4K should be enough, right? */
 
37
#define AVRO_ERROR_SIZE 4096
 
38
 
 
39
/*
 
40
 * To support the avro_prefix_error function, we keep two string buffers
 
41
 * around.  The AVRO_CURRENT_ERROR points at the buffer that's holding
 
42
 * the current error message.  avro_prefix error writes into the other
 
43
 * buffer, and then swaps them.
 
44
 */
 
45
 
 
46
struct avro_error_data_t {
 
47
    char  AVRO_ERROR1[AVRO_ERROR_SIZE];
 
48
    char  AVRO_ERROR2[AVRO_ERROR_SIZE];
 
49
 
 
50
    char  *AVRO_CURRENT_ERROR;
 
51
    char  *AVRO_OTHER_ERROR;
 
52
};
 
53
 
 
54
 
 
55
static struct avro_error_data_t *
 
56
avro_get_error_data(void)
 
57
{
 
58
#if defined THREADSAFE && (defined __unix__ || defined __unix)
 
59
    pthread_once(&error_data_key_once, make_error_data_key);
 
60
 
 
61
    struct avro_error_data_t *ERROR_DATA =
 
62
        (struct avro_error_data_t*) pthread_getspecific(error_data_key);
 
63
 
 
64
    if (!ERROR_DATA) {
 
65
        ERROR_DATA = (struct avro_error_data_t*) malloc(sizeof(struct avro_error_data_t));
 
66
        pthread_setspecific(error_data_key, ERROR_DATA);
 
67
 
 
68
        ERROR_DATA->AVRO_ERROR1[0] = '\0';
 
69
        ERROR_DATA->AVRO_ERROR2[0] = '\0';
 
70
        ERROR_DATA->AVRO_CURRENT_ERROR = ERROR_DATA->AVRO_ERROR1;
 
71
        ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_ERROR2;
 
72
    }
 
73
 
 
74
    return ERROR_DATA;
 
75
#else
 
76
    static struct avro_error_data_t ERROR_DATA = {
 
77
      /* .AVRO_ERROR1 = */ {'\0'},
 
78
      /* .AVRO_ERROR2 = */ {'\0'},
 
79
      /* .AVRO_CURRENT_ERROR = */ ERROR_DATA.AVRO_ERROR1,
 
80
      /* .AVRO_OTHER_ERROR = */ ERROR_DATA.AVRO_ERROR2,
 
81
    };
 
82
 
 
83
    return &ERROR_DATA;
 
84
#endif
 
85
}
 
86
 
 
87
 
 
88
void
 
89
avro_set_error(const char *fmt, ...)
 
90
{
 
91
        va_list  args;
 
92
        va_start(args, fmt);
 
93
        vsnprintf(avro_get_error_data()->AVRO_CURRENT_ERROR, AVRO_ERROR_SIZE, fmt, args);
 
94
        va_end(args);
 
95
        //fprintf(stderr, "--- %s\n", AVRO_CURRENT_ERROR);
 
96
}
 
97
 
 
98
 
 
99
void
 
100
avro_prefix_error(const char *fmt, ...)
 
101
{
 
102
    struct avro_error_data_t *ERROR_DATA = avro_get_error_data();
 
103
 
 
104
        /*
 
105
         * First render the prefix into OTHER_ERROR.
 
106
         */
 
107
 
 
108
        va_list  args;
 
109
        va_start(args, fmt);
 
110
        int  bytes_written = vsnprintf(ERROR_DATA->AVRO_OTHER_ERROR, AVRO_ERROR_SIZE, fmt, args);
 
111
        va_end(args);
 
112
 
 
113
        /*
 
114
         * Then concatenate the existing error onto the end.
 
115
         */
 
116
 
 
117
        if (bytes_written < AVRO_ERROR_SIZE) {
 
118
                strncpy(&ERROR_DATA->AVRO_OTHER_ERROR[bytes_written], ERROR_DATA->AVRO_CURRENT_ERROR,
 
119
                        AVRO_ERROR_SIZE - bytes_written);
 
120
                ERROR_DATA->AVRO_OTHER_ERROR[AVRO_ERROR_SIZE-1] = '\0';
 
121
        }
 
122
 
 
123
        /*
 
124
         * Swap the two error pointers.
 
125
         */
 
126
 
 
127
        char  *tmp;
 
128
        tmp = ERROR_DATA->AVRO_OTHER_ERROR;
 
129
        ERROR_DATA->AVRO_OTHER_ERROR = ERROR_DATA->AVRO_CURRENT_ERROR;
 
130
        ERROR_DATA->AVRO_CURRENT_ERROR = tmp;
 
131
        //fprintf(stderr, "+++ %s\n", AVRO_CURRENT_ERROR);
 
132
}
 
133
 
 
134
 
 
135
const char *avro_strerror(void)
 
136
{
 
137
        return avro_get_error_data()->AVRO_CURRENT_ERROR;
 
138
}