This file is indexed.

/usr/share/octave/packages/io-2.4.5/dbfwrite.m is in octave-io 2.4.5-1.

This file is owned by root:root, with mode 0o644.

The actual contents of the file can be viewed below.

  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
## Copyright (C) 2015-2016 Philip Nienhuis
## 
## This program is free software; you can redistribute it and/or modify it
## under the terms of the GNU General Public License as published by
## the Free Software Foundation; either version 3 of the License, or
## (at your option) any later version.
## 
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
## 
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*- 
## @deftypefn  {Function File} [@var{status}] = dbfwrite (@var{fname}, @var{data})
## Write data in a cell array to a dbf (xBase) file, provisionally dBase III+.
##
## @var{fname} must be a valid file name, optionally with '.dbf' suffix.
## @var{data} should be a cell array of which the top row contains column
## names (character strings). Each column must contain only one class of data,
## except of course the top entry (the column header).
## Value type that can be written are character (text sring), numeric
## (integer and float, the latter with 6 decimal places), and logical.
## 
## Ouput argument @var{status} is 1 if the file was written successfully, 0
## otherwise.
##
## Provisionally only dBase v. III+ files can be written without memos.
##
## @seealso{dbfread}
## @end deftypefn

## Author: Philip Nienhuis <prnienhuis@users.sf.net>
## Created: 2014-12-24

function [status] = dbfwrite (fname, data)

  status = 0;
  ## Input validation
  if (! ischar (fname))
    error ("dbfwrite: file name expected for argument #1\n");
  elseif (! iscell (data))
    error ("dbfwrite: cell array expected for argument #2\n");
  elseif (! iscellstr (data (1, :)))
    error ("dbfwrite: column header titles (text) expected on first row of data\n");
  endif
  ## Column headers length cannot exceed 10 characters
  toolong = [];
  for ii=1:size (data, 2)
    title = data{1, ii};
    if (length (title) > 10)
      toolong = [ toolong, ii ];
      data(1, ii) = title(1:10);
    endif
  endfor
  if (! isempty (toolong))
    ## Truncate headers if required and check for uniqueness
    warning ("dbfwrite: one or more column header(s) > 10 characters - truncated\n");
    fmt = [repmat(sprintf ("%d "), 1, numel (toolong))(:)];
    printf ("Applies to columns %s\n", sprintf (fmt, toolong));
    if (numel (unique (data(1, :))) < numel (data(1, :)))
      error ("dbfwrite: column headers aren't unique - please fix data\n");
    endif
  endif

  ## Assess nr of records
  ## Data contains header row. Data toprow = 2
  nrecs = size (data, 1) - 1;
  tr = 2;

  ## Check file name
  [pth, fnm, ext] = fileparts (fname);
  if (isempty (ext))
    fname = [fname ".dbf"];
  elseif (! strcmpi (ext, ".dbf"))
    error ("dbfwrite: file name should have a '.dbf' suffix\n");
  endif
  ## Try to open file
  fid = fopen (fname, "w+");
  if (fid < 0)
    error ("dbfwrite: could not open file %s\n", fname);
  endif

  ## Start writing header
  ## Provisionally assume dbase III+ w/o memos
  fwrite (fid, 3, "uint8");
  upd = datevec (date);
  fwrite (fid, upd(1) - 1900, "uint8");
  fwrite (fid, upd(2), "uint8");
  fwrite (fid, upd(3), "uint8");
  fwrite (fid, nrecs, "uint32");
  ## The next two uint16 fields are to be written later, just fill temporarily
  pos_lhdr = ftell (fid);
  fwrite (fid, 0, "uint32");
  ## Another place holder, write enough to allow next fseek to succeed
  fwrite (fid, uint32 (zeros (1, 7)), "uint32");

  ## Write record descriptors
  nfields  = size (data, 2);
  fldtyp   = "";
  fldlngs  = {};
  reclen   = 1;                                             ## "Erased" byte first
  fseek (fid, 32, "bof");
  for ii=1:nfields
    decpl = 0;
    recdesc = sprintf ("%d", uint32 (zeros (1, 8)));
    recdesc(1:10) = strjust (sprintf ("%10s", data{1, ii}), "left"); ## Field name
    if (isnumeric ([data{tr:end, ii}]))
      if (isinteger ([data{tr:end, ii}]) ||
        all ([data{tr:end, ii}] - floor([data{tr:end, ii}]) < eps))
        ftype = "N";
        decpl = 0;
      else
        ftype = "F";
        ## ML compatibility for .dbf/.shp file: 6 decimal places
        decpl = 6;
      endif
      fldlng = 20;
    elseif (ischar ([data{tr:end, ii}]))
      ftype = "C";
      fldlng = max (cellfun (@(x) length(x), data(tr:end))) + 1;
    elseif (islogical ([data{tr:end, ii}]))
      ftype = "L";
      fldlng = 1;
    endif
    recdesc(12) = ftype;                                    ## Field type
    fldtyp      = [ fldtyp ftype ];
    recdesc(17) = uint8 (fldlng);                           ## Field length
    recdesc(18) = uint8 (decpl);                            ## Decimal places
    recdesc(32) = "\0";                                     ## Fill to byte# 32
    fwrite (fid, recdesc, "char");
    reclen += fldlng;
    fldlngs = [ fldlngs; sprintf("%d", fldlng) ];
  endfor
  ## Write header record terminator
  fwrite (fid, 13, "uint8");
  ## Remember position
  fpos_data = ftell (fid);
  ## Write missing data in header
  fseek (fid, pos_lhdr, "bof");
  fwrite (fid, fpos_data, "uint16");
  fwrite (fid, reclen, "uint16");

  ## Write data2
  fseek (fid, fpos_data, "bof");
  ## FIXME replace by vectorized code (num2str etc) & concatenating columns
  ##       for speeding up
  for ii=tr:nrecs+tr-1
    ## Write "erased" byte
    fwrite (fid, "\0", "uint8");
    for jj=1:nfields
      switch fldtyp(jj)
        case "C"
          txt = sprintf (["%" fldlngs{jj} "s"], data{ii, jj});
        case "N"
          txt = sprintf (["%" fldlngs{jj} "d"], data{ii, jj});
        case "L"
          if (data{ii, jj})
            txt = "Y";
          else
            txt = "N";
          endif
        case "F"
          txt = sprintf (["%" fldlngs{jj} "f"], data{ii, jj});
        case "D"
          % txt = sprintf (["%" fldlngs{jj} "s"], data{ii, jj});
        otherwise
      endswitch
      fwrite (fid, txt, "char");
    endfor
  endfor
  
  ## Close file
  fclose (fid);
  status = 1;

endfunction