+//
+// sourcefile.cc
+//
+
+#include <sys/types.h> // open, mmap
+#include <sys/stat.h> // open
+#include <sys/mman.h> // mmap
+#include <limits.h> // INT_MAX
+#include <fcntl.h> // open
+#include <unistd.h> // close, stat
+#include <stdio.h> // fdopen
+#include <string.h> // strerror
+#include <errno.h> // errno
+#include <assert.h>
+#include <strstream.h>
+
+#include "string.hh"
+#include "proto.hh"
+#include "plist.hh"
+#include "main.hh" // find_file
+
+#include "sourcefile.hh"
+
+Source_file::Source_file( String &filename_str )
+{
+ data_caddr_m = 0;
+ fildes_i_m = 0;
+ size_off_m = 0;
+ name_str_m = filename_str;
+ istream_p_m = 0;
+
+ open();
+ map();
+ filename_str = name_str_m;
+}
+
+Source_file::~Source_file()
+{
+ delete istream_p_m;
+ istream_p_m = 0;
+ unmap();
+ close();
+}
+
+char const*
+Source_file::ch_c_l()
+{
+ return (char const*)data_caddr_m;
+}
+
+void
+Source_file::close()
+{
+ if ( fildes_i_m ) {
+ ::close( fildes_i_m );
+ fildes_i_m = 0;
+ }
+}
+
+String
+Source_file::error_str( char const* pos_ch_c_l )
+{
+ if ( !in_b( pos_ch_c_l ) )
+ return "";
+
+ char const* begin_ch_c_l = pos_ch_c_l;
+ char const* data_ch_c_l = ch_c_l();
+ while ( begin_ch_c_l > data_ch_c_l )
+ if ( *--begin_ch_c_l == '\n' ) {
+ begin_ch_c_l++;
+ break;
+ }
+
+ char const* end_ch_c_l = pos_ch_c_l;
+ while ( end_ch_c_l < data_ch_c_l + size_off_m )
+ if ( *end_ch_c_l++ == '\n' ) {
+ break;
+ }
+ end_ch_c_l--;
+
+// String( char const* p, int size ) is missing!?
+// String line_str( begin_ch_c_l, end_ch_c_l - begin_ch_c_l );
+
+ int size_i = end_ch_c_l - begin_ch_c_l;
+ char* ch_p = new char[ size_i ];
+ strncpy( ch_p, begin_ch_c_l, size_i );
+ ch_p[ size_i ] = 0;
+ String line_str( ch_p );
+ delete ch_p;
+
+ int error_col_i = 0;
+ char const* scan_ch_c_l = begin_ch_c_l;
+ while ( scan_ch_c_l < pos_ch_c_l )
+ if ( *scan_ch_c_l++ == '\t' )
+ error_col_i = ( error_col_i / 8 + 1 ) * 8;
+ else
+ error_col_i++;
+
+ String str = line_str.left( pos_ch_c_l - begin_ch_c_l )
+ + String( '\n' )
+ + String( ' ', error_col_i )
+ + line_str.mid( pos_ch_c_l - begin_ch_c_l + 1, INT_MAX ); // String::mid should take 0 arg..
+ return str;
+}
+
+bool
+Source_file::in_b( char const* pos_ch_c_l )
+{
+ return ( pos_ch_c_l >= ch_c_l() ) && ( pos_ch_c_l < ch_c_l() + size_off_m );
+}
+
+istream*
+Source_file::istream_l()
+{
+ assert( fildes_i_m );
+ if ( !istream_p_m )
+ istream_p_m = new istrstream( ch_c_l(), size_off_m );
+ return istream_p_m;
+}
+
+int
+Source_file::line_i( char const* pos_ch_c_l )
+{
+ if ( !in_b( pos_ch_c_l ) )
+ return 0;
+
+ int i = 0;
+ char const* scan_ch_c_l = ch_c_l();
+ while ( scan_ch_c_l < pos_ch_c_l )
+ if ( *scan_ch_c_l++ == '\n' )
+ i++;
+ return i;
+}
+
+void
+Source_file::map()
+{
+ data_caddr_m = (caddr_t)mmap( (void*)0, size_off_m, PROT_READ, MAP_FILE | MAP_SHARED, fildes_i_m, 0 );
+
+ if ( (int)data_caddr_m == -1 ) {
+ cerr << "lilypond: can't map: " << name_str_m << ": " << strerror( errno ) << endl;
+ assert( 0 );
+ }
+}
+
+String
+Source_file::name_str()
+{
+ return name_str_m;
+}
+
+void
+Source_file::open()
+{
+ name_str_m = find_file( name_str_m );
+ fildes_i_m = ::open( name_str_m, O_RDONLY );
+
+ if ( fildes_i_m == -1 ) {
+ cerr << "lilypond: can't open: " << name_str_m << ": " << strerror( errno ) << endl;
+ assert( 0 );
+ }
+
+ struct stat file_stat;
+ fstat( fildes_i_m, &file_stat );
+ size_off_m = file_stat.st_size;
+}
+
+void
+Source_file::unmap()
+{
+ if ( data_caddr_m ) {
+ munmap( data_caddr_m, size_off_m );
+ data_caddr_m = 0;
+ size_off_m = 0;
+ }
+}