ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/Convert-UUlib/UUlib.xs
Revision: 1.25
Committed: Sat Sep 24 17:40:45 2022 UTC (19 months, 3 weeks ago) by root
Branch: MAIN
CVS Tags: HEAD
Changes since 1.24: +5 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.1 #include "EXTERN.h"
2     #include "perl.h"
3     #include "XSUB.h"
4    
5 root 1.17 #include "perlmulticore.h"
6    
7 root 1.1 #include "uulib/fptools.h"
8 root 1.2 #include "uulib/uudeview.h"
9 root 1.1
10 root 1.19 static int perlinterp_released;
11 root 1.17
12 root 1.19 #define RELEASE do { perlinterp_released = 1; perlinterp_release (); } while (0)
13     #define ACQUIRE do { perlinterp_acquire (); perlinterp_released = 0; } while (0)
14 root 1.17
15 root 1.19 #define TEMP_ACQUIRE if (perlinterp_released) perlinterp_acquire ();
16     #define TEMP_RELEASE if (perlinterp_released) perlinterp_release ();
17 root 1.17
18 root 1.8 static void
19     uu_msg_callback (void *cb, char *msg, int level)
20 root 1.1 {
21 root 1.17 TEMP_ACQUIRE {
22    
23 root 1.19 dSP;
24    
25     ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 2);
26 root 1.1
27 root 1.19 PUSHs (sv_2mortal (newSVpv (msg, 0)));
28     PUSHs (sv_2mortal (newSViv (level)));
29 root 1.1
30 root 1.19 PUTBACK; (void) perl_call_sv ((SV *)cb, G_VOID|G_DISCARD); SPAGAIN;
31     PUTBACK; FREETMPS; LEAVE;
32 root 1.17
33     } TEMP_RELEASE;
34 root 1.1 }
35    
36 root 1.8 static int
37     uu_busy_callback (void *cb, uuprogress *uup)
38 root 1.1 {
39 root 1.17 int retval;
40    
41     TEMP_ACQUIRE {
42    
43 root 1.19 dSP;
44     int count;
45    
46     ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 6);
47    
48     PUSHs (sv_2mortal (newSViv (uup->action)));
49     PUSHs (sv_2mortal (newSVpv (uup->curfile, 0)));
50     PUSHs (sv_2mortal (newSViv (uup->partno)));
51     PUSHs (sv_2mortal (newSViv (uup->numparts)));
52     PUSHs (sv_2mortal (newSViv (uup->fsize)));
53     PUSHs (sv_2mortal (newSViv (uup->percent)));
54 root 1.1
55 root 1.19 PUTBACK; count = perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN;
56 root 1.1
57 root 1.19 if (count != 1)
58     croak ("busycallback perl callback returned more than one argument");
59 root 1.1
60 root 1.19 retval = POPi;
61 root 1.1
62 root 1.19 PUTBACK; FREETMPS; LEAVE;
63 root 1.1
64 root 1.17 } TEMP_RELEASE;
65    
66 root 1.1 return retval;
67     }
68    
69 root 1.8 static char *
70     uu_fnamefilter_callback (void *cb, char *fname)
71 root 1.1 {
72 root 1.17 static char *str;
73    
74     TEMP_ACQUIRE {
75    
76 root 1.19 dSP;
77     int count;
78    
79     ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 1);
80 root 1.1
81 root 1.19 PUSHs (sv_2mortal (newSVpv (fname, 0)));
82 root 1.1
83 root 1.19 PUTBACK; count = perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN;
84 root 1.1
85 root 1.19 if (count != 1)
86     croak ("fnamefilter perl callback MUST return a single filename exactly");
87 root 1.1
88 root 1.22 FP_free (str); str = FP_strdup (SvPV_nolen (TOPs));
89 root 1.1
90 root 1.19 PUTBACK; FREETMPS; LEAVE;
91 root 1.1
92 root 1.17 } TEMP_RELEASE;
93    
94 root 1.1 return str;
95     }
96    
97 root 1.8 static int
98     uu_file_callback (void *cb, char *id, char *fname, int retrieve)
99 root 1.1 {
100 root 1.17 int retval;
101    
102     TEMP_ACQUIRE {
103    
104 root 1.19 dSP;
105     int count;
106     SV *xfname = newSVpv ("", 0);
107    
108     ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 3);
109 root 1.1
110 root 1.19 PUSHs (sv_2mortal (newSVpv (id, 0)));
111     PUSHs (sv_2mortal (xfname));
112     PUSHs (sv_2mortal (newSViv (retrieve)));
113 root 1.1
114 root 1.19 PUTBACK; count = perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN;
115 root 1.1
116 root 1.19 if (count != 1)
117     croak ("filecallback perl callback must return a single return status");
118 root 1.1
119 root 1.19 strcpy (fname, SvPV_nolen (xfname));
120     retval = POPi;
121 root 1.1
122 root 1.19 PUTBACK; FREETMPS; LEAVE;
123 root 1.1
124 root 1.17 } TEMP_RELEASE;
125    
126 root 1.1 return retval;
127     }
128    
129 root 1.8 static char *
130     uu_filename_callback (void *cb, char *subject, char *filename)
131 root 1.5 {
132 root 1.17 TEMP_ACQUIRE {
133    
134 root 1.19 dSP;
135     int count;
136    
137     ENTER; SAVETMPS; PUSHMARK (SP); EXTEND (SP, 2);
138 root 1.5
139 root 1.23 PUSHs (sv_2mortal (newSVpv (subject, 0)));
140     PUSHs (filename ? sv_2mortal (newSVpv (filename, 0)) : &PL_sv_undef);
141 root 1.5
142 root 1.19 PUTBACK; count = perl_call_sv ((SV *)cb, G_ARRAY); SPAGAIN;
143 root 1.5
144 root 1.19 if (count > 1)
145     croak ("filenamecallback perl callback must return nothing or a single filename");
146 root 1.5
147 root 1.19 if (count)
148     {
149 root 1.22 FP_free (filename);
150 root 1.5
151 root 1.19 filename = SvOK (TOPs)
152 root 1.22 ? FP_strdup (SvPV_nolen (TOPs))
153 root 1.19 : 0;
154     }
155 root 1.5
156 root 1.19 PUTBACK; FREETMPS; LEAVE;
157 root 1.5
158 root 1.17 } TEMP_RELEASE;
159    
160 root 1.5 return filename;
161     }
162    
163     static SV *uu_msg_sv, *uu_busy_sv, *uu_file_sv, *uu_fnamefilter_sv, *uu_filename_sv;
164 root 1.1
165     #define FUNC_CB(cb) (void *)(sv_setsv (cb ## _sv, func), cb ## _sv), func ? cb ## _callback : NULL
166    
167 root 1.8 static int
168     uu_info_file (void *cb, char *info)
169 root 1.1 {
170 root 1.17 int retval;
171    
172     TEMP_ACQUIRE {
173    
174 root 1.19 dSP;
175     int count;
176    
177     ENTER; SAVETMPS; PUSHMARK(SP); EXTEND(SP,1);
178 root 1.1
179 root 1.19 PUSHs(sv_2mortal(newSVpv(info,0)));
180 root 1.1
181 root 1.19 PUTBACK; count = perl_call_sv ((SV *)cb, G_SCALAR); SPAGAIN;
182 root 1.1
183 root 1.19 if (count != 1)
184     croak ("info_file perl callback returned more than one argument");
185 root 1.1
186 root 1.19 retval = POPi;
187 root 1.1
188 root 1.19 PUTBACK; FREETMPS; LEAVE;
189 root 1.1
190 root 1.17 } TEMP_RELEASE;
191    
192 root 1.1 return retval;
193     }
194    
195     static int
196     uu_opt_isstring (int opt)
197     {
198     switch (opt)
199     {
200     case UUOPT_VERSION:
201     case UUOPT_SAVEPATH:
202     case UUOPT_ENCEXT:
203     return 1;
204     default:
205     return 0;
206     }
207     }
208    
209 root 1.19 static void
210     initialise (void)
211     {
212     int retval = UUInitialize ();
213    
214     if (retval != UURET_OK)
215     croak ("unable to initialize uudeview library (%s)", UUstrerror (retval));
216     }
217 root 1.1
218     MODULE = Convert::UUlib PACKAGE = Convert::UUlib PREFIX = UU
219    
220     PROTOTYPES: ENABLE
221    
222     void
223 root 1.8 UUCleanUp ()
224 root 1.1 CODE:
225 root 1.19 UUCleanUp ();
226     initialise ();
227 root 1.1
228     SV *
229 root 1.8 UUGetOption (opt)
230 root 1.1 int opt
231     CODE:
232 root 1.16 {
233     if (opt == UUOPT_PROGRESS)
234     croak ("GetOption(UUOPT_PROGRESS) is not yet implemented");
235     else if (uu_opt_isstring (opt))
236     {
237     char cval[8192];
238    
239     UUGetOption (opt, 0, cval, sizeof cval);
240     RETVAL = newSVpv (cval, 0);
241     }
242     else
243     {
244     RETVAL = newSViv (UUGetOption (opt, 0, 0, 0));
245     }
246     }
247 root 1.1 OUTPUT:
248     RETVAL
249    
250     int
251 root 1.8 UUSetOption (opt, val)
252 root 1.1 int opt
253     SV * val
254     CODE:
255 root 1.16 {
256     STRLEN dc;
257 root 1.1
258 root 1.16 if (uu_opt_isstring (opt))
259     RETVAL = UUSetOption (opt, 0, SvPV (val, dc));
260     else
261     RETVAL = UUSetOption (opt, SvIV (val), (void *)0);
262     }
263 root 1.1 OUTPUT:
264     RETVAL
265    
266     char *
267 root 1.8 UUstrerror (errcode)
268 root 1.1 int errcode
269    
270     void
271 root 1.8 UUSetMsgCallback (func = 0)
272 root 1.1 SV * func
273     CODE:
274 root 1.13 UUSetMsgCallback (FUNC_CB (uu_msg));
275 root 1.1
276     void
277 root 1.8 UUSetBusyCallback (func = 0,msecs = 1000)
278 root 1.1 SV * func
279     long msecs
280     CODE:
281 root 1.13 UUSetBusyCallback (FUNC_CB (uu_busy), msecs);
282 root 1.1
283     void
284 root 1.8 UUSetFileCallback (func = 0)
285 root 1.1 SV * func
286     CODE:
287 root 1.13 UUSetFileCallback (FUNC_CB (uu_file));
288 root 1.1
289     void
290 root 1.8 UUSetFNameFilter (func = 0)
291 root 1.1 SV * func
292     CODE:
293 root 1.13 UUSetFNameFilter (FUNC_CB (uu_fnamefilter));
294 root 1.1
295 root 1.5 void
296 root 1.8 UUSetFileNameCallback (func = 0)
297 root 1.5 SV * func
298     CODE:
299 root 1.13 UUSetFileNameCallback (FUNC_CB (uu_filename));
300 root 1.5
301 root 1.1 char *
302 root 1.8 UUFNameFilter (fname)
303 root 1.1 char * fname
304    
305     void
306 root 1.11 UULoadFile (fname, id = 0, delflag = 0, partno = -1)
307 root 1.1 char * fname
308     char * id
309     int delflag
310 root 1.11 int partno
311 root 1.1 PPCODE:
312 root 1.16 {
313     int count;
314 root 1.17 IV ret;
315    
316     RELEASE;
317     ret = UULoadFileWithPartNo (fname, id, delflag, partno, &count);
318     ACQUIRE;
319 root 1.16
320 root 1.17 XPUSHs (sv_2mortal (newSViv (ret)));
321 root 1.16 if (GIMME_V == G_ARRAY)
322     XPUSHs (sv_2mortal (newSViv (count)));
323     }
324 root 1.1
325     int
326 root 1.8 UUSmerge (pass)
327 root 1.1 int pass
328    
329     int
330     UUQuickDecode(datain,dataout,boundary,maxpos)
331     FILE * datain
332     FILE * dataout
333     char * boundary
334     long maxpos
335    
336     int
337     UUEncodeMulti(outfile,infile,infname,encoding,outfname,mimetype,filemode)
338     FILE * outfile
339     FILE * infile
340     char * infname
341     int encoding
342     char * outfname
343     char * mimetype
344     int filemode
345    
346     int
347 root 1.25 UUEncodePartial(outfile,infile,infname,encoding,outfname,mimetype,filemode,partno,linperfile,crc)
348 root 1.1 FILE * outfile
349     FILE * infile
350     char * infname
351     int encoding
352     char * outfname
353     char * mimetype
354     int filemode
355     int partno
356     long linperfile
357 root 1.25 U32 &crc
358     OUTPUT:
359     RETVAL
360     crc
361 root 1.1
362     int
363     UUEncodeToStream(outfile,infile,infname,encoding,outfname,filemode)
364     FILE * outfile
365     FILE * infile
366     char * infname
367     int encoding
368     char * outfname
369     int filemode
370    
371     int
372     UUEncodeToFile(infile,infname,encoding,outfname,diskname,linperfile)
373     FILE * infile
374     char * infname
375     int encoding
376     char * outfname
377     char * diskname
378     long linperfile
379    
380     int
381     UUE_PrepSingle(outfile,infile,infname,encoding,outfname,filemode,destination,from,subject,isemail)
382     FILE * outfile
383     FILE * infile
384     char * infname
385     int encoding
386     char * outfname
387     int filemode
388     char * destination
389     char * from
390     char * subject
391     int isemail
392    
393     int
394     UUE_PrepPartial(outfile,infile,infname,encoding,outfname,filemode,partno,linperfile,filesize,destination,from,subject,isemail)
395     FILE * outfile
396     FILE * infile
397     char * infname
398     int encoding
399     char * outfname
400     int filemode
401     int partno
402     long linperfile
403     long filesize
404     char * destination
405     char * from
406     char * subject
407     int isemail
408    
409     uulist *
410 root 1.8 UUGetFileListItem (num)
411 root 1.1 int num
412    
413 root 1.18 void
414     GetFileList ()
415     PPCODE:
416 root 1.21 {
417     uulist *iter;
418    
419     for (iter = UUGlobalFileList; iter; iter = iter->NEXT)
420 root 1.18 XPUSHs (sv_setref_pv (sv_newmortal (), "Convert::UUlib::Item", iter));
421 root 1.21 }
422 root 1.18
423 root 1.8 MODULE = Convert::UUlib PACKAGE = Convert::UUlib::Item
424    
425 root 1.1 int
426 root 1.8 rename (item, newname)
427 root 1.1 uulist *item
428     char * newname
429 root 1.8 CODE:
430     RETVAL = UURenameFile (item, newname);
431     OUTPUT:
432     RETVAL
433 root 1.1
434     int
435 root 1.8 decode_temp (item)
436 root 1.1 uulist *item
437 root 1.8 CODE:
438 root 1.17 RELEASE;
439 root 1.8 RETVAL = UUDecodeToTemp (item);
440 root 1.17 ACQUIRE;
441 root 1.8 OUTPUT:
442     RETVAL
443 root 1.1
444     int
445 root 1.8 remove_temp (item)
446 root 1.1 uulist *item
447 root 1.8 CODE:
448 root 1.17 RELEASE;
449 root 1.8 RETVAL = UURemoveTemp (item);
450 root 1.17 ACQUIRE;
451 root 1.8 OUTPUT:
452     RETVAL
453 root 1.1
454     int
455 root 1.8 decode (item, target = 0)
456 root 1.1 uulist *item
457     char * target
458 root 1.8 CODE:
459 root 1.17 RELEASE;
460 root 1.8 RETVAL = UUDecodeFile (item, target);
461 root 1.17 ACQUIRE;
462 root 1.8 OUTPUT:
463     RETVAL
464 root 1.1
465     void
466 root 1.8 info (item, func)
467 root 1.1 uulist *item
468     SV * func
469     CODE:
470 root 1.17 RELEASE;
471     UUInfoFile (item, (void *)func, uu_info_file);
472     ACQUIRE;
473 root 1.1
474     short
475     state(li)
476     uulist *li
477     CODE:
478     RETVAL = li->state;
479     OUTPUT:
480     RETVAL
481    
482     short
483     mode(li,newmode=0)
484     uulist *li
485     short newmode
486     CODE:
487     if (newmode)
488     li->mode = newmode;
489     RETVAL = li->mode;
490     OUTPUT:
491     RETVAL
492    
493     short
494     uudet(li)
495     uulist *li
496     CODE:
497     RETVAL = li->uudet;
498     OUTPUT:
499     RETVAL
500    
501     long
502     size(li)
503     uulist *li
504     CODE:
505     RETVAL = li->size;
506     OUTPUT:
507     RETVAL
508    
509     char *
510 root 1.8 filename (li, newfilename = 0)
511 root 1.1 uulist *li
512     char * newfilename
513     CODE:
514     if (newfilename)
515     {
516 root 1.22 FP_free (li->filename);
517     li->filename = FP_strdup (newfilename);
518 root 1.1 }
519     RETVAL = li->filename;
520     OUTPUT:
521     RETVAL
522    
523     char *
524 root 1.8 subfname (li)
525 root 1.1 uulist *li
526     CODE:
527     RETVAL = li->subfname;
528     OUTPUT:
529     RETVAL
530    
531     char *
532 root 1.8 mimeid (li)
533 root 1.1 uulist *li
534     CODE:
535     RETVAL = li->mimeid;
536     OUTPUT:
537     RETVAL
538    
539     char *
540 root 1.8 mimetype (li)
541 root 1.1 uulist *li
542     CODE:
543     RETVAL = li->mimetype;
544     OUTPUT:
545     RETVAL
546    
547     char *
548 root 1.8 binfile (li)
549 root 1.1 uulist *li
550     CODE:
551     RETVAL = li->binfile;
552     OUTPUT:
553     RETVAL
554    
555 root 1.8 # methods accessing internal data(!)
556 root 1.1
557     void
558 root 1.8 parts (li)
559 root 1.1 uulist *li
560     PPCODE:
561 root 1.16 {
562     struct _uufile *p = li->thisfile;
563 root 1.1
564 root 1.16 while (p)
565     {
566     HV *pi = newHV ();
567    
568 root 1.20 hv_store (pi, "partno" , 6, newSViv (p->partno) , 0);
569     if (p->filename ) hv_store (pi, "filename", 8, newSVpv (p->filename, 0) , 0);
570     if (p->subfname ) hv_store (pi, "subfname", 8, newSVpv (p->subfname, 0) , 0);
571     if (p->mimeid ) hv_store (pi, "mimeid" , 6, newSVpv (p->mimeid , 0) , 0);
572     if (p->mimetype ) hv_store (pi, "mimetype", 8, newSVpv (p->mimetype, 0) , 0);
573     if (p->data->subject) hv_store (pi, "subject" , 7, newSVpv (p->data->subject,0), 0);
574     if (p->data->origin ) hv_store (pi, "origin" , 6, newSVpv (p->data->origin ,0), 0);
575     if (p->data->sfname ) hv_store (pi, "sfname" , 6, newSVpv (p->data->sfname ,0), 0);
576 root 1.16
577     XPUSHs (sv_2mortal (newRV_noinc ((SV *)pi)));
578    
579     p = p->NEXT;
580     }
581     }
582 root 1.1
583     BOOT:
584 root 1.20 {
585     HV *stash = GvSTASH (CvGV (cv));
586    
587     static const struct {
588     const char *name;
589     IV iv;
590     } *civ, const_iv[] = {
591     # define const_iv(name, value) { # name, (IV) value },
592     const_iv (ACT_COPYING , UUACT_COPYING)
593     const_iv (ACT_DECODING , UUACT_DECODING)
594     const_iv (ACT_ENCODING , UUACT_ENCODING)
595     const_iv (ACT_IDLE , UUACT_IDLE)
596     const_iv (ACT_SCANNING , UUACT_SCANNING)
597     const_iv (FILE_DECODED , UUFILE_DECODED)
598     const_iv (FILE_ERROR , UUFILE_ERROR)
599     const_iv (FILE_MISPART , UUFILE_MISPART)
600     const_iv (FILE_NOBEGIN , UUFILE_NOBEGIN)
601     const_iv (FILE_NODATA , UUFILE_NODATA)
602     const_iv (FILE_NOEND , UUFILE_NOEND)
603     const_iv (FILE_OK , UUFILE_OK)
604     const_iv (FILE_READ , UUFILE_READ)
605     const_iv (FILE_TMPFILE , UUFILE_TMPFILE)
606     const_iv (MSG_ERROR , UUMSG_ERROR)
607     const_iv (MSG_FATAL , UUMSG_FATAL)
608     const_iv (MSG_MESSAGE , UUMSG_MESSAGE)
609     const_iv (MSG_NOTE , UUMSG_NOTE)
610     const_iv (MSG_PANIC , UUMSG_PANIC)
611     const_iv (MSG_WARNING , UUMSG_WARNING)
612     const_iv (OPT_VERSION , UUOPT_VERSION)
613     const_iv (OPT_FAST , UUOPT_FAST)
614     const_iv (OPT_DUMBNESS , UUOPT_DUMBNESS)
615     const_iv (OPT_BRACKPOL , UUOPT_BRACKPOL)
616     const_iv (OPT_VERBOSE , UUOPT_VERBOSE)
617     const_iv (OPT_DESPERATE, UUOPT_DESPERATE)
618     const_iv (OPT_IGNREPLY , UUOPT_IGNREPLY)
619     const_iv (OPT_OVERWRITE, UUOPT_OVERWRITE)
620     const_iv (OPT_SAVEPATH , UUOPT_SAVEPATH)
621     const_iv (OPT_IGNMODE , UUOPT_IGNMODE)
622     const_iv (OPT_DEBUG , UUOPT_DEBUG)
623     const_iv (OPT_ERRNO , UUOPT_ERRNO)
624     const_iv (OPT_PROGRESS , UUOPT_PROGRESS)
625     const_iv (OPT_USETEXT , UUOPT_USETEXT)
626     const_iv (OPT_PREAMB , UUOPT_PREAMB)
627     const_iv (OPT_TINYB64 , UUOPT_TINYB64)
628     const_iv (OPT_ENCEXT , UUOPT_ENCEXT)
629     const_iv (OPT_REMOVE , UUOPT_REMOVE)
630     const_iv (OPT_MOREMIME , UUOPT_MOREMIME)
631     const_iv (OPT_DOTDOT , UUOPT_DOTDOT)
632     const_iv (OPT_RBUF , UUOPT_RBUF)
633     const_iv (OPT_WBUF , UUOPT_WBUF)
634     const_iv (OPT_AUTOCHECK, UUOPT_AUTOCHECK)
635     const_iv (RET_CANCEL , UURET_CANCEL)
636     const_iv (RET_CONT , UURET_CONT)
637     const_iv (RET_EXISTS , UURET_EXISTS)
638     const_iv (RET_ILLVAL , UURET_ILLVAL)
639     const_iv (RET_IOERR , UURET_IOERR)
640     const_iv (RET_NODATA , UURET_NODATA)
641     const_iv (RET_NOEND , UURET_NOEND)
642     const_iv (RET_NOMEM , UURET_NOMEM)
643     const_iv (RET_OK , UURET_OK)
644     const_iv (RET_UNSUP , UURET_UNSUP)
645     const_iv (B64_ENCODED , B64ENCODED)
646     const_iv (BH_ENCODED , BH_ENCODED)
647     const_iv (PT_ENCODED , PT_ENCODED)
648     const_iv (QP_ENCODED , QP_ENCODED)
649     const_iv (UU_ENCODED , UU_ENCODED)
650     const_iv (XX_ENCODED , XX_ENCODED)
651     const_iv (YENC_ENCODED , YENC_ENCODED)
652     };
653    
654     for (civ = const_iv + sizeof (const_iv) / sizeof (const_iv [0]); civ > const_iv; civ--)
655     newCONSTSUB (stash, (char *)civ[-1].name, newSViv (civ[-1].iv));
656    
657 root 1.13 uu_msg_sv = newSVsv (&PL_sv_undef);
658     uu_busy_sv = newSVsv (&PL_sv_undef);
659     uu_file_sv = newSVsv (&PL_sv_undef);
660     uu_fnamefilter_sv = newSVsv (&PL_sv_undef);
661     uu_filename_sv = newSVsv (&PL_sv_undef);
662 root 1.20
663 root 1.19 initialise ();
664 root 1.20 }
665 root 1.1