Add GNU LGPL headers to all .c .C and .h files
[oweals/cde.git] / cde / lib / DtSearch / raima / recfcns.c
1 /*
2  * CDE - Common Desktop Environment
3  *
4  * Copyright (c) 1993-2012, The Open Group. All rights reserved.
5  *
6  * These libraries and programs are free software; you can
7  * redistribute them and/or modify them under the terms of the GNU
8  * Lesser General Public License as published by the Free Software
9  * Foundation; either version 2 of the License, or (at your option)
10  * any later version.
11  *
12  * These libraries and programs are distributed in the hope that
13  * they will be useful, but WITHOUT ANY WARRANTY; without even the
14  * implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
15  * PURPOSE. See the GNU Lesser General Public License for more
16  * details.
17  *
18  * You should have received a copy of the GNU Lesser General Public
19  * License along with these librararies and programs; if not, write
20  * to the Free Software Foundation, Inc., 51 Franklin Street, Fifth
21  * Floor, Boston, MA 02110-1301 USA
22  */
23 /* $XConsortium: recfcns.c /main/2 1996/05/09 04:13:59 drk $ */
24 /*
25  *   COMPONENT_NAME: austext
26  *
27  *   FUNCTIONS: r_chkfld
28  *              r_clropt
29  *              r_delrec
30  *              r_gfld
31  *              r_gmem
32  *              r_gset
33  *              r_pfld
34  *              r_pmem
35  *              r_pset
36  *              r_setopt
37  *              r_smem
38  *              r_tstopt
39  *
40  *   ORIGINS: 157
41  *
42  *   OBJECT CODE ONLY SOURCE MATERIALS
43  */
44 /*---------------------------------------------------------------------------
45    recfcns.c - db_VISTA Record Access/Manipulation Functions
46
47    Copyright (C) 1984, 1985, 1986 by Raima Corporation.
48 ---------------------------------------------------------------------------*/
49
50 /* ********************** EDIT HISTORY *******************************
51
52  SCR    DATE    INI                   DESCRIPTION
53 ----- --------- --- -----------------------------------------------------
54   158 15-JUN-88 RSC passed new flag to key_bldcom.
55   103 27-Jun-88 RSC Improve generation of single user version
56       04-Aug-88 RTK MULTI_TASK changes
57   310 10-Aug-88 RSC Cleanup function prototype.
58   420 16-Aug-88 RTK Missing FAR pointer
59
60 */
61 #include <stdio.h>
62 #include "vista.h"
63 #include "dbtype.h"
64
65 #define FALSE 0
66 #define TRUE 1
67
68 /* toggle for checking struct key modifications */
69 static int struct_key_chk = 1;
70
71 /* Check a field for permission to change it
72 */
73 r_chkfld(field, fld_ptr, rec, data )
74 INT field;  /* field_table entry number */
75 FIELD_ENTRY FAR *fld_ptr; /* corresponds to field */
76 char FAR *rec;  /* pointer to record slot */
77 CONST char FAR *data; /* pointer to data area containing field contents */
78 {
79    DB_ADDR dba;
80    long fld;
81    INT rn;
82    char FAR *fptr, ckey[256];
83    int i;
84    FIELD_ENTRY FAR *sfld_ptr;
85    RECORD_ENTRY FAR *rec_ptr;
86
87    bytecpy(&rn, rec, sizeof(INT));
88    rn &= ~RLBMASK; /* mask off rlb */
89    if ( rn != NUM2EXT(fld_ptr->fd_rec, rt_offset) )
90       return( dberr(S_INVFLD) );
91
92    rec_ptr = &record_table[fld_ptr->fd_rec];
93    fld = FLDMARK*rn + field - rec_ptr->rt_fields;
94
95    if ( fld_ptr->fd_type == COMKEY ) {
96
97       /* build compound key value. NOTE: cflag MUST be the same here as for
98          the call to key_bldcom in recwrite, which calls this function. */
99       fptr = rec + rec_ptr->rt_data;
100       key_bldcom(field, fptr, ckey, FALSE);
101       fptr = ckey;
102    }
103    else
104       fptr = rec + fld_ptr->fd_ptr;
105
106    /* do nothing unless the new value is different */
107    if (fldcmp(fld_ptr, data, fptr) == 0) 
108       return( db_status = S_OKAY );
109
110    /* if this is a unique key field, make sure the key does not already
111       exist
112    */
113    if ( fld_ptr->fd_key == UNIQUE ) {
114       dba = curr_rec;
115       /* If the key field is not optional, or optional and stored */
116       if ((!(fld_ptr->fd_flags & OPTKEYMASK) || r_tstopt(fld_ptr, rec)) &&
117           (d_keyfind(fld, data CURRTASK_PARM CURR_DB_PARM) == S_OKAY)) {
118          /* another record is already using this key value */
119          db_status = S_DUPLICATE;
120       }
121       curr_rec = dba;
122       if ( db_status == S_DUPLICATE ) return( db_status );
123    }
124    /* if field is grouped, call r_chkfld for 1st entry of each sub-field */
125    if ( fld_ptr->fd_type == GROUPED ) {
126       for (i = field + 1, sfld_ptr = fld_ptr + 1;
127            (i < size_fd) && (sfld_ptr->fd_flags & STRUCTFLD);
128            ++i, ++sfld_ptr) {
129          fptr = (char *)data - (sfld_ptr->fd_ptr -
130                                        record_table[sfld_ptr->fd_rec].rt_data);
131          if (r_chkfld(i, sfld_ptr, rec, fptr) != S_OKAY)
132             return( db_status );
133       }
134    }
135    return( db_status = S_OKAY );
136 }
137
138
139 /* Delete the current record
140 */
141 r_delrec( rt, db_addr )
142 INT rt;
143 DB_ADDR db_addr;
144 {
145    char FAR *rec;       /* ptr to record slot */
146    char FAR *fptr;      /* field data ptr */
147    char ckey[256];  /* compound key data */
148 #ifndef  NO_TIMESTAMP
149    ULONG timestamp;
150 #endif
151    FILE_NO fno;
152    F_ADDR rno;
153    register int fld;
154    RECORD_ENTRY FAR *rec_ptr;
155    register FIELD_ENTRY FAR *fld_ptr;
156
157    if ( dio_read( db_addr, (char FAR * FAR *)&rec, PGHOLD) != S_OKAY )
158       return( db_status );
159
160    rec_ptr = &record_table[rt];
161    /* remove any key fields from the key files */
162    for (fld = rec_ptr->rt_fields, fld_ptr = &field_table[fld];
163         (fld < size_fd) && (fld_ptr->fd_rec == rt);
164         ++fld, ++fld_ptr) {
165       if ( fld_ptr->fd_key != NOKEY ) {
166          if ( fld_ptr->fd_type == COMKEY ) {
167             key_bldcom(fld, rec + rec_ptr->rt_data, ckey, TRUE);
168             fptr = ckey;
169          }
170          else {
171             fptr = rec + fld_ptr->fd_ptr;
172          }
173          /* delete the key if it exists */
174          if ((!(fld_ptr->fd_flags & OPTKEYMASK) || r_tstopt(fld_ptr, rec)) &&
175              (key_delete(fld, fptr, db_addr) != S_OKAY))
176             return( db_status );
177       }
178    }
179    fno = NUM2INT((FILE_NO)((db_addr >> FILESHIFT) & FILEMASK), ft_offset);
180    rno = ADDRMASK & db_addr;
181 #ifndef  NO_TIMESTAMP
182    /* update timestamp, if necessary */
183    if ( rec_ptr->rt_flags & TIMESTAMPED ) {
184       timestamp = dio_pzgetts(fno);
185       bytecpy( rec + RECCRTIME, &timestamp, sizeof(ULONG));
186       bytecpy( rec + RECUPTIME, &timestamp, sizeof(ULONG));
187    }
188 #endif
189    dio_write(db_addr, NULL, PGFREE);
190
191    /* place this record onto the delete chain */
192    dio_pzdel(fno, rno);
193
194    return( db_status );
195 }
196
197
198 /* Get data field from record
199 */
200 r_gfld(fld_ptr, rec, data )
201 FIELD_ENTRY FAR *fld_ptr;
202 char FAR *rec;  /* pointer to record */
203 char FAR *data; /* pointer to data area to contain field contents */
204 {
205    register int kt_lc;                  /* loop control */
206    INT rn;
207    register FIELD_ENTRY FAR *kfld_ptr;
208    register KEY_ENTRY FAR *key_ptr;
209
210    bytecpy(&rn, rec, sizeof(INT));
211    if ( rn < 0 )
212       return( db_status = S_DELETED );
213
214 #ifndef SINGLE_USER
215    if ( rn & RLBMASK ) {
216       rn &= ~RLBMASK; /* mask off rlb */
217       rlb_status = S_LOCKED;
218    }
219    else {
220       rlb_status = S_UNLOCKED;
221    }
222 #endif
223 #ifndef  ONE_DB
224    rn += curr_db_table->rt_offset;
225 #endif
226
227    if ( fld_ptr->fd_rec != rn )
228       return( dberr(S_INVFLD) );
229
230    if ( fld_ptr->fd_type == KEY ) {
231       /* clear compound key data area */
232       byteset(data, '\0', fld_ptr->fd_len);
233
234       /* copy each field of compound key to data area */
235       for (kt_lc = size_kt - fld_ptr->fd_ptr,
236                                         key_ptr = &key_table[fld_ptr->fd_ptr];
237            (--kt_lc >= 0) && (&field_table[key_ptr->kt_key] == fld_ptr);
238            ++key_ptr) {
239          kfld_ptr = &field_table[key_ptr->kt_field];
240          bytecpy(data + key_ptr->kt_ptr, rec + kfld_ptr->fd_ptr,
241                  kfld_ptr->fd_len);
242       }
243    }
244    else {
245       bytecpy(data, rec + fld_ptr->fd_ptr, fld_ptr->fd_len);
246    }
247    return( db_status = S_OKAY );
248 }
249
250
251 /* Get member pointer from record
252 */
253 r_gmem(set, rec, mem_addr )
254 int set;    /* set table entry number */
255 char FAR *rec;  /* pointer to record */
256 char FAR *mem_addr; /* pointer to member pointer */
257 {
258    INT rt;
259    register int mem, memtot;
260    SET_ENTRY FAR *set_ptr;
261    register MEMBER_ENTRY FAR *mem_ptr;
262
263    /* search member list of set for record */
264    set_ptr = &set_table[set];
265    bytecpy(&rt, rec, sizeof(INT));
266    rt &= ~RLBMASK;
267    for (mem = set_ptr->st_members, memtot = mem + set_ptr->st_memtot,
268                                                 mem_ptr = &member_table[mem];
269         mem < memtot;
270         ++mem, ++mem_ptr) {
271       if (NUM2EXT(mem_ptr->mt_record, rt_offset) == rt) {
272          /* have found correct member record */
273          bytecpy(mem_addr, rec + mem_ptr->mt_mem_ptr, MEMPSIZE);
274          return( db_status = S_OKAY );
275       }
276    }
277    /* this record is not member of set */
278    return( dberr(S_INVMEM) );
279 }
280
281
282 /* Get set pointer from record
283 */
284 r_gset(set, rec, setptr )
285 int set;      /* set table entry number */
286 char FAR *rec;    /* pointer to record */
287 char FAR *setptr; /* pointer to set pointer */
288 {
289    INT rt;
290    int len;
291    SET_ENTRY FAR *set_ptr;
292
293    set_ptr = &set_table[set];
294    bytecpy(&rt, rec, sizeof(INT));
295    if (NUM2EXT(set_ptr->st_own_rt, rt_offset) == (rt & ~RLBMASK)) {
296 #ifndef NO_TIMESTAMP
297       if ( set_ptr->st_flags & TIMESTAMPED )
298          len = SETPSIZE;
299       else
300 #endif
301          len = SETPSIZE - sizeof(ULONG);
302       bytecpy(setptr, rec + set_ptr->st_own_ptr, len);
303       return( db_status = S_OKAY );
304    }
305    return( dberr(S_INVOWN) );
306 }
307
308
309 /* Put data field into record
310 */
311 r_pfld(field, fld_ptr, rec, data, db_addr )
312 INT field;  /* field_table entry number */
313 FIELD_ENTRY FAR *fld_ptr; /* corresponds to field */
314 char FAR *rec;  /* pointer to existing record */
315 CONST char FAR *data; /* pointer to data area containing new field contents */
316 DB_ADDR FAR *db_addr;
317 {
318    DB_ADDR mdba, odba, dba;
319    int set, sn;
320    char memp[MEMPSIZE];
321    register char FAR *fptr;
322    register CONST char FAR *tfptr;
323    register int s, i, strfld;
324    register FIELD_ENTRY FAR *sfld_ptr;
325    register SORT_ENTRY FAR *srt_ptr;
326    DB_ADDR FAR *co_ptr, FAR *cm_ptr;
327
328    db_status = S_OKAY;
329    fptr = rec + fld_ptr->fd_ptr;
330
331    /* do nothing unless the new value is different */
332    if (fldcmp(fld_ptr, fptr, data) == 0) 
333       return( db_status );
334
335    bytecpy(&dba, db_addr, DB_ADDR_SIZE);
336
337    /* if this is a key field, change the key file also */
338    if ((fld_ptr->fd_key != NOKEY) &&
339        (!(fld_ptr->fd_flags & OPTKEYMASK) || r_tstopt(fld_ptr, rec))) {
340       /* delete the old key and insert the new one */
341       if ( key_delete(field, fptr, dba) == S_OKAY ) {
342          if ( key_insert( field, data, dba ) != S_OKAY )
343             return( db_status );
344       }
345       else 
346          return( db_status == S_NOTFOUND? dberr(S_KEYERR): db_status );
347    }
348    /* if subfield of struct field, check to see if struct is a key */
349    if ( struct_key_chk && fld_ptr->fd_flags & STRUCTFLD ) {
350       for (strfld = field - 1, sfld_ptr = &field_table[strfld];
351            sfld_ptr->fd_type != GROUPED;
352             --strfld, --sfld_ptr)
353          ; /* find struct field */
354       if ((sfld_ptr->fd_key != NOKEY) &&
355          /* make sure it is stored */
356           (!(sfld_ptr->fd_flags & OPTKEYMASK) || r_tstopt(sfld_ptr, rec))) {
357          /* delete the old struct key */
358          if (key_delete(strfld, rec + sfld_ptr->fd_ptr, dba) != S_OKAY)
359             return( db_status );
360       }
361       else strfld = -1;
362    }
363    else strfld = -1;
364
365    /* copy data into record area */
366    switch ( fld_ptr->fd_type ) {
367       case CHARACTER:
368          if ( fld_ptr->fd_dim[1] )
369             bytecpy(fptr, data, fld_ptr->fd_len);
370          else if ( fld_ptr->fd_dim[0] )
371             strncpy(fptr, data, fld_ptr->fd_len);
372          else
373             *fptr = *data;
374          break;
375       case GROUPED:
376          if (  ! fld_ptr->fd_dim[0] ) {
377             /* non-arrayed structure */
378             struct_key_chk = 0;
379             for (i = field + 1, sfld_ptr = fld_ptr + 1;
380                  (i < size_fd) && (sfld_ptr->fd_flags & STRUCTFLD);
381                  ++i, ++sfld_ptr) {
382                tfptr = data + sfld_ptr->fd_ptr - fld_ptr->fd_ptr;
383                if ( r_pfld(i, sfld_ptr, rec, tfptr, &dba) != S_OKAY )
384                   break;
385             }
386             struct_key_chk = 1;
387             if ( db_status != S_OKAY ) return( db_status );
388             break;
389          }
390          /* arrayed struct fall-thru to a full field copy */
391       default:
392          bytecpy(fptr, data, fld_ptr->fd_len);
393    }
394    /* if this field is part of an ordered set, reconnect */
395    if (fld_ptr->fd_flags & SORTFLD) {
396       for (s = 0, srt_ptr = sort_table; s < size_srt; ++s, ++srt_ptr) {
397          if ( srt_ptr->se_fld == field ) {
398             sn = srt_ptr->se_set;
399             if ( r_gmem( sn, rec, memp ) != S_OKAY ) return( db_status );
400             if ( ! null_dba(memp+MP_OWNER) ) {
401                /* save currency */
402                odba = *(co_ptr = &curr_own[sn]);
403                mdba = *(cm_ptr = &curr_mem[sn]);
404
405                /* set current owner and member to sorted set */
406                bytecpy(co_ptr, memp+MP_OWNER, DB_ADDR_SIZE);
407                *cm_ptr = dba;
408
409                /* calculate set constant */
410                set = NUM2EXT(sn + SETMARK, st_offset);
411
412                /* disconnect from prior order set and reconnect in new order */
413                d_discon(set CURRTASK_PARM CURR_DB_PARM);
414                d_connect(set CURRTASK_PARM CURR_DB_PARM);
415
416                /* reset currency */
417                *co_ptr = odba;
418                *cm_ptr = mdba;
419             }
420          }
421       }
422    }
423    if ( strfld >= 0 ) {
424       /* insert the new struct key */
425       if ( key_insert( strfld, rec + sfld_ptr->fd_ptr, dba ) != S_OKAY )
426          return( db_status );
427    }
428    return( db_status );
429 }
430
431
432 /* Put member pointer into record
433 */
434 r_pmem(set, rec, mem_addr )
435 int set;    /* set table entry number */
436 char FAR *rec;  /* pointer to record */
437 char FAR *mem_addr; /* pointer to member pointer */
438 {
439    INT rt;
440    register int mem, memtot;
441    SET_ENTRY FAR *set_ptr;
442    register MEMBER_ENTRY FAR *mem_ptr;
443
444    /* search member list of set for record */
445    set_ptr = &set_table[set];
446    bytecpy(&rt, rec, sizeof(INT));
447    rt &= ~RLBMASK;
448    for (mem = set_ptr->st_members, memtot = mem + set_ptr->st_memtot,
449                                                 mem_ptr = &member_table[mem];
450         mem < memtot;
451         ++mem, ++mem_ptr) {
452       if (NUM2EXT(mem_ptr->mt_record, rt_offset) == rt) {
453          /* have found correct member record */
454          bytecpy(rec + mem_ptr->mt_mem_ptr, mem_addr, MEMPSIZE);
455          return( db_status = S_OKAY );
456       }
457    }
458    /* this record is not member of set */
459    return( dberr(S_INVMEM) );
460 }
461
462
463 /* Put set pointer into record
464 */
465 r_pset(set, rec, setptr )
466 int set;       /* set table entry number */
467 char FAR *rec;     /* pointer to record */
468 char FAR *setptr;  /* pointer to set pointer */
469 {
470    INT rt;
471    int len;
472    SET_ENTRY FAR *set_ptr;
473
474    set_ptr = &set_table[set];
475    bytecpy(&rt, rec, sizeof(INT));
476    if (NUM2EXT(set_ptr->st_own_rt, rt_offset) == (rt & ~RLBMASK)) {
477 #ifndef NO_TIMESTAMP
478       if ( set_ptr->st_flags & TIMESTAMPED )
479          len = SETPSIZE;
480       else
481 #endif
482          len = SETPSIZE - sizeof(ULONG);
483       bytecpy(rec + set_ptr->st_own_ptr, setptr, len);
484       return( db_status = S_OKAY );
485    }
486    else {
487       return( dberr(S_INVOWN) );
488    }
489 }
490
491
492 /* Set the current set member from record
493 */
494 r_smem( db_addr, set )
495 DB_ADDR FAR *db_addr;
496 INT set;
497 {
498 #ifndef  NO_TIMESTAMP
499    int nset;
500 #endif
501    char mem[MEMPSIZE], FAR *ptr;
502    DB_ADDR dba;
503
504    bytecpy(&dba, db_addr, DB_ADDR_SIZE);
505
506    /* make sure record is owned */
507    if ((dio_read(dba, (char FAR * FAR *)&ptr, NOPGHOLD) != S_OKAY) ||
508        (r_gmem(set, ptr, mem) != S_OKAY))
509       return( db_status );
510
511    if ( null_dba( mem+MP_OWNER ) ) return( dberr( S_NOTCON ) );
512
513    bytecpy( &curr_own[set], mem+MP_OWNER, DB_ADDR_SIZE );
514
515    /* ownership okay, set the member */
516    curr_mem[set] = dba;
517 #ifndef  NO_TIMESTAMP
518    nset = NUM2EXT(set + SETMARK, st_offset);
519    /* set timestamps */
520    if ( db_tsrecs ) {
521       d_utsco( nset, &co_time[set] CURRTASK_PARM CURR_DB_PARM );
522       d_utscm( nset, &cm_time[set] CURRTASK_PARM CURR_DB_PARM );
523    }
524    if ( db_tssets )
525       d_utscs( nset, &cs_time[set] CURRTASK_PARM CURR_DB_PARM );
526 #endif
527    return( db_status = S_OKAY );
528 }
529
530 /* Set the optional key field "stored" bit */
531 r_setopt( fld_ptr, rec )
532 FIELD_ENTRY FAR *fld_ptr; /* field table entry of optional key */
533 char FAR *rec;  /* Pointer to record */
534 {
535    int offset;  /* offset to the bit map */
536    int keyndx;  /* index into bit map of this key */
537    int byteno, bitno;   /* position within bit map of this key */
538
539    /* calculate the position to the bit map */
540    offset = (record_table[fld_ptr->fd_rec].rt_flags & TIMESTAMPED) ?
541                (RECHDRSIZE + 2*sizeof(LONG)) : RECHDRSIZE;
542
543    /* extract the index into the bit map of this key */
544    keyndx = (((fld_ptr->fd_flags & OPTKEYMASK) >> OPTKEYSHIFT) & OPTKEYNDX) - 1;
545    if ( keyndx < 0 ) return( dberr(S_SYSERR) );
546
547    /* determine which byte, and which bit within the byte */
548    byteno = keyndx/BITS_PER_BYTE;
549    bitno = keyndx - byteno*BITS_PER_BYTE;
550
551    /* set the bit */
552    rec[byteno + offset] |= 1 << (BITS_PER_BYTE - bitno - 1);
553
554    return( db_status = S_OKAY );
555 }
556
557 /* Clear the optional key field "stored" bit */
558 r_clropt( fld_ptr, rec )
559 FIELD_ENTRY FAR *fld_ptr;       /* Field table entry of optional key */
560 char FAR *rec;  /* Pointer to record */
561 {
562    int offset;  /* offset to the bit map */
563    int keyndx;  /* index into bit map of this key */
564    int byteno, bitno;   /* position within bit map of this key */
565
566    /* calculate the position to the bit map */
567    offset = (record_table[fld_ptr->fd_rec].rt_flags & TIMESTAMPED) ?
568                (RECHDRSIZE + 2*sizeof(LONG)) : RECHDRSIZE;
569
570    /* extract the index into the bit map of this key */
571    keyndx = (((fld_ptr->fd_flags & OPTKEYMASK) >> OPTKEYSHIFT) & OPTKEYNDX) - 1;
572    if ( keyndx < 0 ) return( dberr(S_SYSERR) );
573
574    /* determine which byte, and which bit within the byte */
575    byteno = keyndx / BITS_PER_BYTE;
576    bitno = keyndx - byteno*BITS_PER_BYTE;
577
578    /* clear the bit */
579    rec[byteno + offset] &= ~(1 << (BITS_PER_BYTE - bitno - 1));
580
581    return( S_OKAY );
582 }
583
584 /* Test the optional key field "stored" bit */
585 r_tstopt( fld_ptr, rec )
586 FIELD_ENTRY FAR *fld_ptr;       /* Field table entry of optional key */
587 char FAR *rec;  /* Pointer to record */
588 {
589    int offset;  /* offset to the bit map */
590    int keyndx;  /* index into bit map of this key */
591    int byteno, bitno;   /* position within bit map of this key */
592
593    /* calculate the position to the bit map */
594    offset = (record_table[fld_ptr->fd_rec].rt_flags & TIMESTAMPED) ?
595                (RECHDRSIZE + 2*sizeof(LONG)) : RECHDRSIZE;
596
597    /* extract the index into the bit map of this key */
598    keyndx = (((fld_ptr->fd_flags & OPTKEYMASK) >> OPTKEYSHIFT) & OPTKEYNDX) - 1;
599    if ( keyndx < 0 ) return( dberr(S_SYSERR) );
600
601    /* determine which byte, and which bit within the byte */
602    byteno = keyndx / BITS_PER_BYTE;
603    bitno = keyndx - byteno*BITS_PER_BYTE;
604
605    /* extract the bit */
606    if (rec[byteno + offset] & (1 << (BITS_PER_BYTE - bitno - 1)))
607       return( db_status = S_DUPLICATE );
608    return( db_status = S_OKAY );
609 }
610 /* vpp -nOS2 -dUNIX -nBSD -nVANILLA_BSD -nVMS -nMEMLOCK -nWINDOWS -nFAR_ALLOC -f/usr/users/master/config/nonwin recfcns.c */