Exemple #1
0
// Do a private, read-only map of the entirety of a history file with the given name. Returns true if successful. Returns the mapped memory region by reference.
static bool map_file(const wcstring &name, const char **out_map_start, size_t *out_map_len)
{
    bool result = false;
    wcstring filename = history_filename(name, L"");
    if (! filename.empty())
    {
        int fd;
		if((fd = wopen_cloexec(filename, O_RDONLY)) > 0)
		{
			off_t len = lseek( fd, 0, SEEK_END );
			if(len != (off_t)-1)
			{
				size_t mmap_length = (size_t)len;
				if(lseek(fd, 0, SEEK_SET) == 0)
				{
                    char *mmap_start;
					if ((mmap_start = (char *)mmap(0, mmap_length, PROT_READ, MAP_PRIVATE, fd, 0)) != MAP_FAILED)
					{
						result = true;
                        *out_map_start = mmap_start;
                        *out_map_len = mmap_length;
					}
				}
			}
			close( fd );
		}
    }
    return result;
}
Exemple #2
0
void history_t::clear(void) {
    scoped_lock locker(lock);
    new_items.clear();
    deleted_items.clear();
    unsaved_item_count = 0;
    old_item_offsets.clear();
    wcstring filename = history_filename(name, L"");
    if (! filename.empty())
        wunlink(filename);
    this->clear_file_state();
    
}
Exemple #3
0
static void
save_history (GtkWidget *combo) {
  gchar *host;
  GPtrArray *history;
  guint i;
  gchar *filename, *path;
  GString *content;
  GError *error = NULL;

  host = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (combo));

  history = saved_history ();
  for (i=0; i<history->len; i++)
    if (!g_strcmp0 (g_ptr_array_index (history, i), host))
      {
	g_ptr_array_remove_index (history, i);
	break;
      }

  g_ptr_array_add (history, host);
  content = g_string_new (NULL);

  for (i=0; i<history->len; i++)
    g_string_append_printf (content, "%s\n", (char *) g_ptr_array_index (history, i));

  filename = history_filename ();
  path = g_path_get_dirname (filename);
  g_mkdir_with_parents (path, 0755);

  g_file_set_contents (filename,
		       content->str,
		       -1,
		       &error);

  g_free (filename);
  g_free (path);
  g_ptr_array_free (history, TRUE);
  g_string_free (content, TRUE);

  if (error) {
    g_warning (_("Error while saving history file: %s"), error->message);
    g_error_free (error);
  }
}
Exemple #4
0
/**
   Load contents of the backing file to memory
*/
static void history_load( history_mode_t *m )
{
    int fd;
    int ok=0;

    void *context;
    wchar_t *filename;

    if( !m )
        return;

    m->has_loaded=1;

    signal_block();

    context = halloc( 0, 0 );
    filename = history_filename( context, m->name, 0 );

    if( filename )
    {
        if( ( fd = wopen( filename, O_RDONLY ) ) > 0 )
        {
            off_t len = lseek( fd, 0, SEEK_END );
            if( len != (off_t)-1)
            {
                m->mmap_length = (size_t)len;
                if( lseek( fd, 0, SEEK_SET ) == 0 )
                {
                    if( (m->mmap_start = mmap( 0, m->mmap_length, PROT_READ, MAP_PRIVATE, fd, 0 )) != MAP_FAILED )
                    {
                        ok = 1;
                        history_populate_from_mmap( m );
                    }
                }
            }
            close( fd );
        }
    }

    halloc_free( context );
    signal_unblock();
}
Exemple #5
0
static GPtrArray *
saved_history (void)
{
  gchar *filename, *file_contents = NULL;
  gchar **history_from_file = NULL, **list;
  gboolean success;
  gint len;
  GPtrArray *array;

  array = g_ptr_array_new_with_free_func (g_free);

  filename = history_filename ();
  success = g_file_get_contents (filename,
				 &file_contents,
				 NULL,
				 NULL);

  if (success)
    {
      history_from_file = g_strsplit (file_contents, "\n", 0);
      len = g_strv_length (history_from_file);
      if (len > 0 && strlen (history_from_file[len-1]) == 0)
	{
	  g_free (history_from_file[len-1]);
	  history_from_file[len-1] = NULL;
	}

      list = history_from_file;

      while (*list != NULL)
	g_ptr_array_add (array, *list++);
    }

  g_free (filename);
  g_free (file_contents);
  g_free (history_from_file);
  return array;
}
Exemple #6
0
/** Save the specified mode to file */
void history_t::save_internal()
{
    /* This must be called while locked */
    ASSERT_IS_LOCKED(lock);
    
    /* Nothing to do if there's no new items */
    if (new_items.empty() && deleted_items.empty())
        return;
        
    /* Compact our new items so we don't have duplicates */
    this->compact_new_items();
    
	bool ok = true;
    
    wcstring tmp_name = history_filename(name, L".tmp");    
	if( ! tmp_name.empty() )
	{        
        /* Make an LRU cache to save only the last N elements */
        history_lru_cache_t lru(HISTORY_SAVE_MAX);
        
        /* Insert old items in, from old to new. Merge them with our new items, inserting items with earlier timestamps first. */
        std::vector<history_item_t>::const_iterator new_item_iter = new_items.begin();
        
        /* Map in existing items (which may have changed out from underneath us, so don't trust our old mmap'd data) */
        const char *local_mmap_start = NULL;
        size_t local_mmap_size = 0;
        if (map_file(name, &local_mmap_start, &local_mmap_size)) {
            size_t cursor = 0;
            for (;;) {
                size_t offset = offset_of_next_item(local_mmap_start, local_mmap_size, &cursor, 0);
                /* If we get back -1, we're done */
                if (offset == (size_t)(-1))
                    break;

                /* Try decoding an old item */
                const history_item_t old_item = history_t::decode_item(local_mmap_start + offset, local_mmap_size - offset);
                if (old_item.empty() || is_deleted(old_item))
                {
//                    debug(0, L"Item is deleted : %s\n", old_item.str().c_str());
                    continue;
                }
                /* The old item may actually be more recent than our new item, if it came from another session. Insert all new items at the given index with an earlier timestamp. */
                for (; new_item_iter != new_items.end(); ++new_item_iter) {
                    if (new_item_iter->timestamp() < old_item.timestamp()) {
                        /* This "new item" is in fact older. */
                        lru.add_item(*new_item_iter);
                    } else {
                        /* The new item is not older. */
                        break;
                    }
                }
                
                /* Now add this old item */
                lru.add_item(old_item);
            }
            munmap((void *)local_mmap_start, local_mmap_size);
        }
        
        /* Insert any remaining new items */
        for (; new_item_iter != new_items.end(); ++new_item_iter)
        {
            lru.add_item(*new_item_iter);
        }
                
        signal_block();
    
        FILE *out;
		if( (out=wfopen( tmp_name, "w" ) ) )
		{
            /* Write them out */
            for (history_lru_cache_t::iterator iter = lru.begin(); iter != lru.end(); ++iter) {
                const history_lru_node_t *node = *iter;
                if (! node->write_yaml_to_file(out)) {
                    ok = false;
                    break;
                }
            }
            
			if( fclose( out ) || !ok )
			{
				/*
				  This message does not have high enough priority to
				  be shown by default.
				*/
				debug( 2, L"Error when writing history file" );
			}
			else
			{
                wcstring new_name = history_filename(name, wcstring());
				wrename(tmp_name, new_name);
			}
		}
        
        signal_unblock();
        
        /* Make sure we clear all nodes, since this doesn't happen automatically */
        lru.evict_all_nodes();
        
        /* We've saved everything, so we have no more unsaved items */
        unsaved_item_count = 0;
	}	

	if( ok )
	{
		/* Our history has been written to the file, so clear our state so we can re-reference the file. */
		this->clear_file_state();
	}
}
Exemple #7
0
/**
   Save the specified mode to file
*/
static void history_save_mode( void *n, history_mode_t *m )
{
    FILE *out;
    history_mode_t *on_disk;
    int i;
    int has_new=0;
    wchar_t *tmp_name;

    int ok = 1;

    /*
      First check if there are any new entries to save. If not, then
      we can just return
    */
    for( i=0; i<al_get_count(&m->item); i++ )
    {
        void *ptr = al_get( &m->item, i );
        has_new = item_is_new( m, ptr );
        if( has_new )
        {
            break;
        }
    }

    if( !has_new )
    {
        return;
    }

    signal_block();

    /*
      Set up on_disk variable to describe the current contents of the
      history file
    */
    on_disk = history_create_mode( m->name );
    history_load( on_disk );

    tmp_name = history_filename( on_disk, m->name, L".tmp" );

    if( tmp_name )
    {
        tmp_name = wcsdup(tmp_name );

        if( (out=wfopen( tmp_name, "w" ) ) )
        {
            hash_table_t mine;

            hash_init( &mine, &hash_item_func, &hash_item_cmp );

            for( i=0; i<al_get_count(&m->item); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    hash_put( &mine, item_get( m, ptr ), L"" );
                }
            }

            /*
              Re-save the old history
            */
            for( i=0; ok && (i<al_get_count(&on_disk->item)); i++ )
            {
                void *ptr = al_get( &on_disk->item, i );
                item_t *i = item_get( on_disk, ptr );
                if( !hash_get( &mine, i ) )
                {
                    if( item_write( out, on_disk, ptr ) == -1 )
                    {
                        ok = 0;
                        break;
                    }
                }

            }

            hash_destroy( &mine );

            /*
              Add our own items last
            */
            for( i=0; ok && (i<al_get_count(&m->item)); i++ )
            {
                void *ptr = al_get( &m->item, i );
                int is_new = item_is_new( m, ptr );
                if( is_new )
                {
                    if( item_write( out, m, ptr ) == -1 )
                    {
                        ok = 0;
                    }
                }
            }

            if( fclose( out ) || !ok )
            {
                /*
                  This message does not have high enough priority to
                  be shown by default.
                */
                debug( 2, L"Error when writing history file" );
            }
            else
            {
                wrename( tmp_name, history_filename( on_disk, m->name, 0 ) );
            }
        }
        free( tmp_name );
    }

    halloc_free( on_disk);

    if( ok )
    {

        /*
          Reset the history. The item_t entries created in this session
          are not lost or dropped, they are stored in the session_item
          hash table. On reload, they will be automatically inserted at
          the end of the history list.
        */

        if( m->mmap_start && (m->mmap_start != MAP_FAILED ) )
        {
            munmap( m->mmap_start, m->mmap_length );
        }

        al_truncate( &m->item, 0 );
        al_truncate( &m->used, 0 );
        m->pos = 0;
        m->has_loaded = 0;
        m->mmap_start=0;
        m->mmap_length=0;

        m->save_timestamp=time(0);
        m->new_count = 0;
    }

    signal_unblock();
}
Exemple #8
0
int repl() {
#ifdef HAVE_READLINE
    history_truncate_file(history_filename(), 1000);
    read_history(history_filename());
#endif // HAVE_READLINE


    // Eingabeschleife als REPL(read-eval-print loop) -> Eingabe, Verarbeitung, Ausgabe
    do {
        char *user_input = NULL;
        //////////////////////
        // read
        //////////////////////

#ifdef HAVE_READLINE
        user_input = readline("?: ");
        
        if (!user_input) break;
        strim(user_input);

        if (*user_input) add_history(user_input);
#else
        // Eingabepuffer als "String" mit Maximallänge
        user_input = calloc(LINE_BUFFER_SIZE, sizeof(char));
        printf("?: ");
        // Bei end-of-file oder Lesefehler gibt fgets NULL zurück
        // und das Programm soll beendet werden (analog zur Shell)
        //
        // break ist eigentlich nicht schön (=nicht im Struktogramm
        // abbildbar ;) ), dient aber hier der Klarheit, da einige
        // if entfallen können
        if (!fgets(user_input, LINE_BUFFER_SIZE, stdin)) break;
        strim(user_input);
#endif // HAVE_READLINE
        
        //////////////////////
        // eval
        //////////////////////
        
        // Abbruch durch User?
        if (strcmp(user_input, "\\quit") == 0) break;

        // 1. Parsen
        parse_context *p_ctx = start_parse(user_input);

        // 2. Baum traversieren
        if (parse(p_ctx) == 0) {
            eval_context *e_ctx = eval(p_ctx->ast_root);
            if (e_ctx == NULL) fprintf(stderr, "Fatal evaluation error.\n");
            if (e_ctx->success) {
                //////////////////////
                // print
                //////////////////////
                printf("-> %.50Lg\n", e_ctx->result);
            } else {
                print_eval_errors(e_ctx);
            }
            end_eval(e_ctx);
        } else {
            print_parse_errors(p_ctx);
        }
        // Aufräumen
        end_parse(p_ctx);
        free(user_input);
    } while (1); // loop....

#ifdef HAVE_READLINE
    write_history(history_filename());
#endif // HAVE_READLINE

    printf("End.\n");
    return 0;
}