version 1.0
[platform/core/system/tizen-platform-wrapper.git] / src / scratch.c
1 /*
2  * Copyright (C) 2013 Intel Corporation.
3  * 
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Library General Public
6  * License as published by the Free Software Foundation; either
7  * version 2 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Library General Public License for more details.
13  *
14  * You should have received a copy of the GNU Library General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
17  *
18  * Authors:
19  *   José Bollo <jose.bollo@open.eurogiciel.org>
20  *   Stéphane Desneux <stephane.desneux@open.eurogiciel.org>
21  *   Jean-Benoit Martin <jean-benoit.martin@open.eurogiciel.org>
22  *
23  */
24 #define _GNU_SOURCE
25
26 #ifdef HAVE_CONFIG_H
27 # include "config.h"
28 #endif
29
30 #include <stdlib.h>
31
32 #ifndef INITIAL_SCRATCH_CAPACITY
33 #define INITIAL_SCRATCH_CAPACITY  240
34 #endif
35
36 #if INITIAL_SCRATCH_CAPACITY <= 0
37 #error "bad value for INITIAL_SCRATCH_CAPACITY"
38 #endif
39
40 #ifndef NOT_MULTI_THREAD_SAFE
41 #include <pthread.h>
42 static pthread_key_t tlskey;
43 static int key_initialized = 0;
44 #else
45 static void *global_scratch = NULL;
46 #endif
47
48 /* CAUTION: in a multitheaded context, it is expected that
49 =========== the function scratchcat is call under a mutex. 
50 If it is not the case please check for initializing 'tlskey' 
51 only one time before use of it. */
52
53 const char *scratchcat( int ispath, const char **strings)
54 {
55     void *scratch, *p;
56     char *result;
57     size_t length, capacity;
58     const char *instr;
59     char c, pc;
60
61     /* get the recorded pointer on scrtch area */
62 #ifndef NOT_MULTI_THREAD_SAFE
63     if (!key_initialized) {
64         key_initialized = 1;
65         pthread_key_create( &tlskey, (void(*)(void*))free);
66     }
67     scratch = pthread_getspecific( tlskey);
68 #else
69     scratch = global_scratch;
70 #endif
71
72     /* create the scratch area if needed */
73     if (scratch == NULL) {
74         capacity = INITIAL_SCRATCH_CAPACITY;
75         p = malloc( capacity + sizeof(size_t));
76         if (p == NULL)
77             return NULL;
78         *((size_t*)p) = capacity;
79         scratch = p;
80 #ifndef NOT_MULTI_THREAD_SAFE
81         pthread_setspecific( tlskey, p);
82 #else
83         global_scratch = p;
84 #endif
85     }
86
87     /* set local data for scratch area */
88     capacity = *((size_t*)scratch);
89     result = (char*)(1+((size_t*)scratch));
90     length = 0;
91
92     /* copy the strings */
93     c = 0;
94     pc = 1;
95     while(pc) {
96
97         if (c == 0) {
98             instr = *strings++;
99             if (instr != NULL) {
100                 c = *instr;
101                 if (c == 0)
102                     continue;
103                 if (!ispath)
104                     instr++;
105                 else if(c != '/' && pc != '/')
106                     c = '/';
107                 else if(c == '/' && pc == '/') {
108                     instr++;
109                     continue;
110                 }
111                 else
112                     instr++;
113             }
114         }
115         else {
116             c = *instr;
117             if (c == 0)
118                 continue;
119             instr++;
120         }
121
122         /* extend the scratch area if needed */
123         if (length == capacity) {
124             capacity = 2 * capacity;
125             p = realloc( scratch, capacity + sizeof(size_t));
126             if (p == NULL)
127                 return NULL;
128             *((size_t*)p) = capacity;
129             if (p != scratch) {
130                 scratch = p;
131 #ifndef NOT_MULTI_THREAD_SAFE
132                 pthread_setspecific( tlskey, p);
133 #else
134                 global_scratch = p;
135 #endif
136                 result = (char*)(1+((size_t*)p));
137             }
138         }
139
140         /* append the char */
141         pc = result[length++] = c;
142     }
143
144     return result;
145 }
146
147
148 #ifdef TEST_SCRATCH
149 #include <stdio.h>
150 int main(int argc, const char**argv) {
151     int ispath;
152     argv++;
153     ispath = argv[0] && argv[0][0] == '-' && argv[0][1] == 'p';
154     printf("%s\n",scratchcat(ispath,argv+ispath));
155     return 0;
156 }
157 #endif