summaryrefslogtreecommitdiff
path: root/reference/C/CONTRIB/SNIP/glbl_env.c
blob: 9699aae5d96d2541079d1a0914175dfec1835b97 (plain)
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
/*****************************************************************************
   This code is based upon the program SETPATH.PAS (located in BPROGA) by
   David Dubois [71401,747]

   This Turbo C version is written by Peter Thomas [75716,2377]

   This series of routines are designed to Locate, Retrieve, Update, and
   Remove "Variables" from the MASTER copy of the DOS Environment table.
   The routines have been written in a manner that avoids linking any
   EXTERNAL routines for string manipulation, and thus should be independent
   of memory model being used.

   Be careful that changes made to the Environment with these routines
   ONLY OCCUR IN THE MASTER COPY, and that if COMMAND.COM is spawned
   from a routine that has changed the environment, NO CHANGES WILL BE
   SEEN IN THE ENVIRONMENT. This is most apparent when this program is run
   in the INTEGRATED environment: changes made by this technique will
   not appear if the "OS Shell" is invoked, and will only appear on exit
   from TC.

   For full documentation on the techniques used here can be found in the
   file COMENV.ARC located in LIB 2 of BPROGA on Compuserve.

   As David Dubois says:

  I hereby dedicate this knowledge to the public domain. Feel free to use
  it, but if you do, please mention my name. There are no guarantees, and
  in fact, I wouldn't bet a dollar that it will work every time.

  That this works at all is based on experimental, rather than properly
  documented, evidence. There are no guarantees. But then, its free.

*****************************************************************************/

#include <stdio.h>
#include <dos.h>

#ifdef __ZTC__
 #error ZTC/C++ not supported - huge pointers required!
#endif

#ifdef __TURBOC__
 #include <alloc.h>
 #define Fmalloc farmalloc
 #define Ffree farfree
#else
 #include <malloc.h>
 #include <stdlib.h>
 #define far  _far
 #define Fmalloc _fmalloc
 #define Ffree _ffree
 #define MK_FP(seg,offset) \
        ((void far *)(((unsigned long)(seg)<<16) | (unsigned)(offset)))
#endif

/*
 *   Mstr_FindEnvironment:
 *     Scans for the "Master" Environment area, and returns
 *     a pointer to it, and the size of the environment.
*/
void Mstr_FindEnvironment ( char far **Env , unsigned *EnvSize )
{
   unsigned int far *CommandSeg, far *TempSeg ;
   char far *BlockSeg ;

   /*
    *  Scan through PSP's looking for a block that is its own father.
    *  This block is the PSP of COMMAND.COM
   */
  TempSeg = MK_FP ( _psp , 0 ) ;
   do
   {
     CommandSeg = TempSeg ;
     TempSeg = MK_FP ( *(TempSeg+8) , 0 ) ;
   }
   while ( TempSeg != CommandSeg ) ;

   /*
    *  Scan forward through memory looking for the correct MSB.
    *  This will have COMMAND.COM's PSP as owner, and begin with
    *  the character M
   */
   BlockSeg = (char far *)CommandSeg ;
   do
   {
    BlockSeg = MK_FP ( FP_SEG(BlockSeg)+1 , 0 ) ;
   }
   while ( ( *(unsigned int far *)(BlockSeg+1) != FP_SEG ( CommandSeg ) ) ||
           ( *BlockSeg != 'M' ) ) ;

   /*
    *  The environment is the NEXT segment of memory
    *  and bytes 4 and 5 are the size in paragraphs
   */
   *Env = MK_FP ( FP_SEG(BlockSeg)+1 , 0 ) ;
   *EnvSize = 16 * *(unsigned int far *)(BlockSeg+3) ;
}

/*
 *   Mstr_getenv:
 *     Scans the "Master" Environment for a given "sub string"
 *     and returns a pointer to it.
 *     Similar to Turbo routine "getenv" but uses the Master copy of the
 *     environment table.
*/
char far *Mstr_getenv (char far *Env , char far *name)
{
   char far *Sub_Env, far *str1, far *str2 ;

   /*
    *  Start at the beginning of the environment
   */
   Sub_Env = Env ;

   /*
    *  While the "sub string" we're looking at is non-zero
   */
   for ( ; *Sub_Env ; )
   {
     /*
      *  Simulate a "strcmp" on the "sub string" of the environment
      *  and the string we're looking for
     */
     for ( str1 = Sub_Env , str2 = name ;
           (*str1) && (*str2) && ( *str1 == *str2) ;
           str1++ , str2++ ) ;
     /*
      *  If we reached the end of the string we're looing for
      *  we've found the correct portion of the environment.
      *  Return the ptr to the start of this "sub string"
     */
     if ( !*str2 )
       return ( Sub_Env ) ;

     /*
      *  Otherwise, advance to the next "sub string" in the environment
      *  by performing a "strchr" function
     */
     for ( ; *(Sub_Env++) ; ) ;
   }

   /*
    *  Obviously, the string is not present in the environment.
    *  Return this fact.
   */
  return ( NULL ) ;
}

/*
 *   Mstr_delenv:
 *     Scans the "Master" Environment for a given "sub string"
 *     and removes it.
*/
int Mstr_delenv (char far *Env , unsigned EnvSize , char far *name)
{
   char far *Sub_Env , far *New_Env ;
   char huge *Dest , far *Src , huge *End_Env ;

   int Done  ;
   unsigned Ctr ;

   /*
    *  Allocate a chunk of storage to act as a "working" copy of
    *  the Environment table
   */
   New_Env = Fmalloc ( EnvSize ) ;

   /*
    *  Copy the data from the Master to Working copy of the
    *  Environment table.
    *  Simulates a "memcpy" function.
   */
   for ( Src = Env , Dest = (char far *)New_Env , Ctr = 0 ;
         Ctr < EnvSize ;
         *(Dest++) = *(Src++) , Ctr++ ) ;

   /*
    *  Scan the working copy of the environment for the desired
    *  sub string
   */
   Sub_Env = Mstr_getenv ( New_Env , name ) ;

   if ( Sub_Env == NULL )
   {
     /*
      *  If not found, do nothing
     */
     Done = -1 ;
   } else {
     /*
      *  Locate the end of the string to delete
      *  Simulate a "strchr" call
     */
     for ( Src = Sub_Env ; *(Src++) ; ) ;

     /*
      *  Move the rest of the environment back over the "sub string"
      *  being deleted.
      *  Simulated "memcpy" function.
      *  Huge pointers used for pointer comparison purposes.
     */
     for ( Dest = (char huge *)Sub_Env , End_Env = (char huge *) (New_Env + EnvSize ) ;
         ( Dest < End_Env ) ;
         *(Dest++) = *(Src++) ) ;

     /*
      *  Copy the data from the Working to Master copy of the
      *  Environment table.
      *  Simulates a "memcpy" function.
     */
     for ( Src = New_Env , Dest = (char huge *)Env , Ctr = 0 ;
         Ctr < EnvSize ;
         *(Dest++) = *(Src++) , Ctr++ ) ;

     /*
      *  Signal all done
     */
     Done = 0 ;
   }

   /*
    *  Free all working storage
   */
   Ffree ( New_Env ) ;

   return ( Done ) ;
}

/*
 *   Mstr_putenv:
 *     Adds/Replaces a given "sub string" in the Master Environment.
 *     Similar to Turbo routine "putenv" but uses the Master copy of the
 *     environment table.
*/
int Mstr_putenv (char far *Env , unsigned EnvSize , char far *name )
{
   char far *Sub_Env , far *Temp_Name ;
   char huge *Dest , far *Src , huge *End_Env ;
   int Done ;

   /*
    *  Allocate a chunk of storage to create the Variable name to add
    *  to the Environment table
   */
   Temp_Name = Fmalloc ( 256 ) ;

   /*
    *  Extract only the Name portion of the data to add to the Environment
   */
   for ( Src = name , Dest = Temp_Name ;
         *Src && ( *Src != '=' ) ;
        *(Dest++) = *(Src++) ) ;

   /*
    *  Ensure that the resulting name is well formed.
   */
   *(Dest++) = '=' ;
   *Dest = 0 ;

   /*
    *  Delete this sub string if found in the environment
   */
   Mstr_delenv ( Env , EnvSize , Temp_Name ) ;

   /*
    *  Locate the END of the Master table by locating a zero length
    *  String in it
   */
   Sub_Env = Env ;
   for ( ; *Sub_Env ; )
   {
     for ( ; *(Sub_Env++) ; ) ;
   }

   /*
    *  Add the new string to the END of the existing environment, with
    *  trincation IF needed
   */
   for ( Dest = (char huge *)(Sub_Env) , Src = name , End_Env = (char huge *) (Env + EnvSize ) ;
         ( Dest < End_Env ) && (*Src) ;
         *(Dest++) = *(Src++) ) ;

   Done = -1 ;
   if ( !*Src )
   {
     /*
      *  If the string to add was FULLY added, ensure that the
      *  newly updated environment is properly finished
     */
     Done = 0 ;
     *(Dest++) = 0 ;
     *Dest = 0 ;
   }

   /*
    *  As a real safety measure, ensure that the FINAL two bytes of the
    *  Environment are both 0. This will finish the last string AND
    *  ensure that a zero length string is also present
   */
   *(End_Env-1) = 0 ;
  *(End_Env-2) = 0 ;

   /*
    *  Free all working storage
   */
   Ffree ( Temp_Name ) ;

   return ( Done ) ;
}

void main(void)
{
  char far *Env ;
   unsigned EnvSize ;

   /*
    *  Locate the Master Table
   */
   Mstr_FindEnvironment ( &Env, &EnvSize ) ;

   /*
    *  Describe what we've just found
   */
   printf ( "Env = %Fp Size = %u\n\n" , Env , EnvSize ) ;

   /*
    *  Search for, and display LOCATIONS of PATH, FRED and BERT
   */
   printf ( "Search for PATH= returns %Fp\n",  Mstr_getenv ( Env , "PATH=" ) ) ;
   printf ( "Search for FRED= returns %Fp\n",  Mstr_getenv ( Env , "FRED=" ) ) ;
   printf ( "Search for BERT= returns %Fp\n",  Mstr_getenv ( Env , "BERT=" ) ) ;

   /*
    *  Add FRED and BERT to the environment
   */
   Mstr_putenv ( Env , EnvSize , "FRED=fred" ) ;
   Mstr_putenv ( Env , EnvSize , "BERT=bert" ) ;

   printf ( "\nAdded FRED and BERT to environment\n" ) ;

   /*
    *  Search for, and display LOCATIONS of PATH ,FRED and BERT
   */
   printf ( "Search for PATH= returns %Fp\n",  Mstr_getenv ( Env , "PATH=" ) ) ;
   printf ( "Search for FRED= returns %Fp\n",  Mstr_getenv ( Env , "FRED=" ) ) ;
   printf ( "Search for BERT= returns %Fp\n",  Mstr_getenv ( Env , "BERT=" ) ) ;

   /*
    *  Delete FRED from the environment
   */
   Mstr_delenv ( Env , EnvSize , "FRED=" ) ;

   printf ( "\nDeleted FRED= from the environment\n" ) ;

   /*
    *  Search for, and display LOCATIONS of PATH, FRED, and BERT
   */
   printf ( "Search for PATH= returns %Fp\n",  Mstr_getenv ( Env , "PATH=" ) ) ;
   printf ( "Search for FRED= returns %Fp\n",  Mstr_getenv ( Env , "FRED=" ) ) ;
   printf ( "Search for BERT= returns %Fp\n",  Mstr_getenv ( Env , "BERT=" ) ) ;

   printf ( "\nIssue the DOS command SET and see that BERT is now set\n" ) ;

}