EnglishРусский  

   ..

   dbf.g

   field.g

   testdbf.g

Ads

Perfect Automation tool
All-In-One: Script editor, Launcher, Scheduler, Keyboard & Mouse Recorder. Try now!

CreateInstall
Freeware and commercial installers.

Cell Phone Batteries
Batteries Plus offers batteries for laptop, camcorder, cell phone, camera.

Gentee needs your help!
How to advertise with us
 
laptop battery

source\lib\Dbf\dbf.g
  1 /******************************************************************************
  2 *
  3 * Copyright (C) 2004-2008, The Gentee Group. All rights reserved. 
  4 * This file is part of the Gentee open source project - http://www.gentee.com. 
  5 * 
  6 * THIS FILE IS PROVIDED UNDER THE TERMS OF THE GENTEE LICENSE ("AGREEMENT"). 
  7 * ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS FILE CONSTITUTES RECIPIENTS 
  8 * ACCEPTANCE OF THE AGREEMENT.
  9 *
 10 * Author: Alexey Krivonogov ( gentee )
 11 *
 12 ******************************************************************************/
 13 
 14 /*-----------------------------------------------------------------------------
 15 * Id: dbf L "Dbf"
 16 * 
 17 * Summary: This library is used to work with #b(dbf) files. The formats 
 18            #b(dBase III) and #b(dBase IV) are supported. To be able to work, 
 19            you should describe a variable of the #b(dbf) type. For using this
 20            library, it is required to specify the file dbf.g (from Lib
 21            subfolder) with include command. #srcg[
 22 |include : $"...\gentee\lib\dbf\dbf.g"]    
 23 *
 24 * List: *#lng/opers#,dbf_oplen,dbf_opfor,
 25         *#lng/methods#,dbf_append,dbf_bof,dbf_bottom,dbf_close,dbf_create,
 26         dbf_del,dbf_empty,dbf_eof,dbf_geterror,dbf_go,dbf_isdel,dbf_open,
 27         dbf_pack,dbf_recno,dbf_skip,dbf_top, 
 28         *Field methods,dbf_f_count,dbf_f_date,dbf_f_decimal,dbf_f_double,
 29         dbf_f_find,dbf_f_int,dbf_f_logic,dbf_f_memo,
 30         dbf_f_name,dbf_f_offset,dbf_f_ptr,dbf_f_str,dbf_f_type,dbf_f_width,
 31         dbf_fw_date,dbf_fw_double,dbf_fw_int,dbf_fw_logic,dbf_fw_memo,
 32         dbf_fw_str 
 33 * 
 34 -----------------------------------------------------------------------------*/
 35 
 36 define <export>
 37 {
 38    DBF_PAGE       = 0x40000  // Page size 262144
 39    
 40 /*-----------------------------------------------------------------------------
 41 * Id: dbflogic D
 42 * 
 43 * Summary: Logic value.
 44 *
 45 -----------------------------------------------------------------------------*/
 46    DBF_LFALSE     = 0   // The value of the logical field is FALSE.
 47    DBF_LTRUE      = 1   // The value of the logical field is TRUE.
 48    DBF_LUNKNOWN   = 2   // The value of the logical field is undefined. 
 49 
 50 /*-----------------------------------------------------------------------------
 51 * Id: dbftypes D
 52 * 
 53 * Summary: Types of fields.
 54 *
 55 -----------------------------------------------------------------------------*/
 56    DBFF_CHAR      = 'C'   // String.
 57    DBFF_DATE      = 'D'   // Date.
 58    DBFF_LOGIC     = 'L'   // Logical.
 59    DBFF_NUMERIC   = 'N'   // Integer.
 60    DBFF_FLOAT     = 'F'   // Fraction.
 61    DBFF_MEMO      = 'M'   // Memo field.
 62 
 63 /*-----------------------------------------------------------------------------
 64 * Id: dbferrs D
 65 * 
 66 * Summary: Flags for dbf.geterror.
 67 *
 68 -----------------------------------------------------------------------------*/
 69    ERRDBF_OPEN    = 1   // Cannot open dbf file.
 70    ERRDBF_READ          // Cannot read dbf file.
 71    ERRDBF_POS           // File position error.
 72    ERRDBF_EOF           // There is not the current record.
 73    ERRDBF_WRITE         // Cannot write dbf file.
 74    ERRDBF_FOVER         // The length of the string being written is greater /
 75                         // than the size of the field.
 76    ERRDBF_TYPE          // Incompatible field type.
 77    ERRDBT_OPEN          // Cannot open dbt file.
 78    ERRDBT_READ          // Cannot read dbt file.
 79    ERRDBT_POS           // An error of positioning in the dbt file.
 80    ERRDBT_WRITE         // Cannot write dbt file.
 81 //-----------------------------------------------------------------------------
 82 
 83 }
 84 
 85 type dbfhead {
 86     byte     version        
 87     byte     yy
 88     byte     mm
 89     byte     dd
 90     uint     num_recs
 91     ushort   header_len
 92     ushort   record_width
 93     reserved filler[20]
 94 }
 95 
 96 type dbfhfield {
 97     reserved  name[11]
 98     byte      ftype
 99     uint      reserve
100     byte      width
101     byte      decimals
102     reserved  filler[14]
103 }
104 
105 type dbffield {
106     str       name
107     uint      ftype
108     uint      width
109     uint      decimals
110     uint      offset
111 }
112 
113 type dbf
114 {
115    dbfhead    head
116    str        name
117    uint       error
118    file       dbffile
119    file       dbtfile
120    buf        page          // Страница загруженных данных
121    uint       pageoff       // Номер первого загруженного с 0
122    uint       pagecount     // Количество загруженных
123    uint       pagelimit     // Максимально возможное количество 
124                             // элементов на странице
125    uint       cur           // Номер текущего элемента с 0
126    uint       curfor        // Номер текущего элемента с 1 для foreach
127    uint       ptr           // Указатель на текущую запись
128    buf        eofbuf        // Пустой буфер       
129    uint       mblock        // Размер Memo поля
130    arr        fields of dbffield
131 }
132 
133 extern {
134    method uint dbf.top()
135 }
136 
137 method dbf.delete
138 {
139    if this.dbffile.fopen 
140    {
141       this.dbffile.close( )
142       //this.dbffile = 0
143    }
144    if this.dbtfile.fopen 
145    {
146       this.dbtfile.close( )
147       //this.dbtfile = 0
148    }
149    this.page.clear()
150    this.fields.clear()
151 }
152 
153 method uint dbf.error( uint code )
154 {
155    this.error = code
156    return 0
157 }
158 
159 /*-----------------------------------------------------------------------------
160 * Id: dbf_oplen F4
161 * 
162 * Summary: Get the number of records in the database.
163 *  
164 * Return: The number of records.
165 *
166 -----------------------------------------------------------------------------*/
167 
168 operator uint *( dbf dbase )
169 {
170    return dbase.head.num_recs
171 }
172 
173 /*-----------------------------------------------------------------------------
174 * Id: dbf_opfor F5
175 *
176 * Summary: Foreach operator. You can use #b(foreach) operator to look over all 
177            records of the database. #b(Variable) is a number of the current
178            record.
179 *  
180 * Title: foreach var,dbf
181 *
182 * Define: foreach variable,dbf {...}
183 * 
184 -----------------------------------------------------------------------------*/
185 
186 /*-----------------------------------------------------------------------------
187 * Id: dbf_eof F2
188 * 
189 * Summary: Determine is the current record is in the database.
190 *  
191 * Params: fd - This parameter is used in forech operator. /
192           Specify 0->fordata.
193 *
194 * Return: Returns 1 if the current record is not defined/found and 0 otherwise. 
195 *
196 -----------------------------------------------------------------------------*/
197 
198 method  uint dbf.eof( fordata fd )
199 {
200    return this.cur >= *this   
201 }
202 
203 method uint dbf.getdate()
204 {
205    datetime dt
206    
207    dt.gettime()
208    dt.year %= 100
209    if dt.year != this.head.yy || dt.month != this.head.mm ||
210       dt.day != this.head.dd
211    {
212       this.head.yy = dt.year
213       this.head.mm = dt.month
214       this.head.dd = dt.day
215       return 1
216    }
217    return 0
218 }
219 
220 include : "field.g"
221 
222 /*-----------------------------------------------------------------------------
223 * Id: dbf_geterror F3
224 * 
225 * Summary: Getting an error code. Get the error code in case some method is
226            finished unsuccessfully. 
227 *  
228 * Return: The code of the last error is returned.$$[dbferrs] 
229 *
230 -----------------------------------------------------------------------------*/
231 
232 method uint dbf.geterror()
233 {
234    return this.error
235 }
236 
237 /*-----------------------------------------------------------------------------
238 * Id: dbf_open F2
239 * 
240 * Summary: Open a database (a dbf file). 
241 *  
242 * Params: name - The name of the dbf file being opened.
243 *
244 * Return: #lng/retf# 
245 *
246 -----------------------------------------------------------------------------*/
247 
248 method uint dbf.open( str name )
249 {
250    buf   btemp
251    str   dbtname
252    uint  size
253    uint  cur
254    uint  i
255    
256    this.delete()
257    
258    this.name = name
259    if !( this.dbffile.open( name, 0 )) : return this.error( $ERRDBF_OPEN )
260    if this.dbffile.read( btemp, sizeof( dbfhead )) != sizeof( dbfhead )
261    {
262       return this.error( $ERRDBF_READ )
263    }   
264    mcopy( &this.head, btemp.ptr(), sizeof( dbfhead ))
265    if this.head.version == 0x83 || this.head.version == 0x8B
266    {
267       dbtname.fsetext( name, "dbt" )
268       if !( this.dbtfile.open( dbtname, 0 )) 
269       {
270          this.delete()
271          return this.error( $ERRDBT_OPEN )
272       }
273       if this.head.version == 0x8B
274       {
275          btemp.use = 0
276          if this.dbtfile.read( btemp, 32 ) != 32
277          {
278             this.delete()
279             return this.error( $ERRDBT_READ )
280          }
281          this.mblock = ( btemp.ptr() + 20 )->ushort
282          if !this.mblock : this.mblock = 512
283       }
284       else : this.mblock = 512
285    }   
286    size = this.dbffile.getsize( )
287    //this.page.alloc( ?( $DBF_PAGE < size, $DBF_PAGE, size ))
288    this.page.reserve( ?( $DBF_PAGE < size, $DBF_PAGE, size ) )   
289    this.pagelimit = this.page.size / this.head.record_width
290    this.pagecount = 0
291    this.pageoff = 0
292    this.cur = 0
293 
294    btemp.use = 0
295    size = this.head.header_len - sizeof( dbfhead )
296    
297    if this.dbffile.read( btemp, size ) != size
298    {
299       this.delete()
300       return this.error( $ERRDBF_READ )
301    }
302    
303    cur = btemp.ptr()
304    size = 1
305    while cur->byte != 0x0D
306    {
307       cur as dbfhfield
308       i = this.fields.expand( 1 );
309       this.fields[ i ].name.copy( &cur.name )
310       this.fields[ i ].ftype = cur.ftype
311       this.fields[ i ].width = cur.width
312       this.fields[ i ].decimals = cur.decimals
313       this.fields[ i ].offset = size
314       size += cur.width
315       cur as uint
316       cur += sizeof( dbfhfield )
317    }
318 //   print("Size = \(size) Rec_width=\(this.head.record_width)\n")
319    // Зануляем буфер для записи eof
320    this.eofbuf.clear()
321    this.eofbuf.reserve( this.head.record_width + 1 )
322    this.eofbuf.use = this.head.record_width
323    fornum i=0, this.head.record_width : this.eofbuf[i] = ' '
324 //   mzero( this.eofbuf.ptr(), this.eofbuf.size )
325    this.ptr = this.eofbuf.ptr()
326    
327    this.top()
328    return 1
329 }
330 
331 /*-----------------------------------------------------------------------------
332 * Id: dbf_close F3
333 * 
334 * Summary: Close a database. 
335 *  
336 -----------------------------------------------------------------------------*/
337 
338 method dbf.close()
339 {
340    this.delete()
341 }
342 
343 /*-----------------------------------------------------------------------------
344 * Id: dbf_go F2
345 * 
346 * Summary: Move to the record with the specified number.
347 *  
348 * Params: num - The required record number starting from 1.
349 *
350 * Return: #lng/retf# 
351 *
352 -----------------------------------------------------------------------------*/
353 
354 method  uint dbf.go( uint num )
355 {
356    uint  prevcur = this.cur
357    uint  count = this.head.num_recs
358    
359    this.cur = --num
360    
361    if num < *this
362    {
363       if this.pageoff > num || this.pageoff + this.pagecount <= num
364       {
365          if count > this.pagelimit
366          {
367             if prevcur <= num
368             {
369                this.pageoff = num
370                this.pagecount = ?( count - num > this.pagelimit, 
371                                    this.pagelimit, count - num )
372             }
373             else
374             {
375                this.pagecount = ?( num + 1 > this.pagelimit, 
376                                    this.pagelimit, num + 1 )
377                this.pageoff = num + 1 - this.pagecount
378             }
379          }
380          else
381          {
382             this.pageoff = 0
383             this.pagecount = count
384          }
385 //         print("Pagecount=\(this.pagecount)\n")
386          uint  pos = this.head.header_len + 
387                      this.pageoff * this.head.record_width
388          // Загружаем данные
389          if this.dbffile.setpos( pos, $FILE_BEGIN ) != pos
390          {
391              return this.error( $ERRDBF_POS )
392          }
393          uint size = this.pagecount * this.head.record_width
394          this.page.use = 0         
395          if this.dbffile.read( this.page, size ) != size
396          {
397             return this.error( $ERRDBF_READ )
398          }
399 //         print("Read=\(size)\n")
400       }
401       this.ptr = this.page.ptr() + ( this.cur - this.pageoff ) * 
402                  this.head.record_width
403    }
404    else 
405    { 
406       this.cur = *this
407       this.ptr = this.eofbuf.ptr()
408    }
409    
410    return  1
411 }
412 
413 /*-----------------------------------------------------------------------------
414 * Id: dbf_top F3
415 * 
416 * Summary: Move to the first record.
417 *  
418 * Return: #lng/retf# 
419 *
420 -----------------------------------------------------------------------------*/
421 
422 method  uint dbf.top()
423 {
424    return this.go( 1 )
425 }
426 
427 /*-----------------------------------------------------------------------------
428 * Id: dbf_bottom F3
429 * 
430 * Summary: Move to the last record.
431 *  
432 * Return: #lng/retf# 
433 *
434 -----------------------------------------------------------------------------*/
435 
436 method  uint dbf.bottom()
437 {
438    return this.go( *this )
439 }
440 
441 /*-----------------------------------------------------------------------------
442 * Id: dbf_skip F2
443 * 
444 * Summary: Moving to another record. Move forward or backward for the 
445            specified number of records.
446 *  
447 * Params: step - The step of moving. If it is less than zero, the move will /
448                  be toward the beginning of the database. 
449 *
450 * Return: #lng/retf# 
451 *
452 -----------------------------------------------------------------------------*/
453 
454 method  uint dbf.skip( int step )
455 {
456    return this.go( this.cur + 1 + step )
457 }
458 /*
459 method  uint dbf.skip( uint step )
460 {
461    return this.go( this.cur + 1 + step )
462 }*/
463 
464 /*-----------------------------------------------------------------------------
465 * Id: dbf_recno F3
466 * 
467 * Summary: Getting the number of the current record.
468 *  
469 * Return: The number of the current record or 0 if the record is not defined. 
470 *
471 -----------------------------------------------------------------------------*/
472 
473 method  uint dbf.recno()
474 {
475    fordata fd 
476    if this.eof( fd ) : return 0
477    return this.cur + 1
478 }
479 
480 /*-----------------------------------------------------------------------------
481 * Id: dbf_bof F3
482 * 
483 * Summary: Determine is the current record is the first one.
484 *  
485 * Return: 1 is returned if the current record is the first one. 
486 *
487 -----------------------------------------------------------------------------*/
488 
489 method  uint dbf.bof()
490 {
491    return !this.cur && *this
492 }
493 
494 /*-----------------------------------------------------------------------------
495 * Id: dbf_isdel F3
496 * 
497 * Summary: Getting the record deletion mark. Determine if the current record 
498            is marked as deleted. 
499 *  
500 * Return: 1 is returned if the current record is marked as deleted.  
501 *
502 -----------------------------------------------------------------------------*/
503 
504 method  uint dbf.isdel()
505 {
506    return ( this.f_ptr( 1 ) - 1 )->byte == 0x2A
507 }
508 
509 /*-----------------------------------------------------------------------------
510 * Id: dbf_del F3
511 * 
512 * Summary: Set/clear the deletion mark for the current record. 
513 *  
514 * Return: #lng/retf#  
515 *
516 -----------------------------------------------------------------------------*/
517 
518 method  uint dbf.del
519 {
520    fordata fd
521    if this.eof( fd ) : return this.error( $ERRDBF_EOF )
522    
523    uint  pos = this.head.header_len + 
524                      this.cur * this.head.record_width   
525 
526    this.ptr->byte = ?( this.ptr->byte == '*', ' ', '*' )
527    //!this.page.write( this.dbffile, pos, this.ptr - this.page.data, 1 )
528    if !this.dbffile.writepos( pos, this.page.ptr() + this.ptr - this.page.data, 1 )
529    {
530       return this.error( $ERRDBF_WRITE )
531    }
532    return 1
533 }
534 
535 /*-----------------------------------------------------------------------------
536 * Id: dbf_append F3
537 * 
538 * Summary: Adding a record. The method adds a record to a database.  
539 *  
540 * Return: #lng/retf#  
541 *
542 -----------------------------------------------------------------------------*/
543 
544 method uint dbf.append()
545 {
546    str   val
547    uint  size 
548    
549    val.fillspacer( this.head.record_width )
550    val.appendch( 0x1A )
551    
552    uint  pos = this.dbffile.getsize( ) - 1 
553         //this.head.header_len + this.head.num_recs * this.head.record_width
554    
555 //   if !val->buf.write( this.dbffile, pos, 0, *val )
556    if !this.dbffile.writepos( pos, val->buf.ptr(), *val )
557    {
558       return this.error( $ERRDBF_WRITE )
559    }
560    this.dbffile.setpos( 4, $FILE_BEGIN )
561    //ReadFile( this.dbffile, &this.head.num_recs, 4, &size, 0 )
562    size = this.dbffile.read( &this.head.num_recs, 4 )
563    this.head.num_recs++
564    this.getdate()
565    this.dbffile.setpos( 1, $FILE_BEGIN )
566    // Записываем дату и количество записей
567    //WriteFile( this.dbffile, &this.head.yy, 7, &size, 0 )
568    size = this.dbffile.write( &this.head.yy, 7 ) 
569    this.pagecount = 1
570    this.cur = this.head.num_recs - 1
571    this.pageoff = this.cur
572    mcopy( this.page.ptr(), val.ptr(), *val )
573    this.page.use = *val
574    return 1
575 }
576 
577 func  uint  creatememo( str filename, uint sblock )
578 {
579    buf  btemp
580    str  fname 
581    
582    btemp.reserve( 512 )
583    mzero( btemp.ptr(), 512 )
584    btemp.use = 512
585    fname.fnameext( filename )
586    mcopy( btemp.ptr() + 8, fname.ptr(), *fname )
587    ( btemp.ptr() + 20 )->ushort = sblock
588    return btemp.write( fname.fsetext( filename, "dbt" ))   
589 }
590 
591 /*-----------------------------------------------------------------------------
592 * Id: dbf_empty F2
593 * 
594 * Summary: Creating an empty copy. The method creates the same, but empty
595            database.
596 *  
597 * Params: filename - The full name of the dbf file being created.  
598 *
599 * Return: #lng/retf# 
600 *
601 -----------------------------------------------------------------------------*/
602 
603 method uint dbf.empty( str outfile )
604 {
605    buf  btemp
606    dbf  dbftemp
607    
608    this.dbffile.setpos( 0, $FILE_BEGIN )
609    this.dbffile.read( btemp, this.head.header_len )
610    btemp += byte( 0x1A )
611    dbftemp.getdate()
612    mcopy( btemp.ptr() + 1, &dbftemp.head.yy, 3 )
613    ( btemp.ptr() + 4 )->uint = 0
614 
615    if !btemp.write( outfile )
616    {
617       return this.error( $ERRDBF_WRITE )
618    }
619    if this.head.version == 0x83 || this.head.version == 0x8B
620    {
621       if !creatememo( outfile, this.mblock )
622       {
623          return this.error( $ERRDBT_WRITE )
624       }
625    }
626    return 1
627 }
628 
629 method uint dbf.first( fordata fd )
630 {
631    this.top()
632    this.curfor = this.cur + 1
633    return &this.curfor
634 }
635 
636 method uint dbf.next( fordata fd )
637 {
638    this.skip( 1 )
639    this.curfor = this.cur + 1
640    return &this.curfor
641 }
642 
643 define {
644    DBF_PACKSIZE = 1002000
645    DBF_PACKUSE = 1000000
646 }
647 
648 /*-----------------------------------------------------------------------------
649 * Id: dbf_pack F2
650 * 
651 * Summary: Pack a database. The database is copied into a new file excluding
652            records marked as deleted.
653 *  
654 * Params: outfile - The name of the new dbf file.  
655 *
656 * Return: #lng/retf# 
657 *
658 -----------------------------------------------------------------------------*/
659 
660 method uint dbf.pack( str outfile )
661 {
662    if !this.empty( outfile ) : return 0
663 
664    dbf  newb
665    buf  dbfout dbtout
666    str  filler
667    uint nextmemo rw
668    
669    if !newb.open( outfile ) 
670    {
671       return this.error( newb.error )
672    }
673    newb.dbffile.setpos( newb.head.header_len, $FILE_BEGIN )
674    if newb.dbtfile 
675    {
676       newb.dbtfile.setpos( 0, $FILE_END )
677       dbtout.reserve( $DBF_PACKSIZE )
678       filler.fill( "\01A", this.mblock, $FILL_LEN )
679       nextmemo = 1
680    }
681    dbfout.reserve( $DBF_PACKSIZE )
682    foreach cur, this
683    {
684       if !this.isdel()
685       {
686          if newb.dbtfile 
687          {
688             uint i
689             fornum i = 0, *this.fields
690             {
691                if this.fields[ i ].ftype == $DBFF_MEMO &&
692                   this.f_int( i + 1 )                  
693                {
694                   str  val vmemo
695                   uint rsize
696                   uint bmust
697                   
698                   this.f_memo( val, i + 1 )
699                   
700                   rsize = *val + ?( this.head.version == 0x83, 2, 8 )
701                   rsize = rsize / this.mblock + ?( rsize % this.mblock, 1, 0 )
702                   bmust = rsize * this.mblock + *dbtout
703                   
704                   if this.head.version == 0x8B
705                   {
706                      dbtout += 'ff ff 08 00 \i4 \( *val + 8 )'
707                   }
708                   vmemo += nextmemo
709                   vmemo.fillspacel( this.fields[ i ].width )
710                   mcopy( this.f_ptr( i + 1 ), vmemo.ptr(), 
711                          this.fields[ i ].width )
712                          
713                   dbtout.append( val.ptr(), *val )
714                   dbtout.append( filler.ptr(), bmust - *dbtout )
715                   nextmemo += rsize
716                   
717                   if dbtout.use > $DBF_PACKUSE
718                   {
719                      if !newb.dbtfile.write( dbtout )
720                      {
721                         newb.close()
722                         return this.error( $ERRDBT_WRITE )
723                      }
724                      dbtout.use = 0
725                   }
726                }
727             }
728          }
729          dbfout.append( this.ptr, this.head.record_width )
730          newb.head.num_recs++
731          if dbfout.use > $DBF_PACKUSE
732          {
733             if !newb.dbffile.write( dbfout )
734             {
735                newb.close()
736                return this.error( $ERRDBF_WRITE )
737             }
738             dbfout.use = 0
739          }
740       }            
741    }
742    dbfout += byte( 0x1A )
743    if !newb.dbffile.write( dbfout )
744    {
745       newb.close()
746       return this.error( $ERRDBF_WRITE )
747    }
748    newb.dbffile.setpos( 4, $FILE_BEGIN )
749    //WriteFile( newb.dbffile, &newb.head.num_recs, 4, &rw, 0 )
750    newb.dbffile.write( &newb.head.num_recs, 4 ) 
751    
752    if newb.dbtfile 
753    {
754       if !newb.dbtfile.write( dbtout )
755       {
756          newb.close()
757          return this.error( $ERRDBT_WRITE )
758       }
759       newb.dbtfile.setpos( 0, $FILE_BEGIN )
760       //WriteFile( newb.dbtfile, &nextmemo, 4, &rw, 0 )
761       newb.dbtfile.write( &nextmemo, 4 )
762    }
763    newb.close()
764    return 1
765 }
766 
767 /*-----------------------------------------------------------------------------
768 ** Id: dbf_create F2
769 * 
770 * Summary: Create a dbf file and open it.
771 *  
772 * Params: filename - The name of the dbf file being created. 
773           fields - The description of database fields. The line containing /
774           the description of fields separated by a line break or ';' /
775           Field name,Field type,Width,Fractional part length for numbers /
776           The name of a field cannot be longer than 10 characters. /
777           Possible type fields: $$[dbftypes]
778           ver - Version. 0 for dBase III or 1 for dBase IV. 
779 *
780 * Return: #lng/retf# 
781 *
782 -----------------------------------------------------------------------------*/
783 
784 method  uint dbf.create( str filename, str fields, uint ver )
785 {
786    arrstr  field //of str
787    str  nfield
788    buf  out outfield
789    uint ismemo
790    dbf  dbftemp   
791    
792    fields.lines( field, 1, 0->arr )
793    
794    foreach cur, field
795    {
796       nfield += cur
797       nfield.appendch( ';' )
798    }   
799    field.clear()
800    nfield.split( field, ';', $SPLIT_NOSYS )
801    dbftemp.head.record_width = 1
802    foreach sf, field
803    {
804       arrstr     items //of str
805       dbfhfield  dfield
806       
807       sf.split( items, ',', $SPLIT_NOSYS )
808       if *items[0] > 10 : items[0].setlen( 10 )
809       mcopy( &dfield.name, items[0].ptr(), *items[0] )
810       
811       dfield.ftype = ((items[1])->str)[0]
812       dfield.width = uint( items[2] )
813       if !dfield.width : dfield.width = 1
814       switch dfield.ftype
815       {
816          case 'N','F'
817          {
818             if dfield.ftype == 'F' && !ver
819             {
820                dfield.ftype == 'N'            
821             }
822             if dfield.width > 20 : dfield.width = 20                        
823             dfield.decimals = uint( items[3] )
824             
825             if dfield.decimals >= dfield.width - 1
826             {
827                dfield.decimals = dfield.width - 1
828             } 
829          }
830          case 'M'
831          {
832             dfield.width = 10
833             ismemo = 1
834          }
835          case 'L'
836          {
837             dfield.width = 1
838          }
839          case 'D'
840          {
841             dfield.width = 8
842          }
843          default
844          {
845             dfield.ftype = $DBFF_CHAR
846          }
847       }
848       dbftemp.head.record_width += dfield.width
849       outfield.append( &dfield, sizeof( dbfhfield ))
850    }
851    dbftemp.getdate()
852    if ismemo
853    {
854       dbftemp.head.version = ?( ver, 0x8B, 0x83 )
855    }
856    else : dbftemp.head.version = 0x3
857    
858    dbftemp.head.header_len = sizeof( dbfhead ) + *outfield + 2
859   
860    out.copy( &dbftemp.head, sizeof( dbfhead ))
861    out += outfield
862    out += '0d 00 1a'   
863    if !out.write( filename )
864    {
865       return this.error( $ERRDBF_WRITE )
866    }
867    if ismemo && !creatememo( filename, 512 )
868    {
869       return this.error( $ERRDBT_WRITE )
870    }
871    return this.open( filename )
872 }
Edit