xaizek / hstr (License: Apachev2) (since 2018-12-07)
Bash and Zsh shell history suggest box - easily view, navigate, search and manage your command history.
<root> / src / hstr_favorites.c (be966cfcf7d7c27f0a1f936582c44470c6ead9b8) (5,693B) (mode 100644) [raw]
/*
 ============================================================================
 Name        : hstr_favorites.c
 Author      : martin.dvorak@midforger.com
 Copyright   : Apache 2.0
 Description : Favorite commands.
 ============================================================================
*/

#include <stdio.h>
#include <string.h>
#include <unistd.h>

#include "include/hstr_favorites.h"
#include "include/hstr_utils.h"

#define FAVORITE_SEGMENT_SIZE 10

void favorites_init(FavoriteItems *favorites)
{
    favorites->items=NULL;
    favorites->count=0;
    favorites->loaded=false;
    favorites->set=malloc(sizeof(HashSet));
}

void favorites_show(FavoriteItems *favorites)
{
    printf("\n\nFavorites (%d):", favorites->count);
    if(favorites->count) {
        int i;
        for(i=0;i<favorites->count;i++) {
            printf("\n%s",favorites->items[i]);
        }
    }
    printf("\n");
}

char* favorites_get_filename()
{
    char *home = getenv(ENV_VAR_HOME);
    char *fileName = (char*) malloc(strlen(home) + 1 + strlen(FILE_HH_RC) + 1);
    strcpy(fileName, home);
    strcat(fileName, "/");
    strcat(fileName, FILE_HH_RC);
    return fileName;
}

void favorites_get(FavoriteItems *favorites)
{
    if(!favorites->loaded) {
        char* fileName = favorites_get_filename();
        char *file_contents=NULL;
        if(access(fileName, F_OK) != -1) {
            long input_file_size;

            FILE *input_file = fopen(fileName, "rb");
            fseek(input_file, 0, SEEK_END);
            input_file_size = ftell(input_file);
            rewind(input_file);
            file_contents = malloc((input_file_size + 1) * (sizeof(char)));
            if(fread(file_contents, sizeof(char), input_file_size, input_file)==-1) {
                exit(EXIT_FAILURE);
            }
            fclose(input_file);
            file_contents[input_file_size] = 0;

            if(file_contents && strlen(file_contents)) {
                favorites->count = 0;
                char *p=strchr(file_contents,'\n');
                while (p!=NULL) {
                    favorites->count++;
                    p=strchr(p+1,'\n');
                }

                favorites->items = malloc(sizeof(char*) * favorites->count);
                favorites->count=0;
                char *pb=file_contents, *pe, *s;
                pe=strchr(file_contents, '\n');
                HashSet set;
                hashset_init(&set);
                while(pe!=NULL) {
                    *pe=0;
                    if(!hashset_contains(&set,pb)) {
                        s=hstr_strdup(pb);
                        favorites->items[favorites->count++]=s;
                        hashset_add(&set,s);
                    }
                    pb=pe+1;
                    pe=strchr(pb, '\n');
                }
                free(file_contents);
            }
        } else {
            // favorites file not found > favorites don't exist yet
            favorites->loaded=true;
            return;
        }
        free(fileName);
    }
}

void favorites_save(FavoriteItems *favorites)
{
    char *fileName=favorites_get_filename();

    if(favorites->count) {
        FILE *output_file = fopen(fileName, "wb");
        rewind(output_file);
        int i;
        for(i=0; i<favorites->count; i++) {
            if(fwrite(favorites->items[i], sizeof(char), strlen(favorites->items[i]), output_file)==-1) {
                exit(EXIT_FAILURE);
            }
            if(fwrite("\n", sizeof(char), strlen("\n"), output_file)==-1) {
                exit(EXIT_FAILURE);
            }
        }
        fclose(output_file);
    } else {
        if(access(fileName, F_OK) != -1) {
            FILE *output_file = fopen(fileName, "wb");
            fclose(output_file);
        }
    }
    free(fileName);
}

void favorites_add(FavoriteItems *favorites, char *newFavorite)
{
    if(favorites->count) {
        favorites->items=realloc(favorites->items, sizeof(char *) * ++favorites->count);
        favorites->items[favorites->count-1]=hstr_strdup(newFavorite);
        favorites_choose(favorites, newFavorite);
    } else {
        favorites->items=malloc(sizeof(char*));
        favorites->items[0]=hstr_strdup(newFavorite);
        favorites->count=1;
    }

    favorites_save(favorites);
}

void favorites_choose(FavoriteItems *favorites, char *choice)
{
    if(favorites->count && choice) {
        int r;
        char *b=NULL, *next;
        for(r=0; r<favorites->count; r++) {
            if(!strcmp(favorites->items[r],choice)) {
                favorites->items[0]=favorites->items[r];
                if(b) {
                    favorites->items[r]=b;
                }
                favorites_save(favorites);
                return;
            }
            next=favorites->items[r];
            favorites->items[r]=b;
            b=next;
        }
    }
}

bool favorites_remove(FavoriteItems *favorites, char *almostDead)
{
    if(favorites->count) {
        int r, w, count;
        count=favorites->count;
        for(r=0, w=0; r<count; r++) {
            if(!strcmp(favorites->items[r], almostDead)) {
                favorites->count--;
            } else {
                if(w<r) {
                    favorites->items[w]=favorites->items[r];
                }
                w++;
            }
        }
        favorites_save(favorites);
        return true;
    } else {
        return false;
    }
}

void favorites_destroy(FavoriteItems *favorites)
{
    if(favorites) {
        int i;
        for(i=0; i<favorites->count; i++) {
            free(favorites->items[i]);
        }
        hashset_destroy(favorites->set, false);
        free(favorites);
    }
}
Hints

Before first commit, do not forget to setup your git environment:
git config --global user.name "your_name_here"
git config --global user.email "your@email_here"

Clone this repository using HTTP(S):
git clone https://code.reversed.top/user/xaizek/hstr

Clone this repository using ssh (do not forget to upload a key first):
git clone ssh://rocketgit@code.reversed.top/user/xaizek/hstr

You are allowed to anonymously push to this repository.
This means that your pushed commits will automatically be transformed into a pull request:
... clone the repository ...
... make some changes and some commits ...
git push origin master