Created
March 25, 2016 15:58
-
-
Save huseyin/a5226b32c3eeb545fc57 to your computer and use it in GitHub Desktop.
Simple progress bar experiment with C
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* Copyright (c) 2016 Hüseyin Tekinaslan <[email protected]> | |
* | |
* General license of the MIT. | |
* 17 December 2015, Mersin/TURKEY. | |
*/ | |
#include <stdio.h> | |
#include <assert.h> | |
#include "progressbar.h" | |
// Ön tanımlı çubuk genişliği 80 karakterlik olsun. İlkel monitörleri de gözetelim. | |
enum { DEFAULT_WIDTH = 80 }; | |
// Ön tanımlı adım saysını atadık. | |
enum { DEFAULT_STEP = 1 }; | |
// Sayacın çıkacağı maksimum adım sayısını atadık. | |
enum { DEFAULT_TOTAL = 100 }; | |
// Zaman parametrelerini göründüğü üzre saat/dakika/saniye olarak böldük. Bunların | |
// hesaplama algoritmaları aşağıda hesaplanmıştır. | |
struct time_literals { | |
int seconds; | |
int minutes; | |
int hours; | |
}; | |
typedef struct time_literals time_components; | |
// Ön tanımlı ETA boş/dolu etiketlerinin ilk değerleri. | |
static const char *const FULL_ETA = "ETA: %2d:%02d:%02d"; | |
static const char *const EMPTY_ETA = "--:--:--"; | |
static void eta_format(progress *); | |
static time_components calculate_times(int); | |
// @tick ·> Sayacı bir tıklat, int argümanı kadar | |
static void progress_tick(progress *, int); | |
// @percent ·> Yüzde (%) gösterimi | |
static float progress_percent(progress *); | |
// @show ·> Progress çubuğunun son durumunu gör | |
static void progress_show(progress *); | |
// @position ·> Son durumu al | |
static int progress_position(progress *); | |
/* | |
* Progress çubuğunu bir ilkledirelim. Bunun için ayrı bir veri yapısı | |
* tutuldu. Aldığı argümanlar total adım, adım uzunluğu, çubuk genişliği | |
* ve adım karakteridir. Burada şöyle bir açıklama yapalım: | |
* | |
* -> int tipli argümanlara 1 verildiği anda öntanımlı değerlere geçer, | |
* -> char tipli değişkene NULL değeri verildiğinde öntanımlı çubuk | |
* karakterine geçer | |
*/ | |
progress *ProgressBar(int total, int step, int width, char *complete_sep) { | |
progress *bar = (progress*)malloc(sizeof(progress)); | |
/* İlk çalışma zamanını bi alalım. */ | |
bar->time_now = time(NULL); | |
bar->total = (total == 1) ? DEFAULT_TOTAL : total; | |
bar->step = (step == 1) ? DEFAULT_STEP : step; | |
bar->width = (width == 1) ? DEFAULT_WIDTH : width; | |
bar->complete_sep = (complete_sep == NULL) ? "=" : complete_sep; | |
bar->current = 0; | |
return bar; | |
} | |
/* Sayaca bir dokunuş yap, adımlat. Sayaç ilerlesin. */ | |
void progress_inc(progress *bar) { | |
progress_tick(bar, bar->step); | |
} | |
/* Progress çubuğuna anlık değerler set et. */ | |
void progress_set(progress *bar, int n) { | |
if (n < 0) | |
assert(n < 0 && "argüman küçük"); | |
if (bar->total < n) | |
assert(bar->total < n && "bar genişliği totalinden çok daha büyük"); | |
if ((bar->total >= n) && (n >= 0)) | |
bar->current = n; | |
progress_show(bar); | |
} | |
/* | |
* Progress çubuğunu adımlarını bitir. Anlık değeri, total | |
* değer eşitle. | |
*/ | |
void progress_done(progress *bar) { | |
bar->current = bar->total; | |
progress_show(bar); // Ekrana çubuğun son halini bi yaz. | |
} | |
/* Çubuk adımlarını tamamladı mı? */ | |
bool progress_isdone(progress *bar) { | |
return bar->current >= bar->total; | |
} | |
/* Çubuğun işgal ettiği bellek bölgelerini temizle. */ | |
void progress_destroy(progress *bar) { | |
free(bar); | |
} | |
/* Çubuğun anlık adım durumunu artır. */ | |
static void progress_tick(progress *bar, int n) { | |
bar->current += n; | |
/* Anlık değer 0'dan küçükse, 0 yap, */ | |
if (bar->current < 0) | |
bar->current = 0; | |
/* Total değerden büyükse, total yap. */ | |
if (bar->current > bar->total) | |
bar->current = bar->total; | |
progress_show(bar); | |
} | |
/* Progress çubuğunun anlık pozisyonunu al. */ | |
static int progress_position(progress *bar) { | |
int pos; | |
pos = (int)((bar->current * (float)bar->width) / bar->total); | |
return pos; | |
} | |
/* İlerleme durumunun yüzdelik dilimi al. */ | |
static float progress_percent(progress *bar) { | |
float percent; | |
percent = (float)bar->current / ((float)bar->total / (float)100); | |
return percent; | |
} | |
/* Progress çubuğunu ETA etiketleriyle birlikte ekrana yaz. */ | |
static void progress_show(progress *bar) { | |
int i; | |
char line[1 << 10] = ""; // geçici bir çözüm. dinamik hale getirilmeli! (1 << 10 = 1024) | |
for (i=0; i < progress_position(bar); ++i) { | |
/* | |
* Ekrana durum çubuğunu yazarken şu sıraya dikkat edelim: | |
* | |
* ETA ETIKETI [==...] YUZDELIK DILIM | |
* | |
* şeklindedir. | |
*/ | |
printf(" [%s%*s] %.2f %%\r", line, (bar->width-progress_position(bar)), "", | |
progress_percent(bar)); | |
eta_format(bar); | |
strcat(line, bar->complete_sep); | |
fflush(stdout); | |
} | |
if (progress_isdone(bar)) | |
printf("\n"); | |
}; | |
/* | |
* Zaman değişkenlerini hesaplamasını burada yapalım. Bir önceki | |
* yapı dikkate alınarak değişkenler (üretilen değerler) set edilsin. | |
*/ | |
static time_components calculate_times(int time) { | |
int seconds = time % 60; | |
int minutes = (time / 60) % 60; | |
int hours = time / 3600; | |
time_components components = {seconds, minutes, hours}; | |
return components; | |
} | |
/* | |
* ETA etiketini oluştur. İlk başlangıç zamanı ve çalışma zamanını | |
* arasındaki fark baz noktasıdır. | |
*/ | |
static void eta_format(progress *bar) { | |
int elapsed; | |
int eta; | |
time_t new_time = time(NULL); | |
time_components tcomp; | |
if (bar->current == 0) | |
printf(EMPTY_ETA); | |
else { | |
elapsed = difftime(new_time, bar->time_now); | |
eta = elapsed * bar->total / bar->current - elapsed; | |
tcomp = calculate_times(eta); | |
printf(FULL_ETA, tcomp.hours, tcomp.minutes, tcomp.seconds); | |
} | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#ifndef PROGRESS_BAR_H | |
#define PROGRESS_BAR_H | |
#include <stdlib.h> | |
#include <string.h> | |
#include <stdbool.h> | |
#include <time.h> | |
typedef struct { | |
time_t time_now; | |
int total; // Progress total değeri | |
int step; // Progress adım değeri | |
int width; // ProgressBar genişliği | |
int current; // Progress'in anlık değeri | |
char *complete_sep; // ProgressBar prefix | |
} progress; | |
// Yeni bir Progress çubuğu oluşturma adımlarında şu parametreleri: | |
// | |
// @total Progress çubuğunun süreçteki alacağı maksimum değer | |
// @step Progress çubuğunda süreç adımlarını göster | |
// @width Progress çubuğunun eni-genişliği [==...] | |
// @current Sürecin anlık değeri | |
// @complete_sep Progress çubuğunun sayaç prefix'i | |
// | |
// @complete_sep ·> Ön tanımlı olarak '=' ekler. Ön tanımlı değeri | |
// atamak için NULL parametresini gönder. | |
progress *ProgressBar(int, int, int, char*); | |
// @increment ·> Sayacın artımını tıklat (inc) | |
void progress_inc(progress *); | |
// @set ·> Sayacın anlık durumunu dışardan tıklat (set et) | |
void progress_set(progress *, int); | |
// @done ·> Sayacı sıfırla | |
void progress_done(progress *); | |
// @@isdone ·> Sayaç sıfırda mı? | |
bool progress_isdone(progress *); | |
// @destroy ·> Aldığımızı geri veriyoruz | |
void progress_destroy(progress *); | |
#endif // PROGRESS_BAR_H |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment