1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402140314041405140614071408140914101411141214131414141514161417141814191420142114221423142414251426142714281429143014311432143314341435143614371438143914401441144214431444144514461447144814491450145114521453145414551456145714581459146014611462146314641465146614671468146914701471147214731474147514761477147814791480148114821483148414851486148714881489149014911492149314941495149614971498149915001501150215031504150515061507150815091510151115121513151415151516151715181519152015211522152315241525152615271528152915301531153215331534153515361537153815391540154115421543154415451546154715481549155015511552155315541555155615571558155915601561156215631564156515661567156815691570157115721573157415751576157715781579158015811582158315841585158615871588158915901591159215931594159515961597159815991600160116021603160416051606160716081609161016111612161316141615161616171618161916201621162216231624162516261627162816291630163116321633163416351636163716381639164016411642164316441645164616471648164916501651165216531654165516561657165816591660166116621663166416651666166716681669167016711672167316741675167616771678167916801681168216831684168516861687168816891690169116921693169416951696169716981699170017011702170317041705170617071708170917101711171217131714171517161717171817191720172117221723172417251726172717281729173017311732173317341735173617371738173917401741174217431744174517461747174817491750175117521753175417551756175717581759176017611762176317641765176617671768176917701771177217731774177517761777177817791780178117821783178417851786178717881789179017911792179317941795179617971798179918001801180218031804180518061807180818091810181118121813181418151816181718181819182018211822182318241825182618271828182918301831183218331834183518361837183818391840184118421843184418451846184718481849185018511852185318541855185618571858185918601861186218631864186518661867186818691870187118721873187418751876187718781879188018811882188318841885188618871888188918901891189218931894189518961897189818991900190119021903190419051906190719081909191019111912191319141915191619171918191919201921192219231924192519261927192819291930193119321933193419351936193719381939194019411942194319441945194619471948194919501951195219531954195519561957195819591960196119621963196419651966196719681969197019711972197319741975197619771978197919801981198219831984198519861987198819891990199119921993199419951996199719981999200020012002200320042005200620072008200920102011201220132014201520162017201820192020202120222023202420252026202720282029203020312032203320342035203620372038203920402041204220432044204520462047204820492050205120522053205420552056205720582059206020612062206320642065206620672068206920702071207220732074207520762077207820792080208120822083208420852086208720882089209020912092209320942095209620972098209921002101210221032104210521062107210821092110211121122113211421152116211721182119212021212122212321242125212621272128212921302131213221332134213521362137213821392140214121422143214421452146214721482149215021512152215321542155215621572158215921602161216221632164216521662167216821692170217121722173217421752176217721782179218021812182218321842185218621872188218921902191219221932194219521962197219821992200220122022203220422052206220722082209221022112212221322142215221622172218221922202221222222232224222522262227222822292230223122322233223422352236223722382239224022412242224322442245224622472248224922502251225222532254225522562257225822592260226122622263226422652266226722682269227022712272227322742275227622772278227922802281228222832284228522862287228822892290229122922293229422952296229722982299230023012302230323042305230623072308230923102311231223132314231523162317231823192320232123222323232423252326232723282329233023312332233323342335233623372338233923402341234223432344234523462347234823492350235123522353235423552356235723582359236023612362236323642365236623672368236923702371237223732374237523762377237823792380238123822383238423852386238723882389239023912392239323942395239623972398239924002401240224032404240524062407240824092410241124122413241424152416241724182419242024212422242324242425242624272428242924302431243224332434243524362437243824392440244124422443244424452446244724482449245024512452245324542455245624572458245924602461246224632464246524662467246824692470247124722473247424752476247724782479248024812482248324842485248624872488248924902491249224932494249524962497249824992500250125022503250425052506250725082509251025112512251325142515251625172518251925202521252225232524252525262527252825292530253125322533253425352536253725382539254025412542254325442545254625472548254925502551255225532554255525562557255825592560256125622563256425652566256725682569257025712572257325742575257625772578257925802581258225832584258525862587258825892590259125922593259425952596259725982599260026012602260326042605260626072608260926102611261226132614261526162617261826192620262126222623262426252626262726282629263026312632263326342635263626372638263926402641264226432644264526462647264826492650265126522653265426552656265726582659266026612662266326642665266626672668266926702671267226732674267526762677267826792680268126822683268426852686268726882689269026912692269326942695269626972698269927002701270227032704270527062707270827092710271127122713271427152716271727182719272027212722272327242725272627272728272927302731273227332734273527362737273827392740274127422743274427452746274727482749275027512752275327542755275627572758275927602761276227632764276527662767276827692770277127722773277427752776277727782779278027812782278327842785278627872788278927902791279227932794279527962797279827992800280128022803280428052806280728082809281028112812281328142815281628172818281928202821282228232824282528262827282828292830283128322833283428352836283728382839284028412842284328442845284628472848284928502851285228532854285528562857285828592860286128622863286428652866286728682869287028712872287328742875287628772878287928802881288228832884288528862887288828892890289128922893289428952896289728982899290029012902290329042905290629072908290929102911291229132914291529162917291829192920292129222923292429252926292729282929293029312932293329342935293629372938293929402941294229432944294529462947294829492950295129522953295429552956295729582959296029612962296329642965296629672968296929702971297229732974297529762977297829792980298129822983298429852986298729882989299029912992299329942995299629972998299930003001300230033004300530063007300830093010301130123013301430153016301730183019302030213022302330243025302630273028302930303031303230333034303530363037303830393040304130423043304430453046304730483049305030513052305330543055305630573058305930603061306230633064306530663067306830693070307130723073307430753076307730783079308030813082308330843085308630873088308930903091309230933094309530963097309830993100310131023103310431053106310731083109311031113112311331143115311631173118311931203121312231233124312531263127312831293130313131323133313431353136313731383139314031413142314331443145314631473148314931503151315231533154315531563157315831593160316131623163316431653166316731683169317031713172317331743175317631773178317931803181318231833184318531863187318831893190319131923193319431953196319731983199320032013202320332043205320632073208320932103211321232133214321532163217321832193220322132223223322432253226322732283229323032313232323332343235323632373238323932403241324232433244324532463247324832493250325132523253325432553256325732583259326032613262326332643265326632673268326932703271327232733274327532763277327832793280328132823283328432853286328732883289329032913292329332943295329632973298329933003301330233033304330533063307330833093310331133123313331433153316331733183319332033213322332333243325332633273328332933303331333233333334333533363337333833393340334133423343334433453346334733483349335033513352335333543355335633573358335933603361336233633364336533663367336833693370337133723373337433753376337733783379338033813382338333843385338633873388338933903391339233933394339533963397339833993400340134023403340434053406340734083409341034113412341334143415341634173418341934203421342234233424342534263427342834293430343134323433343434353436343734383439344034413442344334443445344634473448344934503451345234533454345534563457345834593460346134623463346434653466346734683469347034713472347334743475347634773478347934803481348234833484348534863487348834893490349134923493349434953496349734983499350035013502350335043505350635073508350935103511351235133514351535163517351835193520352135223523352435253526352735283529353035313532353335343535353635373538353935403541354235433544354535463547354835493550355135523553355435553556355735583559356035613562356335643565356635673568356935703571357235733574357535763577357835793580358135823583358435853586358735883589359035913592359335943595359635973598359936003601360236033604360536063607360836093610361136123613361436153616361736183619362036213622362336243625362636273628362936303631363236333634363536363637363836393640364136423643364436453646364736483649365036513652365336543655365636573658365936603661366236633664366536663667366836693670367136723673367436753676367736783679368036813682368336843685368636873688368936903691369236933694369536963697369836993700370137023703370437053706370737083709371037113712371337143715371637173718371937203721372237233724372537263727372837293730373137323733373437353736373737383739374037413742374337443745374637473748374937503751375237533754375537563757375837593760376137623763376437653766376737683769377037713772377337743775377637773778377937803781378237833784378537863787378837893790379137923793379437953796379737983799380038013802380338043805380638073808380938103811381238133814381538163817381838193820382138223823382438253826382738283829383038313832383338343835383638373838383938403841384238433844384538463847384838493850385138523853385438553856385738583859386038613862386338643865386638673868386938703871387238733874387538763877387838793880388138823883388438853886388738883889389038913892389338943895389638973898389939003901390239033904390539063907390839093910391139123913391439153916391739183919392039213922392339243925392639273928392939303931393239333934393539363937393839393940394139423943394439453946394739483949395039513952395339543955395639573958395939603961396239633964396539663967396839693970397139723973397439753976397739783979398039813982398339843985398639873988398939903991399239933994399539963997399839994000400140024003400440054006400740084009401040114012401340144015401640174018401940204021402240234024402540264027402840294030403140324033403440354036403740384039404040414042404340444045404640474048404940504051405240534054405540564057405840594060406140624063406440654066406740684069407040714072407340744075407640774078407940804081408240834084408540864087408840894090409140924093409440954096409740984099410041014102410341044105410641074108410941104111411241134114411541164117411841194120412141224123412441254126412741284129413041314132413341344135413641374138413941404141414241434144414541464147414841494150415141524153415441554156415741584159416041614162416341644165416641674168416941704171417241734174417541764177417841794180418141824183418441854186418741884189419041914192419341944195419641974198419942004201420242034204420542064207420842094210421142124213421442154216421742184219422042214222422342244225422642274228422942304231423242334234423542364237423842394240424142424243424442454246424742484249425042514252425342544255425642574258425942604261426242634264426542664267426842694270427142724273427442754276427742784279428042814282428342844285428642874288428942904291429242934294429542964297429842994300430143024303430443054306430743084309431043114312431343144315431643174318431943204321432243234324432543264327432843294330433143324333433443354336433743384339434043414342434343444345434643474348434943504351435243534354435543564357435843594360436143624363436443654366436743684369437043714372437343744375437643774378437943804381438243834384438543864387438843894390439143924393439443954396439743984399440044014402440344044405440644074408440944104411441244134414441544164417441844194420442144224423442444254426442744284429443044314432443344344435443644374438443944404441444244434444444544464447444844494450445144524453445444554456445744584459446044614462446344644465446644674468446944704471447244734474447544764477447844794480448144824483448444854486448744884489449044914492449344944495449644974498449945004501450245034504450545064507450845094510451145124513451445154516451745184519452045214522452345244525452645274528452945304531453245334534453545364537453845394540454145424543454445454546454745484549455045514552455345544555455645574558455945604561456245634564456545664567456845694570457145724573457445754576457745784579458045814582458345844585458645874588458945904591459245934594459545964597459845994600460146024603460446054606460746084609461046114612461346144615461646174618461946204621462246234624462546264627462846294630463146324633463446354636463746384639464046414642464346444645464646474648464946504651465246534654465546564657465846594660466146624663466446654666466746684669467046714672467346744675467646774678467946804681468246834684468546864687468846894690469146924693469446954696469746984699470047014702470347044705470647074708470947104711471247134714471547164717471847194720472147224723472447254726472747284729473047314732473347344735473647374738473947404741474247434744474547464747474847494750475147524753475447554756475747584759476047614762476347644765476647674768476947704771477247734774477547764777477847794780478147824783478447854786478747884789479047914792479347944795479647974798479948004801480248034804480548064807480848094810481148124813481448154816481748184819482048214822482348244825482648274828482948304831483248334834483548364837483848394840484148424843484448454846484748484849485048514852485348544855485648574858485948604861486248634864486548664867486848694870487148724873487448754876487748784879488048814882488348844885488648874888488948904891489248934894489548964897489848994900490149024903 |
- /*
- fileio.c - Zip 3
- Copyright (c) 1990-2008 Info-ZIP. All rights reserved.
- See the accompanying file LICENSE, version 2007-Mar-4 or later
- (the contents of which are also included in zip.h) for terms of use.
- If, for some reason, all these files are missing, the Info-ZIP license
- also may be found at: ftp://ftp.info-zip.org/pub/infozip/license.html
- */
- /*
- * fileio.c by Mark Adler
- */
- #define __FILEIO_C
- #include "zip.h"
- #include "crc32.h"
- #ifdef MACOS
- # include "helpers.h"
- #endif
- #ifdef VMS
- # include "vms/vms.h"
- #endif /* def VMS */
- #include <time.h>
- #ifdef NO_MKTIME
- time_t mktime OF((struct tm *));
- #endif
- #ifdef OSF
- #define EXDEV 18 /* avoid a bug in the DEC OSF/1 header files. */
- #else
- #include <errno.h>
- #endif
- #ifdef NO_ERRNO
- extern int errno;
- #endif
- /* -----------------------
- For long option support
- ----------------------- */
- #include <ctype.h>
- #if defined(VMS) || defined(TOPS20)
- # define PAD 5
- #else
- # define PAD 0
- #endif
- #ifdef NO_RENAME
- int rename OF((ZCONST char *, ZCONST char *));
- #endif
- /* Local functions */
- local int optionerr OF((char *, ZCONST char *, int, int));
- local unsigned long get_shortopt OF((char **, int, int *, int *, char **, int *, int));
- local unsigned long get_longopt OF((char **, int, int *, int *, char **, int *, int));
- #ifdef UNICODE_SUPPORT
- local int utf8_char_bytes OF((ZCONST char *utf8));
- local long ucs4_char_from_utf8 OF((ZCONST char **utf8 ));
- local int utf8_from_ucs4_char OF((char *utf8buf, ulg ch));
- local int utf8_to_ucs4_string OF((ZCONST char *utf8, ulg *usc4buf,
- int buflen));
- local int ucs4_string_to_utf8 OF((ZCONST ulg *ucs4, char *utf8buf,
- int buflen));
- #if 0
- local int utf8_chars OF((ZCONST char *utf8));
- #endif
- #endif /* UNICODE_SUPPORT */
- #ifndef UTIL /* the companion #endif is a bit of ways down ... */
- local int fqcmp OF((ZCONST zvoid *, ZCONST zvoid *));
- local int fqcmpz OF((ZCONST zvoid *, ZCONST zvoid *));
- /* Local module level variables. */
- char *label = NULL; /* global, but only used in `system'.c */
- local z_stat zipstatb; /* now use z_stat globally - 7/24/04 EG */
- #if defined(UNICODE_SUPPORT) && defined(WIN32)
- local zw_stat zipstatbw;
- #endif
- #if (!defined(MACOS) && !defined(WINDLL))
- local int zipstate = -1;
- #else
- int zipstate;
- #endif
- /* -1 unknown, 0 old zip file exists, 1 new zip file */
- #if 0
- char *getnam(n, fp)
- char *n; /* where to put name (must have >=FNMAX+1 bytes) */
- #endif
- /* converted to return string pointer from malloc to avoid
- size limitation - 11/8/04 EG */
- #define GETNAM_MAX 9000 /* hopefully big enough for now */
- char *getnam(fp)
- FILE *fp;
- /* Read a \n or \r delimited name from stdin into n, and return
- n. If EOF, then return NULL. Also, if problem return NULL. */
- {
- char name[GETNAM_MAX + 1];
- int c; /* last character read */
- char *p; /* pointer into name area */
- p = name;
- while ((c = getc(fp)) == '\n' || c == '\r')
- ;
- if (c == EOF)
- return NULL;
- do {
- if (p - name >= GETNAM_MAX)
- return NULL;
- *p++ = (char) c;
- c = getc(fp);
- } while (c != EOF && (c != '\n' && c != '\r'));
- #ifdef WIN32
- /*
- * WIN32 strips off trailing spaces and periods in filenames
- * XXX what about a filename that only consists of spaces ?
- * Answer: on WIN32, a filename must contain at least one non-space char
- */
- while (p > name) {
- if ((c = p[-1]) != ' ' && c != '.')
- break;
- --p;
- }
- #endif
- *p = 0;
- /* malloc a copy */
- if ((p = malloc(strlen(name) + 1)) == NULL) {
- return NULL;
- }
- strcpy(p, name);
- return p;
- }
- struct flist far *fexpel(f)
- struct flist far *f; /* entry to delete */
- /* Delete the entry *f in the doubly-linked found list. Return pointer to
- next entry to allow stepping through list. */
- {
- struct flist far *t; /* temporary variable */
- t = f->nxt;
- *(f->lst) = t; /* point last to next, */
- if (t != NULL)
- t->lst = f->lst; /* and next to last */
- if (f->name != NULL) /* free memory used */
- free((zvoid *)(f->name));
- if (f->zname != NULL)
- free((zvoid *)(f->zname));
- if (f->iname != NULL)
- free((zvoid *)(f->iname));
- #ifdef UNICODE_SUPPORT
- if (f->uname)
- free((zvoid *)f->uname);
- # ifdef WIN32
- if (f->namew)
- free((zvoid *)f->namew);
- if (f->inamew)
- free((zvoid *)f->inamew);
- if (f->znamew)
- free((zvoid *)f->znamew);
- # endif
- #endif
- farfree((zvoid far *)f);
- fcount--; /* decrement count */
- return t; /* return pointer to next */
- }
- local int fqcmp(a, b)
- ZCONST zvoid *a, *b; /* pointers to pointers to found entries */
- /* Used by qsort() to compare entries in the found list by name. */
- {
- return strcmp((*(struct flist far **)a)->name,
- (*(struct flist far **)b)->name);
- }
- local int fqcmpz(a, b)
- ZCONST zvoid *a, *b; /* pointers to pointers to found entries */
- /* Used by qsort() to compare entries in the found list by iname. */
- {
- return strcmp((*(struct flist far **)a)->iname,
- (*(struct flist far **)b)->iname);
- }
- char *last(p, c)
- char *p; /* sequence of path components */
- int c; /* path components separator character */
- /* Return a pointer to the start of the last path component. For a directory
- * name terminated by the character in c, the return value is an empty string.
- */
- {
- char *t; /* temporary variable */
- if ((t = strrchr(p, c)) != NULL)
- return t + 1;
- else
- #ifndef AOS_VS
- return p;
- #else
- /* We want to allow finding of end of path in either AOS/VS-style pathnames
- * or Unix-style pathnames. This presents a few little problems ...
- */
- {
- if (*p == '=' || *p == '^') /* like ./ and ../ respectively */
- return p + 1;
- else
- return p;
- }
- #endif
- }
- #if defined(UNICODE_SUPPORT) && defined(WIN32)
- wchar_t *lastw(pw, c)
- wchar_t *pw; /* sequence of path components */
- wchar_t c; /* path components separator character */
- /* Return a pointer to the start of the last path component. For a directory
- * name terminated by the character in c, the return value is an empty string.
- */
- {
- wchar_t *tw; /* temporary variable */
- if ((tw = wcsrchr(pw, c)) != NULL)
- return tw + 1;
- else
- # ifndef AOS_VS
- return pw;
- # else
- /* We want to allow finding of end of path in either AOS/VS-style pathnames
- * or Unix-style pathnames. This presents a few little problems ...
- */
- {
- if (*pw == (wchar_t)'=' || *pw == (wchar_t)'^') /* like ./ and ../ respectively */
- return pw + 1;
- else
- return pw;
- }
- # endif
- }
- #endif
- char *msname(n)
- char *n;
- /* Reduce all path components to MSDOS upper case 8.3 style names. */
- {
- int c; /* current character */
- int f; /* characters in current component */
- char *p; /* source pointer */
- char *q; /* destination pointer */
- p = q = n;
- f = 0;
- while ((c = (unsigned char)*POSTINCSTR(p)) != 0)
- if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
- c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
- c == '?' || c == '[' || c == ']' || c == '|')
- continue; /* char is discarded */
- else if (c == '/')
- {
- *POSTINCSTR(q) = (char)c;
- f = 0; /* new component */
- }
- #ifdef __human68k__
- else if (ismbblead(c) && *p)
- {
- if (f == 7 || f == 11)
- f++;
- else if (*p && f < 12 && f != 8)
- {
- *q++ = c;
- *q++ = *p++;
- f += 2;
- }
- }
- #endif /* __human68k__ */
- else if (c == '.')
- {
- if (f == 0)
- continue; /* leading dots are discarded */
- else if (f < 9)
- {
- *POSTINCSTR(q) = (char)c;
- f = 9; /* now in file type */
- }
- else
- f = 12; /* now just excess characters */
- }
- else
- if (f < 12 && f != 8)
- {
- f += CLEN(p); /* do until end of name or type */
- *POSTINCSTR(q) = (char)(to_up(c));
- }
- *q = 0;
- return n;
- }
- #ifdef UNICODE_SUPPORT
- wchar_t *msnamew(nw)
- wchar_t *nw;
- /* Reduce all path components to MSDOS upper case 8.3 style names. */
- {
- wchar_t c; /* current character */
- int f; /* characters in current component */
- wchar_t *pw; /* source pointer */
- wchar_t *qw; /* destination pointer */
- pw = qw = nw;
- f = 0;
- while ((c = (unsigned char)*pw++) != 0)
- if (c == ' ' || c == ':' || c == '"' || c == '*' || c == '+' ||
- c == ',' || c == ';' || c == '<' || c == '=' || c == '>' ||
- c == '?' || c == '[' || c == ']' || c == '|')
- continue; /* char is discarded */
- else if (c == '/')
- {
- *qw++ = c;
- f = 0; /* new component */
- }
- #ifdef __human68k__
- else if (ismbblead(c) && *pw)
- {
- if (f == 7 || f == 11)
- f++;
- else if (*pw && f < 12 && f != 8)
- {
- *qw++ = c;
- *qw++ = *pw++;
- f += 2;
- }
- }
- #endif /* __human68k__ */
- else if (c == '.')
- {
- if (f == 0)
- continue; /* leading dots are discarded */
- else if (f < 9)
- {
- *qw++ = c;
- f = 9; /* now in file type */
- }
- else
- f = 12; /* now just excess characters */
- }
- else
- if (f < 12 && f != 8)
- {
- f++; /* do until end of name or type */
- *qw++ = towupper(c);
- }
- *qw = 0;
- return nw;
- }
- #endif
- int proc_archive_name(n, caseflag)
- char *n; /* name to process */
- int caseflag; /* true to force case-sensitive match */
- /* Process a name or sh expression in existing archive to operate
- on (or exclude). Return an error code in the ZE_ class. */
- {
- int m; /* matched flag */
- char *p; /* path for recursion */
- struct zlist far *z; /* steps through zfiles list */
- if (strcmp(n, "-") == 0) { /* if compressing stdin */
- zipwarn("Cannot select stdin when selecting archive entries", "");
- return ZE_MISS;
- }
- else
- {
- /* Search for shell expression in zip file */
- p = ex2in(n, 0, (int *)NULL); /* shouldn't affect matching chars */
- m = 1;
- for (z = zfiles; z != NULL; z = z->nxt) {
- if (MATCH(p, z->iname, caseflag))
- {
- z->mark = pcount ? filter(z->zname, caseflag) : 1;
- if (verbose)
- fprintf(mesg, "zip diagnostic: %scluding %s\n",
- z->mark ? "in" : "ex", z->oname);
- m = 0;
- }
- }
- #ifdef UNICODE_SUPPORT
- /* also check escaped Unicode names */
- for (z = zfiles; z != NULL; z = z->nxt) {
- if (z->zuname) {
- #ifdef WIN32
- /* It seems something is lost in going from a listed
- name from zip -su in a console window to using that
- name in a command line. This kluge may fix it
- and just takes zuname, converts to oem (i.e. ouname),
- then converts it back which ends up not the same as
- started with.
- */
- char *zuname = z->wuname;
- #else
- char *zuname = z->zuname;
- #endif
- if (MATCH(p, zuname, caseflag))
- {
- z->mark = pcount ? filter(zuname, caseflag) : 1;
- if (verbose) {
- fprintf(mesg, "zip diagnostic: %scluding %s\n",
- z->mark ? "in" : "ex", z->oname);
- fprintf(mesg, " Escaped Unicode: %s\n",
- z->ouname);
- }
- m = 0;
- }
- }
- }
- #endif
- free((zvoid *)p);
- return m ? ZE_MISS : ZE_OK;
- }
- }
- int check_dup()
- /* Sort the found list and remove duplicates.
- Return an error code in the ZE_ class. */
- {
- struct flist far *f; /* steps through found linked list */
- extent j, k; /* indices for s */
- struct flist far **s; /* sorted table */
- struct flist far **nodup; /* sorted table without duplicates */
- /* sort found list, remove duplicates */
- if (fcount)
- {
- extent fl_size = fcount * sizeof(struct flist far *);
- if ((fl_size / sizeof(struct flist far *)) != fcount ||
- (s = (struct flist far **)malloc(fl_size)) == NULL)
- return ZE_MEM;
- for (j = 0, f = found; f != NULL; f = f->nxt)
- s[j++] = f;
- /* Check names as given (f->name) */
- qsort((char *)s, fcount, sizeof(struct flist far *), fqcmp);
- for (k = j = fcount - 1; j > 0; j--)
- if (strcmp(s[j - 1]->name, s[j]->name) == 0)
- /* remove duplicate entry from list */
- fexpel(s[j]); /* fexpel() changes fcount */
- else
- /* copy valid entry into destination position */
- s[k--] = s[j];
- s[k] = s[0]; /* First entry is always valid */
- nodup = &s[k]; /* Valid entries are at end of array s */
- /* sort only valid items and check for unique internal names (f->iname) */
- qsort((char *)nodup, fcount, sizeof(struct flist far *), fqcmpz);
- for (j = 1; j < fcount; j++)
- if (strcmp(nodup[j - 1]->iname, nodup[j]->iname) == 0)
- {
- char tempbuf[FNMAX+4081];
- sprintf(errbuf, " first full name: %s\n", nodup[j - 1]->name);
- sprintf(tempbuf, " second full name: %s\n", nodup[j]->name);
- strcat(errbuf, " ");
- strcat(errbuf, tempbuf);
- #ifdef EBCDIC
- strtoebc(nodup[j]->iname, nodup[j]->iname);
- #endif
- sprintf(tempbuf, "name in zip file repeated: %s", nodup[j]->iname);
- strcat(errbuf, " ");
- strcat(errbuf, tempbuf);
- if (pathput == 0) {
- strcat(errbuf, "\n this may be a result of using -j");
- }
- #ifdef EBCDIC
- strtoasc(nodup[j]->iname, nodup[j]->iname);
- #endif
- zipwarn(errbuf, "");
- return ZE_PARMS;
- }
- free((zvoid *)s);
- }
- return ZE_OK;
- }
- int filter(name, casesensitive)
- char *name;
- int casesensitive;
- /* Scan the -R, -i and -x lists for matches to the given name.
- Return TRUE if the name must be included, FALSE otherwise.
- Give precedence to -x over -i and -R.
- Note that if both R and i patterns are given then must
- have a match for both.
- This routine relies on the following global variables:
- patterns array of match pattern structures
- pcount total number of patterns
- icount number of -i patterns
- Rcount number of -R patterns
- These data are set up by the command line parsing code.
- */
- {
- unsigned int n;
- int slashes;
- char *p, *q;
- /* without -i patterns, every name matches the "-i select rules" */
- int imatch = (icount == 0);
- /* without -R patterns, every name matches the "-R select rules" */
- int Rmatch = (Rcount == 0);
- if (pcount == 0) return TRUE;
- for (n = 0; n < pcount; n++) {
- if (!patterns[n].zname[0]) /* it can happen... */
- continue;
- p = name;
- switch (patterns[n].select) {
- case 'R':
- if (Rmatch)
- /* one -R match is sufficient, skip this pattern */
- continue;
- /* With -R patterns, if the pattern has N path components (that is,
- N-1 slashes), then we test only the last N components of name.
- */
- slashes = 0;
- for (q = patterns[n].zname; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
- slashes++;
- /* The name may have M path components (M-1 slashes) */
- for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
- slashes--;
- /* Now, "slashes" contains the difference "N-M" between the number
- of path components in the pattern (N) and in the name (M).
- */
- if (slashes < 0)
- /* We found "M > N"
- --> skip the first (M-N) path components of the name.
- */
- for (q = p; (q = MBSCHR(q, '/')) != NULL; MB_NEXTCHAR(q))
- if (++slashes == 0) {
- p = q + 1; /* q points at '/', mblen("/") is 1 */
- break;
- }
- break;
- case 'i':
- if (imatch)
- /* one -i match is sufficient, skip this pattern */
- continue;
- break;
- }
- if (MATCH(patterns[n].zname, p, casesensitive)) {
- switch (patterns[n].select) {
- case 'x':
- /* The -x match takes precedence over everything else */
- return FALSE;
- case 'R':
- Rmatch = TRUE;
- break;
- default:
- /* this must be a type -i match */
- imatch = TRUE;
- break;
- }
- }
- }
- return imatch && Rmatch;
- }
- #ifdef UNICODE_SUPPORT
- # ifdef WIN32
- int newnamew(namew, isdir, casesensitive)
- wchar_t *namew; /* name to add (or exclude) */
- int isdir; /* true for a directory */
- int casesensitive; /* true for case-sensitive matching */
- /* Add (or exclude) the name of an existing disk file. Return an error
- code in the ZE_ class. */
- {
- wchar_t *inamew = NULL; /* internal name */
- wchar_t *znamew = NULL; /* external version of iname */
- wchar_t *undosmw = NULL; /* zname version with "-j" and "-k" options disabled */
- char *oname = NULL; /* iname converted for display */
- char *name = NULL;
- char *iname = NULL;
- char *zname = NULL;
- char *zuname = NULL;
- char *undosm = NULL;
- struct flist far *f; /* where in found, or new found entry */
- struct zlist far *z; /* where in zfiles (if found) */
- int dosflag;
- /* Scanning files ...
- *
- * After 5 seconds output Scanning files...
- * then a dot every 2 seconds
- */
- if (noisy) {
- /* If find files then output message after delay */
- if (scan_count == 0) {
- time_t current = time(NULL);
- scan_start = current;
- }
- scan_count++;
- if (scan_count % 100 == 0) {
- time_t current = time(NULL);
- if (current - scan_start > scan_delay) {
- if (scan_last == 0) {
- zipmessage_nl("Scanning files ", 0);
- scan_last = current;
- }
- if (current - scan_last > scan_dot_time) {
- scan_last = current;
- fprintf(mesg, ".");
- fflush(mesg);
- }
- }
- }
- }
- /* Search for name in zip file. If there, mark it, else add to
- list of new names to do (or remove from that list). */
- if ((inamew = ex2inw(namew, isdir, &dosflag)) == NULL)
- return ZE_MEM;
- /* Discard directory names with zip -rj */
- if (*inamew == (wchar_t)'\0') {
- /* If extensions needs to be swapped, we will have empty directory names
- instead of the original directory. For example, zipping 'c.', 'c.main'
- should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
- if (pathput && !recurse) error("empty name without -j or -r");
- free((zvoid *)inamew);
- return ZE_OK;
- }
- if (dosflag || !pathput) {
- int save_dosify = dosify, save_pathput = pathput;
- dosify = 0;
- pathput = 1;
- /* zname is temporarly mis-used as "undosmode" iname pointer */
- if ((znamew = ex2inw(namew, isdir, NULL)) != NULL) {
- undosmw = in2exw(znamew);
- free(znamew);
- }
- dosify = save_dosify;
- pathput = save_pathput;
- }
- if ((znamew = in2exw(inamew)) == NULL)
- return ZE_MEM;
- /* Convert names from wchar_t to char */
- name = wchar_to_local_string(namew);
- iname = wchar_to_local_string(inamew);
- zname = wchar_to_local_string(znamew);
- oname = local_to_display_string(zname);
- zuname = wchar_to_local_string(znamew);
- if (undosmw == NULL)
- undosmw = znamew;
- undosm = wchar_to_local_string(undosmw);
- if ((z = zsearch(zuname)) != NULL) {
- if (pcount && !filter(undosm, casesensitive)) {
- /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
- * is in effect, two files with different filter options may hit the
- * same z entry.
- */
- if (verbose)
- fprintf(mesg, "excluding %s\n", oname);
- } else {
- z->mark = 1;
- if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
- if (undosmw != znamew)
- free(undosmw);
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_MEM;
- }
- strcpy(z->name, name);
- z->oname = oname;
- oname = NULL;
- z->dosflag = dosflag;
- #ifdef FORCE_NEWNAME
- free((zvoid *)(z->iname));
- z->iname = iname;
- iname = NULL;
- #else
- /* Better keep the old name. Useful when updating on MSDOS a zip file
- * made on Unix.
- */
- #endif /* ? FORCE_NEWNAME */
- }
- if ((z->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
- if (undosmw != znamew)
- free(undosmw);
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_MEM;
- }
- wcscpy(z->namew, namew);
- z->inamew = inamew;
- inamew = NULL;
- z->znamew = znamew;
- znamew = NULL;
- z->uname = wchar_to_utf8_string(z->inamew);
- if (name == label) {
- label = z->name;
- }
- } else if (pcount == 0 || filter(undosm, casesensitive)) {
- /* Check that we are not adding the zip file to itself. This
- * catches cases like "zip -m foo ../dir/foo.zip".
- */
- /* Version of stat() for CMS/MVS isn't complete enough to see if */
- /* files match. Just let ZIP.C compare the filenames. That's good */
- /* enough for CMS anyway since there aren't paths to worry about. */
- zw_stat statbw; /* need for wide stat */
- wchar_t *zipfilew = local_to_wchar_string(zipfile);
- if (zipstate == -1)
- zipstate = strcmp(zipfile, "-") != 0 &&
- zwstat(zipfilew, &zipstatbw) == 0;
- free(zipfilew);
- if (zipstate == 1 && (statbw = zipstatbw, zwstat(namew, &statbw) == 0
- && zipstatbw.st_mode == statbw.st_mode
- && zipstatbw.st_ino == statbw.st_ino
- && zipstatbw.st_dev == statbw.st_dev
- && zipstatbw.st_uid == statbw.st_uid
- && zipstatbw.st_gid == statbw.st_gid
- && zipstatbw.st_size == statbw.st_size
- && zipstatbw.st_mtime == statbw.st_mtime
- && zipstatbw.st_ctime == statbw.st_ctime)) {
- /* Don't compare a_time since we are reading the file */
- if (verbose)
- fprintf(mesg, "file matches zip file -- skipping\n");
- if (undosmw != znamew)
- free(undosmw);
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_OK;
- }
- /* allocate space and add to list */
- if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
- fcount + 1 < fcount ||
- (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
- {
- if (f != NULL)
- farfree((zvoid far *)f);
- if (undosmw != znamew)
- free(undosmw);
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_MEM;
- }
- if (undosmw != znamew)
- free((zvoid *)undosmw);
- strcpy(f->name, name);
- f->iname = iname;
- iname = NULL;
- f->zname = zname;
- zname = NULL;
- /* Unicode */
- if ((f->namew = (wchar_t *)malloc((wcslen(namew) + 1) * sizeof(wchar_t))) == NULL) {
- if (f != NULL)
- farfree((zvoid far *)f);
- if (undosmw != znamew)
- free(undosmw);
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_MEM;
- }
- wcscpy(f->namew, namew);
- f->znamew = znamew;
- znamew = NULL;
- f->uname = wchar_to_utf8_string(inamew);
- f->inamew = inamew;
- inamew = NULL;
- f->oname = oname;
- oname = NULL;
- f->dosflag = dosflag;
- *fnxt = f;
- f->lst = fnxt;
- f->nxt = NULL;
- fnxt = &f->nxt;
- fcount++;
- if (name == label) {
- label = f->name;
- }
- }
- if (undosm) free(undosm);
- if (inamew) free(inamew);
- if (znamew) free(znamew);
- if (name) free(name);
- if (iname) free(iname);
- if (zname) free(zname);
- if (oname) free(oname);
- if (zuname) free(zuname);
- return ZE_OK;
- }
- # endif
- #endif
- int newname(name, isdir, casesensitive)
- char *name; /* name to add (or exclude) */
- int isdir; /* true for a directory */
- int casesensitive; /* true for case-sensitive matching */
- /* Add (or exclude) the name of an existing disk file. Return an error
- code in the ZE_ class. */
- {
- char *iname, *zname; /* internal name, external version of iname */
- char *undosm; /* zname version with "-j" and "-k" options disabled */
- char *oname; /* iname converted for display */
- struct flist far *f; /* where in found, or new found entry */
- struct zlist far *z; /* where in zfiles (if found) */
- int dosflag;
- /* Scanning files ...
- *
- * After 5 seconds output Scanning files...
- * then a dot every 2 seconds
- */
- if (noisy) {
- /* If find files then output message after delay */
- if (scan_count == 0) {
- time_t current = time(NULL);
- scan_start = current;
- }
- scan_count++;
- if (scan_count % 100 == 0) {
- time_t current = time(NULL);
- if (current - scan_start > scan_delay) {
- if (scan_last == 0) {
- zipmessage_nl("Scanning files ", 0);
- scan_last = current;
- }
- if (current - scan_last > scan_dot_time) {
- scan_last = current;
- fprintf(mesg, ".");
- fflush(mesg);
- }
- }
- }
- }
- /* Search for name in zip file. If there, mark it, else add to
- list of new names to do (or remove from that list). */
- if ((iname = ex2in(name, isdir, &dosflag)) == NULL)
- return ZE_MEM;
- /* Discard directory names with zip -rj */
- if (*iname == '\0') {
- #ifndef AMIGA
- /* A null string is a legitimate external directory name in AmigaDOS; also,
- * a command like "zip -r zipfile FOO:" produces an empty internal name.
- */
- # ifndef RISCOS
- /* If extensions needs to be swapped, we will have empty directory names
- instead of the original directory. For example, zipping 'c.', 'c.main'
- should zip only 'main.c' while 'c.' will be converted to '\0' by ex2in. */
- if (pathput && !recurse) error("empty name without -j or -r");
- # endif /* !RISCOS */
- #endif /* !AMIGA */
- free((zvoid *)iname);
- return ZE_OK;
- }
- undosm = NULL;
- if (dosflag || !pathput) {
- int save_dosify = dosify, save_pathput = pathput;
- dosify = 0;
- pathput = 1;
- /* zname is temporarly mis-used as "undosmode" iname pointer */
- if ((zname = ex2in(name, isdir, NULL)) != NULL) {
- undosm = in2ex(zname);
- free(zname);
- }
- dosify = save_dosify;
- pathput = save_pathput;
- }
- if ((zname = in2ex(iname)) == NULL)
- return ZE_MEM;
- #ifdef UNICODE_SUPPORT
- /* Convert name to display or OEM name */
- oname = local_to_display_string(iname);
- #else
- if ((oname = malloc(strlen(zname) + 1)) == NULL)
- return ZE_MEM;
- strcpy(oname, zname);
- #endif
- if (undosm == NULL)
- undosm = zname;
- if ((z = zsearch(zname)) != NULL) {
- if (pcount && !filter(undosm, casesensitive)) {
- /* Do not clear z->mark if "exclude", because, when "dosify || !pathput"
- * is in effect, two files with different filter options may hit the
- * same z entry.
- */
- if (verbose)
- fprintf(mesg, "excluding %s\n", oname);
- free((zvoid *)iname);
- free((zvoid *)zname);
- } else {
- z->mark = 1;
- if ((z->name = malloc(strlen(name) + 1 + PAD)) == NULL) {
- if (undosm != zname)
- free((zvoid *)undosm);
- free((zvoid *)iname);
- free((zvoid *)zname);
- return ZE_MEM;
- }
- strcpy(z->name, name);
- z->oname = oname;
- z->dosflag = dosflag;
- #ifdef FORCE_NEWNAME
- free((zvoid *)(z->iname));
- z->iname = iname;
- #else
- /* Better keep the old name. Useful when updating on MSDOS a zip file
- * made on Unix.
- */
- free((zvoid *)iname);
- free((zvoid *)zname);
- #endif /* ? FORCE_NEWNAME */
- }
- #if defined(UNICODE_SUPPORT) && defined(WIN32)
- z->namew = NULL;
- z->inamew = NULL;
- z->znamew = NULL;
- #endif
- if (name == label) {
- label = z->name;
- }
- } else if (pcount == 0 || filter(undosm, casesensitive)) {
- /* Check that we are not adding the zip file to itself. This
- * catches cases like "zip -m foo ../dir/foo.zip".
- */
- #ifndef CMS_MVS
- /* Version of stat() for CMS/MVS isn't complete enough to see if */
- /* files match. Just let ZIP.C compare the filenames. That's good */
- /* enough for CMS anyway since there aren't paths to worry about. */
- z_stat statb; /* now use structure z_stat and function zstat globally 7/24/04 EG */
- if (zipstate == -1)
- zipstate = strcmp(zipfile, "-") != 0 &&
- zstat(zipfile, &zipstatb) == 0;
- if (zipstate == 1 && (statb = zipstatb, zstat(name, &statb) == 0
- && zipstatb.st_mode == statb.st_mode
- #ifdef VMS
- && memcmp(zipstatb.st_ino, statb.st_ino, sizeof(statb.st_ino)) == 0
- && strcmp(zipstatb.st_dev, statb.st_dev) == 0
- && zipstatb.st_uid == statb.st_uid
- #else /* !VMS */
- && zipstatb.st_ino == statb.st_ino
- && zipstatb.st_dev == statb.st_dev
- && zipstatb.st_uid == statb.st_uid
- && zipstatb.st_gid == statb.st_gid
- #endif /* ?VMS */
- && zipstatb.st_size == statb.st_size
- && zipstatb.st_mtime == statb.st_mtime
- && zipstatb.st_ctime == statb.st_ctime)) {
- /* Don't compare a_time since we are reading the file */
- if (verbose)
- fprintf(mesg, "file matches zip file -- skipping\n");
- if (undosm != zname)
- free((zvoid *)zname);
- if (undosm != iname)
- free((zvoid *)undosm);
- free((zvoid *)iname);
- free(oname);
- return ZE_OK;
- }
- #endif /* CMS_MVS */
- /* allocate space and add to list */
- if ((f = (struct flist far *)farmalloc(sizeof(struct flist))) == NULL ||
- fcount + 1 < fcount ||
- (f->name = malloc(strlen(name) + 1 + PAD)) == NULL)
- {
- if (f != NULL)
- farfree((zvoid far *)f);
- if (undosm != zname)
- free((zvoid *)undosm);
- free((zvoid *)iname);
- free((zvoid *)zname);
- free(oname);
- return ZE_MEM;
- }
- strcpy(f->name, name);
- f->iname = iname;
- f->zname = zname;
- #ifdef UNICODE_SUPPORT
- /* Unicode */
- f->uname = local_to_utf8_string(iname);
- #ifdef WIN32
- f->namew = NULL;
- f->inamew = NULL;
- f->znamew = NULL;
- if (strcmp(f->name, "-") == 0) {
- f->namew = local_to_wchar_string(f->name);
- }
- #endif
- #endif
- f->oname = oname;
- f->dosflag = dosflag;
- *fnxt = f;
- f->lst = fnxt;
- f->nxt = NULL;
- fnxt = &f->nxt;
- fcount++;
- if (name == label) {
- label = f->name;
- }
- }
- if (undosm != zname)
- free((zvoid *)undosm);
- return ZE_OK;
- }
- ulg dostime(y, n, d, h, m, s)
- int y; /* year */
- int n; /* month */
- int d; /* day */
- int h; /* hour */
- int m; /* minute */
- int s; /* second */
- /* Convert the date y/n/d and time h:m:s to a four byte DOS date and
- time (date in high two bytes, time in low two bytes allowing magnitude
- comparison). */
- {
- return y < 1980 ? DOSTIME_MINIMUM /* dostime(1980, 1, 1, 0, 0, 0) */ :
- (((ulg)y - 1980) << 25) | ((ulg)n << 21) | ((ulg)d << 16) |
- ((ulg)h << 11) | ((ulg)m << 5) | ((ulg)s >> 1);
- }
- ulg unix2dostime(t)
- time_t *t; /* unix time to convert */
- /* Return the Unix time t in DOS format, rounded up to the next two
- second boundary. */
- {
- time_t t_even;
- struct tm *s; /* result of localtime() */
- t_even = (time_t)(((unsigned long)(*t) + 1) & (~1));
- /* Round up to even seconds. */
- s = localtime(&t_even); /* Use local time since MSDOS does. */
- if (s == (struct tm *)NULL) {
- /* time conversion error; use current time as emergency value
- (assuming that localtime() does at least accept this value!) */
- t_even = (time_t)(((unsigned long)time(NULL) + 1) & (~1));
- s = localtime(&t_even);
- }
- return dostime(s->tm_year + 1900, s->tm_mon + 1, s->tm_mday,
- s->tm_hour, s->tm_min, s->tm_sec);
- }
- int issymlnk(a)
- ulg a; /* Attributes returned by filetime() */
- /* Return true if the attributes are those of a symbolic link */
- {
- #ifndef QDOS
- #ifdef S_IFLNK
- #ifdef __human68k__
- int *_dos_importlnenv(void);
- if (_dos_importlnenv() == NULL)
- return 0;
- #endif
- return ((a >> 16) & S_IFMT) == S_IFLNK;
- #else /* !S_IFLNK */
- return (int)a & 0; /* avoid warning on unused parameter */
- #endif /* ?S_IFLNK */
- #else
- return 0;
- #endif
- }
- #endif /* !UTIL */
- #if (!defined(UTIL) && !defined(ZP_NEED_GEN_D2U_TIME))
- /* There is no need for dos2unixtime() in the ZipUtils' code. */
- # define ZP_NEED_GEN_D2U_TIME
- #endif
- #if ((defined(OS2) || defined(VMS)) && defined(ZP_NEED_GEN_D2U_TIME))
- /* OS/2 and VMS use a special solution to handle time-stams of files. */
- # undef ZP_NEED_GEN_D2U_TIME
- #endif
- #if (defined(W32_STATROOT_FIX) && !defined(ZP_NEED_GEN_D2U_TIME))
- /* The Win32 stat()-bandaid to fix stat'ing root directories needs
- * dos2unixtime() to calculate the time-stamps. */
- # define ZP_NEED_GEN_D2U_TIME
- #endif
- #ifdef ZP_NEED_GEN_D2U_TIME
- time_t dos2unixtime(dostime)
- ulg dostime; /* DOS time to convert */
- /* Return the Unix time_t value (GMT/UTC time) for the DOS format (local)
- * time dostime, where dostime is a four byte value (date in most significant
- * word, time in least significant word), see dostime() function.
- */
- {
- struct tm *t; /* argument for mktime() */
- ZCONST time_t clock = time(NULL);
- t = localtime(&clock);
- t->tm_isdst = -1; /* let mktime() determine if DST is in effect */
- /* Convert DOS time to UNIX time_t format */
- t->tm_sec = (((int)dostime) << 1) & 0x3e;
- t->tm_min = (((int)dostime) >> 5) & 0x3f;
- t->tm_hour = (((int)dostime) >> 11) & 0x1f;
- t->tm_mday = (int)(dostime >> 16) & 0x1f;
- t->tm_mon = ((int)(dostime >> 21) & 0x0f) - 1;
- t->tm_year = ((int)(dostime >> 25) & 0x7f) + 80;
- return mktime(t);
- }
- #undef ZP_NEED_GEN_D2U_TIME
- #endif /* ZP_NEED_GEN_D2U_TIME */
- #ifndef MACOS
- int destroy(f)
- char *f; /* file to delete */
- /* Delete the file *f, returning non-zero on failure. */
- {
- return unlink(f);
- }
- int replace(d, s)
- char *d, *s; /* destination and source file names */
- /* Replace file *d by file *s, removing the old *s. Return an error code
- in the ZE_ class. This function need not preserve the file attributes,
- this will be done by setfileattr() later.
- */
- {
- z_stat t; /* results of stat() */
- #if defined(CMS_MVS)
- /* cmsmvs.h defines FOPW_TEMP as memory(hiperspace). Since memory is
- * lost at end of run, always do copy instead of rename.
- */
- int copy = 1;
- #else
- int copy = 0;
- #endif
- int d_exists;
- #if defined(VMS) || defined(CMS_MVS)
- /* stat() is broken on VMS remote files (accessed through Decnet).
- * This patch allows creation of remote zip files, but is not sufficient
- * to update them or compress remote files */
- unlink(d);
- #else /* !(VMS || CMS_MVS) */
- d_exists = (LSTAT(d, &t) == 0);
- if (d_exists)
- {
- /*
- * respect existing soft and hard links!
- */
- if (t.st_nlink > 1
- # ifdef S_IFLNK
- || (t.st_mode & S_IFMT) == S_IFLNK
- # endif
- )
- copy = 1;
- else if (unlink(d))
- return ZE_CREAT; /* Can't erase zip file--give up */
- }
- #endif /* ?(VMS || CMS_MVS) */
- #ifndef CMS_MVS
- if (!copy) {
- if (rename(s, d)) { /* Just move s on top of d */
- copy = 1; /* failed ? */
- #if !defined(VMS) && !defined(ATARI) && !defined(AZTEC_C)
- #if !defined(CMS_MVS) && !defined(RISCOS) && !defined(QDOS)
- /* For VMS, ATARI, AMIGA Aztec, VM_CMS, MVS, RISCOS,
- always assume that failure is EXDEV */
- if (errno != EXDEV
- # ifdef THEOS
- && errno != EEXIST
- # else
- # ifdef ENOTSAM
- && errno != ENOTSAM /* Used at least on Turbo C */
- # endif
- # endif
- ) return ZE_CREAT;
- #endif /* !CMS_MVS && !RISCOS */
- #endif /* !VMS && !ATARI && !AZTEC_C */
- }
- }
- #endif /* !CMS_MVS */
- if (copy) {
- FILE *f, *g; /* source and destination files */
- int r; /* temporary variable */
- #ifdef RISCOS
- if (SWI_OS_FSControl_26(s,d,0xA1)!=NULL) {
- #endif
- /* Use zfopen for almost all opens where fopen is used. For
- most OS that support large files we use the 64-bit file
- environment and zfopen maps to fopen, but this allows
- tweeking ports that don't do that. 7/24/04 */
- if ((f = zfopen(s, FOPR)) == NULL) {
- fprintf(mesg," replace: can't open %s\n", s);
- return ZE_TEMP;
- }
- if ((g = zfopen(d, FOPW)) == NULL)
- {
- fclose(f);
- return ZE_CREAT;
- }
- r = fcopy(f, g, (ulg)-1L);
- fclose(f);
- if (fclose(g) || r != ZE_OK)
- {
- unlink(d);
- return r ? (r == ZE_TEMP ? ZE_WRITE : r) : ZE_WRITE;
- }
- unlink(s);
- #ifdef RISCOS
- }
- #endif
- }
- return ZE_OK;
- }
- #endif /* !MACOS */
- int getfileattr(f)
- char *f; /* file path */
- /* Return the file attributes for file f or 0 if failure */
- {
- #ifdef __human68k__
- struct _filbuf buf;
- return _dos_files(&buf, f, 0xff) < 0 ? 0x20 : buf.atr;
- #else
- z_stat s;
- return SSTAT(f, &s) == 0 ? (int) s.st_mode : 0;
- #endif
- }
- int setfileattr(f, a)
- char *f; /* file path */
- int a; /* attributes returned by getfileattr() */
- /* Give the file f the attributes a, return non-zero on failure */
- {
- #if defined(TOPS20) || defined (CMS_MVS)
- return 0;
- #else
- #ifdef __human68k__
- return _dos_chmod(f, a) < 0 ? -1 : 0;
- #else
- return chmod(f, a);
- #endif
- #endif
- }
- /* tempname */
- #ifndef VMS /* VMS-specific function is in VMS.C. */
- char *tempname(zip)
- char *zip; /* path name of zip file to generate temp name for */
- /* Return a temporary file name in its own malloc'ed space, using tempath. */
- {
- char *t = zip; /* malloc'ed space for name (use zip to avoid warning) */
- # ifdef CMS_MVS
- if ((t = malloc(strlen(tempath) + L_tmpnam + 2)) == NULL)
- return NULL;
- # ifdef VM_CMS
- tmpnam(t);
- /* Remove filemode and replace with tempath, if any. */
- /* Otherwise A-disk is used by default */
- *(strrchr(t, ' ')+1) = '\0';
- if (tempath!=NULL)
- strcat(t, tempath);
- return t;
- # else /* !VM_CMS */
- /* For MVS */
- tmpnam(t);
- if (tempath != NULL)
- {
- int l1 = strlen(t);
- char *dot;
- if (*t == '\'' && *(t+l1-1) == '\'' && (dot = strchr(t, '.')))
- {
- /* MVS and not OE. tmpnam() returns quoted string of 5 qualifiers.
- * First is HLQ, rest are timestamps. User can only replace HLQ.
- */
- int l2 = strlen(tempath);
- if (strchr(tempath, '.') || l2 < 1 || l2 > 8)
- ziperr(ZE_PARMS, "On MVS and not OE, tempath (-b) can only be HLQ");
- memmove(t+1+l2, dot, l1+1-(dot-t)); /* shift dot ready for new hlq */
- memcpy(t+1, tempath, l2); /* insert new hlq */
- }
- else
- {
- /* MVS and probably OE. tmpnam() returns filename based on TMPDIR,
- * no point in even attempting to change it. User should modify TMPDIR
- * instead.
- */
- zipwarn("MVS, assumed to be OE, change TMPDIR instead of option -b: ",
- tempath);
- }
- }
- return t;
- # endif /* !VM_CMS */
- # else /* !CMS_MVS */
- # ifdef TANDEM
- char cur_subvol [FILENAME_MAX];
- char temp_subvol [FILENAME_MAX];
- char *zptr;
- char *ptr;
- char *cptr = &cur_subvol[0];
- char *tptr = &temp_subvol[0];
- short err;
- FILE *tempf;
- int attempts;
- t = (char *)malloc(NAMELEN); /* malloc here as you cannot free */
- /* tmpnam allocated storage later */
- zptr = strrchr(zip, TANDEM_DELIMITER);
- if (zptr != NULL) {
- /* ZIP file specifies a Subvol so make temp file there so it can just
- be renamed at end */
- *tptr = *cptr = '\0';
- strcat(cptr, getenv("DEFAULTS"));
- strncat(tptr, zip, _min(FILENAME_MAX, (zptr - zip)) ); /* temp subvol */
- strncat(t, zip, _min(NAMELEN, ((zptr - zip) + 1)) ); /* temp stem */
- err = chvol(tptr);
- ptr = t + strlen(t); /* point to end of stem */
- }
- else
- ptr = t;
- /* If two zips are running in same subvol then we can get contention problems
- with the temporary filename. As a work around we attempt to create
- the file here, and if it already exists we get a new temporary name */
- attempts = 0;
- do {
- attempts++;
- tmpnam(ptr); /* Add filename */
- tempf = zfopen(ptr, FOPW_TMP); /* Attempt to create file */
- } while (tempf == NULL && attempts < 100);
- if (attempts >= 100) {
- ziperr(ZE_TEMP, "Could not get unique temp file name");
- }
- fclose(tempf);
- if (zptr != NULL) {
- err = chvol(cptr); /* Put ourself back to where we came in */
- }
- return t;
- # else /* !CMS_MVS && !TANDEM */
- /*
- * Do something with TMPDIR, TMP, TEMP ????
- */
- if (tempath != NULL)
- {
- if ((t = malloc(strlen(tempath) + 12)) == NULL)
- return NULL;
- strcpy(t, tempath);
- # if (!defined(VMS) && !defined(TOPS20))
- # ifdef MSDOS
- {
- char c = (char)lastchar(t);
- if (c != '/' && c != ':' && c != '\\')
- strcat(t, "/");
- }
- # else
- # ifdef AMIGA
- {
- char c = (char)lastchar(t);
- if (c != '/' && c != ':')
- strcat(t, "/");
- }
- # else /* !AMIGA */
- # ifdef RISCOS
- if (lastchar(t) != '.')
- strcat(t, ".");
- # else /* !RISCOS */
- # ifdef QDOS
- if (lastchar(t) != '_')
- strcat(t, "_");
- # else
- if (lastchar(t) != '/')
- strcat(t, "/");
- # endif /* ?QDOS */
- # endif /* ?RISCOS */
- # endif /* ?AMIGA */
- # endif /* ?MSDOS */
- # endif /* !VMS && !TOPS20 */
- }
- else
- {
- if ((t = malloc(12)) == NULL)
- return NULL;
- *t = 0;
- }
- # ifdef NO_MKTEMP
- {
- char *p = t + strlen(t);
- sprintf(p, "%08lx", (ulg)time(NULL));
- return t;
- }
- # else
- strcat(t, "ziXXXXXX"); /* must use lowercase for Linux dos file system */
- # if defined(UNIX) && !defined(NO_MKSTEMP)
- /* tempname should not be called */
- return t;
- # else
- return mktemp(t);
- # endif
- # endif /* NO_MKTEMP */
- # endif /* TANDEM */
- # endif /* CMS_MVS */
- }
- #endif /* !VMS */
- int fcopy(f, g, n)
- FILE *f, *g; /* source and destination files */
- /* now use uzoff_t for all file sizes 5/14/05 CS */
- uzoff_t n; /* number of bytes to copy or -1 for all */
- /* Copy n bytes from file *f to file *g, or until EOF if (zoff_t)n == -1.
- Return an error code in the ZE_ class. */
- {
- char *b; /* malloc'ed buffer for copying */
- extent k; /* result of fread() */
- uzoff_t m; /* bytes copied so far */
- if ((b = malloc(CBSZ)) == NULL)
- return ZE_MEM;
- m = 0;
- while (n == (uzoff_t)(-1L) || m < n)
- {
- if ((k = fread(b, 1, n == (uzoff_t)(-1) ?
- CBSZ : (n - m < CBSZ ? (extent)(n - m) : CBSZ), f)) == 0)
- {
- if (ferror(f))
- {
- free((zvoid *)b);
- return ZE_READ;
- }
- else
- break;
- }
- if (fwrite(b, 1, k, g) != k)
- {
- free((zvoid *)b);
- fprintf(mesg," fcopy: write error\n");
- return ZE_TEMP;
- }
- m += k;
- }
- free((zvoid *)b);
- return ZE_OK;
- }
- /* from zipfile.c */
- #ifdef THEOS
- /* Macros cause stack overflow in compiler */
- ush SH(uch* p) { return ((ush)(uch)((p)[0]) | ((ush)(uch)((p)[1]) << 8)); }
- ulg LG(uch* p) { return ((ulg)(SH(p)) | ((ulg)(SH((p)+2)) << 16)); }
- #else /* !THEOS */
- /* Macros for converting integers in little-endian to machine format */
- # define SH(a) ((ush)(((ush)(uch)(a)[0]) | (((ush)(uch)(a)[1]) << 8)))
- # define LG(a) ((ulg)SH(a) | ((ulg)SH((a)+2) << 16))
- # ifdef ZIP64_SUPPORT /* zip64 support 08/31/2003 R.Nausedat */
- # define LLG(a) ((zoff_t)LG(a) | ((zoff_t)LG((a)+4) << 32))
- # endif
- #endif /* ?THEOS */
- /* always copies from global in_file to global output file y */
- int bfcopy(n)
- /* now use uzoff_t for all file sizes 5/14/05 CS */
- uzoff_t n; /* number of bytes to copy or -1 for all */
- /* Copy n bytes from in_file to out_file, or until EOF if (zoff_t)n == -1.
- Normally we have the compressed size from either the central directory
- entry or the local header.
- If n != -1 and EOF, close current split and open next and continue
- copying.
- If n == -2, copy until find the extended header (data descriptor). Only
- used for -FF when no size available.
- If fix == 1 calculate CRC of input entry and verify matches.
- If fix == 2 and this entry using data descriptor keep a sliding
- window in the buffer for looking for signature.
- Return an error code in the ZE_ class. */
- {
- char *b; /* malloc'ed buffer for copying */
- extent k; /* result of fread() */
- uzoff_t m; /* bytes copied so far */
- extent brd; /* bytes to read */
- zoff_t data_start = 0;
- zoff_t des_start = 0;
- char *split_path;
- extent kk;
- int i;
- char sbuf[4]; /* buffer for sliding signature window for fix = 2 */
- int des = 0; /* this entry has data descriptor to find */
- if ((b = malloc(CBSZ)) == NULL)
- return ZE_MEM;
- if (copy_only && !display_globaldots) {
- /* initialize dot count */
- dot_count = -1;
- }
- if (fix == 2 && n == (uzoff_t) -2) {
- data_start = zftello(in_file);
- for (kk = 0; kk < 4; kk++)
- sbuf[kk] = 0;
- des = 1;
- }
- des_good = 0;
- m = 0;
- while (des || n == (uzoff_t)(-1L) || m < n)
- {
- if (des || n == (uzoff_t)(-1))
- brd = CBSZ;
- else
- brd = (n - m < CBSZ ? (extent)(n - m) : CBSZ);
- des_start = zftello(in_file);
- if ((k = fread(b, 1, brd, in_file)) == 0)
- {
- if (fix == 2 && k < brd) {
- free((zvoid *)b);
- return ZE_READ;
- }
- else if (ferror(in_file))
- {
- free((zvoid *)b);
- return ZE_READ;
- }
- else {
- break;
- }
- }
- /* end at extended local header (data descriptor) signature */
- if (des) {
- des_crc = 0;
- des_csize = 0;
- des_usize = 0;
- /* If first 4 bytes in buffer are data descriptor signature then
- try to read the data descriptor.
- If not, scan for signature and break if found, let bfwrite flush
- the data and then next read should put the data descriptor at
- the beginning of the buffer.
- */
- if (
- (b[0] != 0x50 /*'P' except EBCDIC*/ ||
- b[1] != 0x4b /*'K' except EBCDIC*/ ||
- b[2] != '\07' ||
- b[3] != '\010')) {
- /* buffer is not start of data descriptor */
- for (kk = 0; kk < k; kk++) {
- /* add byte to end of sbuf */
- for (i = 0; i < 3; i++)
- sbuf[i] = sbuf[i + 1];
- sbuf[3] = b[kk];
- /* see if this is signature */
- if (
- (sbuf[0] == 0x50 /*'P' except EBCDIC*/ &&
- sbuf[1] == 0x4b /*'K' except EBCDIC*/ &&
- sbuf[2] == '\07' &&
- sbuf[3] == '\010')) {
- kk -= 3;
- if (zfseeko(in_file, bytes_this_split + kk, SEEK_SET) != 0) {
- /* seek error */
- ZIPERR(ZE_READ, "seek failed reading descriptor");
- }
- des_start = zftello(in_file);
- k = kk;
- break;
- }
- }
- }
- else
- /* signature at start of buffer */
- {
- des_good = 0;
- #ifdef ZIP64_SUPPORT
- if (zip64_entry) {
- /* read Zip64 data descriptor */
- if (k < 24) {
- /* not enough bytes, so can't be data descriptor
- as data descriptors can't be split across splits
- */
- }
- else
- {
- /* read the Zip64 descriptor */
- des_crc = LG(b + 4);
- des_csize = LLG(b + 8);
- des_usize = LLG(b + 16);
- /* if this is the right data descriptor then the sizes should match */
- if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
- /* apparently this signature does not go with this data so skip */
- /* write out signature as data */
- k = 4;
- if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
- /* seek error */
- ZIPERR(ZE_READ, "seek failed reading descriptor");
- }
- if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
- {
- free((zvoid *)b);
- fprintf(mesg," fcopy: write error\n");
- return ZE_TEMP;
- }
- m += k;
- continue;
- }
- else
- {
- /* apparently this is the correct data descriptor */
- /* we should check the CRC but would need to inflate
- the data */
- /* skip descriptor as will write out later */
- des_good = 1;
- k = 24;
- data_start = zftello(in_file);
- if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
- /* seek error */
- ZIPERR(ZE_READ, "seek failed reading descriptor");
- }
- data_start = zftello(in_file);
- }
- }
- }
- else
- #endif
- {
- /* read standard data descriptor */
- if (k < 16) {
- /* not enough bytes, so can't be data descriptor
- as data descriptors can't be split across splits
- */
- }
- else
- {
- /* read the descriptor */
- des_crc = LG(b + 4);
- des_csize = LG(b + 8);
- des_usize = LG(b + 12);
- /* if this is the right data descriptor then the sizes should match */
- if ((uzoff_t)des_start - (uzoff_t)data_start != des_csize) {
- /* apparently this signature does not go with this data so skip */
- /* write out signature as data */
- k = 4;
- if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
- /* seek error */
- ZIPERR(ZE_READ, "seek failed reading descriptor");
- }
- if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
- {
- free((zvoid *)b);
- fprintf(mesg," fcopy: write error\n");
- return ZE_TEMP;
- }
- m += k;
- continue;
- }
- else
- {
- /* apparently this is the correct data descriptor */
- /* we should check the CRC but this does not work for
- encrypted data */
- /* skip descriptor as will write out later */
- des_good = 1;
- data_start = zftello(in_file);
- k = 16;
- if (zfseeko(in_file, des_start + k, SEEK_SET) != 0) {
- /* seek error */
- ZIPERR(ZE_READ, "seek failed reading descriptor");
- }
- data_start = zftello(in_file);
- }
- }
- }
- }
- }
- if (des_good) {
- /* skip descriptor as will write out later */
- } else {
- /* write out apparently wrong descriptor as data */
- if (bfwrite(b, 1, k, BFWRITE_DATA) != k)
- {
- free((zvoid *)b);
- fprintf(mesg," fcopy: write error\n");
- return ZE_TEMP;
- }
- m += k;
- }
- if (copy_only && !display_globaldots) {
- if (dot_size > 0) {
- /* initial space */
- if (noisy && dot_count == -1) {
- #ifndef WINDLL
- putc(' ', mesg);
- fflush(mesg);
- #else
- fprintf(stdout,"%c",' ');
- #endif
- dot_count++;
- }
- dot_count += k;
- if (dot_size <= dot_count) dot_count = 0;
- }
- if ((verbose || noisy) && dot_size && !dot_count) {
- #ifndef WINDLL
- putc('.', mesg);
- fflush(mesg);
- #else
- fprintf(stdout,"%c",'.');
- #endif
- mesg_line_started = 1;
- }
- }
- if (des_good)
- break;
- if (des)
- continue;
- if ((des || n != (uzoff_t)(-1L)) && m < n && feof(in_file)) {
- /* open next split */
- current_in_disk++;
- if (current_in_disk >= total_disks) {
- /* done */
- break;
- } else if (current_in_disk == total_disks - 1) {
- /* last disk is archive.zip */
- if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
- zipwarn("reading archive: ", in_path);
- return ZE_MEM;
- }
- strcpy(split_path, in_path);
- } else {
- /* other disks are archive.z01, archive.z02, ... */
- split_path = get_in_split_path(in_path, current_in_disk);
- }
- fclose(in_file);
- /* open the split */
- while ((in_file = zfopen(split_path, FOPR)) == NULL) {
- int r = 0;
- /* could not open split */
- if (fix == 1 && skip_this_disk) {
- free(split_path);
- free((zvoid *)b);
- return ZE_FORM;
- }
- /* Ask for directory with split. Updates in_path */
- r = ask_for_split_read_path(current_in_disk);
- if (r == ZE_ABORT) {
- zipwarn("could not find split: ", split_path);
- free(split_path);
- free((zvoid *)b);
- return ZE_ABORT;
- }
- if (r == ZE_EOF) {
- zipmessage_nl("", 1);
- zipwarn("user ended reading - closing archive", "");
- free(split_path);
- free((zvoid *)b);
- return ZE_EOF;
- }
- if (fix == 2 && skip_this_disk) {
- /* user asked to skip this disk */
- zipwarn("skipping split file: ", split_path);
- current_in_disk++;
- }
- if (current_in_disk == total_disks - 1) {
- /* last disk is archive.zip */
- if ((split_path = malloc(strlen(in_path) + 1)) == NULL) {
- zipwarn("reading archive: ", in_path);
- return ZE_MEM;
- }
- strcpy(split_path, in_path);
- } else {
- /* other disks are archive.z01, archive.z02, ... */
- split_path = get_in_split_path(zipfile, current_in_disk);
- }
- }
- if (fix == 2 && skip_this_disk) {
- /* user asked to skip this disk */
- free(split_path);
- free((zvoid *)b);
- return ZE_FORM;
- }
- free(split_path);
- }
- }
- free((zvoid *)b);
- return ZE_OK;
- }
- #ifdef NO_RENAME
- int rename(from, to)
- ZCONST char *from;
- ZCONST char *to;
- {
- unlink(to);
- if (link(from, to) == -1)
- return -1;
- if (unlink(from) == -1)
- return -1;
- return 0;
- }
- #endif /* NO_RENAME */
- #ifdef ZMEM
- /************************/
- /* Function memset() */
- /************************/
- /*
- * memset - for systems without it
- * bill davidsen - March 1990
- */
- char *
- memset(buf, init, len)
- register char *buf; /* buffer loc */
- register int init; /* initializer */
- register unsigned int len; /* length of the buffer */
- {
- char *start;
- start = buf;
- while (len--) *(buf++) = init;
- return(start);
- }
- /************************/
- /* Function memcpy() */
- /************************/
- char *
- memcpy(dst,src,len) /* v2.0f */
- register char *dst, *src;
- register unsigned int len;
- {
- char *start;
- start = dst;
- while (len--)
- *dst++ = *src++;
- return(start);
- }
- /************************/
- /* Function memcmp() */
- /************************/
- int
- memcmp(b1,b2,len) /* jpd@usl.edu -- 11/16/90 */
- register char *b1, *b2;
- register unsigned int len;
- {
- if (len) do { /* examine each byte (if any) */
- if (*b1++ != *b2++)
- return (*((uch *)b1-1) - *((uch *)b2-1)); /* exit when miscompare */
- } while (--len);
- return(0); /* no miscompares, yield 0 result */
- }
- #endif /* ZMEM */
- /*------------------------------------------------------------------
- * Split archives
- */
- /* ask_for_split_read_path
- *
- * If the next split file is not in the current directory, ask
- * the user where it is.
- *
- * in_path is the base path for reading splits and is usually
- * the same as zipfile. The path in in_path must be the archive
- * file ending in .zip as this is assumed by get_in_split_path().
- *
- * Updates in_path if changed. Returns ZE_OK if OK or ZE_ABORT if
- * user cancels reading archive.
- *
- * If fix = 1 then allow skipping disk (user may not have it).
- */
- #define SPLIT_MAXPATH (FNMAX + 4010)
- int ask_for_split_read_path(current_disk)
- ulg current_disk;
- {
- FILE *f;
- int is_readable = 0;
- int i;
- char *split_dir = NULL;
- char *archive_name = NULL;
- char *split_name = NULL;
- char *split_path = NULL;
- char buf[SPLIT_MAXPATH + 100];
- /* get split path */
- split_path = get_in_split_path(in_path, current_disk);
- /* get the directory */
- if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(split_dir, in_path);
- /* remove any name at end */
- for (i = strlen(split_dir) - 1; i >= 0; i--) {
- if (split_dir[i] == '/' || split_dir[i] == '\\'
- || split_dir[i] == ':') {
- split_dir[i + 1] = '\0';
- break;
- }
- }
- if (i < 0)
- split_dir[0] = '\0';
- /* get the name of the archive */
- if ((archive_name = malloc(strlen(in_path) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- if (strlen(in_path) == strlen(split_dir)) {
- archive_name[0] = '\0';
- } else {
- strcpy(archive_name, in_path + strlen(split_dir));
- }
- /* get the name of the split */
- if ((split_name = malloc(strlen(split_path) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- if (strlen(in_path) == strlen(split_dir)) {
- split_name[0] = '\0';
- } else {
- strcpy(split_name, split_path + strlen(split_dir));
- }
- if (i < 0) {
- strcpy(split_dir, "(current directory)");
- }
- fprintf(mesg, "\n\nCould not find:\n");
- fprintf(mesg, " %s\n", split_path);
- /*
- fprintf(mesg, "Please enter the path directory (. for cur dir) where\n");
- fprintf(mesg, " %s\n", split_name);
- fprintf(mesg, "is located\n");
- */
- for (;;) {
- if (is_readable) {
- fprintf(mesg, "\nHit c (change path to where this split file is)");
- fprintf(mesg, "\n q (abort archive - quit)");
- fprintf(mesg, "\n or ENTER (continue with this split): ");
- } else {
- if (fix == 1) {
- fprintf(mesg, "\nHit c (change path to where this split file is)");
- fprintf(mesg, "\n s (skip this split)");
- fprintf(mesg, "\n q (abort archive - quit)");
- fprintf(mesg, "\n or ENTER (try reading this split again): ");
- } else if (fix == 2) {
- fprintf(mesg, "\nHit c (change path to where this split file is)");
- fprintf(mesg, "\n s (skip this split)");
- fprintf(mesg, "\n q (abort archive - quit)");
- fprintf(mesg, "\n e (end this archive - no more splits)");
- fprintf(mesg, "\n z (look for .zip split - the last split)");
- fprintf(mesg, "\n or ENTER (try reading this split again): ");
- } else {
- fprintf(mesg, "\nHit c (change path to where this split file is)");
- fprintf(mesg, "\n q (abort archive - quit)");
- fprintf(mesg, "\n or ENTER (try reading this split again): ");
- }
- }
- fflush(mesg);
- fgets(buf, SPLIT_MAXPATH, stdin);
- /* remove any newline */
- for (i = 0; buf[i]; i++) {
- if (buf[i] == '\n') {
- buf[i] = '\0';
- break;
- }
- }
- if (toupper(buf[0]) == 'Q') {
- return ZE_ABORT;
- } else if ((fix == 1 || fix == 2) && toupper(buf[0]) == 'S') {
- /*
- fprintf(mesg, "\nSkip this split/disk? (files in this split will not be recovered) [n/y] ");
- fflush(mesg);
- fgets(buf, SPLIT_MAXPATH, stdin);
- if (buf[0] == 'y' || buf[0] == 'Y') {
- */
- skip_this_disk = current_in_disk + 1;
- return ZE_FORM;
- } else if (toupper(buf[0]) == 'C') {
- fprintf(mesg, "\nEnter path where this split is (ENTER = same dir, . = current dir)");
- fprintf(mesg, "\n: ");
- fflush(mesg);
- fgets(buf, SPLIT_MAXPATH, stdin);
- is_readable = 0;
- /* remove any newline */
- for (i = 0; buf[i]; i++) {
- if (buf[i] == '\n') {
- buf[i] = '\0';
- break;
- }
- }
- if (buf[0] == '\0') {
- /* Hit ENTER so try old path again - could be removable media was changed */
- strcpy(buf, split_path);
- }
- } else if (fix == 2 && toupper(buf[0]) == 'E') {
- /* no more splits to read */
- return ZE_EOF;
- } else if (fix == 2 && toupper(buf[0]) == 'Z') {
- total_disks = current_disk + 1;
- free(split_path);
- split_path = get_in_split_path(in_path, current_disk);
- buf[0] = '\0';
- strncat(buf, split_path, SPLIT_MAXPATH);
- }
- if (strlen(buf) > 0) {
- /* changing path */
- /* check if user wants current directory */
- if (buf[0] == '.' && buf[1] == '\0') {
- buf[0] = '\0';
- }
- /* remove any name at end */
- for (i = strlen(buf); i >= 0; i--) {
- if (buf[i] == '/' || buf[i] == '\\'
- || buf[i] == ':') {
- buf[i + 1] = '\0';
- break;
- }
- }
- /* update base_path to newdir/split_name - in_path is the .zip file path */
- free(in_path);
- if (i < 0) {
- /* just name so current directory */
- strcpy(buf, "(current directory)");
- if (archive_name == NULL) {
- i = 0;
- } else {
- i = strlen(archive_name);
- }
- if ((in_path = malloc(strlen(archive_name) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(in_path, archive_name);
- } else {
- /* not the current directory */
- /* remove any name at end */
- for (i = strlen(buf); i >= 0; i--) {
- if (buf[i] == '/') {
- buf[i + 1] = '\0';
- break;
- }
- }
- if (i < 0) {
- buf[0] = '\0';
- }
- if ((in_path = malloc(strlen(buf) + strlen(archive_name) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(in_path, buf);
- strcat(in_path, archive_name);
- }
- free(split_path);
- /* get split path */
- split_path = get_in_split_path(in_path, current_disk);
- free(split_dir);
- if ((split_dir = malloc(strlen(in_path) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(split_dir, in_path);
- /* remove any name at end */
- for (i = strlen(split_dir); i >= 0; i--) {
- if (split_dir[i] == '/') {
- split_dir[i + 1] = '\0';
- break;
- }
- }
- /* try to open it */
- if ((f = fopen(split_path, "r")) == NULL) {
- fprintf(mesg, "\nCould not find or open\n");
- fprintf(mesg, " %s\n", split_path);
- /*
- fprintf(mesg, "Please enter the path (. for cur dir) where\n");
- fprintf(mesg, " %s\n", split_name);
- fprintf(mesg, "is located\n");
- */
- continue;
- }
- fclose(f);
- is_readable = 1;
- fprintf(mesg, "Found: %s\n", split_path);
- } else {
- /* try to open it */
- if ((f = fopen(split_path, "r")) == NULL) {
- fprintf(mesg, "\nCould not find or open\n");
- fprintf(mesg, " %s\n", split_path);
- /*
- fprintf(mesg, "Please enter the path (. for cur dir) where\n");
- fprintf(mesg, " %s\n", split_name);
- fprintf(mesg, "is located\n");
- */
- continue;
- }
- fclose(f);
- is_readable = 1;
- fprintf(mesg, "\nFound: %s\n", split_path);
- break;
- }
- }
- free(archive_name);
- free(split_dir);
- free(split_name);
- return ZE_OK;
- }
- /* ask_for_split_write_path
- *
- * Verify the directory for the next split. Called
- * when -sp is used to pause between writing splits.
- *
- * Updates out_path and return 1 if OK or 0 if cancel
- */
- int ask_for_split_write_path(current_disk)
- ulg current_disk;
- {
- unsigned int num = (unsigned int)current_disk + 1;
- int i;
- char *split_dir = NULL;
- char *split_name = NULL;
- char buf[FNMAX + 40];
- /* get the directory */
- if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(split_dir, out_path);
- /* remove any name at end */
- for (i = strlen(split_dir); i >= 0; i--) {
- if (split_dir[i] == '/' || split_dir[i] == '\\'
- || split_dir[i] == ':') {
- split_dir[i + 1] = '\0';
- break;
- }
- }
- /* get the name of the split */
- if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- if (strlen(out_path) == strlen(split_dir)) {
- split_name[0] = '\0';
- } else {
- strcpy(split_name, out_path + strlen(split_dir));
- }
- if (i < 0) {
- strcpy(split_dir, "(current directory)");
- }
- if (mesg_line_started)
- fprintf(mesg, "\n");
- fprintf(mesg, "\nOpening disk %d\n", num);
- fprintf(mesg, "Hit ENTER to write to default path of\n");
- fprintf(mesg, " %s\n", split_dir);
- fprintf(mesg, "or enter a new directory path (. for cur dir) and hit ENTER\n");
- for (;;) {
- fprintf(mesg, "\nPath (or hit ENTER to continue): ");
- fflush(mesg);
- fgets(buf, FNMAX, stdin);
- /* remove any newline */
- for (i = 0; buf[i]; i++) {
- if (buf[i] == '\n') {
- buf[i] = '\0';
- break;
- }
- }
- if (strlen(buf) > 0) {
- /* changing path */
- /* current directory */
- if (buf[0] == '.' && buf[1] == '\0') {
- buf[0] = '\0';
- }
- /* remove any name at end */
- for (i = strlen(buf); i >= 0; i--) {
- if (buf[i] == '/' || buf[i] == '\\'
- || buf[i] == ':') {
- buf[i + 1] = '\0';
- break;
- }
- }
- /* update out_path to newdir/split_name */
- free(out_path);
- if (i < 0) {
- /* just name so current directory */
- strcpy(buf, "(current directory)");
- if (split_name == NULL) {
- i = 0;
- } else {
- i = strlen(split_name);
- }
- if ((out_path = malloc(strlen(split_name) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(out_path, split_name);
- } else {
- /* not the current directory */
- /* remove any name at end */
- for (i = strlen(buf); i >= 0; i--) {
- if (buf[i] == '/') {
- buf[i + 1] = '\0';
- break;
- }
- }
- if (i < 0) {
- buf[0] = '\0';
- }
- if ((out_path = malloc(strlen(buf) + strlen(split_name) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(out_path, buf);
- strcat(out_path, split_name);
- }
- fprintf(mesg, "Writing to:\n %s\n", buf);
- free(split_name);
- free(split_dir);
- if ((split_dir = malloc(strlen(out_path) + 40)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(split_dir, out_path);
- /* remove any name at end */
- for (i = strlen(split_dir); i >= 0; i--) {
- if (split_dir[i] == '/') {
- split_dir[i + 1] = '\0';
- break;
- }
- }
- if ((split_name = malloc(strlen(out_path) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- strcpy(split_name, out_path + strlen(split_dir));
- } else {
- break;
- }
- }
- free(split_dir);
- free(split_name);
- /* for now no way out except Ctrl C */
- return 1;
- }
- /* split_name
- *
- * get name of split being read
- */
- char *get_in_split_path(base_path, disk_number)
- char *base_path;
- ulg disk_number;
- {
- char *split_path = NULL;
- int base_len = 0;
- int path_len = 0;
- ulg num = disk_number + 1;
- char ext[6];
- #ifdef VMS
- int vers_len; /* File version length. */
- char *vers_ptr; /* File version string. */
- #endif /* def VMS */
- /*
- * A split has extension z01, z02, ..., z99, z100, z101, ... z999
- * We currently support up to .z99999
- * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
- * so use that. Means on DOS can only have 100 splits.
- */
- if (num == total_disks) {
- /* last disk is base path */
- if ((split_path = malloc(strlen(base_path) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "base path");
- }
- strcpy(split_path, base_path);
- return split_path;
- } else {
- if (num > 99999) {
- ZIPERR(ZE_BIG, "More than 99999 splits needed");
- }
- sprintf(ext, "z%02lu", num);
- }
- /* create path for this split - zip.c checked for .zip extension */
- base_len = strlen(base_path) - 3;
- path_len = base_len + strlen(ext);
- #ifdef VMS
- /* On VMS, locate the file version, and adjust base_len accordingly.
- Note that path_len is correct, as-is.
- */
- vers_ptr = vms_file_version( base_path);
- vers_len = strlen( vers_ptr);
- base_len -= vers_len;
- #endif /* def VMS */
- if ((split_path = malloc(path_len + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- /* copy base_path except for end zip */
- strcpy(split_path, base_path);
- split_path[base_len] = '\0';
- /* add extension */
- strcat(split_path, ext);
- #ifdef VMS
- /* On VMS, append (preserve) the file version. */
- strcat(split_path, vers_ptr);
- #endif /* def VMS */
- return split_path;
- }
- /* split_name
- *
- * get name of split being written
- */
- char *get_out_split_path(base_path, disk_number)
- char *base_path;
- ulg disk_number;
- {
- char *split_path = NULL;
- int base_len = 0;
- int path_len = 0;
- ulg num = disk_number + 1;
- char ext[6];
- #ifdef VMS
- int vers_len; /* File version length. */
- char *vers_ptr; /* File version string. */
- #endif /* def VMS */
- /*
- * A split has extension z01, z02, ..., z99, z100, z101, ... z999
- * We currently support up to .z99999
- * WinZip will also read .100, .101, ... but AppNote 6.2.2 uses above
- * so use that. Means on DOS can only have 100 splits.
- */
- if (num > 99999) {
- ZIPERR(ZE_BIG, "More than 99999 splits needed");
- }
- sprintf(ext, "z%02lu", num);
- /* create path for this split - zip.c checked for .zip extension */
- base_len = strlen(base_path) - 3;
- path_len = base_len + strlen(ext);
- #ifdef VMS
- /* On VMS, locate the file version, and adjust base_len accordingly.
- Note that path_len is correct, as-is.
- */
- vers_ptr = vms_file_version( base_path);
- vers_len = strlen( vers_ptr);
- base_len -= vers_len;
- #endif /* def VMS */
- if ((split_path = malloc(path_len + 1)) == NULL) {
- ZIPERR(ZE_MEM, "split path");
- }
- /* copy base_path except for end zip */
- strcpy(split_path, base_path);
- split_path[base_len] = '\0';
- /* add extension */
- strcat(split_path, ext);
- #ifdef VMS
- /* On VMS, append (preserve) the file version. */
- strcat(split_path, vers_ptr);
- #endif /* def VMS */
- return split_path;
- }
- /* close_split
- *
- * close a split - assume that the paths needed for the splits are
- * available.
- */
- int close_split(disk_number, tempfile, temp_name)
- ulg disk_number;
- FILE *tempfile;
- char *temp_name;
- {
- char *split_path = NULL;
- split_path = get_out_split_path(out_path, disk_number);
- if (noisy_splits) {
- zipmessage("\tClosing split ", split_path);
- }
- fclose(tempfile);
- rename_split(temp_name, split_path);
- set_filetype(split_path);
- return ZE_OK;
- }
- /* bfwrite
- Does the fwrite but also counts bytes and does splits */
- size_t bfwrite(buffer, size, count, mode)
- ZCONST void *buffer;
- size_t size;
- size_t count;
- int mode;
- {
- size_t bytes_written = 0;
- size_t r;
- size_t b = size * count;
- uzoff_t bytes_left_in_split = 0;
- size_t bytes_to_write = b;
- /* -------------------------------- */
- /* local header */
- if (mode == BFWRITE_LOCALHEADER) {
- /* writing local header - reset entry data count */
- bytes_this_entry = 0;
- /* save start of local header so we can rewrite later */
- current_local_file = y;
- current_local_disk = current_disk;
- current_local_offset = bytes_this_split;
- }
- if (split_size == 0)
- bytes_left_in_split = bytes_to_write;
- else
- bytes_left_in_split = split_size - bytes_this_split;
- if (bytes_to_write > bytes_left_in_split) {
- if (mode == BFWRITE_HEADER ||
- mode == BFWRITE_LOCALHEADER ||
- mode == BFWRITE_CENTRALHEADER) {
- /* if can't write entire header save for next split */
- bytes_to_write = 0;
- } else {
- /* normal data so fill the split */
- bytes_to_write = (size_t)bytes_left_in_split;
- }
- }
- /* -------------------------------- */
- /* central header */
- if (mode == BFWRITE_CENTRALHEADER) {
- /* set start disk for CD */
- if (cd_start_disk == (ulg)-1) {
- cd_start_disk = current_disk;
- cd_start_offset = bytes_this_split;
- }
- cd_entries_this_disk++;
- total_cd_entries++;
- }
- /* -------------------------------- */
- if (bytes_to_write > 0) {
- /* write out the bytes for this split */
- r = fwrite(buffer, size, bytes_to_write, y);
- bytes_written += r;
- bytes_to_write = b - r;
- bytes_this_split += r;
- if (mode == BFWRITE_DATA)
- /* if data descriptor do not include in count */
- bytes_this_entry += r;
- } else {
- bytes_to_write = b;
- }
- if (bytes_to_write > 0) {
- if (split_method) {
- /* still bytes to write so close split and open next split */
- bytes_prev_splits += bytes_this_split;
- if (split_method == 1 && ferror(y)) {
- /* if writing all splits to same place and have problem then bad */
- ZIPERR(ZE_WRITE, "Could not write split");
- }
- if (split_method == 2 && ferror(y)) {
- /* A split must be at least 64K except last .zip split */
- if (bytes_this_split < 64 * (uzoff_t)0x400) {
- ZIPERR(ZE_WRITE, "Not enough space to write split");
- }
- }
- /* close this split */
- if (split_method == 1 && current_local_disk == current_disk) {
- /* keep split open so can update it */
- current_local_tempname = tempzip;
- } else {
- /* close split */
- close_split(current_disk, y, tempzip);
- y = NULL;
- free(tempzip);
- tempzip = NULL;
- }
- cd_entries_this_disk = 0;
- bytes_this_split = 0;
- /* increment disk - disks are numbered 0, 1, 2, ... and
- splits are 01, 02, ... */
- current_disk++;
- if (split_method == 2 && split_bell) {
- /* bell when pause to ask for next split */
- putc('\007', mesg);
- fflush(mesg);
- }
- for (;;) {
- /* if method 2 pause and allow changing path */
- if (split_method == 2) {
- if (ask_for_split_write_path(current_disk) == 0) {
- ZIPERR(ZE_ABORT, "could not write split");
- }
- }
- /* open next split */
- #if defined(UNIX) && !defined(NO_MKSTEMP)
- {
- int yd;
- int i;
- /* use mkstemp to avoid race condition and compiler warning */
- if (tempath != NULL)
- {
- /* if -b used to set temp file dir use that for split temp */
- if ((tempzip = malloc(strlen(tempath) + 12)) == NULL) {
- ZIPERR(ZE_MEM, "allocating temp filename");
- }
- strcpy(tempzip, tempath);
- if (lastchar(tempzip) != '/')
- strcat(tempzip, "/");
- }
- else
- {
- /* create path by stripping name and appending template */
- if ((tempzip = malloc(strlen(zipfile) + 12)) == NULL) {
- ZIPERR(ZE_MEM, "allocating temp filename");
- }
- strcpy(tempzip, zipfile);
- for(i = strlen(tempzip); i > 0; i--) {
- if (tempzip[i - 1] == '/')
- break;
- }
- tempzip[i] = '\0';
- }
- strcat(tempzip, "ziXXXXXX");
- if ((yd = mkstemp(tempzip)) == EOF) {
- ZIPERR(ZE_TEMP, tempzip);
- }
- if ((y = fdopen(yd, FOPW_TMP)) == NULL) {
- ZIPERR(ZE_TEMP, tempzip);
- }
- }
- #else
- if ((tempzip = tempname(zipfile)) == NULL) {
- ZIPERR(ZE_MEM, "allocating temp filename");
- }
- if ((y = zfopen(tempzip, FOPW_TMP)) == NULL) {
- ZIPERR(ZE_TEMP, tempzip);
- }
- #endif
- r = fwrite((char *)buffer + bytes_written, 1, bytes_to_write, y);
- bytes_written += r;
- bytes_this_split += r;
- if (!(mode == BFWRITE_HEADER ||
- mode == BFWRITE_LOCALHEADER ||
- mode == BFWRITE_CENTRALHEADER)) {
- bytes_this_entry += r;
- }
- if (bytes_to_write > r) {
- /* buffer bigger than split */
- if (split_method == 2) {
- /* let user choose another disk */
- zipwarn("Not enough room on disk", "");
- continue;
- } else {
- ZIPERR(ZE_WRITE, "Not enough room on disk");
- }
- }
- if (mode == BFWRITE_LOCALHEADER ||
- mode == BFWRITE_HEADER ||
- mode == BFWRITE_CENTRALHEADER) {
- if (split_method == 1 && current_local_file &&
- current_local_disk != current_disk) {
- /* We're opening a new split because the next header
- did not fit on the last split. We need to now close
- the last split and update the pointers for
- the current split. */
- close_split(current_local_disk, current_local_file,
- current_local_tempname);
- free(current_local_tempname);
- }
- current_local_tempname = tempzip;
- current_local_file = y;
- current_local_offset = 0;
- current_local_disk = current_disk;
- }
- break;
- }
- }
- else
- {
- /* likely have more than fits but no splits */
- /* probably already have error "no space left on device" */
- /* could let flush_outbuf() handle error but bfwrite() is called for
- headers also */
- if (ferror(y))
- ziperr(ZE_WRITE, "write error on zip file");
- }
- }
- /* display dots for archive instead of for each file */
- if (display_globaldots) {
- if (dot_size > 0) {
- /* initial space */
- if (dot_count == -1) {
- #ifndef WINDLL
- putc(' ', mesg);
- fflush(mesg);
- #else
- fprintf(stdout,"%c",' ');
- #endif
- /* assume a header will be written first, so avoid 0 */
- dot_count = 1;
- }
- /* skip incrementing dot count for small buffers like for headers */
- if (size * count > 1000) {
- dot_count++;
- if (dot_size <= dot_count * (zoff_t)size * (zoff_t)count) dot_count = 0;
- }
- }
- if (dot_size && !dot_count) {
- dot_count++;
- #ifndef WINDLL
- putc('.', mesg);
- fflush(mesg);
- #else
- fprintf(stdout,"%c",'.');
- #endif
- mesg_line_started = 1;
- }
- }
- return bytes_written;
- }
- #ifdef UNICODE_SUPPORT
- /*---------------------------------------------
- * Unicode conversion functions
- *
- * Provided by Paul Kienitz
- *
- * Some modifications to work with Zip
- *
- *---------------------------------------------
- */
- /*
- NOTES APPLICABLE TO ALL STRING FUNCTIONS:
- All of the x_to_y functions take parameters for an output buffer and
- its available length, and return an int. The value returned is the
- length of the string that the input produces, which may be larger than
- the provided buffer length. If the returned value is less than the
- buffer length, then the contents of the buffer will be null-terminated;
- otherwise, it will not be terminated and may be invalid, possibly
- stopping in the middle of a multibyte sequence.
- In all cases you may pass NULL as the buffer and/or 0 as the length, if
- you just want to learn how much space the string is going to require.
- The functions will return -1 if the input is invalid UTF-8 or cannot be
- encoded as UTF-8.
- */
- /* utility functions for managing UTF-8 and UCS-4 strings */
- /* utf8_char_bytes
- *
- * Returns the number of bytes used by the first character in a UTF-8
- * string, or -1 if the UTF-8 is invalid or null.
- */
- local int utf8_char_bytes(utf8)
- ZCONST char *utf8;
- {
- int t, r;
- unsigned lead;
- if (!utf8)
- return -1; /* no input */
- lead = (unsigned char) *utf8;
- if (lead < 0x80)
- r = 1; /* an ascii-7 character */
- else if (lead < 0xC0)
- return -1; /* error: trailing byte without lead byte */
- else if (lead < 0xE0)
- r = 2; /* an 11 bit character */
- else if (lead < 0xF0)
- r = 3; /* a 16 bit character */
- else if (lead < 0xF8)
- r = 4; /* a 21 bit character (the most currently used) */
- else if (lead < 0xFC)
- r = 5; /* a 26 bit character (shouldn't happen) */
- else if (lead < 0xFE)
- r = 6; /* a 31 bit character (shouldn't happen) */
- else
- return -1; /* error: invalid lead byte */
- for (t = 1; t < r; t++)
- if ((unsigned char) utf8[t] < 0x80 || (unsigned char) utf8[t] >= 0xC0)
- return -1; /* error: not enough valid trailing bytes */
- return r;
- }
- /* ucs4_char_from_utf8
- *
- * Given a reference to a pointer into a UTF-8 string, returns the next
- * UCS-4 character and advances the pointer to the next character sequence.
- * Returns ~0 and does not advance the pointer when input is ill-formed.
- *
- * Since the Unicode standard says 32-bit values won't be used (just
- * up to the current 21-bit mappings) changed this to signed to allow -1 to
- * be returned.
- */
- long ucs4_char_from_utf8(utf8)
- ZCONST char **utf8;
- {
- ulg ret;
- int t, bytes;
- if (!utf8)
- return -1; /* no input */
- bytes = utf8_char_bytes(*utf8);
- if (bytes <= 0)
- return -1; /* invalid input */
- if (bytes == 1)
- ret = **utf8; /* ascii-7 */
- else
- ret = **utf8 & (0x7F >> bytes); /* lead byte of a multibyte sequence */
- (*utf8)++;
- for (t = 1; t < bytes; t++) /* consume trailing bytes */
- ret = (ret << 6) | (*((*utf8)++) & 0x3F);
- return (long) ret;
- }
- /* utf8_from_ucs4_char - Convert UCS char to UTF-8
- *
- * Returns the number of bytes put into utf8buf to represent ch, from 1 to 6,
- * or -1 if ch is too large to represent. utf8buf must have room for 6 bytes.
- */
- local int utf8_from_ucs4_char(utf8buf, ch)
- char *utf8buf;
- ulg ch;
- {
- int trailing = 0;
- int leadmask = 0x80;
- int leadbits = 0x3F;
- ulg tch = ch;
- int ret;
- if (ch > 0x7FFFFFFF)
- return -1; /* UTF-8 can represent 31 bits */
- if (ch < 0x7F)
- {
- *utf8buf++ = (char) ch; /* ascii-7 */
- return 1;
- }
- do {
- trailing++;
- leadmask = (leadmask >> 1) | 0x80;
- leadbits >>= 1;
- tch >>= 6;
- } while (tch & ~leadbits);
- ret = trailing + 1;
- /* produce lead byte */
- *utf8buf++ = (char) (leadmask | (ch >> (6 * trailing)));
- /* produce trailing bytes */
- while (--trailing >= 0)
- *utf8buf++ = (char) (0x80 | ((ch >> (6 * trailing)) & 0x3F));
- return ret;
- }
- /*===================================================================*/
- /* utf8_to_ucs4_string - convert UTF-8 string to UCS string
- *
- * Return UCS count. Now returns int so can return -1.
- */
- local int utf8_to_ucs4_string(utf8, ucs4buf, buflen)
- ZCONST char *utf8;
- ulg *ucs4buf;
- int buflen;
- {
- int count = 0;
- for (;;)
- {
- long ch = ucs4_char_from_utf8(&utf8);
- if (ch == -1)
- return -1;
- else
- {
- if (ucs4buf && count < buflen)
- ucs4buf[count] = ch;
- if (ch == 0)
- return count;
- count++;
- }
- }
- }
- /* ucs4_string_to_utf8
- *
- *
- */
- local int ucs4_string_to_utf8(ucs4, utf8buf, buflen)
- ZCONST ulg *ucs4;
- char *utf8buf;
- int buflen;
- {
- char mb[6];
- int count = 0;
- if (!ucs4)
- return -1;
- for (;;)
- {
- int mbl = utf8_from_ucs4_char(mb, *ucs4++);
- int c;
- if (mbl <= 0)
- return -1;
- /* We could optimize this a bit by passing utf8buf + count */
- /* directly to utf8_from_ucs4_char when buflen >= count + 6... */
- c = buflen - count;
- if (mbl < c)
- c = mbl;
- if (utf8buf && count < buflen)
- strncpy(utf8buf + count, mb, c);
- if (mbl == 1 && !mb[0])
- return count; /* terminating nul */
- count += mbl;
- }
- }
- #if 0 /* currently unused */
- /* utf8_chars
- *
- * Wrapper: counts the actual unicode characters in a UTF-8 string.
- */
- local int utf8_chars(utf8)
- ZCONST char *utf8;
- {
- return utf8_to_ucs4_string(utf8, NULL, 0);
- }
- #endif
- /* --------------------------------------------------- */
- /* Unicode Support
- *
- * These functions common for all Unicode ports.
- *
- * These functions should allocate and return strings that can be
- * freed with free().
- *
- * 8/27/05 EG
- *
- * Use zwchar for wide char which is unsigned long
- * in zip.h and 32 bits. This avoids problems with
- * different sizes of wchar_t.
- */
- #ifdef WIN32
- zwchar *wchar_to_wide_string(wchar_string)
- wchar_t *wchar_string;
- {
- int i;
- int wchar_len;
- zwchar *wide_string;
- wchar_len = wcslen(wchar_string);
- if ((wide_string = malloc((wchar_len + 1) * sizeof(zwchar))) == NULL) {
- ZIPERR(ZE_MEM, "wchar to wide conversion");
- }
- for (i = 0; i <= wchar_len; i++) {
- wide_string[i] = wchar_string[i];
- }
- return wide_string;
- }
- /* is_ascii_stringw
- * Checks if a wide string is all ascii
- */
- int is_ascii_stringw(wstring)
- wchar_t *wstring;
- {
- wchar_t *pw;
- wchar_t cw;
- if (wstring == NULL)
- return 0;
- for (pw = wstring; (cw = *pw) != '\0'; pw++) {
- if (cw > 0x7F) {
- return 0;
- }
- }
- return 1;
- }
- #endif
- /* is_ascii_string
- * Checks if a string is all ascii
- */
- int is_ascii_string(mbstring)
- char *mbstring;
- {
- char *p;
- uch c;
- if (mbstring == NULL)
- return 0;
- for (p = mbstring; (c = (uch)*p) != '\0'; p++) {
- if (c > 0x7F) {
- return 0;
- }
- }
- return 1;
- }
- /* local to UTF-8 */
- char *local_to_utf8_string(local_string)
- char *local_string;
- {
- zwchar *wide_string = local_to_wide_string(local_string);
- char *utf8_string = wide_to_utf8_string(wide_string);
- free(wide_string);
- return utf8_string;
- }
- /* wide_char_to_escape_string
- provides a string that represents a wide char not in local char set
- An initial try at an algorithm. Suggestions welcome.
- If not an ASCII char, probably need 2 bytes at least. So if
- a 2-byte wide encode it as 4 hex digits with a leading #U.
- Since the Unicode standard has been frozen, it looks like 3 bytes
- should be enough for any large Unicode character. In these cases
- prefix the string with #L.
- So
- #U1234
- is a 2-byte wide character with bytes 0x12 and 0x34 while
- #L123456
- is a 3-byte wide with bytes 0x12, 0x34, and 0x56.
- On Windows, wide that need two wide characters as a surrogate pair
- to represent them need to be converted to a single number.
- */
- /* set this to the max bytes an escape can be */
- #define MAX_ESCAPE_BYTES 8
- char *wide_char_to_escape_string(wide_char)
- zwchar wide_char;
- {
- int i;
- zwchar w = wide_char;
- uch b[9];
- char e[7];
- int len;
- char *r;
- /* fill byte array with zeros */
- for (len = 0; len < sizeof(zwchar); len++) {
- b[len] = 0;
- }
- /* get bytes in right to left order */
- for (len = 0; w; len++) {
- b[len] = (char)(w % 0x100);
- w /= 0x100;
- }
- if ((r = malloc(MAX_ESCAPE_BYTES + 8)) == NULL) {
- ZIPERR(ZE_MEM, "wide_char_to_escape_string");
- }
- strcpy(r, "#");
- /* either 2 bytes or 4 bytes */
- if (len < 3) {
- len = 2;
- strcat(r, "U");
- } else {
- len = 3;
- strcat(r, "L");
- }
- for (i = len - 1; i >= 0; i--) {
- sprintf(e, "%02x", b[i]);
- strcat(r, e);
- }
- return r;
- }
- #if 0
- /* returns the wide character represented by the escape string */
- zwchar escape_string_to_wide(escape_string)
- char *escape_string;
- {
- int i;
- zwchar w;
- char c;
- char u;
- int len;
- char *e = escape_string;
- if (e == NULL) {
- return 0;
- }
- if (e[0] != '#') {
- /* no leading # */
- return 0;
- }
- len = strlen(e);
- /* either #U1234 or #L123456 format */
- if (len != 6 && len != 8) {
- return 0;
- }
- w = 0;
- if (e[1] == 'L') {
- if (len != 8) {
- return 0;
- }
- /* 3 bytes */
- for (i = 2; i < 8; i++) {
- c = e[i];
- u = toupper(c);
- if (u >= 'A' && u <= 'F') {
- w = w * 0x10 + (zwchar)(u + 10 - 'A');
- } else if (c >= '0' && c <= '9') {
- w = w * 0x10 + (zwchar)(c - '0');
- } else {
- return 0;
- }
- }
- } else if (e[1] == 'U') {
- /* 2 bytes */
- for (i = 2; i < 6; i++) {
- c = e[i];
- u = toupper(c);
- if (u >= 'A' && u <= 'F') {
- w = w * 0x10 + (zwchar)(u + 10 - 'A');
- } else if (c >= '0' && c <= '9') {
- w = w * 0x10 + (zwchar)(c - '0');
- } else {
- return 0;
- }
- }
- }
- return w;
- }
- #endif
- char *local_to_escape_string(local_string)
- char *local_string;
- {
- zwchar *wide_string = local_to_wide_string(local_string);
- char *escape_string = wide_to_escape_string(wide_string);
- free(wide_string);
- return escape_string;
- }
- #ifdef WIN32
- char *wchar_to_local_string(wstring)
- wchar_t *wstring;
- {
- zwchar *wide_string = wchar_to_wide_string(wstring);
- char *local_string = wide_to_local_string(wide_string);
- free(wide_string);
- return local_string;
- }
- #endif
- #ifndef WIN32 /* The Win32 port uses a system-specific variant. */
- /* convert wide character string to multi-byte character string */
- char *wide_to_local_string(wide_string)
- zwchar *wide_string;
- {
- int i;
- wchar_t wc;
- int b;
- int state_dependent;
- int wsize = 0;
- int max_bytes = MB_CUR_MAX;
- char buf[9];
- char *buffer = NULL;
- char *local_string = NULL;
- for (wsize = 0; wide_string[wsize]; wsize++) ;
- if (MAX_ESCAPE_BYTES > max_bytes)
- max_bytes = MAX_ESCAPE_BYTES;
- if ((buffer = (char *)malloc(wsize * max_bytes + 1)) == NULL) {
- ZIPERR(ZE_MEM, "wide_to_local_string");
- }
- /* convert it */
- buffer[0] = '\0';
- /* set initial state if state-dependent encoding */
- wc = (wchar_t)'a';
- b = wctomb(NULL, wc);
- if (b == 0)
- state_dependent = 0;
- else
- state_dependent = 1;
- for (i = 0; i < wsize; i++) {
- if (sizeof(wchar_t) < 4 && wide_string[i] > 0xFFFF) {
- /* wchar_t probably 2 bytes */
- /* could do surrogates if state_dependent and wctomb can do */
- wc = zwchar_to_wchar_t_default_char;
- } else {
- wc = (wchar_t)wide_string[i];
- }
- b = wctomb(buf, wc);
- if (unicode_escape_all) {
- if (b == 1 && (uch)buf[0] <= 0x7f) {
- /* ASCII */
- strncat(buffer, buf, b);
- } else {
- /* use escape for wide character */
- char *e = wide_char_to_escape_string(wide_string[i]);
- strcat(buffer, e);
- free(e);
- }
- } else if (b > 0) {
- /* multi-byte char */
- strncat(buffer, buf, b);
- } else {
- /* no MB for this wide */
- if (use_wide_to_mb_default) {
- /* default character */
- strcat(buffer, wide_to_mb_default_string);
- } else {
- /* use escape for wide character */
- char *e = wide_char_to_escape_string(wide_string[i]);
- strcat(buffer, e);
- free(e);
- }
- }
- }
- if ((local_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
- free(buffer);
- ZIPERR(ZE_MEM, "wide_to_local_string");
- }
- strcpy(local_string, buffer);
- free(buffer);
- return local_string;
- }
- #endif /* !WIN32 */
- /* convert wide character string to escaped string */
- char *wide_to_escape_string(wide_string)
- zwchar *wide_string;
- {
- int i;
- int wsize = 0;
- char buf[9];
- char *buffer = NULL;
- char *escape_string = NULL;
- for (wsize = 0; wide_string[wsize]; wsize++) ;
- if ((buffer = (char *)malloc(wsize * MAX_ESCAPE_BYTES + 1)) == NULL) {
- ZIPERR(ZE_MEM, "wide_to_escape_string");
- }
- /* convert it */
- buffer[0] = '\0';
- for (i = 0; i < wsize; i++) {
- if (wide_string[i] <= 0x7f && isprint((char)wide_string[i])) {
- /* ASCII */
- buf[0] = (char)wide_string[i];
- buf[1] = '\0';
- strcat(buffer, buf);
- } else {
- /* use escape for wide character */
- char *e = wide_char_to_escape_string(wide_string[i]);
- strcat(buffer, e);
- free(e);
- }
- }
- if ((escape_string = (char *)malloc(strlen(buffer) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "wide_to_escape_string");
- }
- strcpy(escape_string, buffer);
- free(buffer);
- return escape_string;
- }
- /* convert local string to display character set string */
- char *local_to_display_string(local_string)
- char *local_string;
- {
- char *temp_string;
- char *display_string;
- /* For Windows, OEM string should never be bigger than ANSI string, says
- CharToOem description.
- On UNIX, non-printable characters (0x00 - 0xFF) will be replaced by
- "^x", so more space may be needed. Note that "^" itself is a valid
- name character, so this leaves an ambiguity, but UnZip displays
- names this way, too. (0x00 is not possible, I hope.)
- For all other ports, just make a copy of local_string.
- */
- #ifdef UNIX
- char *cp_dst; /* Character pointers used in the */
- char *cp_src; /* copying/changing procedure. */
- #endif
- if ((temp_string = (char *)malloc(2 * strlen(local_string) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "local_to_display_string");
- }
- #ifdef WIN32
- /* convert to OEM display character set */
- local_to_oem_string(temp_string, local_string);
- #else
- # ifdef UNIX
- /* Copy source string, expanding non-printable characters to "^x". */
- cp_dst = temp_string;
- cp_src = local_string;
- while (*cp_src != '\0') {
- if ((unsigned char)*cp_src < ' ') {
- *cp_dst++ = '^';
- *cp_dst++ = '@'+ *cp_src++;
- }
- else {
- *cp_dst++ = *cp_src++;
- }
- }
- *cp_dst = '\0';
- # else /* not UNIX */
- strcpy(temp_string, local_string);
- # endif /* UNIX */
- #endif
- #ifdef EBCDIC
- {
- char *ebc;
- if ((ebc = malloc(strlen(display_string) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "local_to_display_string");
- }
- strtoebc(ebc, display_string);
- free(display_string);
- display_string = ebc;
- }
- #endif
- if ((display_string = (char *)malloc(strlen(temp_string) + 1)) == NULL) {
- ZIPERR(ZE_MEM, "local_to_display_string");
- }
- strcpy(display_string, temp_string);
- free(temp_string);
- return display_string;
- }
- /* UTF-8 to local */
- char *utf8_to_local_string(utf8_string)
- char *utf8_string;
- {
- zwchar *wide_string = utf8_to_wide_string(utf8_string);
- char *loc = wide_to_local_string(wide_string);
- if (wide_string)
- free(wide_string);
- return loc;
- }
- /* UTF-8 to local */
- char *utf8_to_escape_string(utf8_string)
- char *utf8_string;
- {
- zwchar *wide_string = utf8_to_wide_string(utf8_string);
- char *escape_string = wide_to_escape_string(wide_string);
- free(wide_string);
- return escape_string;
- }
- #ifndef WIN32 /* The Win32 port uses a system-specific variant. */
- /* convert multi-byte character string to wide character string */
- zwchar *local_to_wide_string(local_string)
- char *local_string;
- {
- int wsize;
- wchar_t *wc_string;
- zwchar *wide_string;
- /* for now try to convert as string - fails if a bad char in string */
- wsize = mbstowcs(NULL, local_string, MB_CUR_MAX );
- if (wsize == (size_t)-1) {
- /* could not convert */
- return NULL;
- }
- /* convert it */
- if ((wc_string = (wchar_t *)malloc((wsize + 1) * sizeof(wchar_t))) == NULL) {
- ZIPERR(ZE_MEM, "local_to_wide_string");
- }
- wsize = mbstowcs(wc_string, local_string, strlen(local_string) + 1);
- wc_string[wsize] = (wchar_t) 0;
- /* in case wchar_t is not zwchar */
- if ((wide_string = (zwchar *)malloc((wsize + 1) * sizeof(zwchar))) == NULL) {
- ZIPERR(ZE_MEM, "local_to_wide_string");
- }
- for (wsize = 0; (wide_string[wsize] = (zwchar)wc_string[wsize]); wsize++) ;
- wide_string[wsize] = (zwchar)0;
- free(wc_string);
- return wide_string;
- }
- #endif /* !WIN32 */
- #if 0
- /* All wchar functions are only used by Windows and are
- now in win32zip.c so that the Windows functions can
- be used and multiple character wide characters can
- be handled easily. */
- # ifndef WIN32
- char *wchar_to_utf8_string(wstring)
- wchar_t *wstring;
- {
- zwchar *wide_string = wchar_to_wide_string(wstring);
- char *local_string = wide_to_utf8_string(wide_string);
- free(wide_string);
- return local_string;
- }
- # endif
- #endif
- /* convert wide string to UTF-8 */
- char *wide_to_utf8_string(wide_string)
- zwchar *wide_string;
- {
- int mbcount;
- char *utf8_string;
- /* get size of utf8 string */
- mbcount = ucs4_string_to_utf8(wide_string, NULL, 0);
- if (mbcount == -1)
- return NULL;
- if ((utf8_string = (char *) malloc(mbcount + 1)) == NULL) {
- ZIPERR(ZE_MEM, "wide_to_utf8_string");
- }
- mbcount = ucs4_string_to_utf8(wide_string, utf8_string, mbcount + 1);
- if (mbcount == -1)
- return NULL;
- return utf8_string;
- }
- /* convert UTF-8 string to wide string */
- zwchar *utf8_to_wide_string(utf8_string)
- char *utf8_string;
- {
- int wcount;
- zwchar *wide_string;
- wcount = utf8_to_ucs4_string(utf8_string, NULL, 0);
- if (wcount == -1)
- return NULL;
- if ((wide_string = (zwchar *) malloc((wcount + 2) * sizeof(zwchar))) == NULL) {
- ZIPERR(ZE_MEM, "utf8_to_wide_string");
- }
- wcount = utf8_to_ucs4_string(utf8_string, wide_string, wcount + 1);
- return wide_string;
- }
- #endif /* UNICODE_SUPPORT */
- /*---------------------------------------------------------------
- * Long option support
- * 8/23/2003
- *
- * Defines function get_option() to get and process the command
- * line options and arguments from argv[]. The caller calls
- * get_option() in a loop to get either one option and possible
- * value or a non-option argument each loop.
- *
- * This version does not include argument file support and can
- * work directly on argv. The argument file code complicates things and
- * it seemed best to leave it out for now. If argument file support (reading
- * in command line arguments stored in a file and inserting into
- * command line where @filename is found) is added later the arguments
- * can change and a freeable copy of argv will be needed and can be
- * created using copy_args in the left out code.
- *
- * Supports short and long options as defined in the array options[]
- * in zip.c, multiple short options in an argument (like -jlv), long
- * option abbreviation (like --te for --temp-file if --te unique),
- * short and long option values (like -b filename or --temp-file filename
- * or --temp-file=filename), optional and required values, option negation
- * by trailing - (like -S- to not include hidden and system files in MSDOS),
- * value lists (like -x a b c), argument permuting (returning all options
- * and values before any non-option arguments), and argument files (where any
- * non-option non-value argument in form @path gets substituted with the
- * white space separated arguments in the text file at path). In this
- * version argument file support has been removed to simplify development but
- * may be added later.
- *
- * E. Gordon
- */
- /* message output - char casts are needed to handle constants */
- #define oWARN(message) zipwarn((char *) message, "")
- #define oERR(err,message) ZIPERR(err, (char *) message)
- /* Although the below provides some support for multibyte characters
- the proper thing to do may be to use wide characters and support
- Unicode. May get to it soon. EG
- */
- /* For now stay with muti-byte characters. May support wide characters
- in Zip 3.1.
- */
- /* multibyte character set support
- Multibyte characters use typically two or more sequential bytes
- to represent additional characters than can fit in a single byte
- character set. The code used here is based on the ANSI mblen function. */
- #ifdef MULTIBYTE_GETOPTNS
- int mb_clen(ptr)
- ZCONST char *ptr;
- {
- /* return the number of bytes that the char pointed to is. Return 1 if
- null character or error like not start of valid multibyte character. */
- int cl;
- cl = mblen(ptr, MB_CUR_MAX);
- return (cl > 0) ? cl : 1;
- }
- #endif
- /* moved to zip.h */
- #if 0
- #ifdef UNICODE_SUPPORT
- # define MB_CLEN(ptr) (1)
- # define MB_NEXTCHAR(ptr) ((ptr)++)
- # ifdef MULTIBYTE_GETOPTNS
- # undef MULTIBYTE_GETOPTNS
- # endif
- #else
- # ifdef _MBCS
- # ifndef MULTIBYTE_GETOPTNS
- # define MULTIBYTE_GETOPTNS
- # endif
- # endif
- /* multibyte character set support
- Multibyte characters use typically two or more sequential bytes
- to represent additional characters than can fit in a single byte
- character set. The code used here is based on the ANSI mblen function. */
- # ifdef MULTIBYTE_GETOPTNS
- local int mb_clen OF((ZCONST char *)); /* declare proto first */
- local int mb_clen(ptr)
- ZCONST char *ptr;
- {
- /* return the number of bytes that the char pointed to is. Return 1 if
- null character or error like not start of valid multibyte character. */
- int cl;
- cl = mblen(ptr, MB_CUR_MAX);
- return (cl > 0) ? cl : 1;
- }
- # define MB_CLEN(ptr) mb_clen(ptr)
- # define MB_NEXTCHAR(ptr) ((ptr) += MB_CLEN(ptr))
- # else
- # define MB_CLEN(ptr) (1)
- # define MB_NEXTCHAR(ptr) ((ptr)++)
- # endif
- #endif
- #endif
- /* constants */
- /* function get_args_from_arg_file() can return this in depth parameter */
- #define ARG_FILE_ERR -1
- /* internal settings for optchar */
- #define SKIP_VALUE_ARG -1
- #define THIS_ARG_DONE -2
- #define START_VALUE_LIST -3
- #define IN_VALUE_LIST -4
- #define NON_OPTION_ARG -5
- #define STOP_VALUE_LIST -6
- /* 7/25/04 EG */
- #define READ_REST_ARGS_VERBATIM -7
- /* global veriables */
- int enable_permute = 1; /* yes - return options first */
- /* 7/25/04 EG */
- int doubledash_ends_options = 1; /* when -- what follows are not options */
- /* buffer for error messages (this sizing is a guess but must hold 2 paths) */
- #define OPTIONERR_BUF_SIZE (FNMAX * 2 + 4000)
- local char Far optionerrbuf[OPTIONERR_BUF_SIZE + 1];
- /* error messages */
- static ZCONST char Far op_not_neg_err[] = "option %s not negatable";
- static ZCONST char Far op_req_val_err[] = "option %s requires a value";
- static ZCONST char Far op_no_allow_val_err[] = "option %s does not allow a value";
- static ZCONST char Far sh_op_not_sup_err[] = "short option '%c' not supported";
- static ZCONST char Far oco_req_val_err[] = "option %s requires one character value";
- static ZCONST char Far oco_no_mbc_err[] = "option %s does not support multibyte values";
- static ZCONST char Far num_req_val_err[] = "option %s requires number value";
- static ZCONST char Far long_op_ambig_err[] = "long option '%s' ambiguous";
- static ZCONST char Far long_op_not_sup_err[] = "long option '%s' not supported";
- static ZCONST char Far no_arg_files_err[] = "argument files not enabled\n";
- /* below removed as only used for processing argument files */
- /* get_nextarg */
- /* get_args_from_string */
- /* insert_args */
- /* get_args_from_arg_file */
- /* copy error, option name, and option description if any to buf */
- local int optionerr(buf, err, optind, islong)
- char *buf;
- ZCONST char *err;
- int optind;
- int islong;
- {
- char optname[50];
- if (options[optind].name && options[optind].name[0] != '\0') {
- if (islong)
- sprintf(optname, "'%s' (%s)", options[optind].longopt, options[optind].name);
- else
- sprintf(optname, "'%s' (%s)", options[optind].shortopt, options[optind].name);
- } else {
- if (islong)
- sprintf(optname, "'%s'", options[optind].longopt);
- else
- sprintf(optname, "'%s'", options[optind].shortopt);
- }
- sprintf(buf, err, optname);
- return 0;
- }
- /* copy_args
- *
- * Copy arguments in args, allocating storage with malloc.
- * Copies until a NULL argument is found or until max_args args
- * including args[0] are copied. Set max_args to 0 to copy
- * until NULL. Always terminates returned args[] with NULL arg.
- *
- * Any argument in the returned args can be freed with free(). Any
- * freed argument should be replaced with either another string
- * allocated with malloc or by NULL if last argument so that free_args
- * will properly work.
- */
- char **copy_args(args, max_args)
- char **args;
- int max_args;
- {
- int j;
- char **new_args;
- if (args == NULL) {
- return NULL;
- }
- /* count args */
- for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) ;
- if ((new_args = (char **) malloc((j + 1) * sizeof(char *))) == NULL) {
- oERR(ZE_MEM, "ca");
- }
- for (j = 0; args[j] && (max_args == 0 || j < max_args); j++) {
- if (args[j] == NULL) {
- /* null argument is end of args */
- new_args[j] = NULL;
- break;
- }
- if ((new_args[j] = malloc(strlen(args[j]) + 1)) == NULL) {
- free_args(new_args);
- oERR(ZE_MEM, "ca");
- }
- strcpy(new_args[j], args[j]);
- }
- new_args[j] = NULL;
- return new_args;
- }
- /* free args - free args created with one of these functions */
- int free_args(args)
- char **args;
- {
- int i;
- if (args == NULL) {
- return 0;
- }
- for (i = 0; args[i]; i++) {
- free(args[i]);
- }
- free(args);
- return i;
- }
- /* insert_arg
- *
- * Insert the argument arg into the array args before argument at_arg.
- * Return the new count of arguments (argc).
- *
- * If free_args is true, this function frees the old args array
- * (but not the component strings). DO NOT set free_args on original
- * argv but only on args allocated with malloc.
- */
- int insert_arg(pargs, arg, at_arg, free_args)
- char ***pargs;
- ZCONST char *arg;
- int at_arg;
- int free_args;
- {
- char *newarg = NULL;
- char **args;
- char **newargs = NULL;
- int argnum;
- int newargnum;
- int argcnt;
- int newargcnt;
- if (pargs == NULL) {
- return 0;
- }
- args = *pargs;
- /* count args */
- if (args == NULL) {
- argcnt = 0;
- } else {
- for (argcnt = 0; args[argcnt]; argcnt++) ;
- }
- if (arg == NULL) {
- /* done */
- return argcnt;
- }
- newargcnt = argcnt + 1;
- /* get storage for new args */
- if ((newargs = (char **) malloc((newargcnt + 1) * sizeof(char *))) == NULL) {
- oERR(ZE_MEM, "ia");
- }
- /* copy argument pointers from args to position at_arg, copy arg, then rest args */
- argnum = 0;
- newargnum = 0;
- if (args) {
- for (; args[argnum] && argnum < at_arg; argnum++) {
- newargs[newargnum++] = args[argnum];
- }
- }
- /* copy new arg */
- if ((newarg = (char *) malloc(strlen(arg) + 1)) == NULL) {
- oERR(ZE_MEM, "ia");
- }
- strcpy(newarg, arg);
- newargs[newargnum++] = newarg;
- if (args) {
- for ( ; args[argnum]; argnum++) {
- newargs[newargnum++] = args[argnum];
- }
- }
- newargs[newargnum] = NULL;
- /* free old args array but not component strings - this assumes that
- args was allocated with malloc as copy_args does. DO NOT DO THIS
- on the original argv.
- */
- if (free_args)
- free(args);
- *pargs = newargs;
- return newargnum;
- }
- /* ------------------------------------- */
- /* get_shortopt
- *
- * Get next short option from arg. The state is stored in argnum, optchar, and
- * option_num so no static storage is used. Returns the option_ID.
- *
- * parameters:
- * args - argv array of arguments
- * argnum - index of current arg in args
- * optchar - pointer to index of next char to process. Can be 0 or
- * const defined at top of this file like THIS_ARG_DONE
- * negated - on return pointer to int set to 1 if option negated or 0 otherwise
- * value - on return pointer to string set to value of option if any or NULL
- * if none. If value is returned then the caller should free()
- * it when not needed anymore.
- * option_num - pointer to index in options[] of returned option or
- * o_NO_OPTION_MATCH if none. Do not change as used by
- * value lists.
- * depth - recursion depth (0 at top level, 1 or more in arg files)
- */
- local unsigned long get_shortopt(args, argnum, optchar, negated, value,
- option_num, depth)
- char **args;
- int argnum;
- int *optchar;
- int *negated;
- char **value;
- int *option_num;
- int depth;
- {
- char *shortopt;
- int clen;
- char *nextchar;
- char *s;
- char *start;
- int op;
- char *arg;
- int match = -1;
- /* get arg */
- arg = args[argnum];
- /* current char in arg */
- nextchar = arg + (*optchar);
- clen = MB_CLEN(nextchar);
- /* next char in arg */
- (*optchar) += clen;
- /* get first char of short option */
- shortopt = arg + (*optchar);
- /* no value */
- *value = NULL;
- if (*shortopt == '\0') {
- /* no more options in arg */
- *optchar = 0;
- *option_num = o_NO_OPTION_MATCH;
- return 0;
- }
- /* look for match in options */
- clen = MB_CLEN(shortopt);
- for (op = 0; options[op].option_ID; op++) {
- s = options[op].shortopt;
- if (s && s[0] == shortopt[0]) {
- if (s[1] == '\0' && clen == 1) {
- /* single char match */
- match = op;
- } else {
- /* 2 wide short opt. Could support more chars but should use long opts instead */
- if (s[1] == shortopt[1]) {
- /* match 2 char short opt or 2 byte char */
- match = op;
- if (clen == 1) (*optchar)++;
- break;
- }
- }
- }
- }
- if (match > -1) {
- /* match */
- clen = MB_CLEN(shortopt);
- nextchar = arg + (*optchar) + clen;
- /* check for trailing dash negating option */
- if (*nextchar == '-') {
- /* negated */
- if (options[match].negatable == o_NOT_NEGATABLE) {
- if (options[match].value_type == o_NO_VALUE) {
- optionerr(optionerrbuf, op_not_neg_err, match, 0);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- } else {
- *negated = 1;
- /* set up to skip negating dash */
- (*optchar) += clen;
- clen = 1;
- }
- }
- /* value */
- clen = MB_CLEN(arg + (*optchar));
- /* optional value, one char value, and number value must follow option */
- if (options[match].value_type == o_ONE_CHAR_VALUE) {
- /* one char value */
- if (arg[(*optchar) + clen]) {
- /* has value */
- if (MB_CLEN(arg + (*optchar) + clen) > 1) {
- /* multibyte value not allowed for now */
- optionerr(optionerrbuf, oco_no_mbc_err, match, 0);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- if ((*value = (char *) malloc(2)) == NULL) {
- oERR(ZE_MEM, "gso");
- }
- (*value)[0] = *(arg + (*optchar) + clen);
- (*value)[1] = '\0';
- *optchar += clen;
- clen = 1;
- } else {
- /* one char values require a value */
- optionerr(optionerrbuf, oco_req_val_err, match, 0);
- if (depth > 0) {
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- } else if (options[match].value_type == o_NUMBER_VALUE) {
- /* read chars until end of number */
- start = arg + (*optchar) + clen;
- if (*start == '+' || *start == '-') {
- start++;
- }
- s = start;
- for (; isdigit(*s); MB_NEXTCHAR(s)) ;
- if (s == start) {
- /* no digits */
- optionerr(optionerrbuf, num_req_val_err, match, 0);
- if (depth > 0) {
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- start = arg + (*optchar) + clen;
- if ((*value = (char *) malloc((int)(s - start) + 1)) == NULL) {
- oERR(ZE_MEM, "gso");
- }
- *optchar += (int)(s - start);
- strncpy(*value, start, (int)(s - start));
- (*value)[(int)(s - start)] = '\0';
- clen = MB_CLEN(s);
- } else if (options[match].value_type == o_OPTIONAL_VALUE) {
- /* optional value */
- /* This seemed inconsistent so now if no value attached to argument look
- to the next argument if that argument is not an option for option
- value - 11/12/04 EG */
- if (arg[(*optchar) + clen]) {
- /* has value */
- /* add support for optional = - 2/6/05 EG */
- if (arg[(*optchar) + clen] == '=') {
- /* skip = */
- clen++;
- }
- if (arg[(*optchar) + clen]) {
- if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
- == NULL) {
- oERR(ZE_MEM, "gso");
- }
- strcpy(*value, arg + (*optchar) + clen);
- }
- *optchar = THIS_ARG_DONE;
- } else if (args[argnum + 1] && args[argnum + 1][0] != '-') {
- /* use next arg for value */
- if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
- oERR(ZE_MEM, "gso");
- }
- /* using next arg as value */
- strcpy(*value, args[argnum + 1]);
- *optchar = SKIP_VALUE_ARG;
- }
- } else if (options[match].value_type == o_REQUIRED_VALUE ||
- options[match].value_type == o_VALUE_LIST) {
- /* see if follows option */
- if (arg[(*optchar) + clen]) {
- /* has value following option as -ovalue */
- /* add support for optional = - 6/5/05 EG */
- if (arg[(*optchar) + clen] == '=') {
- /* skip = */
- clen++;
- }
- if ((*value = (char *)malloc(strlen(arg + (*optchar) + clen) + 1))
- == NULL) {
- oERR(ZE_MEM, "gso");
- }
- strcpy(*value, arg + (*optchar) + clen);
- *optchar = THIS_ARG_DONE;
- } else {
- /* use next arg for value */
- if (args[argnum + 1]) {
- if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
- oERR(ZE_MEM, "gso");
- }
- strcpy(*value, args[argnum + 1]);
- if (options[match].value_type == o_VALUE_LIST) {
- *optchar = START_VALUE_LIST;
- } else {
- *optchar = SKIP_VALUE_ARG;
- }
- } else {
- /* no value found */
- optionerr(optionerrbuf, op_req_val_err, match, 0);
- if (depth > 0) {
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- }
- }
- *option_num = match;
- return options[match].option_ID;
- }
- sprintf(optionerrbuf, sh_op_not_sup_err, *shortopt);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- return 0;
- }
- /* get_longopt
- *
- * Get the long option in args array at argnum.
- * Parameters same as for get_shortopt.
- */
- local unsigned long get_longopt(args, argnum, optchar, negated, value,
- option_num, depth)
- char **args;
- int argnum;
- int *optchar;
- int *negated;
- char **value;
- int *option_num;
- int depth;
- {
- char *longopt;
- char *lastchr;
- char *valuestart;
- int op;
- char *arg;
- int match = -1;
- *value = NULL;
- if (args == NULL) {
- *option_num = o_NO_OPTION_MATCH;
- return 0;
- }
- if (args[argnum] == NULL) {
- *option_num = o_NO_OPTION_MATCH;
- return 0;
- }
- /* copy arg so can chop end if value */
- if ((arg = (char *)malloc(strlen(args[argnum]) + 1)) == NULL) {
- oERR(ZE_MEM, "glo");
- }
- strcpy(arg, args[argnum]);
- /* get option */
- longopt = arg + 2;
- /* no value */
- *value = NULL;
- /* find = */
- for (lastchr = longopt, valuestart = longopt;
- *valuestart && *valuestart != '=';
- lastchr = valuestart, MB_NEXTCHAR(valuestart)) ;
- if (*valuestart) {
- /* found =value */
- *valuestart = '\0';
- valuestart++;
- } else {
- valuestart = NULL;
- }
- if (*lastchr == '-') {
- /* option negated */
- *negated = 1;
- *lastchr = '\0';
- } else {
- *negated = 0;
- }
- /* look for long option match */
- for (op = 0; options[op].option_ID; op++) {
- if (options[op].longopt && strcmp(options[op].longopt, longopt) == 0) {
- /* exact match */
- match = op;
- break;
- }
- if (options[op].longopt && strncmp(options[op].longopt, longopt, strlen(longopt)) == 0) {
- if (match > -1) {
- sprintf(optionerrbuf, long_op_ambig_err, longopt);
- free(arg);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- match = op;
- }
- }
- if (match == -1) {
- sprintf(optionerrbuf, long_op_not_sup_err, longopt);
- free(arg);
- if (depth > 0) {
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- /* one long option an arg */
- *optchar = THIS_ARG_DONE;
- /* if negated then see if allowed */
- if (*negated && options[match].negatable == o_NOT_NEGATABLE) {
- optionerr(optionerrbuf, op_not_neg_err, match, 1);
- free(arg);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- /* get value */
- if (options[match].value_type == o_OPTIONAL_VALUE) {
- /* optional value in form option=value */
- if (valuestart) {
- /* option=value */
- if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
- free(arg);
- oERR(ZE_MEM, "glo");
- }
- strcpy(*value, valuestart);
- }
- } else if (options[match].value_type == o_REQUIRED_VALUE ||
- options[match].value_type == o_NUMBER_VALUE ||
- options[match].value_type == o_ONE_CHAR_VALUE ||
- options[match].value_type == o_VALUE_LIST) {
- /* handle long option one char and number value as required value */
- if (valuestart) {
- /* option=value */
- if ((*value = (char *)malloc(strlen(valuestart) + 1)) == NULL) {
- free(arg);
- oERR(ZE_MEM, "glo");
- }
- strcpy(*value, valuestart);
- } else {
- /* use next arg */
- if (args[argnum + 1]) {
- if ((*value = (char *)malloc(strlen(args[argnum + 1]) + 1)) == NULL) {
- free(arg);
- oERR(ZE_MEM, "glo");
- }
- /* using next arg as value */
- strcpy(*value, args[argnum + 1]);
- if (options[match].value_type == o_VALUE_LIST) {
- *optchar = START_VALUE_LIST;
- } else {
- *optchar = SKIP_VALUE_ARG;
- }
- } else {
- /* no value found */
- optionerr(optionerrbuf, op_req_val_err, match, 1);
- free(arg);
- if (depth > 0) {
- /* unwind */
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- }
- } else if (options[match].value_type == o_NO_VALUE) {
- /* this option does not accept a value */
- if (valuestart) {
- /* --option=value */
- optionerr(optionerrbuf, op_no_allow_val_err, match, 1);
- free(arg);
- if (depth > 0) {
- oWARN(optionerrbuf);
- return o_ARG_FILE_ERR;
- } else {
- oERR(ZE_PARMS, optionerrbuf);
- }
- }
- }
- free(arg);
- *option_num = match;
- return options[match].option_ID;
- }
- /* get_option
- *
- * Main interface for user. Use this function to get options, values and
- * non-option arguments from a command line provided in argv form.
- *
- * To use get_option() first define valid options by setting
- * the global variable options[] to an array of option_struct. Also
- * either change defaults below or make variables global and set elsewhere.
- * Zip uses below defaults.
- *
- * Call get_option() to get an option (like -b or --temp-file) and any
- * value for that option (like filename for -b) or a non-option argument
- * (like archive name) each call. If *value* is not NULL after calling
- * get_option() it is a returned value and the caller should either store
- * the char pointer or free() it before calling get_option() again to avoid
- * leaking memory. If a non-option non-value argument is returned get_option()
- * returns o_NON_OPTION_ARG and value is set to the entire argument.
- * When there are no more arguments get_option() returns 0.
- *
- * The parameters argnum (after set to 0 on initial call),
- * optchar, first_nonopt_arg, option_num, and depth (after initial
- * call) are set and maintained by get_option() and should not be
- * changed. The parameters argc, negated, and value are outputs and
- * can be used by the calling program. get_option() returns either the
- * option_ID for the current option, a special value defined in
- * zip.h, or 0 when no more arguments.
- *
- * The value returned by get_option() is the ID value in the options
- * table. This value can be duplicated in the table if different
- * options are really the same option. The index into the options[]
- * table is given by option_num, though the ID should be used as
- * option numbers change when the table is changed. The ID must
- * not be 0 for any option as this ends the table. If get_option()
- * finds an option not in the table it calls oERR to post an
- * error and exit. Errors also result if the option requires a
- * value that is missing, a value is present but the option does
- * not take one, and an option is negated but is not
- * negatable. Non-option arguments return o_NON_OPTION_ARG
- * with the entire argument in value.
- *
- * For Zip, permuting is on and all options and their values are
- * returned before any non-option arguments like archive name.
- *
- * The arguments "-" alone and "--" alone return as non-option arguments.
- * Note that "-" should not be used as part of a short option
- * entry in the table but can be used in the middle of long
- * options such as in the long option "a-long-option". Now "--" alone
- * stops option processing, returning any arguments following "--" as
- * non-option arguments instead of options.
- *
- * Argument file support is removed from this version. It may be added later.
- *
- * After each call:
- * argc is set to the current size of args[] but should not change
- * with argument file support removed,
- * argnum is the index of the current arg,
- * value is either the value of the returned option or non-option
- * argument or NULL if option with no value,
- * negated is set if the option was negated by a trailing dash (-)
- * option_num is set to either the index in options[] for the option or
- * o_NO_OPTION_MATCH if no match.
- * Negation is checked before the value is read if the option is negatable so
- * that the - is not included in the value. If the option is not negatable
- * but takes a value then the - will start the value. If permuting then
- * argnum and first_nonopt_arg are unreliable and should not be used.
- *
- * Command line is read from left to right. As get_option() finds non-option
- * arguments (arguments not starting with - and that are not values to options)
- * it moves later options and values in front of the non-option arguments.
- * This permuting is turned off by setting enable_permute to 0. Then
- * get_option() will return options and non-option arguments in the order
- * found. Currently permuting is only done after an argument is completely
- * processed so that any value can be moved with options they go with. All
- * state information is stored in the parameters argnum, optchar,
- * first_nonopt_arg and option_num. You should not change these after the
- * first call to get_option(). If you need to back up to a previous arg then
- * set argnum to that arg (remembering that args may have been permuted) and
- * set optchar = 0 and first_nonopt_arg to the first non-option argument if
- * permuting. After all arguments are returned the next call to get_option()
- * returns 0. The caller can then call free_args(args) if appropriate.
- *
- * get_option() accepts arguments in the following forms:
- * short options
- * of 1 and 2 characters, e.g. a, b, cc, d, and ba, after a single
- * leading -, as in -abccdba. In this example if 'b' is followed by 'a'
- * it matches short option 'ba' else it is interpreted as short option
- * b followed by another option. The character - is not legal as a
- * short option or as part of a 2 character short option.
- *
- * If a short option has a value it immediately follows the option or
- * if that option is the end of the arg then the next arg is used as
- * the value. So if short option e has a value, it can be given as
- * -evalue
- * or
- * -e value
- * and now
- * -e=value
- * but now that = is optional a leading = is stripped for the first.
- * This change allows optional short option values to be defaulted as
- * -e=
- * Either optional or required values can be specified. Optional values
- * now use both forms as ignoring the later got confusing. Any
- * non-value short options can preceed a valued short option as in
- * -abevalue
- * Some value types (one_char and number) allow options after the value
- * so if oc is an option that takes a character and n takes a number
- * then
- * -abocVccn42evalue
- * returns value V for oc and value 42 for n. All values are strings
- * so programs may have to convert the "42" to a number. See long
- * options below for how value lists are handled.
- *
- * Any short option can be negated by following it with -. Any - is
- * handled and skipped over before any value is read unless the option
- * is not negatable but takes a value and then - starts the value.
- *
- * If the value for an optional value is just =, then treated as no
- * value.
- *
- * long options
- * of arbitrary length are assumed if an arg starts with -- but is not
- * exactly --. Long options are given one per arg and can be abbreviated
- * if the abbreviation uniquely matches one of the long options.
- * Exact matches always match before partial matches. If ambiguous an
- * error is generated.
- *
- * Values are specified either in the form
- * --longoption=value
- * or can be the following arg if the value is required as in
- * --longoption value
- * Optional values to long options must be in the first form.
- *
- * Value lists are specified by o_VALUE_LIST and consist of an option
- * that takes a value followed by one or more value arguments.
- * The two forms are
- * --option=value
- * or
- * -ovalue
- * for a single value or
- * --option value1 value2 value3 ... --option2
- * or
- * -o value1 value2 value3 ...
- * for a list of values. The list ends at the next option, the
- * end of the command line, or at a single "@" argument.
- * Each value is treated as if it was preceeded by the option, so
- * --option1 val1 val2
- * with option1 value_type set to o_VALUE_LIST is the same as
- * --option1=val1 --option1=val2
- *
- * Long options can be negated by following the option with - as in
- * --longoption-
- * Long options with values can also be negated if this makes sense for
- * the caller as:
- * --longoption-=value
- * If = is not followed by anything it is treated as no value.
- *
- * @path
- * When an argument in the form @path is encountered, the file at path
- * is opened and white space separated arguments read from the file
- * and inserted into the command line at that point as if the contents
- * of the file were directly typed at that location. The file can
- * have options, files to zip, or anything appropriate at that location
- * in the command line. Since Zip has permuting enabled, options and
- * files will propagate to the appropriate locations in the command
- * line.
- *
- * Argument files support has been removed from this version. It may
- * be added back later.
- *
- * non-option argument
- * is any argument not given above. If enable_permute is 1 then
- * these are returned after all options, otherwise all options and
- * args are returned in order. Returns option ID o_NON_OPTION_ARG
- * and sets value to the argument.
- *
- *
- * Arguments to get_option:
- * char ***pargs - pointer to arg array in the argv form
- * int *argc - returns the current argc for args incl. args[0]
- * int *argnum - the index of the current argument (caller
- * should set = 0 on first call and not change
- * after that)
- * int *optchar - index of next short opt in arg or special
- * int *first_nonopt_arg - used by get_option to permute args
- * int *negated - option was negated (had trailing -)
- * char *value - value of option if any (free when done with it) or NULL
- * int *option_num - the index in options of the last option returned
- * (can be o_NO_OPTION_MATCH)
- * int recursion_depth - current depth of recursion
- * (always set to 0 by caller)
- * (always 0 with argument files support removed)
- *
- * Caller should only read the returned option ID and the value, negated,
- * and option_num (if required) parameters after each call.
- *
- * Ed Gordon
- * 24 August 2003 (last updated 2 April 2008 EG)
- *
- */
- unsigned long get_option(pargs, argc, argnum, optchar, value,
- negated, first_nonopt_arg, option_num, recursion_depth)
- char ***pargs;
- int *argc;
- int *argnum;
- int *optchar;
- char **value;
- int *negated;
- int *first_nonopt_arg;
- int *option_num;
- int recursion_depth;
- {
- char **args;
- unsigned long option_ID;
- int argcnt;
- int first_nonoption_arg;
- char *arg = NULL;
- int h;
- int optc;
- int argn;
- int j;
- int v;
- int read_rest_args_verbatim = 0; /* 7/25/04 - ignore options and arg files for rest args */
- /* value is outdated. The caller should free value before
- calling get_option again. */
- *value = NULL;
- /* if args is NULL then done */
- if (pargs == NULL) {
- *argc = 0;
- return 0;
- }
- args = *pargs;
- if (args == NULL) {
- *argc = 0;
- return 0;
- }
- /* count args */
- for (argcnt = 0; args[argcnt]; argcnt++) ;
- /* if no provided args then nothing to do */
- if (argcnt < 1 || (recursion_depth == 0 && argcnt < 2)) {
- *argc = argcnt;
- /* return 0 to note that no args are left */
- return 0;
- }
- *negated = 0;
- first_nonoption_arg = *first_nonopt_arg;
- argn = *argnum;
- optc = *optchar;
- if (optc == READ_REST_ARGS_VERBATIM) {
- read_rest_args_verbatim = 1;
- }
- if (argn == -1 || (recursion_depth == 0 && argn == 0)) {
- /* first call */
- /* if depth = 0 then args[0] is argv[0] so skip */
- *option_num = o_NO_OPTION_MATCH;
- optc = THIS_ARG_DONE;
- first_nonoption_arg = -1;
- }
- /* if option_num is set then restore last option_ID in case continuing value list */
- option_ID = 0;
- if (*option_num != o_NO_OPTION_MATCH) {
- option_ID = options[*option_num].option_ID;
- }
- /* get next option if any */
- for (;;) {
- if (read_rest_args_verbatim) {
- /* rest of args after "--" are non-option args if doubledash_ends_options set */
- argn++;
- if (argn > argcnt || args[argn] == NULL) {
- /* done */
- option_ID = 0;
- break;
- }
- arg = args[argn];
- if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, arg);
- *option_num = o_NO_OPTION_MATCH;
- option_ID = o_NON_OPTION_ARG;
- break;
- /* permute non-option args after option args so options are returned first */
- } else if (enable_permute) {
- if (optc == SKIP_VALUE_ARG || optc == THIS_ARG_DONE ||
- optc == START_VALUE_LIST || optc == IN_VALUE_LIST ||
- optc == STOP_VALUE_LIST) {
- /* moved to new arg */
- if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
- /* do the permuting - move non-options after this option */
- /* if option and value separate args or starting list skip option */
- if (optc == SKIP_VALUE_ARG || optc == START_VALUE_LIST) {
- v = 1;
- } else {
- v = 0;
- }
- for (h = first_nonoption_arg; h < argn; h++) {
- arg = args[first_nonoption_arg];
- for (j = first_nonoption_arg; j < argn + v; j++) {
- args[j] = args[j + 1];
- }
- args[j] = arg;
- }
- first_nonoption_arg += 1 + v;
- }
- }
- } else if (optc == NON_OPTION_ARG) {
- /* if not permuting then already returned arg */
- optc = THIS_ARG_DONE;
- }
- /* value lists */
- if (optc == STOP_VALUE_LIST) {
- optc = THIS_ARG_DONE;
- }
- if (optc == START_VALUE_LIST || optc == IN_VALUE_LIST) {
- if (optc == START_VALUE_LIST) {
- /* already returned first value */
- argn++;
- optc = IN_VALUE_LIST;
- }
- argn++;
- arg = args[argn];
- /* if end of args and still in list and there are non-option args then
- terminate list */
- if (arg == NULL && (optc == START_VALUE_LIST || optc == IN_VALUE_LIST)
- && first_nonoption_arg > -1) {
- /* terminate value list with @ */
- /* this is only needed for argument files */
- /* but is also good for show command line so command lines with lists
- can always be read back in */
- argcnt = insert_arg(&args, "@", first_nonoption_arg, 1);
- argn++;
- if (first_nonoption_arg > -1) {
- first_nonoption_arg++;
- }
- }
- arg = args[argn];
- if (arg && arg[0] == '@' && arg[1] == '\0') {
- /* inserted arguments terminator */
- optc = STOP_VALUE_LIST;
- continue;
- } else if (arg && arg[0] != '-') { /* not option */
- /* - and -- are not allowed in value lists unless escaped */
- /* another value in value list */
- if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, args[argn]);
- break;
- } else {
- argn--;
- optc = THIS_ARG_DONE;
- }
- }
- /* move to next arg */
- if (optc == SKIP_VALUE_ARG) {
- argn += 2;
- optc = 0;
- } else if (optc == THIS_ARG_DONE) {
- argn++;
- optc = 0;
- }
- if (argn > argcnt) {
- break;
- }
- if (args[argn] == NULL) {
- /* done unless permuting and non-option args */
- if (first_nonoption_arg > -1 && args[first_nonoption_arg]) {
- /* return non-option arguments at end */
- if (optc == NON_OPTION_ARG) {
- first_nonoption_arg++;
- }
- /* after first pass args are permuted but skipped over non-option args */
- /* swap so argn points to first non-option arg */
- j = argn;
- argn = first_nonoption_arg;
- first_nonoption_arg = j;
- }
- if (argn > argcnt || args[argn] == NULL) {
- /* done */
- option_ID = 0;
- break;
- }
- }
- /* after swap first_nonoption_arg points to end which is NULL */
- if (first_nonoption_arg > -1 && (args[first_nonoption_arg] == NULL)) {
- /* only non-option args left */
- if (optc == NON_OPTION_ARG) {
- argn++;
- }
- if (argn > argcnt || args[argn] == NULL) {
- /* done */
- option_ID = 0;
- break;
- }
- if ((*value = (char *)malloc(strlen(args[argn]) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, args[argn]);
- optc = NON_OPTION_ARG;
- option_ID = o_NON_OPTION_ARG;
- break;
- }
- arg = args[argn];
- /* is it an option */
- if (arg[0] == '-') {
- /* option */
- if (arg[1] == '\0') {
- /* arg = - */
- /* treat like non-option arg */
- *option_num = o_NO_OPTION_MATCH;
- if (enable_permute) {
- /* permute args to move all non-option args to end */
- if (first_nonoption_arg < 0) {
- first_nonoption_arg = argn;
- }
- argn++;
- } else {
- /* not permute args so return non-option args when found */
- if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, arg);
- optc = NON_OPTION_ARG;
- option_ID = o_NON_OPTION_ARG;
- break;
- }
- } else if (arg[1] == '-') {
- /* long option */
- if (arg[2] == '\0') {
- /* arg = -- */
- if (doubledash_ends_options) {
- /* Now -- stops permuting and forces the rest of
- the command line to be read verbatim - 7/25/04 EG */
- /* never permute args after -- and return as non-option args */
- if (first_nonoption_arg < 1) {
- /* -- is first non-option argument - 8/7/04 EG */
- argn--;
- } else {
- /* go back to start of non-option args - 8/7/04 EG */
- argn = first_nonoption_arg - 1;
- }
- /* disable permuting and treat remaining arguments as not
- options */
- read_rest_args_verbatim = 1;
- optc = READ_REST_ARGS_VERBATIM;
- } else {
- /* treat like non-option arg */
- *option_num = o_NO_OPTION_MATCH;
- if (enable_permute) {
- /* permute args to move all non-option args to end */
- if (first_nonoption_arg < 0) {
- first_nonoption_arg = argn;
- }
- argn++;
- } else {
- /* not permute args so return non-option args when found */
- if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, arg);
- optc = NON_OPTION_ARG;
- option_ID = o_NON_OPTION_ARG;
- break;
- }
- }
- } else {
- option_ID = get_longopt(args, argn, &optc, negated, value, option_num, recursion_depth);
- if (option_ID == o_ARG_FILE_ERR) {
- /* unwind as only get this if recursion_depth > 0 */
- return option_ID;
- }
- break;
- }
- } else {
- /* short option */
- option_ID = get_shortopt(args, argn, &optc, negated, value, option_num, recursion_depth);
- if (option_ID == o_ARG_FILE_ERR) {
- /* unwind as only get this if recursion_depth > 0 */
- return option_ID;
- }
- if (optc == 0) {
- /* if optc = 0 then ran out of short opts this arg */
- optc = THIS_ARG_DONE;
- } else {
- break;
- }
- }
- #if 0
- /* argument file code left out
- so for now let filenames start with @
- */
- } else if (allow_arg_files && arg[0] == '@') {
- /* arg file */
- oERR(ZE_PARMS, no_arg_files_err);
- #endif
- } else {
- /* non-option */
- if (enable_permute) {
- /* permute args to move all non-option args to end */
- if (first_nonoption_arg < 0) {
- first_nonoption_arg = argn;
- }
- argn++;
- } else {
- /* no permute args so return non-option args when found */
- if ((*value = (char *)malloc(strlen(arg) + 1)) == NULL) {
- oERR(ZE_MEM, "go");
- }
- strcpy(*value, arg);
- *option_num = o_NO_OPTION_MATCH;
- optc = NON_OPTION_ARG;
- option_ID = o_NON_OPTION_ARG;
- break;
- }
- }
- }
- *pargs = args;
- *argc = argcnt;
- *first_nonopt_arg = first_nonoption_arg;
- *argnum = argn;
- *optchar = optc;
- return option_ID;
- }
|