Open Chinese Convert  0.4.3
A project for conversion between Traditional and Simplified Chinese
 All Data Structures Files Functions Variables Groups Pages
utils.c
1 /*
2  * Open Chinese Convert
3  *
4  * Copyright 2010-2013 BYVoid <byvoid@byvoid.com>
5  *
6  * Licensed under the Apache License, Version 2.0 (the "License");
7  * you may not use this file except in compliance with the License.
8  * You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and
16  * limitations under the License.
17  */
18 
19 #include "utils.h"
20 #include <unistd.h>
21 
22 #ifdef __APPLE__
23  #include "TargetConditionals.h"
24  #ifdef TARGET_OS_MAC
25  #include <mach-o/dyld.h>
26  #elif TARGET_OS_IPHONE
27  #elif TARGET_IPHONE_SIMULATOR
28  #else /* ifdef TARGET_OS_MAC */
29  #endif /* ifdef TARGET_OS_MAC */
30 #elif defined _WIN32 || defined _WIN64
31  #include "Windows.h"
32 #endif /* ifdef __APPLE__ */
33 
34 #if defined _WIN32 || defined _WIN64
35  #define PATH_SEPARATOR '\\'
36 #else
37  #define PATH_SEPARATOR '/'
38 #endif
39 
40 #define PATH_BUFFER_SIZE 4096
41 
42 void perr(const char* str) {
43  fputs(str, stderr);
44 }
45 
46 int qsort_int_cmp(const void* a, const void* b) {
47  return *((int*)a) - *((int*)b);
48 }
49 
50 char* mstrcpy(const char* str) {
51  char* strbuf = (char*)malloc(sizeof(char) * (strlen(str) + 1));
52 
53  strcpy(strbuf, str);
54  return strbuf;
55 }
56 
57 char* mstrncpy(const char* str, size_t n) {
58  char* strbuf = (char*)malloc(sizeof(char) * (n + 1));
59 
60  strncpy(strbuf, str, n);
61  strbuf[n] = '\0';
62  return strbuf;
63 }
64 
65 void skip_utf8_bom(FILE* fp) {
66  int bom[3];
67  int n;
68 
69  /* UTF-8 BOM is EF BB BF */
70  if (fp == NULL) {
71  return;
72  }
73 
74  /* If we are not at beginning of file, return */
75  if (ftell(fp) != 0) {
76  return;
77  }
78 
79  /* Try to read first 3 bytes */
80  for (n = 0; n <= 2 && (bom[n] = getc(fp)) != EOF; n++) {}
81 
82  /* If we can only read <3 bytes, push them back */
83  /* Or if first 3 bytes is not BOM, push them back */
84  if ((n < 3) || (bom[0] != 0xEF) || (bom[1] != 0xBB) || (bom[2] != 0xBF)) {
85  for (n--; n >= 0; n--) {
86  ungetc(bom[n], fp);
87  }
88  }
89 
90  /* Otherwise, BOM is already skipped */
91 }
92 
93 const char* executable_path(void) {
94  static char path_buffer[PATH_BUFFER_SIZE];
95  static int calculated = 0;
96 
97  if (!calculated) {
98 #ifdef __linux
99  ssize_t res = readlink("/proc/self/exe", path_buffer, sizeof(path_buffer));
100  assert(res != -1);
101 #elif __APPLE__
102  uint32_t size = sizeof(path_buffer);
103  int res = _NSGetExecutablePath(path_buffer, &size);
104  assert(res == 0);
105 #elif _WIN32 || _WIN64
106  // NOTE: for "C:\\opencc.exe" on Windows, the returned path "C:" is
107  // incorrect until a '/' is appended to it later in try_open_file()
108  DWORD res = GetModuleFileNameA(NULL, path_buffer, PATH_BUFFER_SIZE);
109  assert(res != 0);
110 #else
111  /* Other unsupported os */
112  assert(0);
113 #endif /* ifdef __linux */
114  char* last_sep = strrchr(path_buffer, PATH_SEPARATOR);
115  assert(last_sep != NULL);
116  *last_sep = '\0';
117  calculated = 1;
118  }
119  return path_buffer;
120 }
121 
122 char* try_open_file(const char* path) {
123  /* Try to find file in current working directory */
124  FILE* fp = fopen(path, "r");
125 
126  if (fp) {
127  fclose(fp);
128  return mstrcpy(path);
129  }
130 
131  /* If path is absolute, return NULL */
132  if (is_absolute_path(path)) {
133  return NULL;
134  }
135 
136  /* Try to find file in executable directory */
137  const char* exe_dir = executable_path();
138  char* filename =
139  (char*)malloc(sizeof(char) * (strlen(path) + strlen(exe_dir) + 2));
140  sprintf(filename, "%s/%s", exe_dir, path);
141  fp = fopen(filename, "r");
142 
143  if (fp) {
144  fclose(fp);
145  return filename;
146  }
147  free(filename);
148 
149  /* Try to use PKGDATADIR */
150  filename =
151  (char*)malloc(sizeof(char) * (strlen(path) + strlen(PKGDATADIR) + 2));
152  sprintf(filename, "%s/%s", PKGDATADIR, path);
153  fp = fopen(filename, "r");
154 
155  if (fp) {
156  fclose(fp);
157  return filename;
158  }
159  free(filename);
160  return NULL;
161 }
162 
163 char* get_file_path(const char* filename) {
164  const char* last_sep = strrchr(filename, '/');
165 
166  if (last_sep == NULL) {
167  last_sep = filename;
168  }
169  char* path = mstrncpy(filename, last_sep - filename);
170  return path;
171 }
172 
173 int is_absolute_path(const char* path) {
174  if (path[0] == '/') {
175  return 1;
176  }
177 
178  if (path[1] == ':') {
179  return 1;
180  }
181  return 0;
182 }