lftp  4.4.15
About: lftp is a command line ftp client (FTP, HTTP, ssl support, background transfer, reget, reput, ...)
  Fossies Dox: lftp-4.4.15.tar.gz  ("inofficial" and yet experimental doxygen-generated source code documentation)  

 All Classes Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups
QueueFeeder.cc
Go to the documentation of this file.
1 /*
2  * lftp - file transfer program
3  *
4  * Copyright (c) 1996-2012 by Alexander V. Lukyanov (lav@yars.free.net)
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program. If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 /* All indexes in this function start at 0; -1 is used contextually to
21  * indicate the last job or moving to the end of the list. */
22 #include <config.h>
23 #include <unistd.h>
24 #include <assert.h>
25 #include <fnmatch.h>
26 #include <stddef.h>
27 
28 #include "QueueFeeder.h"
29 #include "plural.h"
30 #include "misc.h"
31 
32 const char *QueueFeeder::NextCmd(CmdExec *exec, const char *)
33 {
34  if(jobs == NULL) return NULL;
35 
36  /* denext the first job */
37  QueueJob *job = grab_job(0);
38 
39  buffer.truncate(0);
40 
41  if(xstrcmp(cur_pwd, job->pwd)) {
42  buffer.append("cd ").append_quoted(job->pwd).append("; ");
43  cur_pwd.set(job->pwd);
44  }
45 
46  if(xstrcmp(cur_lpwd, job->lpwd)) {
47  buffer.append("lcd ").append_quoted(job->lpwd).append("; ");
48  cur_lpwd.set(job->lpwd);
49  }
50 
51  buffer.append(job->cmd.get()).append('\n');
52  delete job;
53  return buffer;
54 }
55 
56 void QueueFeeder::QueueCmd(const char *cmd, const char *pwd, const char *lpwd, int pos, int v)
57 {
58  QueueJob *job = new QueueJob;
59  job->cmd.set(cmd);
60  job->pwd.set(pwd);
61  job->lpwd.set(lpwd);
62 
63  /* we never want a newline at the end: */
64  if(last_char(job->cmd) == '\n')
65  job->cmd.truncate(strlen(job->cmd)-1);
66 
67  insert_jobs(job, jobs, lastjob, pos != -1? get_job(pos): NULL);
68  PrintJobs(job, v, _("Added job$|s$"));
69 }
70 
71 int QueueFeeder::JobCount(const QueueJob *j)
72 {
73  int job_count=0;
74  for(; j; j=j->next)
75  job_count++;
76  return job_count;
77 }
78 
79 /* verbose:
80  * 0, quiet
81  * 1, interactive
82  * 2, verbose (print changes of pwd and lpwd)
83  * PrintRequeue, output to requeue
84  */
85 xstring& QueueFeeder::FormatJobs(xstring& s,const QueueJob *job, int v, const char *plur) const
86 {
87  if(v < 1)
88  return s;
89 
90  const char *pwd = 0, *lpwd = 0;
91  if(v == PrintRequeue)
92  {
93  for(const QueueJob *j = job; j; j=j->next)
94  {
95  if(xstrcmp(pwd, job->pwd))
96  {
97  s.append("cd ").append_quoted(job->pwd).append(" &\n");
98  pwd = job->pwd;
99  }
100 
101  if(xstrcmp(lpwd, job->lpwd))
102  {
103  s.append("lcd ").append_quoted(job->lpwd).append(" &\n");
104  lpwd = job->lpwd;
105  }
106 
107  s.append("queue ").append_quoted(job->cmd).append('\n');
108  }
109  return s;
110  }
111 
112  int job_count=JobCount(job);
113  if(job_count>1)
114  s.appendf("%s:\n", plural(plur,job_count));
115 
116  pwd = cur_pwd;
117  lpwd = cur_lpwd;
118 
119  int n = 1;
120  for(const QueueJob *j = job; j; j=j->next)
121  {
122  /* Print pwd/lpwd changes when v >= 2. (This only happens when there's
123  * more than one.) */
124  if(xstrcmp(pwd, job->pwd))
125  {
126  if(v > 2) {
127  s.append("\tcd ").append_quoted(job->pwd).append('\n');
128  }
129  pwd = job->pwd;
130  }
131 
132  if(xstrcmp(lpwd, job->lpwd))
133  {
134  if(v > 2) {
135  s.append("\tlcd ").append_quoted(job->lpwd).append('\n');
136  }
137  lpwd = job->lpwd;
138  }
139 
140  if(job_count==1)
141  s.appendf("%s: ", plural(plur,job_count));
142  else
143  s.appendf("\t%2d. ",n++);
144 
145  s.append(j->cmd.get()).append('\n');
146  }
147  return s;
148 }
149 void QueueFeeder::PrintJobs(const QueueJob *job, int v, const char *plur) const
150 {
151  xstring buf("");
152  FormatJobs(buf,job,v,plur);
153  printf("%s",buf.get());
154 }
155 
156 bool QueueFeeder::DelJob(int from, int v)
157 {
158  QueueJob *job = grab_job(from);
159  if(!job)
160  {
161  if(v > 0)
162  {
163  if(from == -1 || !jobs)
164  printf(_("No queued jobs.\n"));
165  else
166  printf(_("No queued job #%i.\n"), from+1);
167  }
168  return false;
169  }
170 
171  PrintJobs(job, v, _("Deleted job$|s$"));
172 
173  FreeList(job);
174  return true;
175 }
176 
177 bool QueueFeeder::DelJob(const char *cmd, int v)
178 {
179  QueueJob *job = grab_job(cmd);
180  if(!job)
181  {
182  if(v > 0)
183  {
184  if(!jobs)
185  printf(_("No queued jobs.\n"));
186  else
187  printf(_("No queued jobs match \"%s\".\n"), cmd);
188  }
189  return false;
190  }
191 
192  PrintJobs(job, v, _("Deleted job$|s$"));
193 
194  FreeList(job);
195  return true;
196 }
197 
198 /* When moving, grab the insertion pointer *before* pulling out things to
199  * move, since doing so will change offsets. (Note that "to == -1" means
200  * "move to the end", not "before the last entry".)
201  */
202 bool QueueFeeder::MoveJob(int from, int to, int v)
203 {
204  /* Safety: make sure we don't try to move an item before itself. */
205  if(from == to) return false;
206 
207  QueueJob *before = to != -1? get_job(to): NULL;
208 
209  QueueJob *job = grab_job(from);
210  if(job == NULL) return false;
211 
212  PrintJobs(job, v, _("Moved job$|s$"));
213  assert(job != before);
214 
215  insert_jobs(job, jobs, lastjob, before);
216  return true;
217 }
218 
219 bool QueueFeeder::MoveJob(const char *cmd, int to, int v)
220 {
221  QueueJob *before = to != -1? get_job(to): NULL;
222 
223  /* Mild hack: we need to make sure the "before" job isn't one that's
224  * going to be moved, so move it upward until it isn't. */
225  while(before && !fnmatch(cmd, before->cmd,FNM_CASEFOLD)) before=before->next;
226 
227  QueueJob *job = grab_job(cmd);
228  if(job == NULL) return false;
229 
230  PrintJobs(job, v, _("Moved job$|s$"));
231 
232  insert_jobs(job, jobs, lastjob, before);
233  return true;
234 }
235 
236 /* remove the given job from the list */
237 void QueueFeeder::unlink_job(QueueJob *job)
238 {
239  /* update head/tail */
240  if(!job->prev) jobs = jobs->next;
241  if(!job->next) lastjob = lastjob->prev;
242 
243  /* linked list stuff */
244  if(job->prev) job->prev->next = job->next;
245  if(job->next) job->next->prev = job->prev;
246  job->prev = job->next = 0;
247 }
248 
249 QueueFeeder::QueueJob *QueueFeeder::get_job(int n)
250 {
251  QueueJob *j;
252  if(n == -1) {
253  j = lastjob;
254  } else {
255  j = jobs;
256  while(j && n--) j=j->next;
257  }
258 
259  return j;
260 }
261 
262 /* get the n'th job, removed from the list; returns NULL (an empty list)
263  * if there aren't that many jobs: */
264 QueueFeeder::QueueJob *QueueFeeder::grab_job(int n)
265 {
266  QueueJob *j = get_job(n);
267  if(j)
268  unlink_job(j);
269  return j;
270 }
271 
272 QueueFeeder::QueueJob *QueueFeeder::grab_job(const char *cmd)
273 {
274  QueueJob *j = jobs, *head = NULL, *tail = NULL;
275 
276  while(j) {
277  QueueJob *match = get_next_match(cmd, j);
278  if(!match) break;
279  j = match->next;
280 
281  /* matches */
282  unlink_job(match);
283  insert_jobs(match, head, tail, NULL);
284  }
285 
286  return head;
287 }
288 
289 QueueFeeder::QueueJob *QueueFeeder::get_next_match(const char *cmd, QueueJob *j)
290 {
291  while(j) {
292  if(!fnmatch(cmd, j->cmd,FNM_CASEFOLD))
293  return j;
294 
295  j = j->next;
296  }
297  return 0;
298 }
299 
300 /* insert a list of jobs before "before", or at the end if before is NULL.
301  * If before is not NULL, it must be contained between lst_head and lst_tail. */
302 void QueueFeeder::insert_jobs(QueueJob *job,
303  QueueJob *&lst_head,
304  QueueJob *&lst_tail,
305  QueueJob *before)
306 {
307  assert(!job->prev); /* this should be an independant, clean list head */
308 
309  /* Find the last entry in the new list. (This is a bit inefficient, as
310  * we usually know this somewhere else, but passing around both head
311  * and tail pointers of the new job list is too klugy.) */
312  QueueJob *tail = job;
313  while(tail->next) tail=tail->next;
314 
315  if(!before) {
316  /* end */
317  job->prev = lst_tail;
318  tail->next = 0; /* superfluous; here for clarity */
319  } else {
320  tail->next = before;
321  job->prev = before->prev;
322  }
323 
324  if(job->prev) job->prev->next = job;
325  if(tail->next) tail->next->prev = tail;
326  if(!tail->next) lst_tail = tail;
327  if(!job->prev) lst_head = job;
328 }
329 
330 /* Free a list of jobs (forward only; j should be a head pointer.) */
331 void QueueFeeder::FreeList(QueueJob *j)
332 {
333  while(j) {
334  QueueJob *job = j;
335  j = j->next;
336  delete job;
337  }
338 }
339 
341 {
342  FreeList(jobs);
343 }
344 
345 
346 xstring& QueueFeeder::FormatStatus(xstring& s,int v,const char *prefix) const
347 {
348  if(jobs == NULL)
349  return s;
350 
351  if(v == PrintRequeue)
352  return FormatJobs(s, jobs, v, "");
353 
354  s.append(prefix).append(_("Commands queued:")).append('\n');
355 
356  int n = 1;
357 
358  const char *pwd = cur_pwd, *lpwd = cur_lpwd;
359  for(const QueueJob *job = jobs; job; job = job->next) {
360  if(v<2 && n>4 && job->next)
361  {
362  s.appendf("%s%2d. ...\n",prefix,n);
363  break;
364  }
365  /* Print pwd/lpwd changes when v >= 2. */
366  if(v >= 2 && (xstrcmp(pwd, job->pwd)))
367  s.appendf("%s cd %s\n",prefix,job->pwd.get());
368  if(v >= 2 && (xstrcmp(lpwd, job->lpwd)))
369  s.appendf("%s lcd %s\n",prefix,job->lpwd.get());
370  pwd = job->pwd;
371  lpwd = job->lpwd;
372 
373  s.appendf("%s%2d. %s\n",prefix,n++,job->cmd.get());
374  }
375  return s;
376 }
virtual ~QueueFeeder()
Definition: QueueFeeder.cc:340
int JobCount() const
Definition: QueueFeeder.h:79
void truncate(size_t n=0)
Definition: xstring.cc:266
xstring & append_quoted(const char *s, int len)
Definition: CmdExec.cc:1046
else return NULL
Definition: strptime.c:525
case j
Definition: strptime.c:477
xstring & FormatStatus(xstring &, int v, const char *prefix="\t") const
Definition: QueueFeeder.cc:346
const char * NextCmd(CmdExec *exec, const char *prompt)
Definition: QueueFeeder.cc:32
xstring & append(const char *s)
Definition: xstring.cc:160
const char * plural(const char *format,...)
Definition: plural.c:89
int fnmatch(const char *pattern, const char *string, int flags)
Definition: fnmatch.c:271
int xstrcmp(const char *s1, const char *s2)
Definition: xstring.cc:27
case n
Definition: strptime.c:497
char last_char(const char *str)
Definition: misc.cc:688
case s
Definition: strptime.c:563
#define FNM_CASEFOLD
Definition: fnmatch.in.h:42
#define _(msgid)
Definition: argmatch.c:33
bool MoveJob(int from, int to, int v=0)
Definition: QueueFeeder.cc:202
bool DelJob(int from, int v=0)
Definition: QueueFeeder.cc:156
const char * set(const char *s)
Definition: xstring.h:108
void QueueCmd(const char *cmd, const char *pwd, const char *lpwd, int pos=0, int verbose=0)
Definition: QueueFeeder.cc:56
xstring & appendf(const char *fmt,...) PRINTF_LIKE(2
Definition: xstring.cc:351