usmart_str.c.bak 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438
  1. #include "usmart_str.h"
  2. #include "usmart.h"
  3. //////////////////////////////////////////////////////////////////////////////////
  4. //本程序只供内部使用,未经作者许可,不得用于其它任何用途
  5. // STM32开发板
  6. //版本:V3.3
  7. //版权所有,盗版必究。
  8. //Copyright(C) 正点原子 2011-2021
  9. //All rights reserved
  10. //********************************************************************************
  11. //升级说明
  12. //V1.4
  13. //增加了对参数为string类型的函数的支持.适用范围大大提高.
  14. //优化了内存占用,静态内存占用为79个字节@10个参数.动态适应数字及字符串长度
  15. //V2.0
  16. //1,修改了list指令,打印函数的完整表达式.
  17. //2,增加了id指令,打印每个函数的入口地址.
  18. //3,修改了参数匹配,支持函数参数的调用(输入入口地址).
  19. //4,增加了函数名长度宏定义.
  20. //V2.1 20110707
  21. //1,增加dec,hex两个指令,用于设置参数显示进制,及执行进制转换.
  22. //注:当dec,hex不带参数的时候,即设定显示参数进制.当后跟参数的时候,即执行进制转换.
  23. //如:"dec 0XFF" 则会将0XFF转为255,由串口返回.
  24. //如:"hex 100" 则会将100转为0X64,由串口返回
  25. //2,新增usmart_get_cmdname函数,用于获取指令名字.
  26. //V2.2 20110726
  27. //1,修正了void类型参数的参数统计错误.
  28. //2,修改数据显示格式默认为16进制.
  29. //V2.3 20110815
  30. //1,去掉了函数名后必须跟"("的限制.
  31. //2,修正了字符串参数中不能有"("的bug.
  32. //3,修改了函数默认显示参数格式的修改方式.
  33. //V2.4 20110905
  34. //1,修改了usmart_get_cmdname函数,增加最大参数长度限制.避免了输入错误参数时的死机现象.
  35. //2,增加USMART_ENTIM2_SCAN宏定义,用于配置是否使用TIM2定时执行scan函数.
  36. //V2.5 20110930
  37. //1,修改usmart_init函数为void usmart_init(u8 sysclk),可以根据系统频率自动设定扫描时间.(固定100ms)
  38. //2,去掉了usmart_init函数中的uart_init函数,串口初始化必须在外部初始化,方便用户自行管理.
  39. //V2.6 20111009
  40. //1,增加了read_addr和write_addr两个函数.可以利用这两个函数读写内部任意地址(必须是有效地址).更加方便调试.
  41. //2,read_addr和write_addr两个函数可以通过设置USMART_USE_WRFUNS为来使能和关闭.
  42. //3,修改了usmart_strcmp,使其规范化.
  43. //V2.7 20111024
  44. //1,修正了返回值16进制显示时不换行的bug.
  45. //2,增加了函数是否有返回值的判断,如果没有返回值,则不会显示.有返回值时才显示其返回值.
  46. //V2.8 20111116
  47. //1,修正了list等不带参数的指令发送后可能导致死机的bug.
  48. //V2.9 20120917
  49. //1,修改了形如:void*xxx(void)类型函数不能识别的bug。
  50. //V3.0 20130425
  51. //1,新增了字符串参数对转义符的支持。
  52. //V3.1 20131120
  53. //1,增加runtime系统指令,可以用于统计函数执行时间.
  54. //用法:
  55. //发送:runtime 1 ,则开启函数执行时间统计功能
  56. //发送:runtime 0 ,则关闭函数执行时间统计功能
  57. ///runtime统计功能,必须设置:USMART_ENTIMX_SCAN 为1,才可以使用!!
  58. //V3.2 20140828
  59. //1,修改usmart_get_aparm函数,加入+/-符号的支持
  60. //2,修改usmart_str2num函数,支持负数转换
  61. //V3.3 20160506
  62. //修正usmart_exe函数在USMART_ENTIMX_SCAN为0的时候,报错的bug
  63. /////////////////////////////////////////////////////////////////////////////////////
  64. //对比字符串str1和str2
  65. //*str1:字符串1指针
  66. //*str2:字符串2指针
  67. //返回值:0,相等;1,不相等;
  68. u8 usmart_strcmp(u8 *str1,u8 *str2)
  69. {
  70. while(1)
  71. {
  72. if(*str1!=*str2)return 1;//不相等
  73. if(*str1=='\0')break;//对比完成了.
  74. str1++;
  75. str2++;
  76. }
  77. return 0;//两个字符串相等
  78. }
  79. //把str1的内容copy到str2
  80. //*str1:字符串1指针
  81. //*str2:字符串2指针
  82. void usmart_strcopy(u8*str1,u8 *str2)
  83. {
  84. while(1)
  85. {
  86. *str2=*str1; //拷贝
  87. if(*str1=='\0')break;//拷贝完成了.
  88. str1++;
  89. str2++;
  90. }
  91. }
  92. //得到字符串的长度(字节)
  93. //*str:字符串指针
  94. //返回值:字符串的长度
  95. u8 usmart_strlen(u8*str)
  96. {
  97. u8 len=0;
  98. while(1)
  99. {
  100. if(*str=='\0')break;//拷贝完成了.
  101. len++;
  102. str++;
  103. }
  104. return len;
  105. }
  106. //m^n函数
  107. //返回值:m^n次方
  108. u32 usmart_pow(u8 m,u8 n)
  109. {
  110. u32 result=1;
  111. while(n--)result*=m;
  112. return result;
  113. }
  114. //把字符串转为数字
  115. //支持16进制转换,但是16进制字母必须是大写的,且格式为以0X开头的.
  116. //支持负数
  117. //*str:数字字符串指针
  118. //*res:转换完的结果存放地址.
  119. //返回值:0,成功转换完成.其他,错误代码.
  120. //1,数据格式错误.2,16进制位数为0.3,起始格式错误.4,十进制位数为0.
  121. u8 usmart_str2num(u8*str,u32 *res)
  122. {
  123. u32 t;
  124. int tnum;
  125. u8 bnum=0; //数字的位数
  126. u8 *p;
  127. u8 hexdec=10; //默认为十进制数据
  128. u8 flag=0; //0,没有符号标记;1,表示正数;2,表示负数.
  129. p=str;
  130. *res=0;//清零.
  131. while(1)
  132. {
  133. if((*p<='9'&&*p>='0')||((*str=='-'||*str=='+')&&bnum==0)||(*p<='F'&&*p>='A')||(*p=='X'&&bnum==1))//参数合法
  134. {
  135. if(*p>='A')hexdec=16; //字符串中存在字母,为16进制格式.
  136. if(*str=='-'){flag=2;str+=1;}//偏移掉符号
  137. else if(*str=='+'){flag=1;str+=1;}//偏移掉符号
  138. else bnum++; //位数增加.
  139. }else if(*p=='\0')break; //碰到结束符,退出.
  140. else return 1; //不全是十进制或者16进制数据.
  141. p++;
  142. }
  143. p=str; //重新定位到字符串开始的地址.
  144. if(hexdec==16) //16进制数据
  145. {
  146. if(bnum<3)return 2; //位数小于3,直接退出.因为0X就占了2个,如果0X后面不跟数据,则该数据非法.
  147. if(*p=='0' && (*(p+1)=='X'))//必须以'0X'开头.
  148. {
  149. p+=2; //偏移到数据起始地址.
  150. bnum-=2;//减去偏移量
  151. }else return 3;//起始头的格式不对
  152. }else if(bnum==0)return 4;//位数为0,直接退出.
  153. while(1)
  154. {
  155. if(bnum)bnum--;
  156. if(*p<='9'&&*p>='0')t=*p-'0'; //得到数字的值
  157. else t=*p-'A'+10; //得到A~F对应的值
  158. *res+=t*usmart_pow(hexdec,bnum);
  159. p++;
  160. if(*p=='\0')break;//数据都查完了.
  161. }
  162. if(flag==2)//是负数?
  163. {
  164. tnum=-*res;
  165. *res=tnum;
  166. }
  167. return 0;//成功转换
  168. }
  169. //得到指令名
  170. //*str:源字符串
  171. //*cmdname:指令名
  172. //*nlen:指令名长度
  173. //maxlen:最大长度(做限制,指令不可能太长的)
  174. //返回值:0,成功;其他,失败.
  175. u8 usmart_get_cmdname(u8*str,u8*cmdname,u8 *nlen,u8 maxlen)
  176. {
  177. *nlen=0;
  178. while(*str!=' '&&*str!='\0') //找到空格或者结束符则认为结束了
  179. {
  180. *cmdname=*str;
  181. str++;
  182. cmdname++;
  183. (*nlen)++;//统计命令长度
  184. if(*nlen>=maxlen)return 1;//错误的指令
  185. }
  186. *cmdname='\0';//加入结束符
  187. return 0;//正常返回
  188. }
  189. //获取下一个字符(当中间有很多空格的时候,此函数直接忽略空格,找到空格之后的第一个字符)
  190. //str:字符串指针
  191. //返回值:下一个字符
  192. u8 usmart_search_nextc(u8* str)
  193. {
  194. str++;
  195. while(*str==' '&&str!='\0')str++;
  196. return *str;
  197. }
  198. //从str中得到函数名
  199. //*str:源字符串指针
  200. //*fname:获取到的函数名字指针
  201. //*pnum:函数的参数个数
  202. //*rval:是否需要显示返回值(0,不需要;1,需要)
  203. //返回值:0,成功;其他,错误代码.
  204. u8 usmart_get_fname(u8*str,u8*fname,u8 *pnum,u8 *rval)
  205. {
  206. u8 res;
  207. u8 fover=0; //括号深度
  208. u8 *strtemp;
  209. u8 offset=0;
  210. u8 parmnum=0;
  211. u8 temp=1;
  212. u8 fpname[6];//void+X+'/0'
  213. u8 fplcnt=0; //第一个参数的长度计数器
  214. u8 pcnt=0; //参数计数器
  215. u8 nchar;
  216. //判断函数是否有返回值
  217. strtemp=str;
  218. while(*strtemp!='\0')//没有结束
  219. {
  220. if(*strtemp!=' '&&(pcnt&0X7F)<5)//最多记录5个字符
  221. {
  222. if(pcnt==0)pcnt|=0X80;//置位最高位,标记开始接收返回值类型
  223. if(((pcnt&0x7f)==4)&&(*strtemp!='*'))break;//最后一个字符,必须是*
  224. fpname[pcnt&0x7f]=*strtemp;//记录函数的返回值类型
  225. pcnt++;
  226. }else if(pcnt==0X85)break;
  227. strtemp++;
  228. }
  229. if(pcnt)//接收完了
  230. {
  231. fpname[pcnt&0x7f]='\0';//加入结束符
  232. if(usmart_strcmp(fpname,"void")==0)*rval=0;//不需要返回值
  233. else *rval=1; //需要返回值
  234. pcnt=0;
  235. }
  236. res=0;
  237. strtemp=str;
  238. while(*strtemp!='('&&*strtemp!='\0') //此代码找到函数名的真正起始位置
  239. {
  240. strtemp++;
  241. res++;
  242. if(*strtemp==' '||*strtemp=='*')
  243. {
  244. nchar=usmart_search_nextc(strtemp); //获取下一个字符
  245. if(nchar!='('&&nchar!='*')offset=res; //跳过空格和*号
  246. }
  247. }
  248. strtemp=str;
  249. if(offset)strtemp+=offset+1;//跳到函数名开始的地方
  250. res=0;
  251. nchar=0;//是否正在字符串里面的标志,0,不在字符串;1,在字符串;
  252. while(1)
  253. {
  254. if(*strtemp==0)
  255. {
  256. res=USMART_FUNCERR;//函数错误
  257. break;
  258. }else if(*strtemp=='('&&nchar==0)fover++;//括号深度增加一级
  259. else if(*strtemp==')'&&nchar==0)
  260. {
  261. if(fover)fover--;
  262. else res=USMART_FUNCERR;//错误结束,没收到'('
  263. if(fover==0)break;//到末尾了,退出
  264. }else if(*strtemp=='"')nchar=!nchar;
  265. if(fover==0)//函数名还没接收完
  266. {
  267. if(*strtemp!=' ')//空格不属于函数名
  268. {
  269. *fname=*strtemp;//得到函数名
  270. fname++;
  271. }
  272. }else //已经接受完了函数名了.
  273. {
  274. if(*strtemp==',')
  275. {
  276. temp=1; //使能增加一个参数
  277. pcnt++;
  278. }else if(*strtemp!=' '&&*strtemp!='(')
  279. {
  280. if(pcnt==0&&fplcnt<5) //当第一个参数来时,为了避免统计void类型的参数,必须做判断.
  281. {
  282. fpname[fplcnt]=*strtemp;//记录参数特征.
  283. fplcnt++;
  284. }
  285. temp++; //得到有效参数(非空格)
  286. }
  287. if(fover==1&&temp==2)
  288. {
  289. temp++; //防止重复增加
  290. parmnum++; //参数增加一个
  291. }
  292. }
  293. strtemp++;
  294. }
  295. if(parmnum==1)//只有1个参数.
  296. {
  297. fpname[fplcnt]='\0';//加入结束符
  298. if(usmart_strcmp(fpname,"void")==0)parmnum=0;//参数为void,表示没有参数.
  299. }
  300. *pnum=parmnum; //记录参数个数
  301. *fname='\0'; //加入结束符
  302. return res; //返回执行结果
  303. }
  304. //从str中得到一个函数的参数
  305. //*str:源字符串指针
  306. //*fparm:参数字符串指针
  307. //*ptype:参数类型 0,数字;1,字符串;0XFF,参数错误
  308. //返回值:0,已经无参数了;其他,下一个参数的偏移量.
  309. u8 usmart_get_aparm(u8 *str,u8 *fparm,u8 *ptype)
  310. {
  311. u8 i=0;
  312. u8 enout=0;
  313. u8 type=0;//默认是数字
  314. u8 string=0; //标记str是否正在读
  315. while(1)
  316. {
  317. if(*str==','&& string==0)enout=1; //暂缓立即退出,目的是寻找下一个参数的起始地址
  318. if((*str==')'||*str=='\0')&&string==0)break;//立即退出标识符
  319. if(type==0)//默认是数字的
  320. {
  321. if((*str>='0' && *str<='9')||*str=='-'||*str=='+'||(*str>='a' && *str<='f')||(*str>='A' && *str<='F')||*str=='X'||*str=='x')//数字串检测
  322. {
  323. if(enout)break; //找到了下一个参数,直接退出.
  324. if(*str>='a')*fparm=*str-0X20; //小写转换为大写
  325. else *fparm=*str; //小写或者数字保持不变
  326. fparm++;
  327. }else if(*str=='"')//找到字符串的开始标志
  328. {
  329. if(enout)break;//找到,后才找到",认为结束了.
  330. type=1;
  331. string=1;//登记STRING 正在读了
  332. }else if(*str!=' '&&*str!=',')//发现非法字符,参数错误
  333. {
  334. type=0XFF;
  335. break;
  336. }
  337. }else//string类
  338. {
  339. if(*str=='"')string=0;
  340. if(enout)break; //找到了下一个参数,直接退出.
  341. if(string) //字符串正在读
  342. {
  343. if(*str=='\\') //遇到转义符(不复制转义符)
  344. {
  345. str++; //偏移到转义符后面的字符,不管什么字符,直接COPY
  346. i++;
  347. }
  348. *fparm=*str; //小写或者数字保持不变
  349. fparm++;
  350. }
  351. }
  352. i++;//偏移量增加
  353. str++;
  354. }
  355. *fparm='\0'; //加入结束符
  356. *ptype=type; //返回参数类型
  357. return i; //返回参数长度
  358. }
  359. //得到指定参数的起始地址
  360. //num:第num个参数,范围0~9.
  361. //返回值:该参数的起始地址
  362. u8 usmart_get_parmpos(u8 num)
  363. {
  364. u8 temp=0;
  365. u8 i;
  366. for(i=0;i<num;i++)temp+=usmart_dev.plentbl[i];
  367. return temp;
  368. }
  369. //从str中得到函数参数
  370. //str:源字符串;
  371. //parn:参数的多少.0表示无参数 void类型
  372. //返回值:0,成功;其他,错误代码.
  373. u8 usmart_get_fparam(u8*str,u8 *parn)
  374. {
  375. u8 i,type;
  376. u32 res;
  377. u8 n=0;
  378. u8 len;
  379. u8 tstr[PARM_LEN+1];//字节长度的缓存,最多可以存放PARM_LEN个字符的字符串
  380. for(i=0;i<MAX_PARM;i++)usmart_dev.plentbl[i]=0;//清空参数长度表
  381. while(*str!='(')//偏移到参数开始的地方
  382. {
  383. str++;
  384. if(*str=='\0')return USMART_FUNCERR;//遇到结束符了
  385. }
  386. str++;//偏移到"("之后的第一个字节
  387. while(1)
  388. {
  389. i=usmart_get_aparm(str,tstr,&type); //得到第一个参数
  390. str+=i; //偏移
  391. switch(type)
  392. {
  393. case 0: //数字
  394. if(tstr[0]!='\0') //接收到的参数有效
  395. {
  396. i=usmart_str2num(tstr,&res); //记录该参数
  397. if(i)return USMART_PARMERR; //参数错误.
  398. *(u32*)(usmart_dev.parm+usmart_get_parmpos(n))=res;//记录转换成功的结果.
  399. usmart_dev.parmtype&=~(1<<n); //标记数字
  400. usmart_dev.plentbl[n]=4; //该参数的长度为4
  401. n++; //参数增加
  402. if(n>MAX_PARM)return USMART_PARMOVER;//参数太多
  403. }
  404. break;
  405. case 1://字符串
  406. len=usmart_strlen(tstr)+1; //包含了结束符'\0'
  407. usmart_strcopy(tstr,&usmart_dev.parm[usmart_get_parmpos(n)]);//拷贝tstr数据到usmart_dev.parm[n]
  408. usmart_dev.parmtype|=1<<n; //标记字符串
  409. usmart_dev.plentbl[n]=len; //该参数的长度为len
  410. n++;
  411. if(n>MAX_PARM)return USMART_PARMOVER;//参数太多
  412. break;
  413. case 0XFF://错误
  414. return USMART_PARMERR;//参数错误
  415. }
  416. if(*str==')'||*str=='\0')break;//查到结束标志了.
  417. }
  418. *parn=n; //记录参数的个数
  419. return USMART_OK;//正确得到了参数
  420. }