PageRenderTime 166ms CodeModel.GetById 29ms RepoModel.GetById 1ms app.codeStats 0ms

/old-mikmod/mikmod/examples/mikplay/getopt.c

https://bitbucket.org/shlomif/mikmod
C | 428 lines | 328 code | 69 blank | 31 comment | 99 complexity | a0e1d4818c15f3ceb5f9c200632d92ad MD5 | raw file
Possible License(s): LGPL-2.1, LGPL-2.0, GPL-2.0
  1. /*
  2. --> GetOpt : Grabs filenames and options from the command-line
  3. Gets options from the command-line, and I mean this is nice stuff!
  4. Long Filename Support: No! [but soon, I hope]
  5. */
  6. #include <string.h>
  7. #include <process.h>
  8. #include <errno.h>
  9. #include <dos.h>
  10. #ifdef DJGPP
  11. #include <dir.h>
  12. #define MAXNAME MAXPATH
  13. #define _MAX_FNAME MAXFILE
  14. #define _MAX_EXT MAXEXT
  15. #define _splitpath fnsplit
  16. #define _makepath fnmerge
  17. #endif
  18. #include "mmio.h"
  19. #include "mmgetopt.h"
  20. #define Numeric(x) (x>='0' && x<='9')
  21. #if defined(__WATCOMC__) && !defined(__CHAR_SIGNED__)
  22. #define AlphaNumeric(x) ((x != 32) && (x != 255) && (x != 0))
  23. #else
  24. #define AlphaNumeric(x) ((x != 32) && (x != -1) && (x != 0))
  25. #endif
  26. FILESTACK *filestack;
  27. unsigned int fcounter;
  28. int sortbydir = 1;
  29. static CHAR *ex_defdir, *ex_defmask;
  30. BOOL strcheck(CHAR *checker, CHAR *checkie)
  31. {
  32. int t;
  33. for(t=0; t<strlen(checker) && t<strlen(checkie); t++)
  34. if(checker[t] != checkie[t]) break;
  35. return(t==strlen(checker));
  36. }
  37. // max values taken from STDIO.H's __NT__ defines to support Win95 long
  38. // filenames.
  39. #ifdef __WATCOMC__
  40. #define MAXPATH 260
  41. #define MAXDRIVE 3
  42. #define MAXDIR 256
  43. #define MAXNAME 256
  44. #define MAXEXT 256
  45. #endif
  46. static CHAR *wildname = NULL, *path = NULL, *drive = NULL,
  47. *dir = NULL, *fname = NULL, *ext = NULL;
  48. static struct find_t ffblk;
  49. static BOOL (*cmpfunc)(CHAR *path1, CHAR *path2);
  50. // Finds the first file in a directory that corresponds to the wildcard
  51. // name 'wildname'.
  52. //
  53. // returns: ptr to full pathname or NULL if file couldn't be found
  54. static CHAR *GetFirstName(CHAR *wildname, int attrib)
  55. {
  56. _splitpath(wildname,drive,dir,fname,ext);
  57. if(!_dos_findfirst(wildname,attrib,&ffblk))
  58. { _splitpath(ffblk.name,NULL,NULL,fname,ext);
  59. _makepath(path,drive,dir,fname,ext);
  60. return path;
  61. }
  62. return NULL;
  63. }
  64. // Finds another file in a directory that corresponds to the wildcard
  65. // name of the GetFirstName call.
  66. // returns:
  67. // ptr to full pathname or NULL if file couldn't be found
  68. static CHAR *GetNextName(void)
  69. {
  70. if(!_dos_findnext(&ffblk))
  71. { _splitpath(ffblk.name,NULL,NULL,fname,ext);
  72. _makepath(path,drive,dir,ffblk.name,NULL);
  73. return path;
  74. }
  75. #ifndef DJGPP
  76. _dos_findclose(&ffblk);
  77. #endif
  78. return NULL;
  79. }
  80. static BOOL sort_byfull(CHAR *path1, CHAR *path2)
  81. // sort files using the FULL path of the file - so files will be sorted
  82. // by their directories as well as their names!
  83. {
  84. return(strcmp(path1,path2) <= 0);
  85. }
  86. static BOOL sort_byname(CHAR *path1, CHAR *path2)
  87. // Sort files by their name only - directories do NOT affect final order.
  88. {
  89. CHAR dname1[_MAX_FNAME],dname2[_MAX_FNAME],dext[_MAX_EXT];
  90. _splitpath(path1,NULL,NULL,dname1,dext);
  91. strcat(dname1,dext);
  92. _splitpath(path2,NULL,NULL,dname2,dext);
  93. strcat(dname2,dext);
  94. return(strcmp(dname1,dname2) <= 0);
  95. }
  96. BOOL ex_init(CHAR *defdir, CHAR *filemask, int sort)
  97. // Initializes the wildcard expander and configures the default assumptions
  98. // for the wildcard expander (MS-DOS systems only).
  99. // Returns 1 on error, _mm_error set
  100. // 0 if successful
  101. {
  102. path = (CHAR *)_mm_calloc(MAXPATH,1);
  103. drive = (CHAR *)_mm_calloc(MAXDRIVE,1);
  104. dir = (CHAR *)_mm_calloc(MAXDIR,1);
  105. fname = (CHAR *)_mm_calloc(MAXNAME,1);
  106. ext = (CHAR *)_mm_calloc(MAXEXT,1);
  107. if(ext == NULL) return 1;
  108. ex_defmask = filemask;
  109. ex_defdir = defdir;
  110. switch(sort)
  111. { case EX_FULLSORT: cmpfunc = sort_byfull; break;
  112. case EX_FILESORT: cmpfunc = sort_byname; break;
  113. }
  114. return 0;
  115. }
  116. void ex_exit(void)
  117. {
  118. if(path!=NULL) free(path);
  119. if(drive!=NULL) free(drive);
  120. if(dir!=NULL) free(dir);
  121. if(fname!=NULL) free(fname);
  122. if(ext!=NULL) free(ext);
  123. path = NULL;
  124. drive = NULL;
  125. dir = NULL;
  126. fname = NULL;
  127. ext = NULL;
  128. }
  129. // adds an item to the FILESTACK linked list -- items are added to the
  130. // start of the list faster that way :)
  131. static void TackOn(CHAR *path, ULONG size)
  132. {
  133. FILESTACK *work, *cruise, *ctmp;
  134. CHAR *doh;
  135. doh = strdup(path);
  136. work = (FILESTACK *)_mm_malloc(sizeof(FILESTACK));
  137. work->path = doh; work->size = size;
  138. work->prev = NULL; work->next = NULL;
  139. if((cruise=filestack) == NULL)
  140. { filestack = work; fcounter++;
  141. return;
  142. }
  143. while(cruise!=NULL)
  144. { if(cmpfunc(path,cruise->path)) break;
  145. ctmp = cruise;
  146. cruise = cruise->next;
  147. }
  148. // now add it to the linked list between cruise->prev and cruise
  149. work->next = cruise;
  150. if(cruise != NULL)
  151. { work->prev = cruise->prev;
  152. cruise->prev = work;
  153. } else
  154. work->prev = ctmp; //->prev;
  155. if(work->prev != NULL)
  156. work->prev->next = work;
  157. // If it's tacked on at the top of the list, reassign 'filestack'
  158. if(cruise==filestack) filestack=work;
  159. fcounter++;
  160. }
  161. // returns 0 if no files were found at all
  162. static BOOL ExpandFilename(CHAR *pattern)
  163. {
  164. CHAR *s;
  165. FILESTACK *temp,*cruise;
  166. if(sortbydir)
  167. { temp = filestack;
  168. filestack = NULL;
  169. }
  170. if(strpbrk(pattern,"*?")==NULL)
  171. { if((s=GetFirstName(pattern,0))==NULL)
  172. { // check it for special cases (null filename, etc)
  173. if(ex_defmask!=NULL && ex_defmask[0]!=NULL)
  174. { _makepath(wildname,NULL,pattern,ex_defmask,NULL);
  175. if((s=GetFirstName(wildname,0))==NULL) goto errorexit;
  176. if(strpbrk(ex_defmask,"*?")==NULL)
  177. TackOn(s,ffblk.size);
  178. else
  179. { do
  180. { TackOn(s,ffblk.size);
  181. } while((s=GetNextName()) != NULL);
  182. }
  183. }
  184. } else
  185. TackOn(s,ffblk.size);
  186. } else
  187. { if((s=GetFirstName(pattern,0)) == NULL) goto errorexit;
  188. do
  189. { TackOn(s,ffblk.size);
  190. } while((s=GetNextName()) != NULL);
  191. }
  192. if(sortbydir && ((cruise=temp)!=NULL))
  193. { while(cruise->next!=NULL)
  194. cruise = cruise->next;
  195. filestack->prev = cruise;
  196. cruise->next = filestack;
  197. filestack = temp;
  198. }
  199. return 1;
  200. errorexit:
  201. if(sortbydir)
  202. filestack = temp;
  203. return 0;
  204. }
  205. int nexpand(int argc, CHAR *argv[])
  206. {
  207. int i = 1, pos = 0, ln;
  208. CHAR *tmp;
  209. tmp = (CHAR *)_mm_malloc(256*sizeof(CHAR));
  210. while(i < argc)
  211. { if(argv[i][0] == 34) // 34 ASCII == Double Quote (")
  212. { ln = 0;
  213. while((argv[i][pos] != 34) && (ln < 255))
  214. { tmp[ln++] = argv[i][pos++];
  215. if(pos >= strlen(argv[i])) { pos = 0; i++; }
  216. }
  217. tmp[ln] = NULL;
  218. ExpandFilename(tmp);
  219. } else
  220. { ExpandFilename(argv[i]);
  221. i++;
  222. continue;
  223. }
  224. pos = 0;
  225. }
  226. free(tmp);
  227. return fcounter;
  228. }
  229. // returns the number of options grabbed from the list
  230. int ngetopt(CHAR *token, P_PARSE *parse, int argc, CHAR *argv[], void (*post)(int, P_VALUE *))
  231. {
  232. int i,s,tokenlen,pos,ln;
  233. CHAR *tmp;
  234. BOOL def = 1; // default search flag
  235. P_VALUE retval;
  236. if((token==NULL) || (parse==NULL) || (post==NULL))
  237. return nexpand(argc, argv);
  238. tmp = (CHAR *)_mm_malloc(256*sizeof(CHAR));
  239. tokenlen = strlen(token);
  240. pos = 0; i = 1;
  241. while(i < argc)
  242. { if(pos==0)
  243. { for(s=0; s<tokenlen; s++)
  244. if(argv[i][0] == token[s]) break;
  245. if(s == tokenlen) // not an option.. maybe a file, put it on the file stack
  246. { if(argv[i][0] == 34) // 34 ASCII == Double Quote (")
  247. { ln = 0;
  248. while((argv[i][pos] != 34) && (ln < 255))
  249. { tmp[ln++] = argv[i][pos++];
  250. if(pos >= strlen(argv[i])) { pos=0; i++; }
  251. }
  252. tmp[ln] = NULL;
  253. ExpandFilename(tmp);
  254. } else
  255. { ExpandFilename(argv[i]);
  256. }
  257. i++; def = 0; pos = 0;
  258. continue;
  259. }
  260. pos++;
  261. }
  262. if(parse==NULL)
  263. { pos = 0; i++;
  264. continue;
  265. }
  266. for(s=0; s<parse->num; s++)
  267. if(strcheck(parse->option[s].token, &argv[i][pos])) break;
  268. if(s == parse->num) { pos = 0; i++; continue; }
  269. pos += strlen(parse->option[s].token);
  270. switch(parse->option[s].type)
  271. { case P_BOOLEAN: // check next char for + / -
  272. if(strlen(argv[i]) > pos)
  273. switch(argv[i][pos])
  274. { case '+': retval.number = 1; post(s,&retval); pos++; break;
  275. case '-': retval.number = 0; post(s,&retval); pos++; break;
  276. default : retval.number = -1; post(s,&retval);
  277. }
  278. else retval.number = -1; post(s,&retval);
  279. break;
  280. case P_NUMVALUE: // check next char / next arg for a value
  281. if(strlen(argv[i]) > pos)
  282. { if(Numeric(argv[i][pos]))
  283. { ln = 0;
  284. while((strlen(argv[i]) > pos) && Numeric(argv[i][pos]))
  285. { tmp[ln] = argv[i][pos];
  286. ln++; pos++;
  287. }
  288. tmp[ln] = NULL;
  289. retval.number = atoi(tmp); post(s,&retval);
  290. } else
  291. { retval.number = 0;
  292. post(s,&retval);
  293. }
  294. } else
  295. { i++; pos = 0;
  296. if(Numeric(argv[i][pos]))
  297. { ln = 0;
  298. while((strlen(argv[i]) > pos) && Numeric(argv[i][pos]))
  299. { tmp[ln] = argv[i][pos];
  300. ln++; pos++;
  301. }
  302. tmp[ln] = NULL;
  303. retval.number = atoi(tmp); post(s,&retval);
  304. } else
  305. { retval.number = 0;
  306. post(s,&retval);
  307. }
  308. }
  309. break;
  310. case P_STRING: // Check for a string value
  311. if(strlen(argv[i]) > pos)
  312. { ln = 0;
  313. if(argv[i][pos] == 34) // check for a double quote(")
  314. { while(argv[i][pos] != 34 && ln < 255)
  315. { tmp[ln++] = argv[i][pos++];
  316. if(pos >= strlen(argv[i])) { pos=0; i++; }
  317. }
  318. tmp[ln] = NULL;
  319. } else if(AlphaNumeric(argv[i][pos]))
  320. { while((strlen(argv[i]) > pos) && AlphaNumeric(argv[i][pos]))
  321. tmp[ln++] = argv[i][pos++];
  322. tmp[ln] = NULL;
  323. retval.text = tmp; post(s,&retval);
  324. } else
  325. { retval.text = NULL;
  326. post(s,&retval);
  327. }
  328. } else
  329. { i++; pos=0; ln=0;
  330. if(argv[i][pos] == 34) // check for a double quote(")
  331. { while(argv[i][pos] != 34 && ln < 255)
  332. { tmp[ln++] = argv[i][pos++];
  333. if(pos >= strlen(argv[i])) { pos=0; i++; }
  334. }
  335. tmp[ln] = NULL;
  336. } else if(AlphaNumeric(argv[i][pos]))
  337. { while((strlen(argv[i]) > pos) && AlphaNumeric(argv[i][pos]))
  338. { tmp[ln] = argv[i][pos];
  339. ln++; pos++;
  340. }
  341. tmp[ln] = NULL;
  342. retval.text = tmp; post(s,&retval);
  343. } else
  344. { retval.text = NULL;
  345. post(s,&retval);
  346. }
  347. }
  348. break;
  349. }
  350. if(pos >= strlen(argv[i])) { pos=0; i++; }
  351. }
  352. // check if we perform a default directory search?
  353. if(def && ex_defdir!=NULL && ex_defdir[0]!=NULL)
  354. ExpandFilename(ex_defdir);
  355. free(tmp);
  356. return fcounter;
  357. }