Pointwise Plugin SDK
 All Classes Files Functions Variables Typedefs Enumerations Enumerator Macros Groups Pages
pwpPlatform.cxx
Go to the documentation of this file.
1 /****************************************************************************
2  *
3  * runtime Plugin platform dependent function calls
4  *
5  * (C) 2021 Cadence Design Systems, Inc. All rights reserved worldwide.
6  *
7  ***************************************************************************/
8 
9 #include <cstdlib>
10 #include <memory>
11 #include <string.h>
12 #include <sys/stat.h>
13 #include <vector>
14 
15 #if defined(WINDOWS)
16 # include <io.h>
17 # include <direct.h>
18 # include <malloc.h>
19 #else
20 # include <stdlib.h>
21 #endif // WINDOWS
22 
23 // apiUtils.h included for ASSERT_COMPILE() macros.
24 // TODO: Consider isolating ASSERT macros to their own header "apiAssert.h"?
25 #include "apiUtils.h"
26 #include "pwpPlatform.h"
27 
28 
29 #if defined(WINDOWS)
30 
31 # define sysTextMode 't'
32 # define sysBinaryMode 'b'
33 # define sysFileno(fp) _fileno(fp)
34 # define sysFstat _fstat64
35 # define sysGetCwd() ::_wgetcwd(0, FILENAME_MAX)
36 
37  using SysStatBuf = struct _stat64;
38  using DirUniquePtr = std::unique_ptr<wchar_t, decltype(free)*>;
39 
40 #else // *nix or mac
41 
42 # define sysTextMode '\0'
43 # define sysBinaryMode 'b'
44 # define sysFileno(fp) fileno(fp)
45 # define sysFstat fstat
46 # define sysGetCwd() ::getcwd(0, FILENAME_MAX)
47 
48  using SysStatBuf = struct stat;
49  using DirUniquePtr = std::unique_ptr<char, decltype(free)*>;
50 
51 #endif // WINDOWS
52 
53 
54 #define strOK(ss) ((nullptr != ss) && ('\0' != ss[0]))
55 #define chrAPPEND(p,c) ((nullptr != p) ? (*p++ = c) : 0)
56 
57 #define isMODE(allBits,modeBits) (((allBits) & (modeBits)) == modeBits)
58 
59 #if !defined(FILENAME_MAX)
60 # define FILENAME_MAX 512
61 #endif
62 
63 
64 #ifdef WINDOWS
65 
66 static wchar_t *
67 utf8ToU16(const char *s)
68 {
69  wchar_t *result = 0;
70  size_t element = 0;
71  if (nullptr != s) {
72  size_t len;
73  len = ::strlen(s) + 1;
74  result = (wchar_t *)::malloc(len * sizeof(wchar_t));
75  //
76  // UTF-8 is a specific scheme for mapping a sequence of 1-4 bytes to a
77  // number from 0x000000 to 0x10FFFF:
78  //
79  // 00000000 -- 0000007F: 0xxxxxxx
80  // 00000080 -- 000007FF: 110xxxxx 10xxxxxx
81  // 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
82  // 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
83  //
84  // where the x's are the bits to be extracted from the sequence and
85  // combined to form the final value.
86  //
87  while ('\0' != *s) {
88  unsigned char c = (unsigned char)*s;
89  switch (0xF0 & c) {
90  // No indicator, so just convert
91  default:
92  result[element] = (wchar_t)c;
93  ++s;
94  break;
95  // Possible two byte utf8 character
96  case 0xC0:
97  case 0xD0:
98  // Two byte character 110xxxxx 10xxxxxx
99  if (0x80 == (*(s + 1) & 0xC0)) {
100  result[element] = (wchar_t)(
101  ((c & 0x1F) << 6) | (*(s + 1) & 0x3F));
102  s += 2;
103  }
104  // Doesn't have the second byte correct, so leave as is
105  else {
106  result[element] = (wchar_t)c;
107  ++s;
108  }
109  break;
110  // Possible three byte utf8 character
111  case 0xE0:
112  // Three byte character 1110xxxx 10xxxxxx 10xxxxxx
113  if (0x80 == (*(s + 1) & 0xC0) && 0x80 == (*(s + 2) & 0xC0)) {
114  result[element] = (wchar_t)(((c & 0x0F) << 12) |
115  ((*(s + 1) & 0x3F) << 6) | (*(s + 2) & 0x3F));
116  s += 3;
117  }
118  // Doesn't have the second and third byte correct, so leave as
119  // is
120  else {
121  result[element] = (wchar_t)c;
122  ++s;
123  }
124  break;
125  // Four byte case which can't be compressed into 16 bits, so just
126  // convert the bytes as is
127  case 0xF0:
128  result[element] = (wchar_t)c;
129  ++s;
130  break;
131  }
132  ++element;
133  }
134  }
135  else {
136  result = (wchar_t *)::malloc(sizeof(wchar_t));
137  }
138  result[element] = 0;
139  return result;
140 }
141 
142 
143 #ifdef NOT_NEEDED
144 static wchar_t *
145 utf8ToU16Old(const char *s)
146 {
147  wchar_t *result = 0;
148  size_t len;
149  size_t element = 0;
150  if (0 != s) {
151  len = ::strlen(s) + 1;
152  result = (wchar_t *)::malloc(len * sizeof(wchar_t));
153  //
154  // UTF-8 is a specific scheme for mapping a sequence of 1-4 bytes to a
155  // number from 0x000000 to 0x10FFFF:
156  //
157  // 00000000 -- 0000007F: 0xxxxxxx
158  // 00000080 -- 000007FF: 110xxxxx 10xxxxxx
159  // 00000800 -- 0000FFFF: 1110xxxx 10xxxxxx 10xxxxxx
160  // 00010000 -- 001FFFFF: 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx
161  //
162  // where the x's are the bits to be extracted from the sequence and
163  // combined to form the final value.
164  //
165  while ('\0' != *s) {
166  unsigned char c = (unsigned char)*s;
167  // Not an encoded character.
168  if (0xC0 > c) {
169  result[element] = (wchar_t)c;
170  ++s;
171  }
172  // Possible 2-byte utf-8 character
173  else if (0xE0 > c) {
174  // Two byte character 110xxxxx 10xxxxxx
175  if (0x80 == (*(s + 1) & 0xC0)) {
176  result[element] = (wchar_t)(
177  (c & 0x1F) << 6 | (*(s + 1) & 0x3F));
178  s += 2;
179  }
180  // Doesn't have the second byte correct, so leave as is
181  else {
182  result[element] = (wchar_t)c;
183  ++s;
184  }
185  }
186  // Possible 3-byte utf-8 character
187  else if (0xF0 > c) {
188  // Three byte character 1110xxxx 10xxxxxx 10xxxxxx
189  if (0x80 == (*(s + 1) & 0xC0) && 0x80 == (*(s + 2) & 0xC)) {
190  result[element] = (wchar_t)(((c & 0x0F) << 12) |
191  ((*(s + 1) & 0x3F) << 6) | (*(s + 2) & 0x3F));
192  s += 3;
193  }
194  // Doesn't have the second and third byte correct, so leave as
195  // is
196  else {
197  result[element] = (wchar_t)c;
198  ++s;
199  }
200  }
201  // Can't convert a 4-byte sequence down to 16 bits so just treat
202  // each byte as is
203  else {
204  result[element] = (wchar_t)c;
205  ++s;
206  }
207  ++element;
208  }
209  }
210  else {
211  result = (wchar_t *)::malloc(sizeof(wchar_t));
212  }
213  result[element] = 0;
214  return result;
215 }
216 #endif // NOT_NEEDED
217 
218 
219 // windows only overload
220 static int
221 pwpSetCurDir(const wchar_t *dir)
222 {
223  return ((nullptr != dir) && (0 == ::_wchdir(dir))) ? 0 : -1;
224 }
225 
226 #endif // WINDOWS
227 
228 
229 FILE *
230 pwpFileOpen(const char *filename, int mode)
231 {
232  FILE *ret = 0;
233  while (strOK(filename)) {
234  char modeStr[4] = {0,0,0,0};
235  char *p = modeStr;
236  // get base mode
237  if (isMODE(mode, pwpRead)) {
238  chrAPPEND(p, 'r');
239  }
240  else if (isMODE(mode, pwpWrite)) {
241  chrAPPEND(p, 'w');
242  }
243  else if (isMODE(mode, pwpAppend)) {
244  chrAPPEND(p, 'a');
245  }
246  else {
247  break; // error
248  }
249 
250  // get extended mode
251  if (isMODE(mode, pwpPlus_)) {
252  chrAPPEND(p, '+');
253  }
254 
255  // get format
256  if (isMODE(mode, pwpBinary) || isMODE(mode, pwpUnformatted)) {
258  }
259  else if (isMODE(mode, pwpFormatted) || isMODE(mode, pwpAscii)) {
261  }
262  else {
263  break; // error
264  }
265 
266 #ifdef WINDOWS
267  DirUniquePtr wname{ utf8ToU16(filename), free };
268  DirUniquePtr wmode{ utf8ToU16(modeStr), free };
269  if (wname && wmode) {
270  ret = ::_wfopen(wname.get(), wmode.get());
271  }
272  else {
273  ret = 0;
274  }
275 #else
276  ret = fopen(filename, modeStr);
277 #endif // WINDOWS
278  break; // force exit from while()
279  }
280  return ret;
281 }
282 
283 
284 int
285 pwpFileClose(FILE *fp)
286 {
287  int ret = sysEOF;
288  if (fp) {
289  ret = fclose(fp);
290  }
291  return ret;
292 }
293 
294 
295 int
296 pwpFileEof(FILE *fp)
297 {
298  return fp ? feof(fp) : 0;
299 }
300 
301 
302 int
303 pwpFileFlush(FILE *fp)
304 {
305  return fp ? fflush(fp) : -1;
306 }
307 
308 
309 int
310 pwpFileGetpos(FILE *fp, sysFILEPOS *pos)
311 {
312  int ret = -1;
313  if (fp && pos) {
314  ret = fgetpos(fp, pos);
315  }
316  return ret;
317 }
318 
319 
320 int
321 pwpFileSetpos(FILE *fp, const sysFILEPOS *pos)
322 {
323  int ret = -1;
324  if (fp && pos) {
325  ret = fsetpos(fp, pos);
326  }
327  return ret;
328 }
329 
330 
331 int
332 pwpFileGetSize(FILE *fp, size_t *size)
333 {
334  SysStatBuf buf;
335  // make sure files over 2GB are supported
336  ASSERT_COMPILE(sizeof(buf.st_size) == sizeof(size_t));
337  int ret = 0;
338  if (0 == fp || 0 == size) {
339  ret = -1;
340  }
341  else if (0 != sysFstat(sysFileno(fp), &buf)) {
342  *size = 0;
343  ret = -1;
344  }
345  else {
346  *size = (size_t)buf.st_size;
347  }
348  return ret;
349 }
350 
351 
352 int
353 pwpFilenameGetSize(const char *filename, size_t *size)
354 {
355  int ret = 0;
356  if (0 == filename || 0 == size) {
357  ret = -1;
358  }
359  else {
360 #ifdef WINDOWS
361  struct _stat64 buf;
362  DirUniquePtr wname{ utf8ToU16(filename), free };
363  if (nullptr == wname) {
364  ret = -1;
365  }
366  else {
367  if (0 != ::_wstat64(wname.get(), &buf)) {
368  *size = 0;
369  ret = -1;
370  }
371  else {
372  *size = (size_t)buf.st_size;
373  }
374  }
375 #else
376  struct stat buf;
377  if (0 != stat(filename, &buf)) {
378  *size = 0;
379  ret = -1;
380  }
381  else {
382  *size = (size_t)buf.st_size;
383  }
384 #endif // WINDOWS
385  }
386  return ret;
387 }
388 
389 
390 size_t
391 pwpFileRead(void *buf, size_t size, size_t count, FILE *fp)
392 {
393  size_t ret = 0;
394  if (buf && size && count && fp) {
395  ret = fread(buf, size, count, fp);
396  }
397  return ret;
398 }
399 
400 
401 size_t
402 pwpFileWrite(const void *buf, size_t size, size_t count, FILE *fp)
403 {
404  size_t ret = 0;
405  if (buf && size && count && fp) {
406  ret = fwrite(buf, size, count, fp);
407  }
408  return ret;
409 }
410 
411 
412 size_t
413 pwpFileWriteStr(const char *str, FILE *fp)
414 {
415  return str ? pwpFileWrite(str, strlen(str), 1, fp) : 0;
416 }
417 
418 
419 void
420 pwpFileRewind(FILE *fp)
421 {
422  if (fp) {
423  rewind(fp);
424  }
425 }
426 
427 
428 int
429 pwpFileDelete(const char *filename)
430 {
431  int ret = 0;
432  if (strOK(filename)) {
433 #ifdef WINDOWS
434  DirUniquePtr wname{ utf8ToU16(filename), free };
435  if (nullptr == wname) {
436  ret = -1;
437  }
438  else {
439  ret = ::_wunlink(wname.get());
440  }
441 #else
442  ret = unlink(filename);
443 #endif // WINDOWS
444  }
445  return ret;
446 }
447 
448 
449 int
450 pwpSetCurDir(const char *dir)
451 {
452 #if defined(WINDOWS)
453  return pwpSetCurDir(DirUniquePtr{ utf8ToU16(dir), free }.get());
454 #else
455  return (nullptr != dir) ? chdir(dir) : -1;
456 #endif
457 }
458 
459 
460 int
461 pwpCwdPush(const char *dir)
462 {
463  static std::vector<DirUniquePtr> dirStack;
464  int ret = -1;
465  if (strOK(dir)) {
466  // sysGetCwd() returns a malloc()'ed buffer
467  DirUniquePtr curDir{ sysGetCwd(), free };
468  if ((nullptr != curDir) && (0 == pwpSetCurDir(dir))) {
469  // Move curDir to dirStack so ~curDir will not free() it
470  dirStack.push_back(std::move(curDir));
471  ret = 0;
472  }
473  // ~curDir will free() ptr if not move()'ed above
474  }
475  else if (!dirStack.empty()) {
476  // pop dir
477  ret = pwpSetCurDir(dirStack.back().get());
478  // ~DirUniquePtr() will free() ptr
479  dirStack.pop_back();
480  }
481  return ret;
482 }
483 
484 
485 int
487 {
488  return pwpCwdPush(nullptr);
489 }
std::unique_ptr< char, decltype(free)* > DirUniquePtr
Definition: pwpPlatform.cxx:49
int pwpFileEof(FILE *fp)
Queries end-of-file status.
int pwpFileClose(FILE *fp)
Closes a file opened with pwpFileOpen().
size_t pwpFileWriteStr(const char *str, FILE *fp)
Write a null-terminated string to a file.
int pwpFileSetpos(FILE *fp, const sysFILEPOS *pos)
Set the current file position.
FILE * pwpFileOpen(const char *filename, int mode)
Opens a file for I/O.
#define sysFstat
Definition: pwpPlatform.cxx:45
size_t pwpFileRead(void *buf, size_t size, size_t count, FILE *fp)
Read an collection of data items from a file.
#define sysGetCwd()
Definition: pwpPlatform.cxx:46
fpos_t sysFILEPOS
File position data type.
Definition: pwpPlatform.h:51
#define sysFileno(fp)
Definition: pwpPlatform.cxx:44
Base plugin utilities.
Cross Platform Functions.
#define sysTextMode
Definition: pwpPlatform.cxx:42
int pwpFileFlush(FILE *fp)
Flush a file to disk.
int pwpCwdPop(void)
Restore the current directory.
int pwpFileGetpos(FILE *fp, sysFILEPOS *pos)
Query the current file position.
#define sysEOF
End-of-file value.
Definition: pwpPlatform.h:50
#define isMODE(allBits, modeBits)
Definition: pwpPlatform.cxx:57
size_t pwpFileWrite(const void *buf, size_t size, size_t count, FILE *fp)
Write an collection of data items to a file.
#define chrAPPEND(p, c)
Definition: pwpPlatform.cxx:55
void pwpFileRewind(FILE *fp)
Reset position to the beginning of the file.
int pwpSetCurDir(const char *dir)
Change the current directory.
int pwpFileDelete(const char *filename)
Delete a file.
struct stat SysStatBuf
Definition: pwpPlatform.cxx:48
int pwpFilenameGetSize(const char *filename, size_t *size)
Get the file&#39;s size in bytes.
ASSERT_COMPILE(sizeof(PWGM_ASSEMBLER_DATA)<=sizeof(PWP_UINT32)*8)
int pwpCwdPush(const char *dir)
Change the current directory using a stack.
#define strOK(ss)
Definition: pwpPlatform.cxx:54
#define sysBinaryMode
Definition: pwpPlatform.cxx:43
int pwpFileGetSize(FILE *fp, size_t *size)
Get the file&#39;s size in bytes.