|
Packit |
8f70b4 |
/*
|
|
Packit |
8f70b4 |
* lftp - file transfer program
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* Copyright (c) 1996-2017 by Alexander V. Lukyanov (lav@yars.free.net)
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is free software; you can redistribute it and/or modify
|
|
Packit |
8f70b4 |
* it under the terms of the GNU General Public License as published by
|
|
Packit |
8f70b4 |
* the Free Software Foundation; either version 3 of the License, or
|
|
Packit |
8f70b4 |
* (at your option) any later version.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* This program is distributed in the hope that it will be useful,
|
|
Packit |
8f70b4 |
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
Packit |
8f70b4 |
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
Packit |
8f70b4 |
* GNU General Public License for more details.
|
|
Packit |
8f70b4 |
*
|
|
Packit |
8f70b4 |
* You should have received a copy of the GNU General Public License
|
|
Packit |
8f70b4 |
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
Packit |
8f70b4 |
*/
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include <config.h>
|
|
Packit |
8f70b4 |
#include <sys/types.h>
|
|
Packit |
8f70b4 |
#ifdef HAVE_TERMIOS_H
|
|
Packit |
8f70b4 |
#include <termios.h>
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
#include <unistd.h>
|
|
Packit |
8f70b4 |
#include <sys/ioctl.h>
|
|
Packit |
8f70b4 |
#include "trio.h"
|
|
Packit |
8f70b4 |
#include <stdarg.h>
|
|
Packit |
8f70b4 |
#include <stdlib.h>
|
|
Packit |
8f70b4 |
#include <mbswidth.h>
|
|
Packit |
8f70b4 |
#include "xstring.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "ResMgr.h"
|
|
Packit |
8f70b4 |
#include "misc.h"
|
|
Packit |
8f70b4 |
#include "StatusLine.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
#include "lftp_tinfo.h"
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
ResDecl res_status_interval ("cmd:status-interval", "0.8s", ResMgr::TimeIntervalValidate,ResMgr::NoClosure);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int StatusLine::GetWidth()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
#ifdef TIOCGWINSZ
|
|
Packit |
8f70b4 |
struct winsize sz;
|
|
Packit |
8f70b4 |
sz.ws_col=sz.ws_row=0;
|
|
Packit |
8f70b4 |
ioctl(fd,TIOCGWINSZ,&sz);
|
|
Packit |
8f70b4 |
if(sz.ws_col==0)
|
|
Packit |
8f70b4 |
sz.ws_col=80;
|
|
Packit |
8f70b4 |
if(sz.ws_row==0)
|
|
Packit |
8f70b4 |
sz.ws_row=24;
|
|
Packit |
8f70b4 |
LastHeight=sz.ws_row;
|
|
Packit |
8f70b4 |
return(LastWidth=sz.ws_col);
|
|
Packit |
8f70b4 |
#else /* !TIOCGWINSZ */
|
|
Packit |
8f70b4 |
return 80;
|
|
Packit |
8f70b4 |
#endif
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
StatusLine::StatusLine(int new_fd)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
to_status_line = get_string_term_cap("tsl", "ts");
|
|
Packit |
8f70b4 |
from_status_line = get_string_term_cap("fsl", "fs");
|
|
Packit |
8f70b4 |
prev_line = get_string_term_cap("cuu1","up");
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
fd=new_fd;
|
|
Packit |
8f70b4 |
update_delayed=false;
|
|
Packit |
8f70b4 |
next_update_title_only=false;
|
|
Packit |
8f70b4 |
strcpy(def_title,"");
|
|
Packit |
8f70b4 |
not_term=!isatty(fd);
|
|
Packit |
8f70b4 |
GetWidth();
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
StatusLine::~StatusLine()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* Don't leave a title behind. */
|
|
Packit |
8f70b4 |
WriteTitle("", fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::Clear(bool title_also)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *empty="";
|
|
Packit |
8f70b4 |
update_timer.Stop();
|
|
Packit |
8f70b4 |
ShowN(&empty,1);
|
|
Packit |
8f70b4 |
update_delayed=false;
|
|
Packit |
8f70b4 |
update_timer.SetMilliSeconds(20);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(title_also)
|
|
Packit |
8f70b4 |
WriteTitle(def_title, fd);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::DefaultTitle(const char *s)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
strncpy(def_title, s, sizeof(def_title));
|
|
Packit |
8f70b4 |
def_title[sizeof(def_title)-1] = 0;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::Show(const char *f,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(f==0 || f[0]==0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
Clear();
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
char newstr[0x800];
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
va_list v;
|
|
Packit |
8f70b4 |
va_start(v,f);
|
|
Packit |
8f70b4 |
vsnprintf(newstr,sizeof(newstr),f,v);
|
|
Packit |
8f70b4 |
va_end(v);
|
|
Packit |
8f70b4 |
newstr[sizeof(newstr)-1]=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *s=newstr;
|
|
Packit |
8f70b4 |
ShowN(&s,1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::ShowN(const char *const* newstr,int n)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!update_delayed && shown.IsEqual(newstr,n))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
if(update_delayed && to_be_shown.IsEqual(newstr,n))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!update_timer.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
/* not yet */
|
|
Packit |
8f70b4 |
to_be_shown.Assign(newstr,n);
|
|
Packit |
8f70b4 |
update_delayed=true;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
update(newstr,n);
|
|
Packit |
8f70b4 |
update_delayed=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *StatusLine::to_status_line;
|
|
Packit |
8f70b4 |
const char *StatusLine::from_status_line;
|
|
Packit |
8f70b4 |
const char *StatusLine::prev_line;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::WriteTitle(const char *s, int fd) const
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!ResMgr::QueryBool("cmd:set-term-status", getenv("TERM")))
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
subst_t subst[] = {
|
|
Packit |
8f70b4 |
{ 'a', "\007" },
|
|
Packit |
8f70b4 |
{ 'e', "\033" },
|
|
Packit |
8f70b4 |
{ 'n', "\n" },
|
|
Packit |
8f70b4 |
{ 's', "lftp" },
|
|
Packit |
8f70b4 |
{ 'v', VERSION },
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
{ 'T', s },
|
|
Packit |
8f70b4 |
{ 0, "" }
|
|
Packit |
8f70b4 |
};
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *status_format = ResMgr::Query("cmd:term-status", getenv("TERM"));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
xstring &disp=xstring::get_tmp();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(status_format && *status_format)
|
|
Packit |
8f70b4 |
SubstTo(disp, status_format, subst);
|
|
Packit |
8f70b4 |
else if(to_status_line && from_status_line)
|
|
Packit |
8f70b4 |
/* If we have no format, and we have both tsl and fsl, use them: */
|
|
Packit |
8f70b4 |
disp.vset(to_status_line, s, from_status_line, NULL);
|
|
Packit |
8f70b4 |
else
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
write(fd, disp, disp.length());
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::update(const char *const *newstr,int newstr_height)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(not_term)
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(!in_foreground_pgrp())
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
/* Don't write blank titles into the title; let Clear() do that. */
|
|
Packit |
8f70b4 |
if(newstr_height>0 && newstr[0][0]) WriteTitle(newstr[0], fd);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(next_update_title_only)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
next_update_title_only=false;
|
|
Packit |
8f70b4 |
return;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int w=GetWidth();
|
|
Packit |
8f70b4 |
int mbflags=0;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(newstr_height>LastHeight)
|
|
Packit |
8f70b4 |
newstr_height=LastHeight;
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// clear old extra lines. Assume we are at beginning of last shown line.
|
|
Packit |
8f70b4 |
int j=shown.Count();
|
|
Packit |
8f70b4 |
if(!prev_line) // if there is no way to go up, show a single line only.
|
|
Packit |
8f70b4 |
j=newstr_height=1;
|
|
Packit |
8f70b4 |
int i=j-newstr_height;
|
|
Packit |
8f70b4 |
char *spaces=string_alloca(w+1);
|
|
Packit |
8f70b4 |
memset(spaces,' ',w);
|
|
Packit |
8f70b4 |
spaces[w]=0;
|
|
Packit |
8f70b4 |
while(i-->0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int tw=mbswidth(shown[--j],mbflags);
|
|
Packit |
8f70b4 |
write(fd,"\r",1);
|
|
Packit |
8f70b4 |
write(fd,spaces,tw);
|
|
Packit |
8f70b4 |
write(fd,"\r",1);
|
|
Packit |
8f70b4 |
write(fd,prev_line,strlen(prev_line));
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
// move to top of shown lines.
|
|
Packit |
8f70b4 |
while(--j>0)
|
|
Packit |
8f70b4 |
write(fd,prev_line,strlen(prev_line));
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int curr_line=0;
|
|
Packit |
8f70b4 |
while(curr_line
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
const char *end=newstr[curr_line];
|
|
Packit |
8f70b4 |
int len=strlen(newstr[curr_line]);
|
|
Packit |
8f70b4 |
int wpos=0;
|
|
Packit |
8f70b4 |
while(len>0)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
int ch_len=mblen(end,len);
|
|
Packit |
8f70b4 |
if(ch_len<1)
|
|
Packit |
8f70b4 |
ch_len=1;
|
|
Packit |
8f70b4 |
int ch_width=mbsnwidth(end,ch_len,mbflags);
|
|
Packit |
8f70b4 |
if(wpos+ch_width>w-1)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
end+=ch_len;
|
|
Packit |
8f70b4 |
len-=ch_len;
|
|
Packit |
8f70b4 |
wpos+=ch_width;
|
|
Packit |
8f70b4 |
if(wpos>=w-1)
|
|
Packit |
8f70b4 |
break;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
// FIXME: this assumes that multibyte chars cannot include ' '.
|
|
Packit |
8f70b4 |
while(end>newstr[curr_line] && end[-1]==' ')
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
end--;
|
|
Packit |
8f70b4 |
wpos--; // FIXME: assumption - space width is 1
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(end-newstr[curr_line]>0)
|
|
Packit |
8f70b4 |
write(fd,newstr[curr_line],end-newstr[curr_line]);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
const char *shown_curr=(curr_line>=shown.Count()?"":shown[curr_line]);
|
|
Packit |
8f70b4 |
int dif=strlen(shown_curr)-(end-newstr[curr_line])+2;
|
|
Packit |
8f70b4 |
if(dif>(w-1)-wpos)
|
|
Packit |
8f70b4 |
dif=(w-1)-wpos;
|
|
Packit |
8f70b4 |
if(dif>0)
|
|
Packit |
8f70b4 |
write(fd,spaces,dif);
|
|
Packit |
8f70b4 |
write(fd,"\r",1);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
if(++curr_line
|
|
Packit |
8f70b4 |
write(fd,"\n",1);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
shown.Assign(newstr,newstr_height);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
update_timer.SetResource("cmd:status-interval",0);
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
void StatusLine::WriteLine(const char *f,...)
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
va_list v;
|
|
Packit |
8f70b4 |
va_start(v,f);
|
|
Packit |
8f70b4 |
xstring& newstr=xstring::vformat(f,v).append('\n');
|
|
Packit |
8f70b4 |
va_end(v);
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
Clear();
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
write(fd,newstr,newstr.length());
|
|
Packit |
8f70b4 |
update_delayed=false;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
|
|
Packit |
8f70b4 |
int StatusLine::Do()
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
if(!update_delayed)
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
if(update_timer.Stopped())
|
|
Packit |
8f70b4 |
{
|
|
Packit |
8f70b4 |
update(to_be_shown.Set(),to_be_shown.Count());
|
|
Packit |
8f70b4 |
update_delayed=false;
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
}
|
|
Packit |
8f70b4 |
return STALL;
|
|
Packit |
8f70b4 |
}
|