ftphoney

ftphoney Commit Details


Date:2014-04-27 00:58:22 (10 years 5 months ago)
Author:Natalie Adams
Branch:master
Commit:d93a0f6a57577943074d5460873bd3d11a7da81c
Message:adding first version

Changes:

File differences

ftphoney.sln
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

Microsoft Visual Studio Solution File, Format Version 11.00
# Visual Studio 2010
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ftphoney", "ftphoney\ftphoney.vcxproj", "{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Win32 = Debug|Win32
Release|Win32 = Release|Win32
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Debug|Win32.ActiveCfg = Debug|Win32
{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Debug|Win32.Build.0 = Debug|Win32
{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Release|Win32.ActiveCfg = Release|Win32
{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}.Release|Win32.Build.0 = Release|Win32
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
EndGlobal
ftphoney/ftphoney.vcxproj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
<?xml version="1.0" encoding="utf-8"?>
<Project DefaultTargets="Build" ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<ItemGroup Label="ProjectConfigurations">
<ProjectConfiguration Include="Debug|Win32">
<Configuration>Debug</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
<ProjectConfiguration Include="Release|Win32">
<Configuration>Release</Configuration>
<Platform>Win32</Platform>
</ProjectConfiguration>
</ItemGroup>
<PropertyGroup Label="Globals">
<ProjectGuid>{C70E332A-1CEB-4ABD-B84D-70C7751C88EB}</ProjectGuid>
<Keyword>Win32Proj</Keyword>
<RootNamespace>ftphoney</RootNamespace>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>true</UseDebugLibraries>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'" Label="Configuration">
<ConfigurationType>Application</ConfigurationType>
<UseDebugLibraries>false</UseDebugLibraries>
<WholeProgramOptimization>true</WholeProgramOptimization>
<CharacterSet>Unicode</CharacterSet>
</PropertyGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.props" />
<ImportGroup Label="ExtensionSettings">
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<ImportGroup Label="PropertySheets" Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<Import Project="$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props" Condition="exists('$(UserRootDir)\Microsoft.Cpp.$(Platform).user.props')" Label="LocalAppDataPlatform" />
</ImportGroup>
<PropertyGroup Label="UserMacros" />
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<LinkIncremental>true</LinkIncremental>
</PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<LinkIncremental>false</LinkIncremental>
</PropertyGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
<ClCompile>
<PrecompiledHeader>
</PrecompiledHeader>
<WarningLevel>Level3</WarningLevel>
<Optimization>Disabled</Optimization>
<PreprocessorDefinitions>WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<AdditionalDependencies>ws2_32.lib;ptypes_d.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
<ClCompile>
<WarningLevel>Level3</WarningLevel>
<PrecompiledHeader>
</PrecompiledHeader>
<Optimization>MaxSpeed</Optimization>
<FunctionLevelLinking>true</FunctionLevelLinking>
<IntrinsicFunctions>true</IntrinsicFunctions>
<PreprocessorDefinitions>WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions)</PreprocessorDefinitions>
<AdditionalIncludeDirectories>$(SolutionDir)\include</AdditionalIncludeDirectories>
</ClCompile>
<Link>
<SubSystem>Console</SubSystem>
<GenerateDebugInformation>true</GenerateDebugInformation>
<EnableCOMDATFolding>true</EnableCOMDATFolding>
<OptimizeReferences>true</OptimizeReferences>
<AdditionalDependencies>ws2_32.lib;ptypes_r.lib;%(AdditionalDependencies)</AdditionalDependencies>
</Link>
</ItemDefinitionGroup>
<ItemGroup>
<ClCompile Include="..\src\main.cpp" />
</ItemGroup>
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
<ImportGroup Label="ExtensionTargets">
</ImportGroup>
</Project>
include/ptypes/pasync.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PASYNC_H__
#define __PASYNC_H__
#ifdef WIN32
# define _WINSOCKAPI_ // prevent inclusion of winsock.h, since we need winsock2.h
# include <windows.h>
#else
# include <pthread.h>
# ifndef __bsdi__
# include <semaphore.h>
# endif
#endif
#ifndef __PPORT_H__
#include "pport.h"
#endif
#ifndef __PTYPES_H__
#include "ptypes.h"
#endif
PTYPES_BEGIN
//
// Summary of implementation:
//
// atomic increment/decrement/exchange
// MSVC/BCC/i386: internal, asm
// GCC/i386: internal, asm
// GCC/PowerPC: internal, asm
// GCC/SPARC: internal, asm
// Other: internal, mutex hash table
//
// mutex
// Win32: Critical section
// Other: POSIX mutex
//
// trigger
// Win32: Event
// Other: internal, POSIX condvar/mutex
//
// rwlock:
// Win32: internal, Event/mutex
// MacOS: internal, POSIX condvar/mutex
// Other: POSIX rwlock
//
// semaphore:
// Win32: = timedsem
// MacOS: = timedsem
// Other: POSIX semaphore
//
// timedsem (with timed waiting):
// Win32: Semaphore
// Other: internal, POSIX mutex/condvar
//
#ifdef _MSC_VER
#pragma pack(push, 4)
#endif
#ifdef WIN32
typedef int pthread_id_t;
typedef HANDLE pthread_t;
#else
typedef pthread_t pthread_id_t;
#endif
ptpublic void ptdecl psleep(uint milliseconds);
ptpublic bool ptdecl pthrequal(pthread_id_t id); // note: this is NOT the thread handle, use thread::get_id()
ptpublic pthread_id_t ptdecl pthrself(); // ... same
// -------------------------------------------------------------------- //
// --- mutex ---------------------------------------------------------- //
// -------------------------------------------------------------------- //
#ifdef WIN32
struct ptpublic mutex: public noncopyable
{
protected:
CRITICAL_SECTION critsec;
public:
mutex() { InitializeCriticalSection(&critsec); }
~mutex() { DeleteCriticalSection(&critsec); }
void enter() { EnterCriticalSection(&critsec); }
void leave() { LeaveCriticalSection(&critsec); }
void lock() { enter(); }
void unlock() { leave(); }
};
#else
struct ptpublic mutex: public noncopyable
{
protected:
pthread_mutex_t mtx;
public:
mutex() { pthread_mutex_init(&mtx, 0); }
~mutex() { pthread_mutex_destroy(&mtx); }
void enter() { pthread_mutex_lock(&mtx); }
void leave() { pthread_mutex_unlock(&mtx); }
void lock() { enter(); }
void unlock() { leave(); }
};
#endif
//
// scopelock
//
class scopelock: public noncopyable
{
protected:
mutex* mtx;
public:
scopelock(mutex& imtx): mtx(&imtx) { mtx->lock(); }
~scopelock() { mtx->unlock(); }
};
//
// mutex table for hashed memory locking (undocumented)
//
#define _MUTEX_HASH_SIZE 29 // a prime number for hashing
#ifdef WIN32
# define pmemlock mutex
# define pmementer(m) (m)->lock()
# define pmemleave(m) (m)->unlock()
#else
# define _MTX_INIT PTHREAD_MUTEX_INITIALIZER
# define pmemlock pthread_mutex_t
# define pmementer pthread_mutex_lock
# define pmemleave pthread_mutex_unlock
#endif
ptpublic extern pmemlock _mtxtable[_MUTEX_HASH_SIZE];
#define pgetmemlock(addr) (_mtxtable + pintptr(addr) % _MUTEX_HASH_SIZE)
// -------------------------------------------------------------------- //
// --- trigger -------------------------------------------------------- //
// -------------------------------------------------------------------- //
#ifdef WIN32
class ptpublic trigger: public noncopyable
{
protected:
HANDLE handle; // Event object
public:
trigger(bool autoreset, bool state);
~trigger() { CloseHandle(handle); }
void wait() { WaitForSingleObject(handle, INFINITE); }
void post() { SetEvent(handle); }
void signal() { post(); }
void reset() { ResetEvent(handle); }
};
#else
class ptpublic trigger: public noncopyable
{
protected:
pthread_mutex_t mtx;
pthread_cond_t cond;
int state;
bool autoreset;
public:
trigger(bool autoreset, bool state);
~trigger();
void wait();
void post();
void signal() { post(); }
void reset();
};
#endif
// -------------------------------------------------------------------- //
// --- rwlock --------------------------------------------------------- //
// -------------------------------------------------------------------- //
#if defined(WIN32) || defined(__DARWIN__) || defined(__bsdi__)
# define __PTYPES_RWLOCK__
#elif defined(linux)
// on Linux rwlocks are included only with -D_GNU_SOURCE.
// programs that don't use rwlocks, do not need to define
// _GNU_SOURCE either.
# if defined(_GNU_SOURCE) || defined(__USE_UNIX98)
# define __POSIX_RWLOCK__
# endif
#else
# define __POSIX_RWLOCK__
#endif
#ifdef __PTYPES_RWLOCK__
struct ptpublic rwlock: protected mutex
{
protected:
#ifdef WIN32
HANDLE reading; // Event object
HANDLE finished; // Event object
int readcnt;
int writecnt;
#else
pthread_mutex_t mtx;
pthread_cond_t readcond;
pthread_cond_t writecond;
int locks;
int writers;
int readers;
#endif
public:
rwlock();
~rwlock();
void rdlock();
void wrlock();
void unlock();
void lock() { wrlock(); }
};
#elif defined(__POSIX_RWLOCK__)
struct ptpublic rwlock: public noncopyable
{
protected:
pthread_rwlock_t rw;
public:
rwlock();
~rwlock() { pthread_rwlock_destroy(&rw); }
void rdlock() { pthread_rwlock_rdlock(&rw); }
void wrlock() { pthread_rwlock_wrlock(&rw); }
void unlock() { pthread_rwlock_unlock(&rw); }
void lock() { wrlock(); }
};
#endif
#if defined(__PTYPES_RWLOCK__) || defined(__POSIX_RWLOCK__)
//
// scoperead & scopewrite
//
class scoperead: public noncopyable
{
protected:
rwlock* rw;
public:
scoperead(rwlock& irw): rw(&irw) { rw->rdlock(); }
~scoperead() { rw->unlock(); }
};
class scopewrite: public noncopyable
{
protected:
rwlock* rw;
public:
scopewrite(rwlock& irw): rw(&irw) { rw->wrlock(); }
~scopewrite() { rw->unlock(); }
};
#endif
// -------------------------------------------------------------------- //
// --- semaphore ------------------------------------------------------ //
// -------------------------------------------------------------------- //
#if defined(WIN32) || defined(__DARWIN__) || defined(__bsdi__)
# define __SEM_TO_TIMEDSEM__
#endif
#ifdef __SEM_TO_TIMEDSEM__
// map ordinary semaphore to timed semaphore
class timedsem;
typedef timedsem semaphore;
#else
class ptpublic semaphore: public unknown
{
protected:
sem_t handle;
public:
semaphore(int initvalue);
virtual ~semaphore();
void wait();
void post();
void signal() { post(); }
};
#endif
class ptpublic timedsem: public unknown
{
protected:
#ifdef WIN32
HANDLE handle;
#else
int count;
pthread_mutex_t mtx;
pthread_cond_t cond;
#endif
public:
timedsem(int initvalue);
virtual ~timedsem();
bool wait(int msecs = -1);
void post();
void signal() { post(); }
};
// -------------------------------------------------------------------- //
// --- thread --------------------------------------------------------- //
// -------------------------------------------------------------------- //
class ptpublic thread: public unknown
{
protected:
#ifdef WIN32
unsigned id;
#endif
pthread_t handle;
int autofree;
int running;
int signaled;
int finished;
int freed;
int reserved; // for priorities
timedsem relaxsem;
virtual void execute() = 0;
virtual void cleanup();
bool relax(int msecs) { return relaxsem.wait(msecs); }
friend void _threadepilog(thread* thr);
#ifdef WIN32
friend unsigned __stdcall _threadproc(void* arg);
#else
friend void* _threadproc(void* arg);
#endif
public:
thread(bool iautofree);
virtual ~thread();
#ifdef WIN32
pthread_id_t get_id() { return int(id); }
#else
pthread_id_t get_id() { return handle; }
#endif
bool get_running() { return running != 0; }
bool get_finished() { return finished != 0; }
bool get_signaled() { return signaled != 0; }
void start();
void signal();
void waitfor();
};
// -------------------------------------------------------------------- //
// --- jobqueue & msgqueue -------------------------------------------- //
// -------------------------------------------------------------------- //
const int MSG_USER = 0;
const int MSG_QUIT = -1;
const int DEF_QUEUE_LIMIT = 5000;
class ptpublic message: public unknown
{
protected:
message* next; // next in the message chain, used internally
semaphore* sync; // used internally by msgqueue::send(), when called from a different thread
friend class jobqueue; // my friends, job queue and message queue...
friend class msgqueue;
public:
int id;
pintptr param;
pintptr result;
message(int iid, pintptr iparam = 0);
virtual ~message();
};
class ptpublic jobqueue: public noncopyable
{
private:
int limit; // queue limit
message* head; // queue head
message* tail; // queue tail
int qcount; // number of items in the queue
timedsem sem; // queue semaphore
timedsem ovrsem; // overflow semaphore
mutex qlock; // critical sections in enqueue and dequeue
protected:
bool enqueue(message* msg, int timeout = -1);
bool push(message* msg, int timeout = -1);
message* dequeue(bool safe = true, int timeout = -1);
void purgequeue();
public:
jobqueue(int ilimit = DEF_QUEUE_LIMIT);
virtual ~jobqueue();
int get_count() const { return qcount; }
int get_limit() const { return limit; }
bool post(message* msg, int timeout = -1);
bool post(int id, pintptr param = 0, int timeout = -1);
bool posturgent(message* msg, int timeout = -1);
bool posturgent(int id, pintptr param = 0, int timeout = -1);
message* getmessage(int timeout = -1);
#ifdef PTYPES19_COMPAT
int msgsavail() const { return get_count(); }
#endif
};
template <class T> class tjobqueue: protected jobqueue
{
public:
tjobqueue(int ilimit = DEF_QUEUE_LIMIT);
int get_count() const { return jobqueue::get_count(); }
int get_limit() const { return jobqueue::get_limit(); }
bool post(T* msg, int timeout = -1) { return jobqueue::post(msg, timeout); }
bool posturgent(T* msg, int timeout = -1) { return jobqueue::posturgent(msg, timeout); }
T* getmessage(int timeout = -1) { return (T*)jobqueue::getmessage(timeout); }
};
class ptpublic msgqueue: protected jobqueue
{
private:
mutex thrlock; // lock for the queue processing
pthread_id_t owner; // thread ID of the queue processing thread
pintptr finishmsg(message* msg);
void handlemsg(message* msg);
void takeownership();
protected:
bool quit;
void defhandler(message& msg);
virtual void msghandler(message& msg) = 0;
public:
msgqueue(int ilimit = DEF_QUEUE_LIMIT);
virtual ~msgqueue();
// functions calling from the owner thread:
void processone(); // process one message, may hang if no msgs in the queue
void processmsgs(); // process all available messages and return
void run(); // process messages until MSG_QUIT
// functions calling from any thread:
int get_count() const { return jobqueue::get_count(); }
int get_limit() const { return jobqueue::get_limit(); }
bool post(message* msg, int timeout = -1) { return jobqueue::post(msg, timeout); }
bool post(int id, pintptr param = 0, int timeout = -1) { return jobqueue::post(id, param, timeout); }
bool posturgent(message* msg, int timeout = -1) { return jobqueue::posturgent(msg, timeout); }
bool posturgent(int id, pintptr param = 0, int timeout = -1) { return jobqueue::posturgent(id, param, timeout); }
pintptr send(message* msg);
pintptr send(int id, pintptr param = 0);
#ifdef PTYPES19_COMPAT
int msgsavail() const { return get_count(); }
#endif
};
#ifdef _MSC_VER
#pragma pack(pop)
#endif
PTYPES_END
#endif // __PASYNC_H__
include/ptypes/pinet.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PINET_H__
#define __PINET_H__
#ifndef __PPORT_H__
#include "pport.h"
#endif
#ifndef __PTYPES_H__
#include "ptypes.h"
#endif
#ifndef __PSTREAMS_H__
#include "pstreams.h"
#endif
#ifdef WIN32
# include <winsock2.h>
#else
# include <netdb.h> // for socklen_t
# include <sys/types.h>
# include <sys/socket.h>
#endif
PTYPES_BEGIN
#ifdef _MSC_VER
#pragma pack(push, 4)
#endif
//
// BSD-compatible socket error codes for Win32
//
#if defined(WSAENOTSOCK) && !defined(ENOTSOCK)
#define EWOULDBLOCK WSAEWOULDBLOCK
#define EINPROGRESS WSAEINPROGRESS
#define EALREADY WSAEALREADY
#define ENOTSOCK WSAENOTSOCK
#define EDESTADDRREQ WSAEDESTADDRREQ
#define EMSGSIZE WSAEMSGSIZE
#define EPROTOTYPE WSAEPROTOTYPE
#define ENOPROTOOPT WSAENOPROTOOPT
#define EPROTONOSUPPORT WSAEPROTONOSUPPORT
#define ESOCKTNOSUPPORT WSAESOCKTNOSUPPORT
#define EOPNOTSUPP WSAEOPNOTSUPP
#define EPFNOSUPPORT WSAEPFNOSUPPORT
#define EAFNOSUPPORT WSAEAFNOSUPPORT
#define EADDRINUSE WSAEADDRINUSE
#define EADDRNOTAVAIL WSAEADDRNOTAVAIL
#define ENETDOWN WSAENETDOWN
#define ENETUNREACH WSAENETUNREACH
#define ENETRESET WSAENETRESET
#define ECONNABORTED WSAECONNABORTED
#define ECONNRESET WSAECONNRESET
#define ENOBUFS WSAENOBUFS
#define EISCONN WSAEISCONN
#define ENOTCONN WSAENOTCONN
#define ESHUTDOWN WSAESHUTDOWN
#define ETOOMANYREFS WSAETOOMANYREFS
#define ETIMEDOUT WSAETIMEDOUT
#define ECONNREFUSED WSAECONNREFUSED
#define ELOOP WSAELOOP
// #define ENAMETOOLONG WSAENAMETOOLONG
#define EHOSTDOWN WSAEHOSTDOWN
#define EHOSTUNREACH WSAEHOSTUNREACH
// #define ENOTEMPTY WSAENOTEMPTY
#define EPROCLIM WSAEPROCLIM
#define EUSERS WSAEUSERS
#define EDQUOT WSAEDQUOT
#define ESTALE WSAESTALE
#define EREMOTE WSAEREMOTE
// NOTE: these are not errno constants in UNIX!
#define HOST_NOT_FOUND WSAHOST_NOT_FOUND
#define TRY_AGAIN WSATRY_AGAIN
#define NO_RECOVERY WSANO_RECOVERY
#define NO_DATA WSANO_DATA
#endif
// shutdown() constants
#if defined(SD_RECEIVE) && !defined(SHUT_RD)
# define SHUT_RD SD_RECEIVE
# define SHUT_WR SD_SEND
# define SHUT_RDWR SD_BOTH
#endif
// max backlog value for listen()
#ifndef SOMAXCONN
# define SOMAXCONN -1
#endif
typedef char* sockval_t;
#ifndef WIN32
# define closesocket close
#endif
#if (defined(__DARWIN__) && !defined(_SOCKLEN_T)) || defined(WIN32) || defined(__hpux)
typedef int psocklen;
#else
typedef socklen_t psocklen;
#endif
// -------------------------------------------------------------------- //
// --- IP address class and DNS utilities ---------------------------- //
// -------------------------------------------------------------------- //
//
// IP address
//
struct ptpublic ipaddress
{
public:
union
{
uchar data[4];
ulong ldata;
};
ipaddress() {}
ipaddress(ulong a) { ldata = a; }
ipaddress(const ipaddress& a) { ldata = a.ldata; }
ipaddress(int a, int b, int c, int d);
ipaddress& operator= (ulong a) { ldata = a; return *this; }
ipaddress& operator= (const ipaddress& a) { ldata = a.ldata; return *this; }
uchar& operator [] (int i) { return data[i]; }
operator ulong() const { return ldata; }
};
ptpublic extern ipaddress ipnone;
ptpublic extern ipaddress ipany;
ptpublic extern ipaddress ipbcast;
//
// IP peer info: host name, IP and the port name
// used internally in ipstream and ipmessage
//
class ptpublic ippeerinfo: public noncopyable
{
protected:
ipaddress ip; // target IP
string host; // target host name; either IP or hostname must be specified
int port; // target port number
void notfound(); // throws a (estream*) exception
ptpublic friend bool ptdecl psockname(int, ippeerinfo&);
public:
ippeerinfo();
ippeerinfo(ipaddress iip, const string& ihost, int iport);
ipaddress get_ip(); // resolves the host name if necessary (only once)
string get_host(); // performs reverse-lookup if necessary (only once)
int get_port() { return port; }
void clear();
string asstring(bool showport) const;
};
ptpublic string ptdecl iptostring(ipaddress ip);
ptpublic ipaddress ptdecl phostbyname(const char* name);
ptpublic string ptdecl phostbyaddr(ipaddress ip);
ptpublic string ptdecl phostcname(const char* name);
// internal utilities
ptpublic int ptdecl usockerrno();
ptpublic const char* ptdecl usockerrmsg(int code);
ptpublic bool ptdecl psockwait(int handle, int timeout);
ptpublic bool ptdecl psockname(int handle, ippeerinfo&);
// -------------------------------------------------------------------- //
// --- TCP socket classes -------------------------------------------- //
// -------------------------------------------------------------------- //
// additional IO status codes
const int IO_RESOLVING = 10;
const int IO_RESOLVED = 11;
const int IO_CONNECTING = 20;
const int IO_CONNECTED = 21;
//
// ipstream
//
class ptpublic ipstream: public fdxstm, public ippeerinfo
{
friend class ipstmserver;
protected:
int svsocket; // server socket descriptor, used internally by ipstmserver
#ifdef WIN32
// sockets are not compatible with file handles on Windows
virtual int dorawread(char* buf, int count);
virtual int dorawwrite(const char* buf, int count);
#endif
virtual int uerrno();
virtual const char* uerrmsg(int code);
virtual void doopen();
virtual large doseek(large newpos, ioseekmode mode);
virtual void doclose();
virtual void sockopt(int socket);
void closehandle();
public:
ipstream();
ipstream(ipaddress ip, int port);
ipstream(const char* host, int port);
ipstream(const string& host, int port);
virtual ~ipstream();
virtual int classid();
virtual string get_streamname();
bool waitfor(int timeout);
ipaddress get_myip();
int get_myport();
void set_ip(ipaddress);
void set_host(const string&);
void set_host(const char*);
void set_port(int);
};
//
// common internal interfaces for ipstmserver and ipmsgserver
//
class ipbindinfo: public unknown, public ippeerinfo
{
public:
int handle;
ipbindinfo(ipaddress iip, const string& ihost, int iport);
virtual ~ipbindinfo();
};
class ptpublic ipsvbase: public unknown
{
protected:
int socktype;
bool active;
tobjlist<ipbindinfo> addrlist; // list of local socket addresses to bind to
void error(ippeerinfo& peer, int code, const char* defmsg);
bool dopoll(int* i, int timeout);
void setupfds(void* set, int i);
virtual void open();
virtual void close();
virtual void dobind(ipbindinfo*) = 0;
virtual void sockopt(int socket);
public:
ipsvbase(int isocktype);
virtual ~ipsvbase();
int bind(ipaddress ip, int port);
int bindall(int port);
int get_addrcount() { return addrlist.get_count(); }
const ipbindinfo& get_addr(int i) { return *addrlist[i]; }
void clear();
};
//
// ipstmserver
//
class ptpublic ipstmserver: public ipsvbase
{
protected:
virtual void dobind(ipbindinfo*);
public:
ipstmserver();
virtual ~ipstmserver();
bool poll(int i = -1, int timeout = 0);
bool serve(ipstream& client, int i = -1, int timeout = -1);
};
// -------------------------------------------------------------------- //
// --- UDP socket classes -------------------------------------------- //
// -------------------------------------------------------------------- //
//
// ipmessage
//
class ptpublic ipmessage: public unknown, public ippeerinfo
{
protected:
int handle;
void error(int code, const char* msg);
void open();
void close();
virtual void sockopt(int socket);
public:
ipmessage();
ipmessage(ipaddress ip, int port);
ipmessage(const char* host, int port);
ipmessage(const string& host, int port);
virtual ~ipmessage();
void set_ip(ipaddress iip);
void set_host(const string&);
void set_host(const char*);
void set_port(int);
ipaddress get_myip();
int get_myport();
int get_handle() { return handle; }
bool waitfor(int timeout);
int receive(char* buf, int count, ipaddress& src);
int receive(char* buf, int count);
string receive(int max, ipaddress& src);
string receive(int max);
void send(const char* buf, int count);
void send(const string& s) { send(s, length(s)); }
};
//
// ipmsgserver
//
class ptpublic ipmsgserver: public ipsvbase, public ippeerinfo
{
protected:
int handle;
virtual void close();
virtual void dobind(ipbindinfo*);
public:
ipmsgserver();
virtual ~ipmsgserver();
int get_handle() { return handle; }
bool poll(int i = -1, int timeout = 0);
int receive(char* buf, int count);
string receive(int max);
void send(const char* buf, int count);
void send(const string& s) { send(s, length(s)); }
void sendto(const char* buf, int count, ipaddress ip, int port);
void sendto(const string& s, ipaddress ip, int port)
{ sendto(s, length(s), ip, port); }
};
#ifdef _MSC_VER
#pragma pack(pop)
#endif
PTYPES_END
#endif // __PINET_H__
include/ptypes/pport.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PPORT_H__
#define __PPORT_H__
#if defined(linux)
# include <stdint.h> // for uintptr_t
#endif
#include <sys/types.h>
#ifndef __cplusplus
# error "This is a C++ source"
#endif
#define PTYPES_NAMESPACE pt
//
// conditional namespace declarations
//
#ifdef PTYPES_NAMESPACE
# define PTYPES_BEGIN namespace PTYPES_NAMESPACE {
# define PTYPES_END }
# define USING_PTYPES using namespace PTYPES_NAMESPACE;
#else
# define PTYPES_NAMESPACE
# define PTYPES_BEGIN
# define PTYPES_END
# define USING_PTYPES
#endif
//
// Windows DLL export/import and calling convention macros
//
#ifdef WIN32
# if defined(PTYPES_DLL_EXPORTS)
# define ptpublic __declspec(dllexport)
# elif defined(PTYPES_DLL)
# define ptpublic__declspec(dllimport)
# else
# define ptpublic
# endif
# define ptdecl__stdcall
# define __PFASTCALL __fastcall
#else
# define ptpublic
# define ptdecl
# define __PFASTCALL
#endif
//
// versioning
//
extern "C" ptpublic unsigned long __ptypes_version;
// this enables old algebraic list interfaces; NO_PTYPES19_COMPAT
// can be defined at command line
#if !defined(NO_PTYPES19_COMPAT)
# define PTYPES19_COMPAT
#endif
PTYPES_BEGIN
#ifdef _MSC_VER
// we don't want "unreferenced inline function" warning
# pragma warning (disable: 4514)
// ... also "copy constructor/assignment operator could not be generated"
# pragma warning (disable: 4511)
# pragma warning (disable: 4512)
// disable deprecation warnings for snprintf and others
# pragma warning (disable: 4996)
#endif
#if defined(_DEBUG) && !defined(DEBUG)
# define DEBUG
#endif
#if defined(__WIN32__) && !defined(WIN32)
# define WIN32
#endif
// __APPLE__ is the only predefined macro on MacOS X
#if defined(__APPLE__)
# define __DARWIN__
#endif
// CHECK_BOUNDS enables bounds checking for strings and lists
#if defined(DEBUG) && !defined(CHECK_BOUNDS)
# define CHECK_BOUNDS
#endif
// COUNT_OBJALLOC helps to keep track of the number of
// objects created/destroyed
#if defined(DEBUG) && !defined(COUNT_OBJALLOC)
# define COUNT_OBJALLOC
#endif
//
// useful typedefs
//
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned short ushort;
typedef unsigned char uchar;
typedef signed char schar;
typedef char* pchar;
typedef const char* pconst;
typedef void* ptr;
typedef int* pint;
#ifdef WIN32
typedef uint pintptr;
#else
typedef uintptr_t pintptr;
#endif
//
// portable 64-bit integers
//
#if defined(_MSC_VER) || defined(__BORLANDC__)
typedef __int64 large;
typedef unsigned __int64 ularge;
# define LLCONST(a) (a##i64)
#else
typedef long long large;
typedef unsigned long long ularge;
# define LLCONST(a) (a##ll)
#endif
#define LARGE_MIN (LLCONST(-9223372036854775807)-1)
#define LARGE_MAX (LLCONST(9223372036854775807))
#define ULARGE_MAX (LLCONST(18446744073709551615u))
#if defined(_MSC_VER) || defined(__BORLANDC__)
# define strcasecmp stricmp
# define snprintf _snprintf
#endif
//
// misc.
//
// I like Pascal's nil
#define nil 0
inline int imax(int x, int y) { return (x > y) ? x : y; }
inline int imin(int x, int y) { return (x < y) ? x : y; }
inline large lmax(large x, large y) { return (x > y) ? x : y; }
inline large lmin(large x, large y) { return (x < y) ? x : y; }
//
// critical error processing
//
#define CRIT_FIRST 0xC0000
typedef void (ptdecl *_pcrithandler)(int code, const char* msg);
ptpublic _pcrithandler ptdecl getcrithandler();
ptpublic _pcrithandler ptdecl setcrithandler(_pcrithandler newh);
ptpublic void ptdecl fatal(int code, const char* msg);
//
// memory management (undocumented)
// hides some BSD* incompatibility issues
//
ptpublic void* ptdecl memalloc(uint a);
ptpublic void* ptdecl memrealloc(void* p, uint a);
ptpublic void ptdecl memfree(void* p);
ptpublic void ptdecl memerror();
ptpublic int ptdecl memquantize(int);
PTYPES_END
#endif // __PPORT_H__
include/ptypes/pstreams.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PSTREAMS_H__
#define __PSTREAMS_H__
#ifndef __PPORT_H__
#include "pport.h"
#endif
#ifndef __PTYPES_H__
#include "ptypes.h"
#endif
#ifndef PTYPES_ST
# ifndef __PASYNC_H__
# include "pasync.h" // for logfile.lock
# endif
#endif
#include <stdarg.h>
#include <errno.h>
#ifdef WIN32
# define _WINSOCKAPI_ // prevent inclusion of winsock.h, because we need winsock2.h
# include "windows.h" // for OVERLAPPED
#endif
PTYPES_BEGIN
#ifdef _MSC_VER
#pragma pack(push, 4)
#endif
// -------------------------------------------------------------------- //
// --- abstract stream i/o classes ----------------------------------- //
// -------------------------------------------------------------------- //
//
// stream exception class
//
class iobase;
class ptpublic estream: public exception
{
protected:
int code;
iobase* errstm;
public:
estream(iobase* ierrstm, int icode, const char* imsg);
estream(iobase* ierrstm, int icode, const string& imsg);
virtual ~estream();
int get_code() { return code; }
iobase* get_errstm() { return errstm; }
};
typedef void (ptdecl *iostatusevent)(iobase* sender, int code);
ptpublic int ptdecl unixerrno();
ptpublic const char* ptdecl unixerrmsg(int code);
// status codes: compatible with WinInet API
// additional status codes are defined in pinet.h for ipsocket
const int IO_CREATED = 1;
const int IO_OPENING = 5;
const int IO_OPENED = 35;
const int IO_READING = 37;
const int IO_WRITING = 38;
const int IO_EOF = 45;
const int IO_CLOSING = 250;
const int IO_CLOSED = 253;
//
// iobase
//
enum ioseekmode
{
IO_BEGIN,
IO_CURRENT,
IO_END
};
const int invhandle = -1;
class ptpublic iobase: public component
{
friend class fdxoutstm;
protected:
bool active; // active status, changed by open() and close()
bool cancelled; // the stream was cancelled by cancel()
bool eof; // end of file reached, only for input streams
int handle; // used in many derivative classes
large abspos; // physical stream position
int bufsize; // buffer size, can be changed only when not active
char* bufdata; // internal: allocated buffer data
int bufpos; // internal: current position
int bufend; // internal: current data size in the buffer
int stmerrno; // UNIX-compatible error numbers, see comments in piobase.cxx
string deferrormsg; // internal: default error message when an exception is thrown,
int status; // stream status code, see IO_xxx constants above
iostatusevent onstatus; // user-defined status change handler
virtual void bufalloc();
virtual void buffree();
void bufclear() { bufpos = 0; bufend = 0; }
void errstminactive();
void errbufrequired();
void requireactive() { if (!active) errstminactive(); }
void requirebuf() { requireactive(); if (bufdata == 0) errbufrequired(); }
int convertoffset(large);
virtual void doopen() = 0;
virtual void doclose();
virtual large doseek(large newpos, ioseekmode mode);
virtual void chstat(int newstat);
virtual int uerrno();
virtual const char* uerrmsg(int code);
public:
iobase(int ibufsize = -1);
virtual ~iobase();
void open();
void close();
void cancel();
void reopen() { open(); }
large seekx(large newpos, ioseekmode mode = IO_BEGIN);
int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
void error(int code, const char* defmsg);
virtual void flush();
virtual string get_errormsg();
virtual string get_errstmname();
virtual string get_streamname() = 0;
bool get_active() { return active; }
void set_active(bool newval);
bool get_cancelled() { return cancelled; }
void set_cancelled(bool newval) { cancelled = newval; }
int get_handle() { return handle; }
int get_bufsize() { return bufsize; }
void set_bufsize(int newval);
int get_stmerrno() { return stmerrno; }
int get_status() { return status; }
iostatusevent get_onstatus() { return onstatus; }
void set_onstatus(iostatusevent newval) { onstatus = newval; }
};
typedef iobase* piobase;
ptpublic extern int defbufsize;
ptpublic extern int stmbalance;
//
// instm - abstract input stream
//
const char eofchar = 0;
class ptpublic instm: public iobase
{
protected:
virtual int dorawread(char* buf, int count);
int rawread(char* buf, int count);
virtual void bufvalidate();
void skipeol();
public:
instm(int ibufsize = -1);
virtual ~instm();
virtual int classid();
bool get_eof();
void set_eof(bool ieof) { eof = ieof; }
bool get_eol();
int get_dataavail();
char preview();
char get();
void putback();
string token(const cset& chars);
string token(const cset& chars, int limit);
int token(const cset& chars, char* buf, int size);
string line();
string line(int limit);
int line(char* buf, int size, bool eateol = true);
int read(void* buf, int count);
int skip(int count);
int skiptoken(const cset& chars);
void skipline(bool eateol = true);
large tellx();
int tell() { return convertoffset(tellx()); }
large seekx(large newpos, ioseekmode mode = IO_BEGIN);
int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
};
typedef instm* pinstm;
//
// outstm - abstract output stream
//
class ptpublic outstm: public iobase
{
protected:
bool flusheol;
virtual int dorawwrite(const char* buf, int count);
int rawwrite(const char* buf, int count);
virtual void bufvalidate();
void bufadvance(int delta)
{ bufpos += delta; if (bufend < bufpos) bufend = bufpos; }
bool canwrite();
public:
outstm(bool iflusheol = false, int ibufsize = -1);
virtual ~outstm();
virtual int classid();
bool get_flusheol() { return flusheol; }
void set_flusheol(bool newval) { flusheol = newval; }
virtual void flush();
bool get_eof() { return eof; }
void put(char c);
void put(const char* str);
void put(const string& str);
void vputf(const char* fmt, va_list);
void putf(const char* fmt, ...);
void putline(const char* str);
void putline(const string& str);
void puteol();
int write(const void* buf, int count);
large tellx() { return abspos + bufpos; }
int tell() { return convertoffset(tellx()); }
large seekx(large newpos, ioseekmode mode = IO_BEGIN);
int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
};
typedef outstm* poutstm;
// %t and %T formats
ptpublic extern char* shorttimefmt; // "%d-%b-%Y %X"
ptpublic extern char* longtimefmt; // "%a %b %d %X %Y"
//
// internal class used in fdxstm
//
class ptpublic fdxstm;
class ptpublic fdxoutstm: public outstm
{
friend class fdxstm;
protected:
fdxstm* in;
virtual void chstat(int newstat);
virtual int uerrno();
virtual const char* uerrmsg(int code);
virtual void doopen();
virtual void doclose();
virtual int dorawwrite(const char* buf, int count);
public:
fdxoutstm(int ibufsize, fdxstm* iin);
virtual ~fdxoutstm();
virtual string get_streamname();
};
typedef fdxstm* pfdxstm;
//
// fdxstm: abstract full-duplex stream (for sockets and pipes)
//
class ptpublic fdxstm: public instm
{
friend class fdxoutstm;
protected:
fdxoutstm out;
virtual int dorawwrite(const char* buf, int count);
public:
fdxstm(int ibufsize = -1);
virtual ~fdxstm();
virtual int classid();
void set_bufsize(int newval); // sets both input and output buffer sizes
void open(); // rewritten to pass the call to the output stream too
void close();
void cancel();
virtual void flush();
large tellx(bool); // true for input and false for output
int tell(bool forin) { return convertoffset(tellx(forin)); }
// output interface: pretend this class is derived both
// from instm and outstm. actually we can't use multiple
// inheritance here, since this is a full-duplex stream,
// hence everything must be duplicated for input and output
void putf(const char* fmt, ...);
void put(char c) { out.put(c); }
void put(const char* str) { out.put(str); }
void put(const string& str) { out.put(str); }
void putline(const char* str) { out.putline(str); }
void putline(const string& str) { out.putline(str); }
void puteol() { out.puteol(); }
int write(const void* buf, int count) { return out.write(buf, count); }
bool get_flusheol() { return out.get_flusheol(); }
void set_flusheol(bool newval) { out.set_flusheol(newval); }
operator outstm&() { return out; }
};
//
// abstract input filter class
//
class ptpublic infilter: public instm
{
protected:
instm* stm;
char* savebuf;
int savecount;
string postponed;
void copytobuf(string& s);
void copytobuf(pconst& buf, int& count);
bool copytobuf(char c);
virtual void freenotify(component* sender);
virtual void doopen();
virtual void doclose();
virtual int dorawread(char* buf, int count);
virtual void dofilter() = 0;
bool bufavail() { return savecount > 0; }
void post(const char* buf, int count);
void post(const char* s);
void post(char c);
virtual void post(string s);
public:
infilter(instm* istm, int ibufsize = -1);
virtual ~infilter();
virtual string get_errstmname();
instm* get_stm() { return stm; }
void set_stm(instm* stm);
};
//
// abstract output filter class
//
class ptpublic outfilter: public outstm
{
protected:
outstm* stm;
virtual void freenotify(component* sender);
virtual void doopen();
virtual void doclose();
public:
outfilter(outstm* istm, int ibufsize = -1);
virtual ~outfilter();
virtual string get_errstmname();
outstm* get_stm() { return stm; }
void set_stm(outstm* stm);
};
//
// inmemory - memory stream
//
class ptpublic inmemory: public instm
{
protected:
string mem;
virtual void bufalloc();
virtual void buffree();
virtual void bufvalidate();
virtual void doopen();
virtual void doclose();
virtual large doseek(large newpos, ioseekmode mode);
virtual int dorawread(char* buf, int count);
public:
inmemory(const string& imem);
virtual ~inmemory();
virtual int classid();
virtual string get_streamname();
large seekx(large newpos, ioseekmode mode = IO_BEGIN);
int seek(int newpos, ioseekmode mode = IO_BEGIN) { return convertoffset(seekx(newpos, mode)); }
string get_strdata() { return mem; }
void set_strdata(const string& data);
};
//
// outmemory - memory stream
//
class ptpublic outmemory: public outstm
{
protected:
string mem;
int limit;
virtual void doopen();
virtual void doclose();
virtual large doseek(large newpos, ioseekmode mode);
virtual int dorawwrite(const char* buf, int count);
public:
outmemory(int limit = -1);
virtual ~outmemory();
virtual int classid();
virtual string get_streamname();
large tellx() { return abspos; }
int tell() { return (int)abspos; }
string get_strdata();
};
// -------------------------------------------------------------------- //
// --- file input/output --------------------------------------------- //
// -------------------------------------------------------------------- //
//
// infile - file input
//
class outfile;
class ptpublic infile: public instm
{
protected:
string filename;
int syshandle; // if not -1, assigned to handle in open() instead of opening a file by a name
int peerhandle; // pipe peer handle, needed for closing the peer after fork() on unix
virtual void doopen();
virtual void doclose();
public:
infile();
infile(const char* ifn);
infile(const string& ifn);
virtual ~infile();
virtual int classid();
void pipe(outfile&);
virtual string get_streamname();
int get_syshandle() { return syshandle; }
void set_syshandle(int ihandle) { close(); syshandle = ihandle; }
int get_peerhandle() { return peerhandle; }
string get_filename() { return filename; }
void set_filename(const string& ifn) { close(); filename = ifn; }
void set_filename(const char* ifn) { close(); filename = ifn; }
};
//
// outfile - file output
//
class ptpublic outfile: public outstm
{
protected:
friend class infile; // infile::pipe() needs access to peerhandle
string filename;
int syshandle; // if not -1, assigned to handle in open() instead of opening a file by a name
int peerhandle; // pipe peer handle, needed for closing the peer after fork() on unix
int umode; // unix file mode (unix only), default = 644
bool append; // append (create new if needed), default = false
virtual void doopen();
virtual void doclose();
public:
outfile();
outfile(const char* ifn, bool iappend = false);
outfile(const string& ifn, bool iappend = false);
virtual ~outfile();
virtual int classid();
virtual void flush();
virtual string get_streamname();
int get_syshandle() { return syshandle; }
void set_syshandle(int ihandle) { close(); syshandle = ihandle; }
int get_peerhandle() { return peerhandle; }
string get_filename() { return filename; }
void set_filename(const string& ifn) { close(); filename = ifn; }
void set_filename(const char* ifn) { close(); filename = ifn; }
bool get_append() { return append; }
void set_append(bool iappend) { close(); append = iappend; }
int get_umode() { return umode; }
void set_umode(int iumode) { close(); umode = iumode; }
};
//
// logfile - file output with thread-safe putf()
//
class ptpublic logfile: public outfile
{
protected:
#ifndef PTYPES_ST
mutex lock;
#endif
public:
logfile();
logfile(const char* ifn, bool iappend = true);
logfile(const string& ifn, bool iappend = true);
virtual ~logfile();
virtual int classid();
void vputf(const char* fmt, va_list);
void putf(const char* fmt, ...);
};
//
// intee - UNIX tee-style utility class
//
class ptpublic intee: public infilter {
protected:
outfile file;
virtual void doopen();
virtual void doclose();
virtual void dofilter();
public:
intee(instm* istm, const char* ifn, bool iappend = false);
intee(instm* istm, const string& ifn, bool iappend = false);
virtual ~intee();
outfile* get_file() { return &file; }
virtual string get_streamname();
};
// -------------------------------------------------------------------- //
// --- named pipes --------------------------------------------------- //
// -------------------------------------------------------------------- //
// on Unix this directory can be overridden by providing the
// full path, e.g. '/var/run/mypipe'. the path is ignored on
// Windows and is always replaced with '\\<server>\pipe\'
#ifndef WIN32
# define DEF_NAMED_PIPES_DIR "/tmp/"
#endif
#ifdef WIN32
const int DEF_PIPE_TIMEOUT = 20000; // in milliseconds, for reading and writing
const int DEF_PIPE_OPEN_TIMEOUT = 1000; // for connecting to the remote pipe:
const int DEF_PIPE_OPEN_RETRY = 5; // will double the timeout value for each retry,
// i.e. 1 second, then 2, then 4 etc.
const int DEF_PIPE_SYSTEM_BUF_SIZE = 4096;
#endif
class ptpublic namedpipe: public fdxstm
{
friend class npserver;
protected:
string pipename;
int svhandle;
#ifdef WIN32
// we use overlapped IO in order to have timed waiting in serve()
// and also to implement timeout error on the client side
OVERLAPPED ovr;
virtual int dorawread(char* buf, int count);
virtual int dorawwrite(const char* buf, int count);
static string ptdecl realpipename(const string& pipename, const string& svrname = nullstring);
void initovr();
#else
static string realpipename(const string& pipename);
static bool setupsockaddr(const string& pipename, void* sa);
void initovr() {}
#endif
virtual void doopen();
virtual void doclose();
virtual large doseek(large, ioseekmode);
public:
namedpipe();
namedpipe(const string& ipipename);
#ifdef WIN32
namedpipe(const string& ipipename, const string& servername);
#endif
virtual ~namedpipe();
virtual int classid();
virtual void flush();
virtual string get_streamname();
string get_pipename() { return pipename; }
void set_pipename(const string&);
void set_pipename(const char*);
};
class ptpublic npserver: public unknown
{
string pipename;
int handle;
bool active;
void error(int code, const char* defmsg);
void open();
void close();
#ifdef WIN32
void openinst();
void closeinst();
#endif
public:
npserver(const string& ipipename);
~npserver();
bool serve(namedpipe& client, int timeout = -1);
};
// -------------------------------------------------------------------- //
// --- utility streams ----------------------------------------------- //
// -------------------------------------------------------------------- //
//
// MD5 -- message digest algorithm
// Derived from L. Peter Deutsch's work, please see src/pmd5.cxx
//
const int md5_digsize = 16;
typedef uchar md5_digest[md5_digsize];
// from md5.h
typedef unsigned char md5_byte_t; /* 8-bit byte */
typedef unsigned int md5_word_t; /* 32-bit word */
typedef struct md5_state_s
{
md5_word_t count[2];/* message length in bits, lsw first */
md5_word_t abcd[4];/* digest buffer */
md5_byte_t buf[64];/* accumulate block */
} md5_state_t;
class ptpublic outmd5: public outfilter
{
protected:
md5_state_s ctx;
md5_digest digest;
virtual void doopen();
virtual void doclose();
virtual int dorawwrite(const char* buf, int count);
public:
outmd5(outstm* istm = nil);
virtual ~outmd5();
virtual string get_streamname();
const unsigned char* get_bindigest() { close(); return digest; }
string get_digest();
};
//
// null output stream
//
class ptpublic outnull: public outstm
{
protected:
virtual int dorawwrite(const char*, int);
virtual void doopen();
virtual void doclose();
public:
outnull();
virtual ~outnull();
virtual string get_streamname();
};
// -------------------------------------------------------------------- //
// --- unit ---------------------------------------------------------- //
// -------------------------------------------------------------------- //
#ifdef _MSC_VER
// disable "type name first seen using 'struct' now seen using 'class'" warning
# pragma warning (disable: 4099)
// disable "class '...' needs to have dll-interface to be used by clients of class
// '...'" warning, since the compiler may sometimes give this warning incorrectly.
# pragma warning (disable: 4251)
#endif
class unit_thread;
class ptpublic unit: public component
{
protected:
friend class unit_thread;
unit* pipe_next; // next unit in the pipe chain, assigned by connect()
unit_thread* main_thread; // async execution thread, started by run() if necessary
int running; // running status, to protect from recursive calls to run() and waitfor()
void do_main();
public:
compref<instm> uin;
compref<outstm> uout;
unit();
virtual ~unit();
virtual int classid();
// things that may be overridden in descendant classes
virtual void main(); // main code, called from run()
virtual void cleanup(); // main code cleanup, called from run()
// service methods
void connect(unit* next);
void run(bool async = false);
void waitfor();
};
typedef unit* punit;
typedef unit CUnit; // send me a $10 check if you use this alias (not obligatory though,
// because the library is free, after all)
//
// standard input, output and error devices
//
ptpublic extern infile pin;
ptpublic extern logfile pout;
ptpublic extern logfile perr;
ptpublic extern outnull pnull;
#ifdef _MSC_VER
#pragma pack(pop)
#endif
PTYPES_END
#endif // __PSTREAMS_H__
include/ptypes/ptime.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PTIME_H__
#define __PTIME_H__
#ifndef __PPORT_H__
#include "pport.h"
#endif
#ifndef __PTYPES_H__
#include "ptypes.h"
#endif
#include <time.h>
PTYPES_BEGIN
// datetime type: 64-bit, number of milliseconds since midnight 01/01/0001
typedef large datetime;
#define invdatetime LLCONST(-1)
#define _msecsmax 86400000 // number of milliseconds in one day
#define _daysmax 3652059 // number of days between 01/01/0001 and 12/31/9999
#define _datetimemax LLCONST(315537897600000) // max. allowed number for datetime type
#define _unixepoch LLCONST(62135596800000) // difference between time_t and datetime in milliseconds
// datetime general utilities
inline int days(datetime d) { return int(d / _msecsmax); }
inline int msecs(datetime d) { return int(d % _msecsmax); }
ptpublic datetime ptdecl mkdt(int days, int msecs);
ptpublic bool ptdecl isvalid(datetime);
ptpublic datetime ptdecl now(bool utc = true);
ptpublic void ptdecl tzupdate();
ptpublic int ptdecl tzoffset();
ptpublic string ptdecl dttostring(datetime, const char* fmt);
ptpublic string ptdecl nowstring(const char* fmt, bool utc = true);
ptpublic datetime ptdecl utodatetime(time_t u);
ptpublic struct tm* ptdecl dttotm(datetime dt, struct tm& t);
// date/calendar manipulation
ptpublic bool ptdecl isleapyear(int year);
ptpublic int ptdecl daysinmonth(int year, int month);
ptpublic int ptdecl daysinyear(int year, int month);
ptpublic int ptdecl dayofweek(datetime);
ptpublic bool ptdecl isdatevalid(int year, int month, int day);
ptpublic datetime ptdecl encodedate(int year, int month, int day);
ptpublic bool ptdecl decodedate(datetime, int& year, int& month, int& day);
// time manipulation
ptpublic bool ptdecl istimevalid(int hour, int min, int sec, int msec = 0);
ptpublic datetime ptdecl encodetime(int hour, int min, int sec, int msec = 0);
ptpublic bool ptdecl decodetime(datetime, int& hour, int& min, int& sec, int& msec);
ptpublic bool ptdecl decodetime(datetime, int& hour, int& min, int& sec);
PTYPES_END
#endif // __PTIME_H__
include/ptypes/ptypes.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
/*
*
* C++ Portable Types Library (PTypes)
* Version 2.1.1 Released 27-Jun-2007
*
* Copyright (C) 2001-2007 Hovik Melikyan
*
* http://www.melikyan.com/ptypes/
*
*/
#ifndef __PTYPES_H__
#define __PTYPES_H__
#ifndef __PPORT_H__
#include "pport.h"
#endif
#include <string.h>
PTYPES_BEGIN
#ifdef _MSC_VER
#pragma pack(push, 4)
// disable "non dll-interface class '...' used as base for dll-interface class '...'" warning
#pragma warning(disable : 4275)
// disable "conditional expression constant" warning
#pragma warning(push)
#pragma warning(disable : 4127)
#endif
ptpublic int __PFASTCALL pincrement(int* target);
ptpublic int __PFASTCALL pdecrement(int* target);
ptpublic int __PFASTCALL pexchange(int* target, int value);
ptpublic void* __PFASTCALL pexchange(void** target, void* value);
template <class T> inline T* tpexchange(T** target, T* value)
{ return (T*)pexchange((void**)target, (void*)value); }
#if ((__GNUC__ == 3) && (__GNUC_MINOR__ >= 3)) || (__GNUC__ == 4) || defined(__hpux)
# define VARIANT_TYPECAST_HACK
#endif
// -------------------------------------------------------------------- //
// --- string class --------------------------------------------------- //
// -------------------------------------------------------------------- //
// dynamic string class with thread-safe ref-counted buffer
struct _strrec
{
int refcount;
int length;
};
typedef _strrec* _pstrrec;
#define STR_BASE(x) (_pstrrec(x)-1)
#define STR_REFCOUNT(x) (STR_BASE(x)->refcount)
#define STR_LENGTH(x) (STR_BASE(x)->length)
#define PTR_TO_PSTRING(p) (pstring(&(p)))
#define PTR_TO_STRING(p) (*PTR_TO_PSTRING(p))
ptpublic extern char* emptystr;
class ptpublic variant;
class ptpublic string
{
friend class variant;
protected:
char* data;
static void idxerror();
void _alloc(int);
void _realloc(int);
void _free();
void initialize() { data = emptystr; }
void initialize(const char*, int);
void initialize(const char*);
void initialize(char);
void initialize(const string& s);
void initialize(const char*, int, const char*, int);
void initialize(const variant&);
void finalize();
void assign(const char*, int);
void assign(const char*);
void assign(const string&);
void assign(char);
#ifdef CHECK_BOUNDS
void idx(int index) const { if (unsigned(index) >= unsigned(STR_LENGTH(data))) idxerror(); }
#else
void idx(int) const { }
#endif
string(const char* s1, int len1, const char* s2, int len2) { initialize(s1, len1, s2, len2); }
public:
friend int length(const string& s);
friend int refcount(const string& s);
friend void assign(string& s, const char* buf, int len);
friend void clear(string& s);
friend bool isempty(const string& s);
ptpublic friend char* ptdecl setlength(string&, int);
ptpublic friend char* ptdecl unique(string&);
ptpublic friend void ptdecl concat(string& s, const char* sc, int catlen);
ptpublic friend void ptdecl concat(string& s, const char* s1);
ptpublic friend void ptdecl concat(string& s, char s1);
ptpublic friend void ptdecl concat(string& s, const string& s1);
ptpublic friend string ptdecl copy(const string& s, int from, int cnt);
ptpublic friend string ptdecl copy(const string& s, int from);
ptpublic friend void ptdecl ins(const char* s1, int s1len, string& s, int at);
ptpublic friend void ptdecl ins(const char* s1, string& s, int at);
ptpublic friend void ptdecl ins(char s1, string& s, int at);
ptpublic friend void ptdecl ins(const string& s1, string& s, int at);
ptpublic friend void ptdecl del(string& s, int at, int cnt);
ptpublic friend void ptdecl del(string& s, int at);
ptpublic friend int ptdecl pos(const char* s1, const string& s);
ptpublic friend int ptdecl pos(char s1, const string& s);
friend int pos(const string& s1, const string& s);
ptpublic friend int ptdecl rpos(char s1, const string& s);
ptpublic friend bool ptdecl contains(const char* s1, int len, const string& s, int at);
ptpublic friend bool ptdecl contains(const char* s1, const string& s, int at);
ptpublic friend bool ptdecl contains(char s1, const string& s, int at);
ptpublic friend bool ptdecl contains(const string& s1, const string& s, int at);
ptpublic friend string ptdecl dup(const string& s);
string() { initialize(); }
string(const char* sc, int initlen) { initialize(sc, initlen); }
string(const char* sc) { initialize(sc); }
string(char c) { initialize(c); }
string(const string& s) { initialize(s); }
~string() { finalize(); }
#ifdef VARIANT_TYPECAST_HACK
string(const variant& v) { initialize(v); }
#endif
string& operator= (const char* sc) { assign(sc); return *this; }
string& operator= (char c) { assign(c); return *this; }
string& operator= (const string& s) { assign(s); return *this; }
string& operator+= (const char* sc) { concat(*this, sc); return *this; }
string& operator+= (char c) { concat(*this, c); return *this; }
string& operator+= (const string& s) { concat(*this, s); return *this; }
string operator+ (const char* sc) const;
string operator+ (char c) const;
string operator+ (const string& s) const;
ptpublic friend string ptdecl operator+ (const char* sc, const string& s);
ptpublic friend string ptdecl operator+ (char c, const string& s);
bool operator== (const char* sc) const { return strcmp(data, sc) == 0; }
bool operator== (char) const;
bool operator== (const string&) const;
bool operator!= (const char* sc) const { return !(*this == sc); }
bool operator!= (char c) const { return !(*this == c); }
bool operator!= (const string& s) const { return !(*this == s); }
friend bool operator== (const char*, const string&);
friend bool operator== (char, const string&);
friend bool operator!= (const char*, const string&);
friend bool operator!= (char, const string&);
operator const char*() const { return data; }
operator const uchar*() const { return (uchar*)data; }
char& operator[] (int i) { idx(i); return unique(*this)[i]; }
const char& operator[] (int i) const { idx(i); return data[i]; }
friend void initialize(string& s);
friend void initialize(string& s, const string& s1);
friend void initialize(string& s, const char* s1);
friend void finalize(string& s);
};
typedef string* pstring;
inline int length(const string& s) { return STR_LENGTH(s.data); }
inline int refcount(const string& s) { return STR_REFCOUNT(s.data); }
inline void assign(string& s, const char* buf, int len) { s.assign(buf, len); }
inline void clear(string& s) { s.finalize(); }
inline bool isempty(const string& s) { return length(s) == 0; }
inline int pos(const string& s1, const string& s) { return pos(s1.data, s); }
inline bool operator== (const char* sc, const string& s){ return s == sc; }
inline bool operator== (char c, const string& s) { return s == c; }
inline bool operator!= (const char* sc, const string& s){ return s != sc; }
inline bool operator!= (char c, const string& s) { return s != c; }
inline void initialize(string& s) { s.initialize(); }
inline void initialize(string& s, const string& s1) { s.initialize(s1); }
inline void initialize(string& s, const char* s1) { s.initialize(s1); }
inline void finalize(string& s) { s.finalize(); }
ptpublic extern int stralloc;
ptpublic extern string nullstring;
// -------------------------------------------------------------------- //
// --- string utilities ----------------------------------------------- //
// -------------------------------------------------------------------- //
ptpublic string ptdecl fill(int width, char pad);
ptpublic string ptdecl pad(const string& s, int width, char c, bool left = true);
ptpublic string ptdecl itostring(large value, int base, int width = 0, char pad = 0);
ptpublic string ptdecl itostring(ularge value, int base, int width = 0, char pad = 0);
ptpublic string ptdecl itostring(int value, int base, int width = 0, char pad = 0);
ptpublic string ptdecl itostring(unsigned value, int base, int width = 0, char pad = 0);
ptpublic string ptdecl itostring(large v);
ptpublic string ptdecl itostring(ularge v);
ptpublic string ptdecl itostring(int v);
ptpublic string ptdecl itostring(unsigned v);
ptpublic large ptdecl stringtoi(const char*);
ptpublic large ptdecl stringtoie(const char*);
ptpublic ularge ptdecl stringtoue(const char*, int base);
ptpublic string ptdecl lowercase(const char* s);
ptpublic string ptdecl lowercase(const string& s);
char hex4(char c);
inline char locase(char c)
{ if (c >= 'A' && c <= 'Z') return char(c + 32); return c; }
inline char upcase(char c)
{ if (c >= 'a' && c <= 'z') return char(c - 32); return c; }
inline int hstrlen(const char* p) // some Unix systems do not accept NULL
{ return p == nil ? 0 : (int)strlen(p); }
// -------------------------------------------------------------------- //
// --- character set -------------------------------------------------- //
// -------------------------------------------------------------------- //
const int _csetbits = 256;
const int _csetbytes = _csetbits / 8;
const int _csetwords = _csetbytes / sizeof(int);
const char _csetesc = '~';
class ptpublic cset
{
protected:
char data[_csetbytes];
void assign(const cset& s) { memcpy(data, s.data, _csetbytes); }
void assign(const char* setinit);
void clear() { memset(data, 0, _csetbytes); }
void fill() { memset(data, -1, _csetbytes); }
void include(char b) { data[uchar(b) / 8] |= uchar(1 << (uchar(b) % 8)); }
void include(char min, char max);
void exclude(char b) { data[uchar(b) / 8] &= uchar(~(1 << (uchar(b) % 8))); }
void unite(const cset& s);
void subtract(const cset& s);
void intersect(const cset& s);
void invert();
bool contains(char b) const { return (data[uchar(b) / 8] & (1 << (uchar(b) % 8))) != 0; }
bool eq(const cset& s) const { return memcmp(data, s.data, _csetbytes) == 0; }
bool le(const cset& s) const;
public:
cset() { clear(); }
cset(const cset& s) { assign(s); }
cset(const char* setinit) { assign(setinit); }
cset& operator= (const cset& s) { assign(s); return *this; }
cset& operator+= (const cset& s) { unite(s); return *this; }
cset& operator+= (char b) { include(b); return *this; }
cset operator+ (const cset& s) const { cset t = *this; return t += s; }
cset operator+ (char b) const { cset t = *this; return t += b; }
cset& operator-= (const cset& s) { subtract(s); return *this; }
cset& operator-= (char b) { exclude(b); return *this; }
cset operator- (const cset& s) const { cset t = *this; return t -= s; }
cset operator- (char b) const { cset t = *this; return t -= b; }
cset& operator*= (const cset& s) { intersect(s); return *this; }
cset operator* (const cset& s) const { cset t = *this; return t *= s; }
cset operator! () const { cset t = *this; t.invert(); return t; }
bool operator== (const cset& s) const { return eq(s); }
bool operator!= (const cset& s) const { return !eq(s); }
bool operator<= (const cset& s) const { return le(s); }
bool operator>= (const cset& s) const { return s.le(*this); }
friend cset operator+ (char b, const cset& s);
friend bool operator& (char b, const cset& s);
friend void assign(cset& s, const char* setinit);
friend void clear(cset& s);
friend void fill(cset& s);
friend void include(cset& s, char b);
friend void include(cset& s, char min, char max);
friend void exclude(cset& s, char b);
ptpublic friend string ptdecl asstring(const cset& s);
};
inline cset operator+ (char b, const cset& s) { return s + b; }
inline bool operator& (char b, const cset& s) { return s.contains(b); }
inline void assign(cset& s, const char* setinit) { s.assign(setinit); }
inline void clear(cset& s) { s.clear(); }
inline void fill(cset& s) { s.fill(); }
inline void include(cset& s, char b) { s.include(b); }
inline void include(cset& s, char min, char max) { s.include(min, max); }
inline void exclude(cset& s, char b) { s.exclude(b); }
// -------------------------------------------------------------------- //
// --- basic abstract classes ----------------------------------------- //
// -------------------------------------------------------------------- //
// basic class with virtual destructor; historically was used as a base
// for all list items. also helps to count the number of created and
// destroyed objects in a program (objalloc global) in DEBUG mode, to
// detect memory leaks. most classes in ptypes are derived from unknown.
ptpublic extern int objalloc;
class ptpublic unknown
{
private:
// make all classes non-copyable by default
unknown(const unknown&);
const unknown& operator= (const unknown&);
public:
#ifdef COUNT_OBJALLOC
unknown() { pincrement(&objalloc); }
virtual ~unknown() { pdecrement(&objalloc); }
#else
unknown() { }
virtual ~unknown() { }
#endif
};
typedef unknown* punknown;
// provide non-copyable base for all classes that are
// not derived from 'unknown'
class ptpublic noncopyable
{
private:
noncopyable(const noncopyable&);
const noncopyable& operator= (const noncopyable&);
public:
noncopyable() {}
~noncopyable() {}
};
// -------------------------------------------------------------------- //
// --- exception ------------------------------------------------------ //
// -------------------------------------------------------------------- //
// the basic exception class. NOTE: the library always throws dynamically
// allocated exception objects.
class ptpublic exception: public unknown
{
protected:
string message;
public:
exception(const char* imsg);
exception(const string& imsg);
virtual ~exception();
virtual string get_message() { return message; }
};
// conversion exception class for stringtoie() and stringtoue()
class ptpublic econv: public exception
{
public:
econv(const char* msg): exception(msg) {}
econv(const string& msg): exception(msg) {}
virtual ~econv();
};
// -------------------------------------------------------------------- //
// --- tpodlist ------------------------------------------------------- //
// -------------------------------------------------------------------- //
// _podlist implements dynamic array of small POD structures; it serves
// as a basis for all list types in the library. this class is undocumented.
// tpodlist template must be used instead.
class _podlist: public noncopyable
{
protected:
void* list; // pointer to the array
int count; // number of items in the list
int capacity; // allocated for the list
int itemsize; // list item size
/*#ifndef DEBUG
static
#endif*/
static void idxerror();
//void idxerror() const { fatal(CRIT_FIRST + 30, "List index out of bounds"); }
_podlist& operator =(const _podlist& t);
void grow();
void* doins(int index);
void doins(int index, const _podlist&);
void* doget(int index) const { return (char*)list + index * itemsize; }
void dodel(int index);
void dodel(int index, int count);
void dopop();
#ifdef CHECK_BOUNDS
void idx(int index) const { if (unsigned(index) >= unsigned(count)) idxerror(); }
void idxa(int index) const { if (unsigned(index) > unsigned(count)) idxerror(); }
#else
void idx(int) const { }
void idxa(int) const { }
#endif
public:
_podlist(int itemsize);
~_podlist();
int get_count() const { return count; }
void set_count(int newcount, bool zero = false);
int get_capacity() const { return capacity; }
void set_capacity(int newcap);
void clear() { set_count(0); }
void pack() { set_capacity(count); }
void* ins(int index) { idxa(index); return doins(index); }
void ins(int index, const _podlist& t) { idxa(index); doins(index, t); }
void* add();
void add(const _podlist& t);
void* operator [](int index) { idx(index); return doget(index); }
void* top() { return operator [](count - 1); }
void del(int index) { idx(index); dodel(index); }
void del(int index, int count) { idx(index); dodel(index, count); }
void pop() { idx(0); dopop(); }
};
// tpodlist is a fully-inlined template based on _podlist
template <class X, bool initzero = false> class ptpublic tpodlist: public _podlist
{
protected:
X& dozero(X& t) { if (initzero) memset(&t, 0, sizeof(X)); return t; }
X& doget(int index) const { return ((X*)list)[index]; }
X& doins(int index) { X& t = *(X*)_podlist::doins(index); return dozero(t); }
void doins(int index, const X& item) { *(X*)_podlist::doins(index) = item; }
public:
tpodlist(): _podlist(sizeof(X)) {}
tpodlist<X, initzero>& operator =(const tpodlist<X, initzero>& t)
{ _podlist::operator =(t); return *this; }
~tpodlist() { }
void set_count(int newcount) { _podlist::set_count(newcount, initzero); }
X& ins(int index) { idxa(index); return doins(index); }
void ins(int index, const X& item) { idxa(index); doins(index, item); }
void ins(int index, const tpodlist<X, initzero>& t)
{ _podlist::ins(index, t); }
X& add() { grow(); return dozero(doget(count++)); }
void add(const X& item) { grow(); doget(count++) = item; }
void add(const tpodlist<X, initzero>& t)
{ _podlist::add(t); }
X& operator [](int index) { idx(index); return doget(index); }
const X& operator [](int index) const { idx(index); return doget(index); }
X& top() { idx(0); return doget(count - 1); }
};
// -------------------------------------------------------------------- //
// --- tobjlist ------------------------------------------------------- //
// -------------------------------------------------------------------- //
// _objlist is a base for the tobjlist template, don't use it directly.
// also, _objlist is a base for _strlist and derivatives.
class ptpublic _objlist: public unknown, protected tpodlist<void*, true>
{
protected:
struct
{
unsigned ownobjects :1; // list is responsible for destroying the items; used in _objlist
unsigned ownslobjects :1; // same but for _strlist items (in _stritem structure)
unsigned sorted :1; // sorted list (_objlist+)
unsigned duplicates :1; // sorted: allows duplicate keys (_objlist+)
unsigned casesens :1; // sorted: string comparison is case sensitive (_strlist+)
unsigned _reserved :27;
} config;
_objlist(bool ownobjects); // we hide this ctor, since _objlist actually can't free objects
void* doget(int index) const { return ((void**)list)[index]; }
void doput(int index, void* obj);
void dodel(int index);
void dodel(int index, int count);
void* dopop();
void dofree(int index, int count);
virtual void dofree(void* obj); // pure method; defined in tobjlist instances
virtual int compare(const void* key, const void* obj) const; // pure method; defined in _strlist
public:
_objlist();
virtual ~_objlist();
int get_count() const { return count; }
void set_count(int newcount);
int get_capacity() const { return capacity; }
void set_capacity(int newcap) { tpodlist<void*,true>::set_capacity(newcap); }
void clear() { set_count(0); }
void pack() { tpodlist<void*,true>::pack(); }
void ins(int index, void* obj) { tpodlist<void*,true>::ins(index, obj); }
void add(void* obj) { tpodlist<void*,true>::add(obj); }
void put(int index, void* obj) { idx(index); doput(index, obj); }
void* operator [](int index) const { idx(index); return doget(index); }
void* top() const { idx(0); return doget(count - 1); }
void* pop() { idx(0); return dopop(); }
void del(int index) { idx(index); dodel(index); }
void del(int index, int count) { idx(index); dodel(index, count); }
int indexof(void* obj) const;
bool search(const void* key, int& index) const;
};
// the tobjlist template implements a list of pointers to arbitrary
// structures. optionally can automatically free objects (ownobjects)
// when removed from a list. only 2 virtual functions are being
// instantiated by this template, the rest is static code in _objlist.
template <class X> class tobjlist: public _objlist
{
protected:
X* doget(int index) const { return (X*)_objlist::doget(index); }
virtual void dofree(void* obj);
public:
tobjlist(bool ownobjects = false): _objlist(ownobjects) {}
virtual ~tobjlist();
bool get_ownobjects() const { return config.ownobjects; }
void set_ownobjects(bool newval) { config.ownobjects = newval; }
void ins(int index, X* obj) { _objlist::ins(index, obj); }
void add(X* obj) { _objlist::add(obj); }
void put(int index, X* obj) { _objlist::put(index, obj); }
X* operator [](int index) const { idx(index); return (X*)doget(index); }
X* top() const { return (X*)_objlist::top(); }
X* pop() { return (X*)_objlist::pop(); }
int indexof(X* obj) const { return _objlist::indexof(obj); }
#ifdef PTYPES19_COMPAT
friend inline void ins(tobjlist& s, int i, X* obj) { s.ins(i, obj); }
friend inline int add(tobjlist& s, X* obj) { s.add(obj); return s.get_count() - 1; }
friend inline void put(tobjlist& s, int i, X* obj) { s.put(i, obj); }
friend inline int indexof(const tobjlist& s, X* obj) { return s.indexof(obj); }
friend inline int push(tobjlist& s, X* obj) { s.add(obj); return s.get_count() - 1; }
friend inline X* pop(tobjlist& s) { return (X*)s.pop(); }
friend inline X* top(const tobjlist& s) { return (X*)s.top(); }
friend inline X* get(const tobjlist& s, int i) { return (X*)s[i]; }
#endif
};
template <class X> void tobjlist<X>::dofree(void* item)
{
delete (X*)item;
}
template <class X> tobjlist<X>::~tobjlist()
{
set_count(0);
}
// -------------------------------------------------------------------- //
// --- tstrlist ------------------------------------------------------- //
// -------------------------------------------------------------------- //
// _strlist is a base for the tstrlist template
typedef int slflags; // left for compatibility
#define SL_SORTED 1
#define SL_DUPLICATES 2
#define SL_CASESENS 4
#define SL_OWNOBJECTS 8
struct _stritem
{
string key;
void* obj;
_stritem(const string& ikey, void* iobj)
: key(ikey), obj(iobj) {}
};
class ptpublic _strlist: protected tobjlist<_stritem>
{
protected:
static void sortederror();
static void notsortederror();
static void duperror();
virtual void dofree(void* item);
virtual int compare(const void* key, const void* item) const;
virtual void dofreeobj(void* obj); // pure; tstrlist overrides it
const string& dogetkey(int index) const { return doget(index)->key; }
void* dogetobj(int index) const { return doget(index)->obj; }
void doins(int index, const string& key, void* obj);
void doput(int index, const string& key, void* obj);
void doput(int index, void* obj);
public:
_strlist(int flags = 0);
virtual ~_strlist();
int get_count() const { return count; }
void set_count(int newcount) { tobjlist<_stritem>::set_count(newcount); }
int get_capacity() const { return capacity; }
void set_capacity(int newcap) { tobjlist<_stritem>::set_capacity(newcap); }
void clear() { tobjlist<_stritem>::clear(); }
void pack() { tobjlist<_stritem>::pack(); }
bool get_sorted() const { return config.sorted; }
bool get_duplicates() const { return config.duplicates; }
bool get_casesens() const { return config.casesens; }
bool get_ownobjects() const { return config.ownslobjects; }
void set_ownobjects(bool newval) { config.ownslobjects = newval; }
void ins(int index, const string& key, void* obj) { idxa(index); doins(index, key, obj); }
void put(int index, const string& key, void* obj) { idx(index); doput(index, key, obj); }
void put(int index, void* obj) { idx(index); doput(index, obj); }
int put(const string& key, void* obj);
int add(const string& key, void* obj);
void* operator [](int index) const { idx(index); return dogetobj(index); }
void* operator [](const char* key) const;
const string& getkey(int index) const { idx(index); return dogetkey(index); }
bool search(const char* key, int& index) const { return _objlist::search(key, index); }
void del(int index) { idx(index); dodel(index); }
void del(int index, int delcount) { idx(index); dodel(index, delcount); }
void del(const char* key) { put(key, nil); }
int indexof(const char* key) const;
int indexof(void* obj) const;
};
// the tstrlist template implements a list of string/object pairs,
// optionally sorted for fast searching by string key.
template <class X> class tstrlist: public _strlist
{
protected:
virtual void dofreeobj(void* obj);
public:
tstrlist(int flags = 0): _strlist(flags) {}
virtual ~tstrlist();
void ins(int index, const string& key, X* obj) { _strlist::ins(index, key, obj); }
void put(int index, const string& key, X* obj) { _strlist::put(index, key, obj); }
void put(int index, X* obj) { _strlist::put(index, obj); }
int put(const string& key, X* obj) { return _strlist::put(key, obj); }
int add(const string& key, X* obj) { return _strlist::add(key, obj); }
X* operator [](int index) const { return (X*)_strlist::operator [](index); }
X* operator [](const char* key) const { return (X*)_strlist::operator [](key); }
int indexof(X* obj) const { return _strlist::indexof(obj); }
int indexof(const char* key) const { return _strlist::indexof(key); }
#ifdef PTYPES19_COMPAT
// pre-2.0 interface for backwards compatibility
friend inline void ins(tstrlist& s, int i, const string& str, X* obj) { s.ins(i, str, obj); }
friend inline int add(tstrlist& s, const string& str, X* obj) { return s.add(str, obj); }
friend inline void put(tstrlist& s, int i, const string& str, X* obj) { s.put(i, str, obj); }
friend inline void put(tstrlist& s, int i, X* obj) { s.put(i, obj); }
friend inline int indexof(const tstrlist& s, X* obj) { return s.indexof(obj); }
friend inline X* get(const tstrlist& s, int i) { return (X*)s[i]; }
#endif
};
template <class X> void tstrlist<X>::dofreeobj(void* obj)
{
delete (X*)obj;
}
template <class X> tstrlist<X>::~tstrlist()
{
set_count(0);
}
// -------------------------------------------------------------------- //
// --- textmap -------------------------------------------------------- //
// -------------------------------------------------------------------- //
// textmap is a list of string pairs (key/value)
struct _textitem
{
string key;
string value;
_textitem(const string& ikey, const string& ivalue)
: key(ikey), value(ivalue) {}
};
class ptpublic textmap: protected tobjlist<_textitem>
{
protected:
virtual int compare(const void* key, const void* item) const;
const string& dogetvalue(int index) const { return doget(index)->value; }
const string& dogetkey(int index) const { return doget(index)->key; }
public:
textmap(bool casesens = false);
virtual ~textmap();
int get_count() const { return tobjlist<_textitem>::get_count(); }
void pack() { tobjlist<_textitem>::pack(); }
void clear() { tobjlist<_textitem>::clear(); }
int put(const string& key, const string& value);
void del(int index) { idx(index); dodel(index); }
void del(const char* key) { put(key, nullstring); }
const string& get(int index) const { idx(index); return dogetvalue(index); }
const string& getkey(int index) const { idx(index); return dogetkey(index); }
const string& get(const char* key) const;
const string& operator [](int index) const { return get(index); }
const string& operator [](const char* key) const { return get(key); }
int indexof(const char* key) const;
};
// -------------------------------------------------------------------- //
// --- component ------------------------------------------------------ //
// -------------------------------------------------------------------- //
// the component class is an abstract class that provides reference
// counting and delete notification mechanisms. all stream classes
// in ptypes are derived from component.
// class ID's for all basic types: the first byte (least significant)
// contains the base ID, the next is for the second level of inheritance,
// etc. total of 4 levels allowed for basic types. call classid() for an
// object, mask out first N bytes of interest and compare with a CLASS_XXX
// value. f.ex. to determine whether an object is of type infile or any
// derivative: (o->classid() & 0xffff) == CLASS2_INFILE. this scheme is for
// internal use by PTypes and Objection; partly replaces the costly C++ RTTI
// system.
// first level of inheritance
const int CLASS_UNDEFINED = 0x00000000;
const int CLASS_INSTM = 0x00000001;
const int CLASS_OUTSTM = 0x00000002;
const int CLASS_UNIT = 0x00000003;
// second level of inheritance
const int CLASS2_INFILE = 0x00000100 | CLASS_INSTM;
const int CLASS2_INMEMORY = 0x00000200 | CLASS_INSTM;
const int CLASS2_FDX = 0x00000300 | CLASS_INSTM;
const int CLASS2_OUTFILE = 0x00000100 | CLASS_OUTSTM;
const int CLASS2_OUTMEMORY = 0x00000200 | CLASS_OUTSTM;
// third level of inheritance
const int CLASS3_LOGFILE = 0x00010000 | CLASS2_OUTFILE;
const int CLASS3_IPSTM = 0x00020000 | CLASS2_FDX;
const int CLASS3_NPIPE = 0x00030000 | CLASS2_FDX;
class ptpublic component: public unknown
{
protected:
int refcount; // reference counting, used by addref() and release()
tobjlist<component>* freelist; // list of components to notify about destruction, safer alternative to ref-counting
void* typeinfo; // reserved for future use
virtual void freenotify(component* sender);
public:
component();
virtual ~component();
void addnotification(component* obj);
void delnotification(component* obj);
ptpublic friend component* ptdecl addref(component*);
ptpublic friend bool ptdecl release(component*);
friend int refcount(component* c);
virtual int classid();
void set_typeinfo(void* t) { typeinfo = t; }
void* get_typeinfo() { return typeinfo; }
};
typedef component* pcomponent;
inline int refcount(component* c) { return c->refcount; }
template <class T> inline T* taddref(T* c)
{ return (T*)addref((component*)c); }
template <class T> class compref
{
protected:
T* ref;
public:
compref() { ref = 0; }
compref(const compref<T>& r) { ref = taddref<T>(r.ref); }
compref(T* c) { ref = taddref<T>(c); }
~compref() { release(ref); }
compref<T>& operator =(T* c);
compref<T>& operator =(const compref<T>& r) { return operator =(r.ref); }
T& operator *() const { return *ref; }
T* operator ->() const { return ref; }
bool operator ==(const compref<T>& r) const { return ref == r.ref; }
bool operator ==(T* c) const { return ref == c; }
bool operator !=(const compref<T>& r) const { return ref != r.ref; }
bool operator !=(T* c) const { return ref != c; }
operator T*() const { return ref; }
};
template <class T> compref<T>& compref<T>::operator =(T* c)
{
release(tpexchange<T>(&ref, taddref<T>(c)));
return *this;
}
// -------------------------------------------------------------------- //
// --- variant -------------------------------------------------------- //
// -------------------------------------------------------------------- //
enum {
VAR_NULL,
VAR_INT,
VAR_BOOL,
VAR_FLOAT,
VAR_STRING,
VAR_ARRAY,
VAR_OBJECT,
VAR_COMPOUND = VAR_STRING
};
class ptpublic _varray;
class ptpublic variant
{
friend class string;
friend class _varray;
protected:
int tag; // VAR_XXX
union {
large i; // 64-bit int value
bool b; // bool value
double f; // double value
char* s; // string object; can't declare as string because of the union
_varray* a; // pointer to a reference-counted _strlist object
component* o; // pointer to a reference-counted component object (or derivative)
} value; // we need this name to be able to copy the entire union in some situations
void initialize() { tag = VAR_NULL; }
void initialize(large v) { tag = VAR_INT; value.i = v; }
void initialize(bool v) { tag = VAR_BOOL; value.b = v; }
void initialize(double v) { tag = VAR_FLOAT; value.f = v; }
void initialize(const char* v) { tag = VAR_STRING; PTYPES_NAMESPACE::initialize(PTR_TO_STRING(value.s), v); }
void initialize(const string& v) { tag = VAR_STRING; PTYPES_NAMESPACE::initialize(PTR_TO_STRING(value.s), v); }
void initialize(_varray* a);
void initialize(component* o);
void initialize(const variant& v);
void finalize();
void assign(large);
void assign(bool);
void assign(double);
void assign(const char*);
void assign(const string&);
void assign(_varray*);
void assign(component*);
void assign(const variant&);
bool equal(const variant& v) const;
variant(_varray* a) { initialize(a); }
public:
// construction
variant() { initialize(); }
variant(int v) { initialize(large(v)); }
variant(unsigned int v) { initialize(large(v)); }
variant(large v) { initialize(v); }
variant(bool v) { initialize(v); }
variant(double v) { initialize(v); }
variant(const char* v) { initialize(v); }
variant(const string& v) { initialize(v); }
variant(component* v) { initialize(v); }
variant(const variant& v) { initialize(v); }
~variant() { finalize(); }
// assignment
variant& operator= (int v) { assign(large(v)); return *this; }
variant& operator= (unsigned int v) { assign(large(v)); return *this; }
variant& operator= (large v) { assign(v); return *this; }
variant& operator= (bool v) { assign(v); return *this; }
variant& operator= (double v) { assign(v); return *this; }
variant& operator= (const char* v) { assign(v); return *this; }
variant& operator= (const string& v) { assign(v); return *this; }
variant& operator= (component* v) { assign(v); return *this; }
variant& operator= (const variant& v) { assign(v); return *this; }
// typecast
operator int() const;
operator unsigned int() const;
operator long() const;
operator unsigned long() const;
operator large() const;
operator bool() const;
operator double() const;
operator string() const;
operator component*() const;
// comparison
bool operator== (const variant& v) const { return equal(v); }
bool operator!= (const variant& v) const { return !equal(v); }
// typification
ptpublic friend void ptdecl clear(variant&);
friend int vartype(const variant& v);
friend bool isnull(const variant& v);
friend bool isint(const variant& v);
friend bool isbool(const variant& v);
friend bool isfloat(const variant& v);
friend bool isstring(const variant& v);
friend bool isarray(const variant& v);
friend bool isobject(const variant& v);
friend bool iscompound(const variant& v);
// array manipulation
ptpublic friend void ptdecl aclear(variant&);
ptpublic friend variant ptdecl aclone(const variant&);
ptpublic friend const variant& ptdecl get(const variant&, const string& key);
ptpublic friend const variant& ptdecl get(const variant&, large key);
ptpublic friend void ptdecl put(variant&, const string& key, const variant& item);
ptpublic friend void ptdecl put(variant&, large key, const variant& item);
ptpublic friend void ptdecl del(variant&, const string& key);
ptpublic friend void ptdecl del(variant&, large key);
ptpublic friend void ptdecl add(variant & v, const variant & var);
// indexed access to arrays
ptpublic friend int ptdecl alength(const variant&);
ptpublic friend void ptdecl apack(variant&);
ptpublic friend bool ptdecl anext(const variant& a, int&, variant& item);
ptpublic friend bool ptdecl anext(const variant& a, int&, variant& item, string& key);
ptpublic friend bool ptdecl anext(const variant& array, int& index, variant& item, variant & key);
ptpublic friend int ptdecl aadd(variant&, const variant& item);
ptpublic friend void ptdecl aput(variant&, int index, const variant& item);
ptpublic friend void ptdecl ains(variant&, int index, const variant& item);
ptpublic friend void ptdecl adel(variant&, int index);
ptpublic friend const variant& ptdecl aget(const variant&, int index);
ptpublic friend string ptdecl akey(const variant&, int index);
const variant& operator[](const char* key) const { return get(*this, string(key)); }
const variant& operator[](const string& key) const { return get(*this, key); }
const variant& operator[](large key) const { return get(*this, key); }
// 'manual' initialization/finalization, undocumented. use with care!
friend void initialize(variant& v);
friend void initialize(variant& v, large i);
friend void initialize(variant& v, int i);
friend void initialize(variant& v, unsigned int i);
friend void initialize(variant& v, bool i);
friend void initialize(variant& v, double i);
friend void initialize(variant& v, const char* i);
friend void initialize(variant& v, const string& i);
friend void initialize(variant& v, component* i);
friend void initialize(variant& v, const variant& i);
friend void finalize(variant& v);
};
typedef variant* pvariant;
inline int vartype(const variant& v) { return v.tag; }
inline bool isnull(const variant& v) { return v.tag == VAR_NULL; }
inline bool isint(const variant& v) { return v.tag == VAR_INT; }
inline bool isbool(const variant& v) { return v.tag == VAR_BOOL; }
inline bool isfloat(const variant& v) { return v.tag == VAR_FLOAT; }
inline bool isstring(const variant& v) { return v.tag == VAR_STRING; }
inline bool isarray(const variant& v) { return v.tag == VAR_ARRAY; }
inline bool isobject(const variant& v) { return v.tag == VAR_OBJECT; }
inline bool iscompound(const variant& v) { return v.tag >= VAR_COMPOUND; }
inline void initialize(variant& v) { v.initialize(); }
inline void initialize(variant& v, large i) { v.initialize(i); }
inline void initialize(variant& v, int i) { v.initialize(large(i)); }
inline void initialize(variant& v, unsigned int i) { v.initialize(large(i)); }
inline void initialize(variant& v, bool i) { v.initialize(i); }
inline void initialize(variant& v, double i) { v.initialize(i); }
inline void initialize(variant& v, const char* i) { v.initialize(i); }
inline void initialize(variant& v, const string& i) { v.initialize(i); }
inline void initialize(variant& v, component* i) { v.initialize(i); }
inline void initialize(variant& v, const variant& i) { v.initialize(i); }
inline void finalize(variant& v) { if (v.tag >= VAR_COMPOUND) v.finalize(); }
ptpublic extern const variant nullvar;
// variant exception class; may be thrown when a variant
// is being typecast'ed to 32-bit int and the value is
// out of range
class ptpublic evariant: public exception
{
protected:
public:
evariant(const char* msg): exception(msg) {}
evariant(const string& msg): exception(msg) {}
virtual ~evariant();
};
/*
Added by Nathan Adams - the following is not apart of the original ptypes
*/
enum {
ARR_ASSOCIATIVE,
ARR_LIST,
ARR_NULL
};
/*
The reason for a tparray is that while a variant can be an
associative array - it stores numeric keys as hex strings
this can be very problematic if you want to loop through
all the elements and know if a given key was a number.
(For example for JSON encoding)
A tparray uses a variant for both the keys/values so
this really opens it up to a wide range of uses. Also,
it performs no conversions on the data so when you loop
through all the keys/vals they are what you stored them as.
This object's complexity is O(n) and it could in theory be better
by sectioning off the arrays such that
-------------------------------------------------------
| string | string | string | number | number | number |
-------------------------------------------------------
This would increase the complexity of adding items, and
if you don't have a very diverse number of items them you
may not benefit much from the algorithm.
*/
class ptpublic tparray : public component
{
protected:
int tag;
// using a tpodlist was causing variant data corrupt errors
// perhaps it has to do with the issue of the converting to pointers
// TODO: Write dynamic array class
//std::vector<variant> _keys;
//std::vector<variant> _vals;
variant _keys;
variant _vals;
//tpodlist<variant> _keys;
//tpodlist<variant> _vals;
public:
static const void * TYPE; //declared in ptparray.cxx - http://stackoverflow.com/questions/1639154/how-to-declare-a-static-const-char-in-your-header-file
tparray() { typeinfo = const_cast<void*>(TYPE); tag = ARR_NULL; }
//anext function acts similar for variants and loops through elements
// This is allowed for both types
ptpublic friend bool ptdecl anext(const tparray& a, int& i, variant& val);
// This is only allowed for Associative arrays as a list doesn't have keys
ptpublic friend bool ptdecl anext(const tparray& a, int& i, variant& val, variant & key);
/*
Initialy the object will be NULL - but calling one of these functions
will change the type (permanently)
*/
ptpublic friend void ptdecl add(tparray & t, const variant & val);
ptpublic friend void ptdecl add(tparray & t, const variant & key, const variant & val);
// get will perform a O(n) search for the matching variant in the keys array
ptpublic friend variant ptdecl get(tparray & t, const variant & val);
// This will return the value at the given index
ptpublic friend variant ptdecl at(tparray & t, large index);
// This will return the key at the given index
ptpublic friend variant ptdecl keyat(tparray & t, large index);
friend bool isassoc(const tparray& t);
friend bool islist(const tparray& t);
friend bool isnull(const tparray& t);
};
inline bool isassoc(const tparray& t) { return t.tag == ARR_ASSOCIATIVE; }
inline bool islist(const tparray& t) { return t.tag == ARR_LIST; }
inline bool isnull(const tparray& t) { return t.tag == ARR_NULL; }
//http://stackoverflow.com/a/7936901/195722
template<typename T> class ByRef {
public:
ByRef() {
}
ByRef(const T value) : mValue(value) {
}
operator T&() const {
return((T&)mValue);
}
private:
T mValue;
};
class json
{
protected:
string ParseString(const string & json, int & index, bool & success);
large ParseNumber(const string & json, int & index, bool & success);
#ifndef USE_VARIANT
tparray * ParseObject(const string & json, int & index, bool & success);
tparray * ParseArray(const string & json, int & index, bool & success);
#else
variant ParseObject(const string & json, int & index, bool & success);
variant ParseArray(const string & json, int & index, bool & success);
#endif
int GetLastIndexOfNumber(const string & json, int index);
variant ParseValue(const string & json, int & index, bool & success);
int LookAhead(const string & json, int index);
void EatWhiteSpace(const string & json, int & index);
int NextToken(const string & json, int & index);
bool SerializeValue(const variant & value, string & builder);
bool SerializeString(const string & aString, string & builder);
bool SerializeObject(const tparray & anObject, string & builder);
bool SerializeArray(const tparray & anArray, string & builder);
bool SerializeNumber(large number, string & builder);
public:
enum Token { TOKEN_NONE,
TOKEN_CURLY_OPEN,
TOKEN_CURLY_CLOSE,
TOKEN_SQUARED_OPEN,
TOKEN_SQUARED_CLOSE,
TOKEN_COLON,
TOKEN_COMMA,
TOKEN_STRING,
TOKEN_NUMBER,
TOKEN_TRUE,
TOKEN_FALSE,
TOKEN_NULL };
variant JsonDecode(const string & json, bool & success = ByRef<bool>(true));
string JsonEncode(const variant & v);
};
class Parameter : public component
{
public:
string longparameter;
string shortparameter;
int numberofparameters;
bool required;
string hint;
Parameter(string longpara, string shortpara, string hint, bool required = false, int numberofparameters = 0)
{
this->longparameter = longpara;
this->shortparameter = shortpara;
this->hint = hint;
this->required = required;
this->numberofparameters = numberofparameters;
}
};
class pparser
{
private:
variant choices;
//char * argv;
tobjlist<Parameter> * paras;
tobjlist<char> argv;
tobjlist<char> invalidparas;
tobjlist<char> missingparas;
bool checkreq;
public:
pparser(int argc, char * argv[], const tobjlist<Parameter> & parameters);
void printusage(const char * header, const char * pname, const char * footer);
// Checks to make sure all required parameters are set
bool check() { return this->checkreq; }
// Returns true if parameter is set
bool isparameterset(const Parameter * para);
// Gets an array of variants of all the options to the parameters
// A variant will make it easier to convert to an int or another type
variant getoptions(const Parameter * para);
};
// -------------------------------------------------------------------- //
// --- pre-2.0 compatibility declarations ----------------------------- //
// -------------------------------------------------------------------- //
#ifdef PTYPES19_COMPAT
// ptypes-1.9 objlist and strlist: accept only 'unknown' and
// derivatives as a base type
class ptpublic objlist: public tobjlist<unknown>
{
public:
objlist(bool ownobjects = false);
virtual ~objlist();
};
inline int length(const _objlist& s) { return s.get_count(); }
inline void setlength(_objlist& s, int newcount) { s.set_count(newcount); }
inline void pack(_objlist& s) { s.pack(); }
inline void clear(_objlist& s) { s.clear(); }
inline int push(_objlist& s, unknown* obj) { s.add(obj); return length(s) - 1; }
inline unknown* top(const _objlist& s) { return (unknown*)s.top(); }
inline void ins(_objlist& s, int i, unknown* obj) { s.ins(i, obj); }
inline int add(_objlist& s, unknown* obj) { s.add(obj); return length(s) - 1; }
inline void put(_objlist& s, int i, unknown* obj) { s.put(i, obj); }
inline unknown* get(const _objlist& s, int i) { return (unknown*)s[i]; }
inline unknown* pop(_objlist& s) { return (unknown*)s.pop(); }
inline void del(_objlist& s, int i) { s.del(i); }
inline int indexof(const _objlist& s, unknown* obj) { return s.indexof(obj); }
class ptpublic strlist: public tstrlist<unknown>
{
public:
strlist(int flags = 0);
virtual ~strlist();
};
inline int length(const _strlist& s) { return s.get_count(); }
inline void clear(_strlist& s) { s.clear(); }
inline void pack(_strlist& s) { s.pack(); }
inline bool search(const _strlist& s, const char* key, int& i) { return s.search(key, i); }
inline void ins(_strlist& s, int i, const string& key, unknown* obj) { s.ins(i, key, obj); }
inline int add(_strlist& s, const string& key, unknown* obj) { return s.add(key, obj); }
inline void put(_strlist& s, int i, const string& key, unknown* obj) { s.put(i, key, obj); }
inline void put(_strlist& s, int i, unknown* obj) { s.put(i, obj); }
inline unknown* get(const _strlist& s, int i) { return (unknown*)s[i]; }
inline const string& getstr(const _strlist& s, int i) { return s.getkey(i); }
inline void del(_strlist& s, int i) { s.del(i); }
inline int find(const _strlist& s, const char* key) { return s.indexof(key); }
inline int indexof(const _strlist& s, unknown* obj) { return s.indexof(obj); }
// ptypes-1.9 strmap: now replaced with _strlist(SL_SORTED)
class ptpublic strmap: public tstrlist<unknown>
{
public:
strmap(int flags = 0);
virtual ~strmap();
};
inline void put(strmap& m, const string& key, unknown* obj) { m.put(key, obj); }
inline unknown* get(const strmap& m, const char* key) { return m[key]; }
inline void del(strmap& m, const char* key) { m.del(key); }
template <class X> class tstrmap: public strmap
{
public:
tstrmap(): strmap() {}
tstrmap(int iflags): strmap(iflags) {}
friend inline X* get(const tstrmap& m, const char* str) { return (X*)PTYPES_NAMESPACE::get((const strmap&)m, str); }
friend inline void put(tstrmap& m, const string& str, X* obj) { unknown* t = obj; PTYPES_NAMESPACE::put(m, str, t); }
X* operator[] (const char* str) const { return (X*)PTYPES_NAMESPACE::get(*this, str); }
};
// ptypes-1.9 textmap interface
inline int length(const textmap& m) { return m.get_count(); }
inline void clear(textmap& m) { m.clear(); }
inline const string& get(const textmap& m, const string& k) { return m.get(k); }
inline void put(textmap& m, const string& k, const string& v) { m.put(k, v); }
inline void del(textmap& m, const string& k) { m.del(k); }
#endif // PTYPES19_COMPAT
#ifdef _MSC_VER
#pragma warning(pop)
#pragma pack(pop)
#endif
PTYPES_END
#endif // __PTYPES_H__
src/main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
#include <ptypes/ptypes.h>
#include <ptypes/pasync.h>
#include <ptypes/pinet.h>
#include <ptypes/ptime.h>
USING_PTYPES;
semaphore s(10);
#define DEF_KEEP_ALIVE_TIMEOUT 15000
void writeLog(ipaddress ip, string resp, string ask)
{
const char * fmt = "%m-%d-%Y_%H:%M:%S";
string out = "[" + dttostring(now(), fmt) + " - " + iptostring(ip) + "] - " + ask + " => " + resp;
pout.putline(out);
}
void writeClient(ipstream * client, string msg)
{
client->putline(msg);
client->flush();
writeLog(client->get_ip(), msg, "SERVER");
}
class ftp : public thread
{
protected:
virtual void execute();
virtual void cleanup() { delete stream; }
private:
ipstream * stream;
void commands();
public:
ftp(ipstream * client) : thread(true), stream(client) { }
};
void ftp::commands()
{
while(true)
{
if (!stream->get_active())
break;
if (!stream->waitfor(DEF_KEEP_ALIVE_TIMEOUT))
break;
if (stream->get_eof())
break;
string s;
s = stream->line(256);
writeLog(stream->get_ip(), s, "REQUEST");
if (lowercase(s) == "syst")
{
writeClient(stream, "215 UNIX Type: L8");
} else if ( lowercase(s) == "feat" )
{
writeClient(stream, "211-Features:");
writeClient(stream, "EPRT");
writeClient(stream, "EPSV");
writeClient(stream, "MDTM");
writeClient(stream, "PASV");
writeClient(stream, "REST STREAM");
writeClient(stream, "TVFS");
writeClient(stream, "UTF8");
writeClient(stream, "211 END");
} else if ( pos("TYPE", s) != -1 )
{
writeClient(stream, "200 Switching modes");
} else if ( lowercase(s) == "pwd")
{
writeClient(stream, "257 \"/\""); // root directory access oh yeah!
} else if ( pos("OPTS", s) != -1 )
{
writeClient(stream, "200 OK"); // hehe - accept setting any options
} else if ( lowercase(s) == "quit")
{
writeClient(stream, "215 goodbye");
break;
} else {
writeClient(stream, "200 OK"); // whatever you say client!
}
}
}
void ftp::execute()
{
try
{
string s;
if (stream->get_active())
{
writeClient(stream, "220 ProFTPD 1.3.2c Server (datanethost.net_FTP_Service)");
// client enters username
s = stream->line(256);
writeLog(stream->get_ip(), s, "BANNER");
writeClient(stream, "330 Password required to access user account");
s = stream->line(256);
writeLog(stream->get_ip(), s, "PASSWORD");
writeClient(stream, "230 Logged in.");
commands();
}
} catch (estream * e)
{
pout.putline(e->get_message());
perr.putline("ERROR!");
delete e;
} catch (...)
{
perr.putline("ERROR2!");
}
stream->close();
s.signal();
}
class ftpthread : public thread, protected ipstmserver
{
protected:
virtual void execute(); // override thread::execute()
virtual void cleanup() { } // override thread::cleanup()
private:
int port;
tobjlist<ftp> ftpworkers;
public:
ftpthread(int port) : thread(false), port(port) {}
virtual ~ftpthread() { waitfor(); }
};
void ftpthread::execute()
{
bindall(port);
while(true)
{
ipstream * client = new ipstream();
s.wait();
serve(*client);
ftp * f = new ftp(client); // thread will automatically be freed
// don't believe me?
// I don't either. check pthread.cxx
// also Dr. Memory verifies this
// I'll believe Dr. Memory over you
f->start();
}
}
int main(int argc, char * args[])
{
int port = atoi(args[1]);
ftpthread thftp(port);
thftp.start();
thftp.waitfor();
return 0;
}

Archive Download the corresponding diff file

Branches

Number of commits:
Page rendered in 0.20438s using 14 queries.