source: branches/client-2.1/src/printf.c@ 767

Last change on this file since 767 was 145, checked in by Yuri Dario, 17 years ago

Merged daemon code, now the plugin calls directly samba client library (still using smbrp code).

  • Property svn:eol-style set to native
File size: 15.0 KB
Line 
1/* ----------------------------------------------------------------- */
2/* PRINTF: diverts PRINTF calls to an OS/2 Named Queue */
3/* Copyright (c) IBM Corporation, 1991, 1992 */
4/* ----------------------------------------------------------------- */
5/* This version for OS/2 2.x, 32-bit programs. Mike Cowlishaw */
6/* */
7/* This routine, when linked into an .EXE instead of the usual C */
8/* runtime, sends the edited result string to a named queue (if */
9/* it exists). If the queue does not exist, then all printf data */
10/* are discarded (ignored). */
11/* */
12/* The result string is accumulated until a line feed (LF) character */
13/* is received; the whole line is then sent to the queue. Lines are */
14/* automatically broken at a set (tailorable) length, if necessary. */
15/* */
16/* This routine may be tailored by altering the #defines at the */
17/* top: */
18/* */
19/* PRINTFID - An ID string that is prefixed to each line of */
20/* data before being sent to the queue. This */
21/* can be any string, or the null string. */
22/* PRINTFMAXLEN - Maximum length of string that can be formatted */
23/* in a single call. */
24/* Results are unpredictable if this length is */
25/* exceeded. Default is 250. */
26/* PRINTFLINELEN - Maximum length of a line that will be sent. */
27/* This excludes the prefix and its blank. If the */
28/* calls to printf cause a line to be generated */
29/* that is longer than this, the line will be */
30/* broken at this point. */
31/* PRINTFTHREADS - Maximum number of threads expected. This may */
32/* need to be increased if the process limitation */
33/* is removed, or you can save a little storage */
34/* by decreasing it. PRINTFs from threads larger */
35/* than this number are ignored. */
36/* PRINTFQNAME - The name of the public queue that the result */
37/* is to be sent to. Normally '\QUEUES\PRINTF32'. */
38/* Note that the \QUEUES\ part is required. */
39/* */
40/* Returns: */
41/* n: Count of data characters, if successfully received */
42/* 0: If no queue existed (i.e., no server) */
43/* <0: An error occurred (e.g., out of memory) */
44/* */
45/* Restrictions: */
46/* 1. Total length of data (length of PRINTFID, + PRINTFMAXLEN) */
47/* must be less than 32K-1. */
48/* 2. This has only been tested under IBM C Set/2 compiler. It */
49/* may need modification for other compilers. */
50/* 3. This version uses a static array to point to the per-thread */
51/* data. The code could be made read-only by hanging this */
52/* array (and the other static information) off a system-owned */
53/* anchor of some kind. */
54/* 4. To use PRINTF within other than the main thread in a */
55/* program, that thread must be started with _beginthread */
56/* (not DosCreateThread). This restriction is a consequence of */
57/* the use of C library routines (sprintf) in PRINTF, and may */
58/* not apply to all compilers. */
59/* 5. If the last PRINTF done by a thread does not end in '\n' */
60/* then the final part-line may be lost, or appear later. */
61/* */
62/* Protocol: */
63/* PRINTF writes its data to the named queue using the following */
64/* protocol: */
65/* Address -- Holds the address of the string to be sent. This */
66/* is a 0-terminated string) starting at offset 0. */
67/* Length -- The length of the data, including terminator. */
68/* A negative length indicates a BELL in the data. */
69/* Request -- Timestamp (when queue was written) in C long */
70/* integer format (as returned by time()). */
71/* This may be 0L if not required. */
72/* */
73/* Notes: */
74/* 1. PMPRINTF uses a queue and shared memory messages because: */
75/* (a) It makes collection at the receiving end very easy. */
76/* (b) I wanted to experiment with queues and shared memory. */
77/* This make not be the most cost-effective method. */
78/* 2. Typical IBM C Set/2 compiler invocation: */
79/* icc /c /Gm /O+ /Q /J /Kabgop */
80/* If you get linking errors (duplicate symbols, etc.), try */
81/* recompiling PRINTF.C with the same options as you use for */
82/* your main program. */
83/* 3. PRINTF sends the timestamp across the queue as a GMT long */
84/* integer, the result from a call to the C function time(). */
85/* This will only be correct if the environment variable TZ has */
86/* been set (e.g., TZ=EST5EDT), or you are in the same time */
87/* zone as the default for your compiler. */
88/* For more information, see the tzset() function description */
89/* in your C compiler manual. */
90
91/* ----- Customization variables ----- */
92#define PRINTFID ""
93#define PRINTFMAXLEN 300
94#define PRINTFLINELEN 100
95#define PRINTFTHREADS 54
96#define PRINTFQNAME "\\QUEUES\\PRINTF32"
97
98/* ----- Includes and externals ----- */
99#include <stdlib.h> /* standard C functions */
100#include <stddef.h> /* .. */
101#include <string.h> /* .. */
102#include <time.h> /* .. */
103#include <stdarg.h> /* .. */
104#include <stdio.h> /* (needed to pick up real name) */
105#define INCL_DOS /* Operating system definitions */
106#include <os2.h> /* For OS/2 functions */
107
108#define max(a,b) (a>b ? a : b)
109
110/* ----- Local defines ----- */
111#define PRINTFIDSIZE sizeof(PRINTFID)
112#define PRINTFMAXBUF PRINTFIDSIZE+PRINTFLINELEN
113
114/* ----- Per-thread output buffer and current indices into line ---- */
115struct perthread {
116 LONG lineindex; /* where next char */
117 LONG tidemark; /* rightmost char */
118 int bell; /* TRUE if line has bell */
119 UCHAR line[PRINTFMAXBUF]; /* accumulator */
120 };
121
122/* ----- Local static variables ----- */
123static ULONG ourpid=0; /* our process ID */
124static ULONG servepid=0; /* process IDs of the server */
125static HQUEUE qhandle=0; /* handle for the queue */
126static struct perthread *tps[PRINTFTHREADS+1]; /* -> per-thread data */
127
128/* ----- Local subroutine ----- */
129static int printf_(struct perthread *);
130
131/* ----------------------------------------------------------------- */
132/* The "printf" function. Note this has a variable number of */
133/* arguments. */
134/* ----------------------------------------------------------------- */
135int debug_printf(const char *f, ...)
136 {
137 TIB *ptib; /* process/thread id structures */
138 PIB *ppib; /* .. */
139 TID ourtid; /* thread ID */
140 struct perthread *tp; /* pointer to per-thread data */
141 int rc; /* returncode */
142 ULONG urc; /* returncode */
143
144 urc=DosOpenQueue(&servepid, &qhandle, PRINTFQNAME); /* Open the Q */
145 /* Non-0 RC means Q does not exist or cannot be opened */
146 if (urc==343) return 0; /* queue does not exist, so quit */
147 if (urc!=0) return -1; /* report any other error */
148
149 /* First determine our thread ID (and hence get access to the */
150 /* correct per-thread data. If the per-thread data has not been */
151 /* allocated, then allocate it now. It is never freed, once */
152 /* allocated, as PRINTF is not notified of end-of-thread. */
153 DosGetInfoBlocks(&ptib,&ppib); /* get process/thread info */
154 ourtid=ptib->tib_ptib2->tib2_ultid; /* .. and copy TID */
155 if (ourtid>PRINTFTHREADS) /* too many threads .. */
156 return 0; /* .. so quit, quietly */
157 tp=tps[ourtid]; /* copy to local pointer */
158 if (tp==NULL) { /* uninitialized (NULL=0) */
159 /* allocate a per-thread structure */
160 tp=(struct perthread *)malloc(sizeof(struct perthread));
161 if (tp==NULL) return -1; /* out of memory -- return error */
162 tps[ourtid]=tp; /* save for future calls */
163 strcpy(tp->line,PRINTFID); /* initialize: line.. */
164 tp->lineindex=PRINTFIDSIZE-1; /* ..where next char */
165 tp->tidemark =PRINTFIDSIZE-2; /* ..rightmost char */
166 tp->bell=FALSE; /* ..if line has bell */
167 if (ourpid==0) ourpid=ppib->pib_ulpid; /* save PID for all to use */
168 }
169
170 { /* Block for declarations -- only needed if queue exists, etc. */
171 LONG count; /* count of characters formatted */
172 UCHAR buffer[PRINTFMAXLEN+1]; /* formatting area */
173 LONG i, newind; /* work */
174 UCHAR ch; /* .. */
175 va_list argptr; /* -> variable argument list */
176
177 va_start(argptr, f); /* get pointer to argument list */
178 count=vsprintf(buffer, f, argptr);
179 va_end(argptr); /* done with variable arguments */
180
181 if (count<0) return count-1000;/* bad start */
182
183 if (count>PRINTFMAXLEN) {
184 /* Disaster -- we are probably "dead", but just in case we */
185 /* are not, carry on with truncated data. */
186 count=PRINTFMAXLEN;
187 }
188 buffer[count]='\0'; /* ensure terminated */
189 /* OK, ready to go with the data now in BUFFER */
190 /* We copy from the formatted string to the output (line) buffer, */
191 /* taking note of certain control characters and sending a line */
192 /* the queue whenever we see a LF control, or when the line */
193 /* fills (causing a forced break). */
194 for (i=0; ; i++) {
195 ch=buffer[i]; if (!ch) break;
196 switch(ch) {
197 case '\r': /* carriage return */
198 tp->lineindex=PRINTFIDSIZE-1; /* back to start of line */
199 break;
200 case '\n': /* new line */
201 case '\f': /* form feed */
202 rc=printf_(tp); /* print a line */
203 if (rc!=0) return rc; /* error */
204 break;
205 case '\t': /* tab */
206 newind=tp->lineindex-PRINTFIDSIZE+1; /* offset into data */
207 newind=tp->lineindex+5-newind%5; /* new index requested */
208 if (newind>=PRINTFMAXBUF) newind=PRINTFMAXBUF; /* clamp */
209 for (; tp->lineindex<newind; tp->lineindex++) {
210 if (tp->lineindex>tp->tidemark) { /* beyond current end */
211 tp->line[tp->lineindex]=' '; /* add space */
212 tp->tidemark=tp->lineindex;
213 }
214 }
215 break;
216 case '\v': /* vertical tab */
217 /* ignore it */
218 break;
219 case '\b': /* backspace */
220 tp->lineindex=max(tp->lineindex-1,PRINTFIDSIZE);
221 break;
222 case '\a': /* alert (bell) */
223 tp->bell=TRUE;
224 break;
225 default: /* ordinary character */
226 tp->line[tp->lineindex]=ch;
227 if (tp->lineindex>tp->tidemark) /* is rightmost.. */
228 tp->tidemark=tp->lineindex;
229 tp->lineindex++; /* step for next */
230 } /* switch */
231 if (tp->lineindex>=PRINTFMAXBUF) {
232 rc=printf_(tp); /* print a line */
233 if (rc!=0) return rc; /* error */
234 }
235
236 } /* copy loop */
237 return count; /* all formatted data processed */
238 } /* block */
239 } /* printf */
240
241/* ----- printf_(tp) -- Local subroutine to send a line ------------ */
242/* A line has been completed (or overflowed): write it to the queue. */
243int printf_(struct perthread *tp) /* pointer to per-thread data */
244 {
245 ULONG urc; /* unsigned returncode */
246 PSZ pszTo, pszFrom; /* character pointers */
247 PVOID addr; /* address of output data */
248 long size; /* total size of output data */
249 time_t timenow; /* holds current time */
250
251 tp->line[tp->tidemark+1]='\0'; /* add terminator */
252 size=tp->tidemark+2; /* total length of data */
253
254 /* Get some shared memory that can be given away */
255 urc=DosAllocSharedMem(&addr, NULL, (unsigned)size,
256 OBJ_GIVEABLE|PAG_WRITE|PAG_COMMIT);
257 if (urc!=0) return -2; /* error */
258
259 pszTo=addr; /* copy for clarity */
260 pszFrom=&(tp->line[0]); /* pointer to source */
261 strcpy(pszTo,pszFrom); /* copy the string to shared memory */
262
263 if (ourpid!=servepid) { /* (no giveaway needed if to self) */
264 urc=DosGiveSharedMem(addr, servepid, PAG_READ); /* give access */
265 if (urc!=0) return -3;} /* error */
266
267 /* Write the selector, size, and timestamp to the queue */
268 if (tp->bell) size=-size; /* BELL passed by negation */
269 time(&timenow); /* optional - else use 0 */
270 urc=DosWriteQueue(qhandle, /* handle */
271 (unsigned)timenow, /* 'request' (timestamp) */
272 (unsigned)size, /* 'length' (length/bell) */
273 addr, /* 'address' (address) */
274 0); /* priority (FIFO if enabled) */
275 if (urc!=0) return -4; /* error */
276 if (ourpid!=servepid) { /* if given away.. */
277 urc=DosFreeMem(addr); /* .. *we* are done with it */
278 if (urc!=0) return -5;} /* error */
279 /* Reset the line buffer and indices */
280 tp->lineindex=PRINTFIDSIZE-1; /* where next char */
281 tp->tidemark =PRINTFIDSIZE-2; /* rightmost char */
282 tp->bell =FALSE; /* true if line has bell */
283 return 0; /* success! */
284 } /* printf_ */
Note: See TracBrowser for help on using the repository browser.