Example #1
0
/*
 * GCI_migrateStreng converts a streng into a GCI_str. No further memory
 * allocation is done and it is STRONGLY forbidden to use GCI_strfree.
 * The return value shall be used for further operations.
 */
static const GCI_str *GCI_migrateStreng( GCI_str *str,
                                         const streng *string )
{
   if ( Str_len( string ) == RX_NO_STRING )
   {
      str->used = str->max = 0;
      str->val = NULL;
   }
   else if ( ( str->val = (char *) Str_val( string ) ) == NULL )
      str->used = str->max = 0;
   else
      str->used = str->max = (int) Str_len( string );

   return str;
}
Example #2
0
static void tracemsg( tsd_t *TSD )
{
   streng *message;
   const streng *msg;

   msg = errortext( TSD, 0, 3, 0, 0 );
   message = Str_makeTSD( 12 + Str_len( msg ) );
   Str_catstrTSD( message, "       +++ " );
   Str_catTSD( message, msg );
   printout( TSD, message );
   Free_stringTSD( message );
}
Example #3
0
void set_trace( tsd_t *TSD, const streng *setting )
{
   int cptr,error;
   tra_tsd_t *tt;

   if ( myisnumber( TSD, setting ) )
   {
      cptr = streng_to_int( TSD, setting, &error );
      if ( error )
         exiterror( ERR_INVALID_INTEGER, 7, tmpstr_of( TSD, setting ) );

      /*
       * If the number is positive, interactive tracing continues
       * for the supplied number of clauses, but no pausing is done.
       * If the number is negative, no trace output is inhibited
       * (as is the pauses) for the supplied number of clauses.
       * If the number is zero, this is the same as TRACE OFF
       */
      tt = (tra_tsd_t *)TSD->tra_tsd;
      if ( cptr == 0 )
      {
         TSD->currlevel->tracestat = 'O';
         TSD->systeminfo->interactive = 0;
         TSD->currlevel->traceint = 0;
         TSD->trace_stat = TSD->currlevel->tracestat;
      }
      else if ( cptr > 0 )
      {
         tt->quiet = 0;
         tt->intercount = cptr + 1;
      }
      else
      {
         tt->quiet = 1;
         tt->intercount = -cptr + 1;
      }
   }
   else
   {
      for ( cptr = 0; cptr < Str_len( setting ); cptr++ )
      {
         set_trace_char( TSD, setting->value[cptr] );
         if ( rx_isalpha( setting->value[cptr] ) )
            return;
      }
   }
}
Example #4
0
void doparse( tsd_t *TSD, const streng *source, cnodeptr thisptr, int caseless )
{
   int start=0,point=0,length=0, end=0, nextstart=0, solid=0 ;
   const streng *pattern=NULL ;
   const streng *xtmp=NULL ;
   char tch=' ' ;

   nextstart = 0 ;  /* too keep gcc from complaining about uninitialized */
   tch = TSD->currlevel->tracestat ;
   TSD->traceparse = ((tch=='I') || (tch=='R')) ;

recurse:
   /*
    * Cache the length of source, to avoid chasing ponters later.
    * Then make pattern default to the nullstring. The nullstring is
    * so muched used, that we don't want to allocate and deallocate
    * that all the time.
    */
   length = source->len ;
   pattern = &nullstring ;

   /*
    * There are two main cases, either this is the last pattern, in
    * which case we use the rest of the string. Or either there is
    * another pattern further out, in which case we have to find it.
    *
    */
   if (thisptr->p[1])
   {
      /*
       * We are not the last pattern, so first find the next pattern.
       * First cache the type, so we don't chase pointers. There are
       * two main choises: either seek for a string of some sort, or
       * use an offset of some sort.
       */
      solid = thisptr->p[1]->type ;
      if ((solid==X_TPL_MVE)||(solid==X_TPL_VAR))
      {
         /*
          * The pattern to search for is either a literal string, or it
          * is the value hold in a variable, set pattern to whatever
          * it might be. Pattern previous points to a statically
          * allocated variable, so don't bother to deallocate.
          */
         if (solid==X_TPL_MVE)
            pattern = thisptr->p[1]->name ;
         else
            pattern = handle_var( TSD, thisptr->p[1]->p[0] ) ;
         /*
          * Then we must find where in the source string pattern occurs.
          * If it don't occur there, we use the rest of the string, else
          * we use the string up to, but not including, the first char
          * that matched pattern. The 'bmstrstr' returns -1 for not
          * found, so correct that to rest-of-string. Also note that if
          * the pattern is the nullstring, it should match the end of
          * the string.
          */
         if (Str_len(pattern))
         {
            end = bmstrstr( source, start, pattern, caseless ) ;
            if (end<0)
            {
               point = end = length ;
               nextstart = end ;
            }
            else
            {
               nextstart = end + Str_len(pattern) ;
               point = end ;
            }
         }
         else
         {
            nextstart = point = end = length ;
         }

         /*
          * While 'end' marks how much to stuff into variables, nextstart
          * marks where to start the search for the next pattern (if
          * any). Remember that patterns "eat" up the part of the
          * parse string that they match.
          */
/*       nextstart = end + Str_len(pattern) ; */
      }
      else
      {
         /*
          * The next pattern to match is not a string to match, but a
          * positional movement, which will always be numeric, and if
          * it contains a sign, that should have been stripped off during
          * parsing. But a variable may be negative, too.
          */
         if (thisptr->p[1]->name)
            xtmp = thisptr->p[1]->name ;
         else
            xtmp = handle_var( TSD, thisptr->p[1]->p[0] ) ;

         end = streng_to_int( TSD, xtmp, &nextstart ) ;
         if (nextstart)
            exiterror( ERR_INVALID_INTEGER, 4, tmpstr_of( TSD, xtmp ) );

         /*
          * Depending on what sort of positional movement, do the right
          * thing.
          */
         if (solid==X_NEG_OFFS)
         {
            /*
             * If it is a movement backwards, the concept goes something
             * like move-it-foreward-to-a-backwards-position. That is,
             * the string to be parsed continues forwards to the end of
             * the sting and stops there, while the nextposition wraps
             * round to the start again.
             *
             * Anyway, parse all the rest of the sting in this parse, and
             * start on the specified position for the next parse.
             */
            start = point ;
            nextstart = point - end ;
            end = length ;
            if (nextstart > length)
               nextstart = length;
            if (nextstart < 0)
               nextstart = 0;

            point = nextstart ;
         }

         else if (solid==X_POS_OFFS)
         {
            /*
             * If the movement is forward, it is simpler, just move the
             * position of both the end of thisptr, and the start of next
             * to the right point.
             */
            start = point ;
            nextstart = point + end ;
            if (nextstart > length)
               nextstart = length;
            if (nextstart < 0)
               nextstart = 0;
            end = nextstart ;
            if (end<=start)
               end = length ;

            point = nextstart ;
         }

         else if (solid==X_ABS_OFFS)
         {
            /*
             * Same applies if the position is absolute, just move it.
             */
            end--;
            if (end > length)
               end = length;
            if (end < 0)        /* fixes bug 1107757 */
               end = 0;

            point = nextstart = end;
            if (end <= start)
               end = length;
         }
      }
   }
   else
      /*
       * We are last pattern to match, set the end of the string to
       * be parsed to the rest of the string available.
       */
      end = nextstart = length ;

   /*
    * Make sure that we didn't do anything illegal when we pushed
    * around on the value of end and nextstart. These should have been
    * set correctly in the statements above.
    */
   assert((0<=nextstart) && (nextstart<=length)) ;

   /*
    * Then handle end. It must be _after_ the last character in
    * the pattern, while it must not be larger than length.
    */
   assert((start <= end) && (end <= length)) ;

   /*
    * Now we have marked off an area to be parsed, so call 'doparse3' to
    * put values into the variables. Note that end is decremented,
    * since doparse3 expects ptr to last char to use, not ptr to char
    * after last char to use.
    */
   if (thisptr->p[0])
   {
      doparse3( TSD, thisptr->p[0], source->value+start, end-start);
      --end;
   }

   /*
    * Then make a tailrecursive call, or rather, simulate one. This
    * operation will take care of the next set of variables to be
    * parsed values into.
    */
   if ((thisptr=thisptr->p[2]) != NULL)
   {
      start = nextstart ;
      goto recurse ;
   }

}
Example #5
0
int intertrace( tsd_t *TSD )
{
   streng *str=NULL;
   int retvalue1,rc;
   tra_tsd_t *tt;

   tt = (tra_tsd_t *)TSD->tra_tsd;

   if ( tt->intercount )
   {
      tt->intercount -= 1;
      if ( tt->intercount == 0 )
      {
         tt->quiet = 0;
         tt->traceflag = 0;
      }
      else
         return 0;
   }

   if ( tt->traceflag )
      return 0;

   if ( tt->notnow == 1 )
   {
      tt->notnow = 2;
      return 0;
   }
   else if ( tt->notnow == 2 )
   {
      tt->notnow = 0;
      tracemsg( TSD );
   }
   tt->traceflag = 1;
   retvalue1 = -1;

   for ( ; retvalue1 < 0; )
   {
      rc = HOOK_GO_ON;
      if ( TSD->systeminfo->hooks & HOOK_MASK( HOOK_TRCIN ) )
         rc = hookup_input( TSD, HOOK_TRCIN, &str );

      if ( rc == HOOK_GO_ON )
         str = readkbdline( TSD );

      if ( str->len == 0 )
      {
         tt->traceflag = 0;
         retvalue1 = 0;
      }

      if ( ( Str_len( str ) == 1 ) && (str->value[0] == '=' ) )
      {
         tt->traceflag = 0;
         retvalue1 = 1;
      }
      else if ( str->len )
      {
         dointerpret( TSD, str );
         if ( !TSD->systeminfo->interactive )
         {
            tt->intercount = tt->quiet = 0;
            return 0;
         }
         if ( tt->intercount )
         {
            if ( tt->quiet )
               tt->traceflag = 1;
            else
               tt->traceflag = 0;
            return 0;
         }
      }
   }

   return retvalue1;
}
Example #6
0
PFN wrapper_get_addr( const tsd_t *TSD, const struct library *lptr, const streng *name )
{
   PFN addr;
   handle_type handle=(handle_type)lptr->handle;
   char *funcname ;
#if defined(DYNAMIC_WIN32)
   char LoadError[256];
   char *entryname;
   unsigned u;
   char c;
#endif
#if defined(DYNAMIC_OS2)
   char *entryname;
   unsigned u;
   char c;
   ULONG ordinal;
   APIRET rc=0L;
#endif
#if defined(DYNAMIC_BEOS)
   status_t rc=0;
#endif
#if defined(DYNAMIC_STATIC)
   int rc=0;
#endif
#if defined(MODULES_NEED_USCORE)
   streng *us_func;
#endif

   funcname = str_of( TSD, name ) ;

#if defined(DYNAMIC_STATIC)
   rc = static_dlsym( handle, funcname,(void **)&addr );
   if ( rc != 0 )
   {
      char buf[150];
      sprintf(buf,"static_dlsym() failed with %d looking for %s", rc, funcname );
      set_err_message(TSD,  buf, "" ) ;
      addr = NULL;
   }
#elif defined(DYNAMIC_DLOPEN)
# if defined(MODULES_NEED_USCORE)
   /*
    * Some platforms need to have an underscore prepended to the function
    * name to be found in a loadable module.
    */
   FreeTSD( funcname );
   us_func = Str_makeTSD( Str_len( name ) + 1 );
   memcpy( us_func->value, "_", 1 );
   us_func->len = 1;
   Str_catTSD( us_func, name );
   funcname = str_of( TSD, us_func );
   Free_stringTSD( us_func );
# endif
   /*
    * Note, the following assignment is not allowed by ANSI, but SVR4.2
    * includes it as an example, so it is probably safe in this context
    */
   addr = (PFN)(dlsym( handle, funcname )) ;

   /* deal with, eg 'SysLoadFuncs' when the function is 'sysloadfuncs' or 'SYSLOADFUNCS' */
   if (addr == NULL)
   {
      mem_upper( funcname, strlen( funcname ) );
      addr = (PFN)(dlsym( handle, funcname )) ;

      if (addr == NULL)
      {
         mem_lower( funcname, strlen( funcname ) );
         addr = (PFN)(dlsym( handle, funcname )) ;

         if (addr==NULL)
            set_err_message( TSD,  "dlsym() failed: ", dlerror() );
      }
   }

#elif defined(DYNAMIC_HPSHLOAD)
   {
      long eaddr ;
      int rc;

      if (rc = shl_findsym( &handle, funcname, TYPE_PROCEDURE, &eaddr ))
      {
         mem_upper( funcname, strlen( funcname ) );
         if (rc = shl_findsym( &handle, funcname, TYPE_PROCEDURE, &eaddr ))
         {
            mem_lower( funcname, strlen( funcname ) );
            if (rc = shl_findsym( &handle, funcname, TYPE_PROCEDURE, &eaddr ))
            {
               addr = NULL ;
               set_err_message( TSD,  "shl_findsym() failed: ", strerror(errno) );
            }
         }
      }

      if (!rc)
         addr = (PFN)eaddr ;
   }

#elif defined(DYNAMIC_AIXLOAD)
   addr = (PFN)handle ;

#elif defined(DYNAMIC_OS2)
   if ( ( sscanf( funcname, "#%u%c", &u, &c ) == 1 ) && ( u != 0 ) )
   {
      ordinal = (ULONG) u;
      entryname = NULL;
   }
   else
   {
      ordinal = 0L;
      entryname = funcname;
   }
   rc = DosQueryProcAddr(handle,ordinal,entryname,&addr);
   if (rc)
   {
      char buf[150];
      sprintf(buf,"DosQueryProcAddr() failed with %lu looking for %.90s", (long) rc, funcname );
      set_err_message(TSD, buf, "" ) ;
   }

#elif defined(DYNAMIC_WIN32)
   /*  13/12/1999 JH moved cast, (HMODULE), from second parm to first.  Removed
    * a compiler warning,
    */
   if ( ( sscanf( funcname, "#%u%c", &u, &c ) == 1 ) && ( u != 0 ) &&
                                                             ( u <= 0xFFFF ) )
      entryname = (char *) u;
   else
      entryname = funcname;

   addr = (PFN) GetProcAddress( (HMODULE) handle, entryname );

   if ( ( addr == NULL ) && ( funcname == entryname ) )
   {
      strlwr(funcname);
      addr = (PFN)GetProcAddress((HMODULE)handle,funcname);

      if (addr == NULL)
      {
         strupr(funcname);
         addr = (PFN)GetProcAddress((HMODULE)handle, funcname);
      }
   }
   if (addr == NULL)
   {
      char buf[150];
      FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL );
      sprintf( buf, "Failed to find \"%s\" in external library: GetProcAddress() failed: ", funcname );
      set_err_message( TSD, buf, LoadError );
   }

#elif defined(DYNAMIC_BEOS)
   rc = get_image_symbol(handle,funcname,B_SYMBOL_TYPE_TEXT,(void **)&addr);
   if (rc == B_BAD_IMAGE_ID)
   {
      char buf[150];
      sprintf(buf,"get_image_symbol() failed with %d looking for %s", rc, funcname );
      set_err_message( TSD,  buf, "" );
      addr = NULL;
   }

#elif defined(DYNAMIC_SKYOS)
fprintf(stderr,"%s %d:\n",__FILE__,__LINE__);
   addr = (PFN)GetDllFunction( handle, funcname );
   if ( addr == NULL )
   {
      char buf[150];
      sprintf(buf,"GetDllFunction() failed looking for %s", funcname );
      set_err_message( TSD,  buf, "" );
      addr = NULL;
   }
fprintf(stderr,"%s %d:\n",__FILE__,__LINE__);
#endif

   FreeTSD( funcname );

   if (addr)
      return (PFN)addr ;
   else
      return NULL ;
}
Example #7
0
void *wrapper_load( const tsd_t *TSD, const streng *module )
{
   handle_type handle=(handle_type)NULL ;
#if defined(DYNAMIC_OS2)
   CHAR LoadError[256];
   APIRET rc=0L;
#endif
#if defined(DYNAMIC_WIN32)
   char LoadError[256];
#endif
#if defined(DYNAMIC_HPSHLOAD) || defined(DYNAMIC_BEOS)
   char buf[1024];
#endif
#ifdef DYNAMIC_SKYOS
   sDllHandle tmp_handle;
#endif
   char *file_name, *module_name, *udpart, *postfix, *orig_module;

   orig_module = str_ofTSD( module );
#ifdef DYNLIBLEN
   module_name = (char *)MallocTSD( Str_len( module ) + strlen(DYNLIBPRE) +
                                    strlen(DYNLIBPST) + 1 ) ;
   strcpy(module_name, DYNLIBPRE );
   udpart = module_name + strlen(DYNLIBPRE);
   memcpy(udpart, module->value, Str_len(module) );
   strcpy(udpart + Str_len(module), DYNLIBPST );
   file_name = module_name;
   postfix = udpart + Str_len(module);
# if defined(DYNAMIC_HPSHLOAD)
   file_name = buf;
# endif
#else
   file_name = module_name = str_ofTSD(module);
#endif

#if defined(DYNAMIC_STATIC)
   handle = static_dlopen( file_name );
   if (handle == NULL)
   {
      set_err_message(TSD, "static_dlopen() failed loading:", file_name );
      handle = (handle_type)NULL;
   }
#elif defined(DYNAMIC_DLOPEN)
   /*
    * Try and load the module name exactly as specified (before wrapping it
    * in lib*.so)
    */
   handle = dlopen( orig_module, RTLD_LAZY ) ;
   if (handle == NULL)
   {
      handle = dlopen( file_name, RTLD_LAZY ) ;
      /* deal with incorrect case in call */
      if (handle == NULL)
      {
         mem_lower( udpart, Str_len( module ) );
         handle = dlopen(module_name, RTLD_LAZY);

         if (handle == NULL)
         {
            mem_upper( udpart, Str_len( module ) );
            handle = dlopen(module_name, RTLD_LAZY);
            /*
             * Reset the original module portion of the filename to be
             * searched again so that any error message returned uses the
             * original module name
             */
            if ( handle == NULL )
            {
               memcpy(udpart, module->value, Str_len(module) );
               handle = dlopen(module_name, RTLD_LAZY);
            }
         }
      }
   }

   /* or maybe it's just not there */
   if (handle==NULL)
   {
      char *msg=NULL;
      msg = dlerror();
      if (msg)
         set_err_message(TSD, "dlopen() failed: ", msg ) ;
      else
         set_err_message(TSD, "", "");
   }
#elif defined(DYNAMIC_HPSHLOAD)
   /*
    * Try and load the module name exactly as specified (before wrapping it
    * in lib*.sl)
    */
   find_shared_library( TSD, orig_module, "SHLIB_PATH", buf );
   handle = shl_load( file_name, BIND_IMMEDIATE | DYNAMIC_PATH, 0L ) ;
   if (handle == NULL)
   {
      find_shared_library(TSD,module_name,"SHLIB_PATH",buf);
      handle = shl_load( file_name, BIND_IMMEDIATE | DYNAMIC_PATH, 0L ) ;
      if (handle == NULL)
      {
         mem_lower( udpart, Str_len( module ) );
         find_shared_library( TSD, module_name, "SHLIB_PATH", buf );
         handle = shl_load( file_name, BIND_IMMEDIATE | DYNAMIC_PATH ,0L ) ;

         if (handle == NULL)
         {
            mem_upper( udpart, Str_len( module ) );
            find_shared_library( TSD, module_name, "SHLIB_PATH", buf );
            handle = shl_load( file_name, BIND_IMMEDIATE | DYNAMIC_PATH ,0L ) ;
         }
      }
   }

   if (handle==NULL)
      set_err_message(TSD,  "shl_load() failed: ", strerror(errno)) ;
#elif defined(DYNAMIC_AIXLOAD)
   /*
    * Try and load the module name exactly as specified (before wrapping it
    * in lib*.a)
    */
   handle = load( orig_module, 1, NULL ) ;
   if ( handle == NULL )
   {
      handle = load( file_name, 1, NULL ) ;
      if ( handle == NULL )
      {
         set_err_message(TSD,  "load() failed: ", strerror( errno )) ;
      }
      else
      {
         int rc=loadbind( 0, (void *)wrapper_dummy_for_aix, (void *)handle ) ;
         if (rc)
         {
            handle = NULL ;
            set_err_message(TSD,  "loadbind() failed: ", strerror( errno )) ;
         }
      }
#elif defined(DYNAMIC_OS2)
   rc = DosLoadModule( LoadError, sizeof(LoadError),
                       file_name, &handle ) ;
   if (rc)
   {
      set_err_message(TSD, "DosLoadModule() unable to load DLL: ", LoadError);
      handle = (handle_type)NULL;
   }
#elif defined(DYNAMIC_WIN32)
   handle = LoadLibrary( file_name ) ;
   if (handle==NULL)
   {
      char buf[150];
      FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), MAKELANGID( LANG_NEUTRAL, SUBLANG_DEFAULT), LoadError, 256, NULL ) ;
      sprintf( buf, "Failed to load \"%s\" library: LoadLibrary() failed: ", file_name );
      set_err_message(TSD, buf, LoadError);
   }
#elif defined(DYNAMIC_BEOS)
   handle = load_add_on( orig_module );
   if (handle < B_NO_ERROR)
   {
      handle = load_add_on( file_name );
      if (handle < B_NO_ERROR)
      {
         sprintf( buf, "load_add_on() failed loading \"%s\" with error:", file_name );
         set_err_message(TSD, buf, strerror( handle ) );
         handle = (handle_type)NULL;
      }
   }
#elif defined(DYNAMIC_SKYOS)
   handle = (handle_type)MallocTSD( sizeof( sDllHandle ) );
   /*
    * Don't try and load the module without the trimmings.
    * You get a binary popup window otherwise!
    */
fprintf(stderr,"%s %d %x %s:\n",__FILE__,__LINE__,handle,file_name);
   if ( DllLoad( file_name, &tmp_handle ) != 0 )
   {
      char buf[150];
      sprintf( buf, "Failed to load \"%s\" library: DllLoad() failed: ", file_name );
      set_err_message(TSD, buf, strerror( errno ) );
      FreeTSD( handle );
      handle = (handle_type)NULL;
   }
fprintf(stderr,"%s %d:\n",__FILE__,__LINE__);
   memcpy( handle, &tmp_handle, sizeof( sDllHandle ) );
fprintf(stderr,"%s %d:\n",__FILE__,__LINE__);
#endif

   FreeTSD( module_name );
   FreeTSD( orig_module );

   return (void *)handle ;
}

void wrapper_unload( const tsd_t *TSD, void *libhandle )
{
#ifdef DYNAMIC_STATIC

   libhandle = libhandle;

#elif defined(DYNAMIC_DLOPEN)

   dlclose((handle_type) libhandle);

#elif defined(DYNAMIC_HPSHLOAD)

   shl_unload((handle_type) libhandle);

#elif defined(DYNAMIC_AIXLOAD)

   unload((handle_type) libhandle);

#elif defined(DYNAMIC_OS2)

   DosFreeModule((handle_type) libhandle);

#elif defined(DYNAMIC_WIN32)

   FreeLibrary((handle_type) libhandle);

#elif defined(DYNAMIC_BEOS)

   unload_add_on((handle_type) libhandle);

#elif defined(DYNAMIC_SKYOS)

fprintf(stderr,"%s %d:\n",__FILE__,__LINE__);
   FreeTSD( libhandle );

#else
   (libhandle = libhandle);
#endif
}
Example #8
0
/* get the next line of input, normalize end of line termination (i.e. convert
   "\r", "\r\n" and "\n\r" to "\n"
   Calls the new_line_cb call back and returns the pointer to the null-terminated 
   text data in Str *line, including the final "\n".
   Returns NULL on end of file. */
char *SrcFile_getline( SrcFile *self )
{
    int c, c1;
    bool found_newline;
    char *line;

    /* clear result string */
    Str_clear( self->line );

    /* check for line stack */
    if ( ! List_empty( self->line_stack ) )
    {
        line = List_pop( self->line_stack );

        /* we own the string now and need to release memory */
		Str_set( self->line, line );
        m_free( line );

        /* dont increment line number as we are still on same file input line */
        return Str_data(self->line);
    }

    /* check for EOF condition */
    if ( self->file == NULL )
        return NULL;

    /* read characters */
    found_newline = false;
    while ( ! found_newline && ( c = getc( self->file ) ) != EOF )
    {
        switch ( c )
        {
        case '\r':
        case '\n':
            c1 = getc( self->file );

            if ( ( c1 == '\r' || c1 == '\n' ) &&	/* next char also newline */
                    c1 != c )						/* "\r\n" or "\n\r" */
            {
                /* c1 will be discarded */
            }
            else								/* not composite newline - push back */
            {
                if ( c1 != EOF )
                {
                    ungetc( c1, self->file );	/* push back except EOF */
                }
            }

            /* normalize newline and fall through to default */
            found_newline = true;
            c = '\n';

        default:
            Str_append_char( self->line, c );
        }
    }

    /* terminate string if needed */
    if ( Str_len(self->line) > 0 && ! found_newline )
        Str_append_char( self->line, '\n' );

	/* signal new line, even empty one, to show end line in list */
    self->line_nr += self->line_inc;
	call_new_line_cb( self->line_filename, self->line_nr, Str_data(self->line) );

	/* check for end of file
	   even if EOF found, we need to return any chars in line first */
    if ( Str_len(self->line) > 0 )		
    {
        return Str_data(self->line);
    }
    else
    {
        /* EOF - close file */
        xfclose( self->file );				/* close input */
        self->file = NULL;

//		call_new_line_cb( NULL, 0, NULL );
        return NULL;						/* EOF */
    }
}